{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "comp-575",
  "type": "registry:component",
  "title": "Comp 575",
  "description": "Comp 575",
  "files": [
    {
      "path": "registry/ui-basic/comp-575.tsx",
      "content": "\"use client\";\r\n\r\nimport React, { useState } from \"react\";\r\n\r\nimport { Tree, TreeItem, TreeItemLabel } from \"@/components/ui/tree\";\r\nimport {\r\n\tcreateOnDropHandler,\r\n\tdragAndDropFeature,\r\n\thotkeysCoreFeature,\r\n\tkeyboardDragAndDropFeature,\r\n\tselectionFeature,\r\n\tsyncDataLoaderFeature,\r\n} from \"@headless-tree/core\";\r\nimport { AssistiveTreeDescription, useTree } from \"@headless-tree/react\";\r\nimport {\r\n\tRiBracesLine,\r\n\tRiCodeSSlashLine,\r\n\tRiFileLine,\r\n\tRiFileTextLine,\r\n\tRiImageLine,\r\n\tRiReactjsLine,\r\n} from \"@remixicon/react\";\r\n\r\ninterface Item {\r\n\tname: string;\r\n\tchildren?: string[];\r\n\tfileExtension?: string;\r\n}\r\n\r\nconst initialItems: Record<string, Item> = {\r\n\tapp: {\r\n\t\tname: \"app\",\r\n\t\tchildren: [\r\n\t\t\t\"app/layout.tsx\",\r\n\t\t\t\"app/page.tsx\",\r\n\t\t\t\"app/(dashboard)\",\r\n\t\t\t\"app/api\",\r\n\t\t],\r\n\t},\r\n\t\"app/layout.tsx\": { name: \"layout.tsx\", fileExtension: \"tsx\" },\r\n\t\"app/page.tsx\": { name: \"page.tsx\", fileExtension: \"tsx\" },\r\n\t\"app/(dashboard)\": {\r\n\t\tname: \"(dashboard)\",\r\n\t\tchildren: [\"app/(dashboard)/dashboard\"],\r\n\t},\r\n\t\"app/(dashboard)/dashboard\": {\r\n\t\tname: \"dashboard\",\r\n\t\tchildren: [\"app/(dashboard)/dashboard/page.tsx\"],\r\n\t},\r\n\t\"app/(dashboard)/dashboard/page.tsx\": {\r\n\t\tname: \"page.tsx\",\r\n\t\tfileExtension: \"tsx\",\r\n\t},\r\n\t\"app/api\": { name: \"api\", children: [\"app/api/hello\"] },\r\n\t\"app/api/hello\": { name: \"hello\", children: [\"app/api/hello/route.ts\"] },\r\n\t\"app/api/hello/route.ts\": { name: \"route.ts\", fileExtension: \"ts\" },\r\n\tcomponents: {\r\n\t\tname: \"components\",\r\n\t\tchildren: [\"components/button.tsx\", \"components/card.tsx\"],\r\n\t},\r\n\t\"components/button.tsx\": { name: \"button.tsx\", fileExtension: \"tsx\" },\r\n\t\"components/card.tsx\": { name: \"card.tsx\", fileExtension: \"tsx\" },\r\n\tlib: { name: \"lib\", children: [\"lib/utils.ts\"] },\r\n\t\"lib/utils.ts\": { name: \"utils.ts\", fileExtension: \"ts\" },\r\n\tpublic: {\r\n\t\tname: \"public\",\r\n\t\tchildren: [\"public/favicon.ico\", \"public/vercel.svg\"],\r\n\t},\r\n\t\"public/favicon.ico\": { name: \"favicon.ico\", fileExtension: \"ico\" },\r\n\t\"public/vercel.svg\": { name: \"vercel.svg\", fileExtension: \"svg\" },\r\n\t\"package.json\": { name: \"package.json\", fileExtension: \"json\" },\r\n\t\"tailwind.config.ts\": { name: \"tailwind.config.ts\", fileExtension: \"ts\" },\r\n\t\"tsconfig.json\": { name: \"tsconfig.json\", fileExtension: \"json\" },\r\n\t\"next.config.mjs\": { name: \"next.config.mjs\", fileExtension: \"mjs\" },\r\n\t\"README.md\": { name: \"README.md\", fileExtension: \"md\" },\r\n\troot: {\r\n\t\tname: \"Project Root\",\r\n\t\tchildren: [\r\n\t\t\t\"app\",\r\n\t\t\t\"components\",\r\n\t\t\t\"lib\",\r\n\t\t\t\"public\",\r\n\t\t\t\"package.json\",\r\n\t\t\t\"tailwind.config.ts\",\r\n\t\t\t\"tsconfig.json\",\r\n\t\t\t\"next.config.mjs\",\r\n\t\t\t\"README.md\",\r\n\t\t],\r\n\t},\r\n};\r\n\r\n// Helper function to get icon based on file extension\r\nfunction getFileIcon(extension: string | undefined, className: string) {\r\n\tswitch (extension) {\r\n\t\tcase \"tsx\":\r\n\t\tcase \"jsx\":\r\n\t\t\treturn <RiReactjsLine className={className} />;\r\n\t\tcase \"ts\":\r\n\t\tcase \"js\":\r\n\t\tcase \"mjs\":\r\n\t\t\treturn <RiCodeSSlashLine className={className} />;\r\n\t\tcase \"json\":\r\n\t\t\treturn <RiBracesLine className={className} />;\r\n\t\tcase \"svg\":\r\n\t\tcase \"ico\":\r\n\t\tcase \"png\":\r\n\t\tcase \"jpg\":\r\n\t\t\treturn <RiImageLine className={className} />;\r\n\t\tcase \"md\":\r\n\t\t\treturn <RiFileTextLine className={className} />;\r\n\t\tdefault:\r\n\t\t\treturn <RiFileLine className={className} />;\r\n\t}\r\n}\r\n\r\nconst indent = 20;\r\n\r\nexport default function Component() {\r\n\tconst [items, setItems] = useState(initialItems);\r\n\r\n\tconst tree = useTree<Item>({\r\n\t\tinitialState: {\r\n\t\t\texpandedItems: [\"app\", \"app/(dashboard)\", \"app/(dashboard)/dashboard\"],\r\n\t\t\tselectedItems: [\"components\"],\r\n\t\t},\r\n\t\tindent,\r\n\t\trootItemId: \"root\",\r\n\t\tgetItemName: (item) => item.getItemData()?.name ?? \"Unknown\",\r\n\t\tisItemFolder: (item) => (item.getItemData()?.children?.length ?? 0) > 0,\r\n\t\tcanReorder: false,\r\n\t\tonDrop: createOnDropHandler((parentItem, newChildrenIds) => {\r\n\t\t\tsetItems((prevItems) => {\r\n\t\t\t\t// Sort the children alphabetically\r\n\t\t\t\tconst sortedChildren = [...newChildrenIds].sort((a, b) => {\r\n\t\t\t\t\tconst itemA = prevItems[a];\r\n\t\t\t\t\tconst itemB = prevItems[b];\r\n\r\n\t\t\t\t\t// First sort folders before files\r\n\t\t\t\t\tconst isAFolder = (itemA?.children?.length ?? 0) > 0;\r\n\t\t\t\t\tconst isBFolder = (itemB?.children?.length ?? 0) > 0;\r\n\r\n\t\t\t\t\tif (isAFolder && !isBFolder) return -1;\r\n\t\t\t\t\tif (!isAFolder && isBFolder) return 1;\r\n\r\n\t\t\t\t\t// Then sort alphabetically by name\r\n\t\t\t\t\treturn (itemA?.name ?? \"\").localeCompare(itemB?.name ?? \"\");\r\n\t\t\t\t});\r\n\r\n\t\t\t\treturn {\r\n\t\t\t\t\t...prevItems,\r\n\t\t\t\t\t[parentItem.getId()]: {\r\n\t\t\t\t\t\t...prevItems[parentItem.getId()],\r\n\t\t\t\t\t\tchildren: sortedChildren,\r\n\t\t\t\t\t},\r\n\t\t\t\t};\r\n\t\t\t});\r\n\t\t}),\r\n\t\tdataLoader: {\r\n\t\t\tgetItem: (itemId) => items[itemId],\r\n\t\t\tgetChildren: (itemId) => items[itemId]?.children ?? [],\r\n\t\t},\r\n\t\tfeatures: [\r\n\t\t\tsyncDataLoaderFeature,\r\n\t\t\tselectionFeature,\r\n\t\t\thotkeysCoreFeature,\r\n\t\t\tdragAndDropFeature,\r\n\t\t\tkeyboardDragAndDropFeature,\r\n\t\t],\r\n\t});\r\n\r\n\treturn (\r\n\t\t<div className=\"flex h-full flex-col gap-2 first:*:grow\">\r\n\t\t\t<div>\r\n\t\t\t\t<Tree\r\n\t\t\t\t\tclassName=\"relative before:absolute before:inset-0 before:-ms-1 before:bg-[repeating-linear-gradient(to_right,transparent_0,transparent_calc(var(--tree-indent)-1px),var(--border)_calc(var(--tree-indent)-1px),var(--border)_calc(var(--tree-indent)))]\"\r\n\t\t\t\t\tindent={indent}\r\n\t\t\t\t\ttree={tree}\r\n\t\t\t\t>\r\n\t\t\t\t\t<AssistiveTreeDescription tree={tree} />\r\n\t\t\t\t\t{tree.getItems().map((item) => {\r\n\t\t\t\t\t\treturn (\r\n\t\t\t\t\t\t\t<TreeItem key={item.getId()} item={item} className=\"pb-0!\">\r\n\t\t\t\t\t\t\t\t<TreeItemLabel className=\"rounded-none py-1\">\r\n\t\t\t\t\t\t\t\t\t<span className=\"flex items-center gap-2\">\r\n\t\t\t\t\t\t\t\t\t\t{!item.isFolder() &&\r\n\t\t\t\t\t\t\t\t\t\t\tgetFileIcon(\r\n\t\t\t\t\t\t\t\t\t\t\t\titem.getItemData()?.fileExtension,\r\n\t\t\t\t\t\t\t\t\t\t\t\t\"text-muted-foreground pointer-events-none size-4\"\r\n\t\t\t\t\t\t\t\t\t\t\t)}\r\n\t\t\t\t\t\t\t\t\t\t{item.getItemName()}\r\n\t\t\t\t\t\t\t\t\t</span>\r\n\t\t\t\t\t\t\t\t</TreeItemLabel>\r\n\t\t\t\t\t\t\t</TreeItem>\r\n\t\t\t\t\t\t);\r\n\t\t\t\t\t})}\r\n\t\t\t\t</Tree>\r\n\t\t\t</div>\r\n\r\n\t\t\t<p\r\n\t\t\t\taria-live=\"polite\"\r\n\t\t\t\trole=\"region\"\r\n\t\t\t\tclassName=\"text-muted-foreground mt-2 text-xs\"\r\n\t\t\t>\r\n\t\t\t\tFile editor with drag and drop ∙{\" \"}\r\n\t\t\t\t<a\r\n\t\t\t\t\thref=\"https://headless-tree.lukasbach.com\"\r\n\t\t\t\t\tclassName=\"hover:text-foreground underline\"\r\n\t\t\t\t\ttarget=\"_blank\"\r\n\t\t\t\t\trel=\"noopener noreferrer\"\r\n\t\t\t\t>\r\n\t\t\t\t\tAPI\r\n\t\t\t\t</a>\r\n\t\t\t</p>\r\n\t\t</div>\r\n\t);\r\n}\r\n",
      "type": "registry:ui"
    },
    {
      "path": "components/ui/tree.tsx",
      "content": "\"use client\";\n\nimport * as React from \"react\";\n\nimport { cn } from \"@/registry/utilities/cn\";\nimport { ItemInstance } from \"@headless-tree/core\";\nimport { ChevronDownIcon } from \"lucide-react\";\nimport { Slot } from \"radix-ui\";\n\ninterface TreeContextValue<T = any> {\n\tindent: number;\n\tcurrentItem?: ItemInstance<T>;\n\ttree?: any;\n}\n\nconst TreeContext = React.createContext<TreeContextValue>({\n\tindent: 20,\n\tcurrentItem: undefined,\n\ttree: undefined,\n});\n\nfunction useTreeContext<T = any>() {\n\treturn React.useContext(TreeContext) as TreeContextValue<T>;\n}\n\ninterface TreeProps extends React.HTMLAttributes<HTMLDivElement> {\n\tindent?: number;\n\ttree?: any;\n}\n\nfunction Tree({ indent = 20, tree, className, ...props }: TreeProps) {\n\tconst containerProps =\n\t\ttree && typeof tree.getContainerProps === \"function\"\n\t\t\t? tree.getContainerProps()\n\t\t\t: {};\n\tconst mergedProps = { ...props, ...containerProps };\n\n\t// Extract style from mergedProps to merge with our custom styles\n\tconst { style: propStyle, ...otherProps } = mergedProps;\n\n\t// Merge styles\n\tconst mergedStyle = {\n\t\t...propStyle,\n\t\t\"--tree-indent\": `${indent}px`,\n\t} as React.CSSProperties;\n\n\treturn (\n\t\t<TreeContext.Provider value={{ indent, tree }}>\n\t\t\t<div\n\t\t\t\tdata-slot=\"tree\"\n\t\t\t\tstyle={mergedStyle}\n\t\t\t\tclassName={cn(\"flex flex-col\", className)}\n\t\t\t\t{...otherProps}\n\t\t\t/>\n\t\t</TreeContext.Provider>\n\t);\n}\n\ninterface TreeItemProps<T = any>\n\textends React.HTMLAttributes<HTMLButtonElement> {\n\titem: ItemInstance<T>;\n\tindent?: number;\n\tasChild?: boolean;\n}\n\nfunction TreeItem<T = any>({\n\titem,\n\tclassName,\n\tasChild,\n\tchildren,\n\t...props\n}: Omit<TreeItemProps<T>, \"indent\">) {\n\tconst { indent } = useTreeContext<T>();\n\n\tconst itemProps = typeof item.getProps === \"function\" ? item.getProps() : {};\n\tconst mergedProps = { ...props, ...itemProps };\n\n\t// Extract style from mergedProps to merge with our custom styles\n\tconst { style: propStyle, ...otherProps } = mergedProps;\n\n\t// Merge styles\n\tconst mergedStyle = {\n\t\t...propStyle,\n\t\t\"--tree-padding\": `${item.getItemMeta().level * indent}px`,\n\t} as React.CSSProperties;\n\n\tconst Comp = asChild ? Slot.Root : \"button\";\n\n\treturn (\n\t\t<TreeContext.Provider value={{ indent, currentItem: item }}>\n\t\t\t<Comp\n\t\t\t\tdata-slot=\"tree-item\"\n\t\t\t\tstyle={mergedStyle}\n\t\t\t\tclassName={cn(\n\t\t\t\t\t\"z-10 ps-(--tree-padding) outline-hidden select-none not-last:pb-0.5 focus:z-20 data-disabled:pointer-events-none data-disabled:opacity-50\",\n\t\t\t\t\tclassName\n\t\t\t\t)}\n\t\t\t\tdata-focus={\n\t\t\t\t\ttypeof item.isFocused === \"function\"\n\t\t\t\t\t\t? item.isFocused() || false\n\t\t\t\t\t\t: undefined\n\t\t\t\t}\n\t\t\t\tdata-folder={\n\t\t\t\t\ttypeof item.isFolder === \"function\"\n\t\t\t\t\t\t? item.isFolder() || false\n\t\t\t\t\t\t: undefined\n\t\t\t\t}\n\t\t\t\tdata-selected={\n\t\t\t\t\ttypeof item.isSelected === \"function\"\n\t\t\t\t\t\t? item.isSelected() || false\n\t\t\t\t\t\t: undefined\n\t\t\t\t}\n\t\t\t\tdata-drag-target={\n\t\t\t\t\ttypeof item.isDragTarget === \"function\"\n\t\t\t\t\t\t? item.isDragTarget() || false\n\t\t\t\t\t\t: undefined\n\t\t\t\t}\n\t\t\t\tdata-search-match={\n\t\t\t\t\ttypeof item.isMatchingSearch === \"function\"\n\t\t\t\t\t\t? item.isMatchingSearch() || false\n\t\t\t\t\t\t: undefined\n\t\t\t\t}\n\t\t\t\taria-expanded={item.isExpanded()}\n\t\t\t\t{...otherProps}\n\t\t\t>\n\t\t\t\t{children}\n\t\t\t</Comp>\n\t\t</TreeContext.Provider>\n\t);\n}\n\ninterface TreeItemLabelProps<T = any>\n\textends React.HTMLAttributes<HTMLSpanElement> {\n\titem?: ItemInstance<T>;\n}\n\nfunction TreeItemLabel<T = any>({\n\titem: propItem,\n\tchildren,\n\tclassName,\n\t...props\n}: TreeItemLabelProps<T>) {\n\tconst { currentItem } = useTreeContext<T>();\n\tconst item = propItem || currentItem;\n\n\tif (!item) {\n\t\tconsole.warn(\"TreeItemLabel: No item provided via props or context\");\n\t\treturn null;\n\t}\n\n\treturn (\n\t\t<span\n\t\t\tdata-slot=\"tree-item-label\"\n\t\t\tclassName={cn(\n\t\t\t\t\"in-focus-visible:ring-ring/50 bg-background hover:bg-accent in-data-[selected=true]:bg-accent in-data-[selected=true]:text-accent-foreground in-data-[drag-target=true]:bg-accent flex items-center gap-1 rounded-sm px-2 py-1.5 text-sm transition-colors not-in-data-[folder=true]:ps-7 in-focus-visible:ring-[3px] in-data-[search-match=true]:bg-blue-400/20! [&_svg]:pointer-events-none [&_svg]:shrink-0\",\n\t\t\t\tclassName\n\t\t\t)}\n\t\t\t{...props}\n\t\t>\n\t\t\t{item.isFolder() && (\n\t\t\t\t<ChevronDownIcon className=\"text-muted-foreground size-4 in-aria-[expanded=false]:-rotate-90\" />\n\t\t\t)}\n\t\t\t{children ||\n\t\t\t\t(typeof item.getItemName === \"function\"\n\t\t\t\t\t? item.getItemName()\n\t\t\t\t\t: null)}\n\t\t</span>\n\t);\n}\n\nfunction TreeDragLine({\n\tclassName,\n\t...props\n}: React.HTMLAttributes<HTMLDivElement>) {\n\tconst { tree } = useTreeContext();\n\n\tif (!tree || typeof tree.getDragLineStyle !== \"function\") {\n\t\tconsole.warn(\n\t\t\t\"TreeDragLine: No tree provided via context or tree does not have getDragLineStyle method\"\n\t\t);\n\t\treturn null;\n\t}\n\n\tconst dragLine = tree.getDragLineStyle();\n\treturn (\n\t\t<div\n\t\t\tstyle={dragLine}\n\t\t\tclassName={cn(\n\t\t\t\t\"bg-primary before:bg-background before:border-primary absolute z-30 -mt-px h-0.5 w-[unset] before:absolute before:-top-[3px] before:left-0 before:size-2 before:rounded-full before:border-2\",\n\t\t\t\tclassName\n\t\t\t)}\n\t\t\t{...props}\n\t\t/>\n\t);\n}\n\nexport { Tree, TreeItem, TreeItemLabel, TreeDragLine };\n",
      "type": "registry:ui"
    },
    {
      "path": "registry/utilities/cn.ts",
      "content": "import { ClassValue, clsx } from \"clsx\";\r\nimport { twMerge } from \"tailwind-merge\";\r\n\r\nexport function cn(...inputs: ClassValue[]) {\r\n\treturn twMerge(clsx(inputs));\r\n}\r\n",
      "type": "registry:ui"
    }
  ]
}