import { Button } from "$components/Button"; import { ChevronRightIcon, IconProps, type IconSize } from "$icons"; import type { CSSProperties, MouseEventHandler, Ref } from "react"; import { forwardRef, useCallback, useMemo } from "react"; type IconMemo = { Component: React.ComponentType; size: IconSize }; type TreeItemProps = { icon: IconMemo; label: string; isSelected?: boolean; isExpanded?: boolean; hasChildItems?: boolean; level?: number; onClick?: () => void; onToggle?: () => void; onContextMenu?: MouseEventHandler; children?: React.ReactNode; isDragging?: boolean; isDropTarget?: boolean; }; function TreeItemComponent( { icon, label, isSelected = false, isExpanded = false, hasChildItems = false, level = 0, onClick, onToggle, onContextMenu, children, isDragging = false, isDropTarget = false, }: TreeItemProps, ref: Ref, ) { const paddingLeft = level * 16 + 12; const handleButtonClick: MouseEventHandler = useCallback((e) => { e.stopPropagation(); onToggle?.(); }, [onToggle]); const containerStyle: CSSProperties = useMemo( () => ({ paddingLeft: `${paddingLeft}px`, paddingRight: "8px", paddingTop: "6px", paddingBottom: "6px" }), [paddingLeft], ); const containerClasses = useMemo(() => { const base = [ "sidebar-item group flex items-center gap-2", "cursor-pointer rounded mx-2 text-[0.8125rem]", isSelected ? "sidebar-item--selected" : "sidebar-item--unselected", isDragging || isDropTarget ? "" : "transition-colors duration-150", ]; if (isDragging) { base.push("opacity-30"); } if (isDropTarget) { base.push("ring-2 ring-stroke-interactive !bg-layer-hover-01 text-text-primary sidebar-drop-pulse"); } if (isSelected) { base.push("bg-layer-accent-01 text-text-primary border-l-2 border-accent-blue"); } else { base.push("bg-transparent text-text-secondary"); } return base.join(" "); }, [isSelected, isDragging, isDropTarget]); const buttonStyle: CSSProperties = useMemo(() => ({ transform: isExpanded ? "rotate(90deg)" : "rotate(0deg)" }), [ isExpanded, ]); const labelStyle: CSSProperties = useMemo(() => ({ fontWeight: isSelected ? 500 : 400 }), [isSelected]); return (
{hasChildItems ? ( ) : } {label} {children}
); } export const TreeItem = forwardRef(TreeItemComponent);