{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "tree-view",
  "title": "Tree View",
  "description": "A shadcn-style tree view component built with Ark UI primitives.",
  "dependencies": ["@ark-ui/react", "lucide-react"],
  "registryDependencies": ["button"],
  "files": [
    {
      "path": "src/components/ui/tree-view.tsx",
      "content": "\"use client\";\n\nimport {\n  createTreeCollection,\n  TreeView as TreeViewPrimitive,\n} from \"@ark-ui/react/tree-view\";\nimport {\n  CheckIcon,\n  ChevronRight,\n  FileIcon,\n  GlobeIcon,\n  LayersIcon,\n  MinusIcon,\n  PlusIcon,\n  TrashIcon,\n} from \"lucide-react\";\nimport { forwardRef } from \"react\";\nimport { Button } from \"@/components/ui/button\";\nimport { cn } from \"@/lib/utils\";\n\nexport type TreeViewProps<T> = TreeViewPrimitive.RootProps<T>;\n\nexport const TreeView = <T,>({ className, ...props }: TreeViewProps<T>) => (\n  <TreeViewPrimitive.Root\n    className={cn(\n      \"flex w-full max-w-md flex-col gap-2 text-sm text-foreground\",\n      className,\n    )}\n    data-slot=\"tree-view\"\n    {...props}\n  />\n);\n\nexport type TreeViewLabelProps = TreeViewPrimitive.LabelProps;\n\nexport const TreeViewLabel = ({ className, ...props }: TreeViewLabelProps) => (\n  <TreeViewPrimitive.Label\n    className={cn(\"font-medium text-sm\", className)}\n    data-slot=\"tree-view-label\"\n    {...props}\n  />\n);\n\nexport type TreeViewTreeProps = TreeViewPrimitive.TreeProps;\n\nexport const TreeViewTree = forwardRef<HTMLDivElement, TreeViewTreeProps>(\n  ({ className, ...props }, ref) => (\n    <TreeViewPrimitive.Tree\n      ref={ref}\n      className={cn(\"flex flex-col\", className)}\n      data-slot=\"tree-view-tree\"\n      {...props}\n    />\n  ),\n);\n\nexport const TreeViewBranch = ({\n  className,\n  ...props\n}: TreeViewPrimitive.BranchProps) => (\n  <TreeViewPrimitive.Branch\n    className={cn(\"relative\", className)}\n    data-slot=\"tree-view-branch\"\n    {...props}\n  />\n);\n\nexport const TreeViewBranchControl = ({\n  className,\n  ...props\n}: TreeViewPrimitive.BranchControlProps) => (\n  <TreeViewPrimitive.BranchControl\n    className={cn(\n      \"group flex w-full cursor-pointer items-center gap-2 rounded-md px-2 py-1.5 text-start transition-colors hover:bg-accent/60 data-selected:bg-accent data-disabled:pointer-events-none data-disabled:opacity-50\",\n      className,\n    )}\n    data-slot=\"tree-view-branch-control\"\n    {...props}\n  />\n);\n\nexport const TreeViewBranchIndicator = ({\n  className,\n  ...props\n}: TreeViewPrimitive.BranchIndicatorProps) => (\n  <TreeViewPrimitive.BranchIndicator\n    className={cn(\n      \"inline-flex size-4 items-center justify-center text-muted-foreground transition-transform data-state-open:rotate-90\",\n      className,\n    )}\n    data-slot=\"tree-view-branch-indicator\"\n    {...props}\n  />\n);\n\nexport const TreeViewBranchText = ({\n  className,\n  ...props\n}: TreeViewPrimitive.BranchTextProps) => (\n  <TreeViewPrimitive.BranchText\n    className={cn(\n      \"inline-flex min-w-0 flex-1 items-center gap-2 truncate\",\n      className,\n    )}\n    data-slot=\"tree-view-branch-text\"\n    {...props}\n  />\n);\n\nexport const TreeViewBranchContent = ({\n  className,\n  ...props\n}: TreeViewPrimitive.BranchContentProps) => (\n  <TreeViewPrimitive.BranchContent\n    className={cn(\"relative\", className)}\n    data-slot=\"tree-view-branch-content\"\n    {...props}\n  />\n);\n\nexport const TreeViewBranchIndentGuide = ({\n  className,\n  ...props\n}: TreeViewPrimitive.BranchIndentGuideProps) => (\n  <TreeViewPrimitive.BranchIndentGuide\n    className={cn(\"absolute inset-y-0 inset-s-4 w-px bg-border/70\", className)}\n    data-slot=\"tree-view-branch-indent-guide\"\n    {...props}\n  />\n);\n\nexport const TreeViewItem = ({\n  className,\n  ...props\n}: TreeViewPrimitive.ItemProps) => (\n  <TreeViewPrimitive.Item\n    className={cn(\n      \"flex w-full cursor-pointer items-center gap-2 rounded-md px-2 py-1.5 text-start transition-colors hover:bg-accent/60 data-selected:bg-accent data-disabled:pointer-events-none data-disabled:opacity-50\",\n      className,\n    )}\n    data-slot=\"tree-view-item\"\n    {...props}\n  />\n);\n\nexport const TreeViewItemText = ({\n  className,\n  ...props\n}: TreeViewPrimitive.ItemTextProps) => (\n  <TreeViewPrimitive.ItemText\n    className={cn(\n      \"inline-flex min-w-0 flex-1 items-center gap-2 truncate\",\n      className,\n    )}\n    data-slot=\"tree-view-item-text\"\n    {...props}\n  />\n);\n\nexport const TreeViewNodeCheckbox = ({\n  className,\n  ...props\n}: TreeViewPrimitive.NodeCheckboxProps) => (\n  <TreeViewPrimitive.NodeCheckbox\n    className={cn(\n      \"inline-flex size-4 items-center justify-center rounded-sm border border-input bg-background text-primary data-state-checked:border-primary data-state-checked:bg-primary data-state-checked:text-primary-foreground data-state-indeterminate:border-primary data-state-indeterminate:bg-primary data-state-indeterminate:text-primary-foreground\",\n      className,\n    )}\n    data-slot=\"tree-view-node-checkbox\"\n    {...props}\n  />\n);\n\nexport const TreeViewNodeCheckboxIndicator = ({\n  className,\n  ...props\n}: TreeViewPrimitive.NodeCheckboxIndicatorProps) => (\n  <TreeViewPrimitive.NodeCheckboxIndicator\n    className={cn(\"inline-flex items-center justify-center\", className)}\n    data-slot=\"tree-view-node-checkbox-indicator\"\n    {...props}\n  />\n);\n\nexport const TreeViewNodeRenameInput = ({\n  className,\n  ...props\n}: TreeViewPrimitive.NodeRenameInputProps) => (\n  <TreeViewPrimitive.NodeRenameInput\n    className={cn(\n      \"h-7 min-w-0 flex-1 rounded border border-primary/50 bg-background px-1.5 text-sm outline-none ring-offset-background focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-1\",\n      className,\n    )}\n    data-slot=\"tree-view-node-rename-input\"\n    {...props}\n  />\n);\n\nexport const TreeViewNodeProvider = TreeViewPrimitive.NodeProvider;\nexport const TreeViewNodeContext = TreeViewPrimitive.NodeContext;\nexport const TreeViewRootProvider = TreeViewPrimitive.RootProvider;\n\nexport type ShowcaseTreeNode = {\n  id: string;\n  name: string;\n  href?: string;\n  children?: ShowcaseTreeNode[];\n};\n\nexport const TREE_VIEW_SHOWCASE_ROOT: ShowcaseTreeNode = {\n  id: \"ROOT\",\n  name: \"\",\n  children: [\n    {\n      id: \"node_modules\",\n      name: \"node_modules\",\n      children: [\n        { id: \"node_modules/zag-js\", name: \"zag-js\" },\n        { id: \"node_modules/panda\", name: \"panda\" },\n        {\n          id: \"node_modules/@types\",\n          name: \"@types\",\n          children: [\n            { id: \"node_modules/@types/react\", name: \"react\" },\n            { id: \"node_modules/@types/react-dom\", name: \"react-dom\" },\n          ],\n        },\n      ],\n    },\n    {\n      id: \"src\",\n      name: \"src\",\n      children: [\n        { id: \"src/app.tsx\", name: \"app.tsx\", href: \"/docs/introduction\" },\n        { id: \"src/index.ts\", name: \"index.ts\", href: \"/docs/installation\" },\n      ],\n    },\n    { id: \"package.json\", name: \"package.json\" },\n    {\n      id: \"README.md\",\n      name: \"README.md\",\n      href: \"https://ark-ui.com/docs/components/tree-view\",\n    },\n  ],\n};\n\nexport const createShowcaseTreeCollection = () =>\n  createTreeCollection<ShowcaseTreeNode>({\n    nodeToValue: (node) => node.id,\n    nodeToString: (node) => node.name,\n    rootNode: structuredClone(TREE_VIEW_SHOWCASE_ROOT),\n  });\n\nexport const TreeViewShowcaseNodeCheckboxControl = () => (\n  <TreeViewNodeCheckbox\n    className={cn(\n      \"cursor-pointer peer relative flex size-4 shrink-0 items-center justify-center rounded border transition-colors outline-none group-has-disabled/field:opacity-50 after:absolute after:-inset-x-3 after:-inset-y-2 focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/50 disabled:cursor-not-allowed disabled:opacity-50 data-invalid:border-destructive data-invalid:ring-3 data-invalid:ring-destructive/20 data-invalid:data-[state='checked']:border-primary dark:bg-input/30 dark:data-invalid:border-destructive/50 dark:data-invalid:ring-destructive/40 data-[state='checked']:border-primary data-[state='checked']:bg-primary data-[state='checked']:text-primary-foreground dark:data-[state='checked']:bg-primary\",\n    )}\n  >\n    <TreeViewNodeCheckboxIndicator\n      className=\"grid place-content-center text-current transition-none [&>svg]:size-3.5\"\n      indeterminate={<MinusIcon />}\n    >\n      <CheckIcon />\n    </TreeViewNodeCheckboxIndicator>\n  </TreeViewNodeCheckbox>\n);\n\ntype TreeViewShowcaseNodeActionsProps = {\n  node: ShowcaseTreeNode;\n  indexPath: number[];\n  onAdd?: (node: ShowcaseTreeNode, indexPath: number[]) => void;\n  onRemove?: (indexPath: number[]) => void;\n};\n\nexport const TreeViewShowcaseNodeActions = ({\n  node,\n  indexPath,\n  onAdd,\n  onRemove,\n}: TreeViewShowcaseNodeActionsProps) => {\n  if (!onAdd && !onRemove) return null;\n\n  return (\n    <div className=\"ms-auto inline-flex items-center gap-1\">\n      {onRemove ? (\n        <Button\n          className=\"h-6 px-2 text-xs\"\n          onClick={(event) => {\n            event.stopPropagation();\n            onRemove(indexPath);\n          }}\n          variant=\"outline\"\n          size=\"icon-sm\"\n        >\n          <TrashIcon className=\"size-3.5 text-muted-foreground\" />\n        </Button>\n      ) : null}\n      {onAdd && node.children ? (\n        <Button\n          className=\"h-6 px-2 text-xs\"\n          onClick={(event) => {\n            event.stopPropagation();\n            onAdd(node, indexPath);\n          }}\n          variant=\"outline\"\n          size=\"icon-sm\"\n        >\n          <PlusIcon className=\"size-3.5 text-muted-foreground\" />\n        </Button>\n      ) : null}\n    </div>\n  );\n};\n\nexport type TreeViewShowcaseNodeRendererProps = {\n  node: ShowcaseTreeNode;\n  indexPath: number[];\n  checkbox?: boolean;\n  links?: boolean;\n  rename?: boolean;\n  onAdd?: (node: ShowcaseTreeNode, indexPath: number[]) => void;\n  onRemove?: (indexPath: number[]) => void;\n};\n\nexport const TreeViewShowcaseNodeRenderer = ({\n  node,\n  indexPath,\n  checkbox,\n  links,\n  rename,\n  onAdd,\n  onRemove,\n}: TreeViewShowcaseNodeRendererProps) => (\n  <TreeViewNodeProvider indexPath={indexPath} node={node}>\n    <TreeViewNodeContext>\n      {(nodeState) =>\n        node.children ? (\n          <TreeViewBranch>\n            <TreeViewBranchControl\n              data-depth={nodeState.depth}\n              style={{\n                paddingInlineStart: \"calc((var(--depth) - 1) * 22px)\",\n              }}\n            >\n              <TreeViewBranchIndicator className=\"group/indicator\">\n                <ChevronRight className=\"size-4 transition-transform rtl:rotate-180 group-data-[state=open]/indicator:rotate-90 rtl:group-data-[state=open]/indicator:rotate-90\" />\n              </TreeViewBranchIndicator>\n              {checkbox ? <TreeViewShowcaseNodeCheckboxControl /> : null}\n              {rename && nodeState.renaming ? (\n                <TreeViewNodeRenameInput />\n              ) : (\n                <TreeViewBranchText>\n                  <LayersIcon className=\"size-3.5 text-muted-foreground\" />\n                  {node.name}\n                </TreeViewBranchText>\n              )}\n              <TreeViewShowcaseNodeActions\n                indexPath={indexPath}\n                node={node}\n                onAdd={onAdd}\n                onRemove={onRemove}\n              />\n            </TreeViewBranchControl>\n            <TreeViewBranchContent>\n              <TreeViewBranchIndentGuide />\n              {node.children.map((child, childIndex) => (\n                <TreeViewShowcaseNodeRenderer\n                  checkbox={checkbox}\n                  indexPath={[...indexPath, childIndex]}\n                  key={child.id}\n                  links={links}\n                  node={child}\n                  onAdd={onAdd}\n                  onRemove={onRemove}\n                  rename={rename}\n                />\n              ))}\n            </TreeViewBranchContent>\n          </TreeViewBranch>\n        ) : (\n          <TreeViewItem\n            asChild={Boolean(links && node.href)}\n            data-depth={nodeState.depth}\n            style={{\n              paddingInlineStart: \"calc(((var(--depth) - 1) * 22px) + 22px)\",\n            }}\n          >\n            {links && node.href ? (\n              <a\n                className=\"flex w-full items-center gap-2\"\n                href={node.href}\n                rel={node.href.startsWith(\"http\") ? \"noreferrer\" : undefined}\n                target={node.href.startsWith(\"http\") ? \"_blank\" : undefined}\n              >\n                {checkbox ? <TreeViewShowcaseNodeCheckboxControl /> : null}\n                {rename && nodeState.renaming ? (\n                  <TreeViewNodeRenameInput />\n                ) : (\n                  <TreeViewItemText>\n                    <FileIcon className=\"size-3.5 text-muted-foreground\" />\n                    {node.name}\n                  </TreeViewItemText>\n                )}\n                {node.href.startsWith(\"http\") ? (\n                  <GlobeIcon className=\"ms-auto size-3 text-muted-foreground\" />\n                ) : null}\n                <TreeViewShowcaseNodeActions\n                  indexPath={indexPath}\n                  node={node}\n                  onAdd={onAdd}\n                  onRemove={onRemove}\n                />\n              </a>\n            ) : (\n              <>\n                {checkbox ? <TreeViewShowcaseNodeCheckboxControl /> : null}\n                {rename && nodeState.renaming ? (\n                  <TreeViewNodeRenameInput />\n                ) : (\n                  <TreeViewItemText>\n                    <FileIcon className=\"size-3.5 text-muted-foreground\" />\n                    {node.name}\n                  </TreeViewItemText>\n                )}\n                <TreeViewShowcaseNodeActions\n                  indexPath={indexPath}\n                  node={node}\n                  onAdd={onAdd}\n                  onRemove={onRemove}\n                />\n              </>\n            )}\n          </TreeViewItem>\n        )\n      }\n    </TreeViewNodeContext>\n  </TreeViewNodeProvider>\n);\n\nexport {\n  createTreeCollection,\n  useTreeView,\n  useTreeViewContext,\n} from \"@ark-ui/react/tree-view\";\n",
      "type": "registry:ui",
      "target": "src/components/ui/tree-view.tsx"
    }
  ],
  "type": "registry:ui"
}
