"use client"; import * as React from "react"; import { StackSimpleIcon } from "@phosphor-icons/react"; import { Button, ScrollFade } from "@repo/ui"; import { Eye, EyeOff, Trash2 } from "lucide-react"; import type { ToolcraftLayer } from "../../state/types"; import { getLayerDisplayName, isGroupLayer, layerDepthIndentPx, type LayerDropPlacement, } from "./layers-panel-model"; type LayerRowProps = { depth: number; hasMedia: boolean; insertIndicatorDepth?: number; insertPlacement?: LayerDropPlacement; isDragging: boolean; isDropTarget: boolean; isGroupDropAvailable: boolean; isGroupHighlighted: boolean; isReorderDragging: boolean; isSelected: boolean; isVisible: boolean; layer: ToolcraftLayer; onDelete: () => void; onPointerCancel: React.PointerEventHandler; onPointerDown: React.PointerEventHandler; onPointerMove: React.PointerEventHandler; onPointerUp: React.PointerEventHandler; onRename: (displayName: string) => void; onSelect: () => void; onToggleCollapsed: () => void; onToggleVisibility: () => void; }; const selectedLayerSurfaceClassName = "bg-[color:color-mix(in_oklab,var(--accent)_20%,transparent)]"; const hoveredLayerSurfaceClassName = "hover:bg-[color:color-mix(in_oklab,var(--foreground)_10%,transparent)]"; function cn(...classNames: Array): string { return classNames.filter(Boolean).join(" "); } function LayerNameEditor({ displayName, draftName, onCancel, onCommit, onDraftNameChange, }: { displayName: string; draftName: string; onCancel: () => void; onCommit: () => void; onDraftNameChange: (value: string) => void; }): React.JSX.Element { const inputRef = React.useRef(null); React.useEffect(() => { const input = inputRef.current; if (!input) { return; } input.focus(); input.select(); }, []); return (
onDraftNameChange(event.currentTarget.value)} onClick={(event) => event.stopPropagation()} onKeyDown={(event) => { if (event.key === "Enter") { event.preventDefault(); onCommit(); } if (event.key === "Escape") { event.preventDefault(); onCancel(); } }} onPointerDown={(event) => event.stopPropagation()} ref={inputRef} value={draftName} />
); } function LayerNameContent({ displayName, isVisible, }: { displayName: string; isVisible: boolean; }): React.JSX.Element { return (
{displayName}
); } function LayerRowIcon({ collapsed, displayName, hasMedia, isGroup, isVisible, onToggleCollapsed, }: { collapsed?: boolean; displayName: string; hasMedia: boolean; isGroup: boolean; isVisible: boolean; onToggleCollapsed?: () => void; }): React.JSX.Element { const iconClassName = cn( "size-3 shrink-0 text-[color:var(--foreground)] transition-opacity duration-150 ease-out", isVisible ? "opacity-60" : "opacity-30", ); return ( ); } function LayerActionButtons({ displayName, isEditingName, isDragging, isReorderDragging, isVisible, layer, onDelete, onToggleVisibility, }: { displayName: string; isEditingName: boolean; isDragging: boolean; isReorderDragging: boolean; isVisible: boolean; layer: ToolcraftLayer; onDelete: () => void; onToggleVisibility: () => void; }): React.JSX.Element | null { if (isEditingName) { return null; } const mutedIconStyle = isVisible ? undefined : { opacity: 0.3 }; return (
); } function useLayerNameEditing({ displayName, onRename, }: { displayName: string; onRename: (displayName: string) => void; }) { const [isEditingName, setIsEditingName] = React.useState(false); const [draftName, setDraftName] = React.useState(displayName); const skipNextBlurCommitRef = React.useRef(false); const startEditingName = (): void => { setDraftName(displayName); setIsEditingName(true); }; const commitEditingName = (): void => { if (skipNextBlurCommitRef.current) { skipNextBlurCommitRef.current = false; return; } const nextDisplayName = draftName.trim().replace(/\s+/g, " "); if (nextDisplayName && nextDisplayName !== displayName) { onRename(nextDisplayName); } setIsEditingName(false); }; const cancelEditingName = (): void => { skipNextBlurCommitRef.current = true; setDraftName(displayName); setIsEditingName(false); }; return { cancelEditingName, commitEditingName, draftName, isEditingName, setDraftName, startEditingName, }; } export function LayerRow({ depth, hasMedia, insertIndicatorDepth, insertPlacement, isDragging, isDropTarget, isGroupDropAvailable, isGroupHighlighted, isReorderDragging, isSelected, isVisible, layer, onDelete, onPointerCancel, onPointerDown, onPointerMove, onPointerUp, onRename, onSelect, onToggleCollapsed, onToggleVisibility, }: LayerRowProps): React.JSX.Element { const displayName = getLayerDisplayName(layer); const isGroup = isGroupLayer(layer); const nameEditing = useLayerNameEditing({ displayName, onRename }); return (
  • { event.preventDefault(); nameEditing.startEditingName(); }} onKeyDown={(event) => { if ( nameEditing.isEditingName || !(event.key === "Enter" || event.key === " ") || (event.target instanceof Element && event.target.closest("button,input,select,textarea")) ) { return; } event.preventDefault(); onSelect(); }} onPointerCancel={onPointerCancel} onPointerDown={onPointerDown} onPointerMove={onPointerMove} onPointerUp={onPointerUp} role="option" tabIndex={0} > {insertPlacement ? (
  • ); }