{"$schema":"https://ui.shadcn.com/schema/registry-item.json","name":"tree","type":"registry:ui","title":"Tree","description":"","dependencies":["@base-ui/react","@headless-tree/core","cn"],"registryDependencies":[],"files":[{"path":"tree.tsx","type":"registry:ui","content":"/* eslint-disable @typescript-eslint/no-explicit-any */\n\"use client\"\n\nimport { createContext, useContext } from \"react\"\nimport { mergeProps } from \"@base-ui/react/merge-props\"\nimport { useRender } from \"@base-ui/react/use-render\"\nimport type { ItemInstance } from \"@headless-tree/core\"\n\nimport { cn } from \"cn\"\nimport { IconPlaceholder } from \"@/app/(create)/components/icon-placeholder\"\n\ntype ToggleIconType = \"chevron\" | \"plus-minus\"\n\ninterface TreeContextValue<T = any> {\n  indent: number\n  currentItem?: ItemInstance<T>\n  tree?: any\n  toggleIconType?: ToggleIconType\n}\n\nconst TreeContext = createContext<TreeContextValue>({\n  indent: 20,\n  currentItem: undefined,\n  tree: undefined,\n  toggleIconType: \"plus-minus\",\n})\n\nfunction useTreeContext<T = any>() {\n  return useContext(TreeContext) as TreeContextValue<T>\n}\n\ninterface TreeProps extends React.HTMLAttributes<HTMLDivElement> {\n  indent?: number\n  tree?: any\n  toggleIconType?: ToggleIconType\n}\n\nfunction Tree({\n  indent = 20,\n  tree,\n  className,\n  toggleIconType = \"chevron\",\n  ...props\n}: TreeProps) {\n  const containerProps =\n    tree && typeof tree.getContainerProps === \"function\"\n      ? tree.getContainerProps()\n      : {}\n  const mergedProps = { ...props, ...containerProps }\n\n  // Extract style from mergedProps to merge with our custom styles\n  const { style: propStyle, ...otherProps } = mergedProps\n\n  // Merge styles\n  const mergedStyle = {\n    ...propStyle,\n    \"--tree-indent\": `${indent}px`,\n  } as React.CSSProperties\n\n  return (\n    <TreeContext.Provider value={{ indent, tree, toggleIconType }}>\n      <div\n        data-slot=\"tree\"\n        style={mergedStyle}\n        className={cn(\"flex flex-col\", className)}\n        {...otherProps}\n      />\n    </TreeContext.Provider>\n  )\n}\n\ninterface TreeItemProps<T = any> extends Omit<\n  useRender.ComponentProps<\"button\">,\n  \"indent\"\n> {\n  item: ItemInstance<T>\n  indent?: number\n}\n\nfunction TreeItem<T = any>({\n  item,\n  className,\n  render,\n  children,\n  ...props\n}: TreeItemProps<T>) {\n  const parentContext = useTreeContext<T>()\n  const { indent } = parentContext\n\n  const itemProps = typeof item.getProps === \"function\" ? item.getProps() : {}\n  const mergedProps = { ...props, children, ...itemProps }\n\n  // Extract style from mergedProps to merge with our custom styles\n  const { style: propStyle, ...otherProps } = mergedProps\n\n  // Merge styles\n  const mergedStyle = {\n    ...propStyle,\n    \"--tree-padding\": `${item.getItemMeta().level * indent}px`,\n  } as React.CSSProperties\n\n  const defaultProps = {\n    \"data-slot\": \"tree-item\",\n    style: mergedStyle,\n    className: cn(\n      \"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      className\n    ),\n    \"data-focus\":\n      typeof item.isFocused === \"function\"\n        ? item.isFocused() || false\n        : undefined,\n    \"data-folder\":\n      typeof item.isFolder === \"function\"\n        ? item.isFolder() || false\n        : undefined,\n    \"data-selected\":\n      typeof item.isSelected === \"function\"\n        ? item.isSelected() || false\n        : undefined,\n    \"data-drag-target\":\n      typeof item.isDragTarget === \"function\"\n        ? item.isDragTarget() || false\n        : undefined,\n    \"data-search-match\":\n      typeof item.isMatchingSearch === \"function\"\n        ? item.isMatchingSearch() || false\n        : undefined,\n    \"aria-expanded\": item.isExpanded(),\n  }\n\n  return (\n    <TreeContext.Provider value={{ ...parentContext, currentItem: item }}>\n      {useRender({\n        defaultTagName: \"button\",\n        render,\n        props: mergeProps<\"button\">(defaultProps, otherProps),\n      })}\n    </TreeContext.Provider>\n  )\n}\n\ninterface TreeItemLabelProps<\n  T = any,\n> extends React.HTMLAttributes<HTMLSpanElement> {\n  item?: ItemInstance<T>\n}\n\nfunction TreeItemLabel<T = any>({\n  item: propItem,\n  children,\n  className,\n  ...props\n}: TreeItemLabelProps<T>) {\n  const { currentItem, toggleIconType } = useTreeContext<T>()\n  const item = propItem || currentItem\n\n  if (!item) {\n    console.warn(\"TreeItemLabel: No item provided via props or context\")\n    return null\n  }\n\n  return (\n    <span\n      data-slot=\"tree-item-label\"\n      className={cn(\n        \"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 transition-colors not-in-data-[folder=true]:ps-7 in-focus-visible:ring-[3px] in-data-[search-match=true]:bg-blue-50! [&_svg]:pointer-events-none [&_svg]:shrink-0\",\n        \"rounded-md\",\n        \"py-1.5\",\n        \"px-2\",\n        \"text-sm\",\n        className\n      )}\n      {...props}\n    >\n      {item.isFolder() &&\n        (toggleIconType === \"plus-minus\" ? (\n          item.isExpanded() ? (\n            <IconPlaceholder\n              lucide=\"MinusIcon\"\n              tabler=\"IconMinus\"\n              hugeicons=\"MinusSignIcon\"\n              phosphor=\"MinusIcon\"\n              remixicon=\"RiSubtractLine\"\n              className=\"text-muted-foreground size-3.5\"\n              stroke=\"currentColor\"\n              strokeWidth=\"1\"\n            />\n          ) : (\n            <IconPlaceholder\n              lucide=\"PlusIcon\"\n              tabler=\"IconPlus\"\n              hugeicons=\"PlusSignIcon\"\n              phosphor=\"PlusIcon\"\n              remixicon=\"RiAddLine\"\n              className=\"text-muted-foreground size-3.5\"\n              stroke=\"currentColor\"\n              strokeWidth=\"1\"\n            />\n          )\n        ) : (\n          <IconPlaceholder\n            lucide=\"ChevronDownIcon\"\n            tabler=\"IconChevronDown\"\n            hugeicons=\"ArrowDown01Icon\"\n            phosphor=\"CaretDownIcon\"\n            remixicon=\"RiArrowDownSLine\"\n            className=\"text-muted-foreground size-4 in-aria-[expanded=false]:-rotate-90\"\n          />\n        ))}\n      {children ||\n        (typeof item.getItemName === \"function\" ? item.getItemName() : null)}\n    </span>\n  )\n}\n\nfunction TreeDragLine({\n  className,\n  ...props\n}: React.HTMLAttributes<HTMLDivElement>) {\n  const { tree } = useTreeContext()\n\n  if (!tree || typeof tree.getDragLineStyle !== \"function\") {\n    console.warn(\n      \"TreeDragLine: No tree provided via context or tree does not have getDragLineStyle method\"\n    )\n    return null\n  }\n\n  const dragLine = tree.getDragLineStyle()\n  return (\n    <div\n      style={dragLine}\n      className={cn(\n        \"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:border-2\",\n        \"before:rounded-full\",\n        className\n      )}\n      {...props}\n    />\n  )\n}\n\nexport { Tree, TreeItem, TreeItemLabel, TreeDragLine }","target":"components/reui/tree.tsx"}]}