Files
kandev/apps/web/components/task/chat/messages/expandable-row.tsx
T

73 lines
2.3 KiB
TypeScript

"use client";
import { ReactNode, memo, useCallback } from "react";
import { IconChevronDown, IconChevronRight } from "@tabler/icons-react";
import { cn } from "@/lib/utils";
type ExpandableRowProps = {
/** The icon to display (will transition to chevron on hover when expandable) */
icon: ReactNode;
/** Header content displayed next to the icon */
header: ReactNode;
/** Whether there is expandable content */
hasExpandableContent: boolean;
/** Current expanded state */
isExpanded: boolean;
/** Callback when toggled */
onToggle: () => void;
/** Expanded content (rendered outside clickable area) */
children?: ReactNode;
};
export const ExpandableRow = memo(function ExpandableRow({
icon,
header,
hasExpandableContent,
isExpanded,
onToggle,
children,
}: ExpandableRowProps) {
const handleClick = useCallback(() => {
if (hasExpandableContent) onToggle();
}, [hasExpandableContent, onToggle]);
return (
<div className="w-full group/expandable">
{/* Clickable header row */}
<div
className={cn(
"flex items-center gap-3 w-full rounded px-2 py-1 -mx-2 transition-colors",
hasExpandableContent && "hover:bg-muted/50 cursor-pointer",
)}
onClick={handleClick}
>
{/* Icon with hover-to-show chevron */}
<div className="flex-shrink-0 relative w-4 h-4">
<div
className={cn(
"absolute inset-0 transition-opacity",
hasExpandableContent && "group-hover/expandable:opacity-0",
)}
>
{icon}
</div>
{hasExpandableContent &&
(isExpanded ? (
<IconChevronDown className="h-4 w-4 text-muted-foreground absolute inset-0 opacity-0 group-hover/expandable:opacity-100 transition-opacity" />
) : (
<IconChevronRight className="h-4 w-4 text-muted-foreground absolute inset-0 opacity-0 group-hover/expandable:opacity-100 transition-opacity" />
))}
</div>
{/* Header content */}
<div className="flex-1 min-w-0">{header}</div>
</div>
{/* Expanded content - outside clickable area */}
{isExpanded && hasExpandableContent && children && (
<div className="mt-2 ml-7">{children}</div>
)}
</div>
);
});