import { ReactNode, ComponentType } from 'react'; type TreeItemId = string; /** A single node in the consumer's tree data. Generic over your payload. */ interface TreeNode { id: TreeItemId; data: T; /** Inline children. Omit (and provide a `loadChildren`) for async loading. */ children?: TreeNode[]; /** * Set to `true` to mark a node as a folder even when its `children` array * is empty (e.g. an unloaded async folder). Default: derived from * `Array.isArray(children)`. */ isFolder?: boolean; /** Disable interaction. */ disabled?: boolean; } /** * Internal flat-row representation used by the renderer + keyboard nav. * Produced by `flattenTree`; consumed by `TreeRow`, the keyboard hook, * and the type-ahead hook. */ interface FlatRow { node: TreeNode; level: number; parentId: TreeItemId | null; isFolder: boolean; isExpanded: boolean; isLoading: boolean; hasError: boolean; /** 1-based position among visible siblings (for `aria-posinset`). */ posInSet: number; /** Count of visible siblings sharing this row's parent (for `aria-setsize`). */ setSize: number; } interface TreeRowRenderProps { node: TreeNode; level: number; isSelected: boolean; isExpanded: boolean; isFocused: boolean; isFolder: boolean; isLoading: boolean; isMatchingSearch: boolean; } type TreeRowSlot = (props: TreeRowRenderProps) => ReactNode; type TreeContextMenuSlot = (props: TreeRowRenderProps, trigger: ReactNode) => ReactNode; /** * Declarative context-menu item. Pass `'separator'` (string) in place of an * object to insert a `` between groups. * * For more advanced needs (submenus, checkbox items, custom JSX), drop down * to `renderContextMenu` instead. */ interface TreeContextMenuAction { /** Stable React key. */ id: string; label: ReactNode; /** Lucide-style icon component. Rendered as ``. */ icon?: ComponentType<{ className?: string; }>; /** Right-aligned keyboard hint (e.g. `'⌘C'`, `'↵'`). Cosmetic. */ shortcut?: ReactNode; /** Disable the item — still rendered, not selectable. */ disabled?: boolean; /** Style as destructive (red). */ destructive?: boolean; /** Click / Enter handler. Receives the row meta. */ onSelect: (props: TreeRowRenderProps) => void; } type TreeContextMenuItem = TreeContextMenuAction | 'separator'; /** * Context passed to a `contextMenuActions` resolver. `row` is the row the * user right-clicked. `selectedNodes` is the multi-selection at the * moment the menu opens — when the right-clicked row was not in the * selection, Tree first switches selection to that single row, so * `selectedNodes` always contains the right-clicked node. */ interface TreeContextMenuActionsContext extends TreeRowRenderProps { /** Multi-selection at the moment the menu opens. Always non-empty. */ selectedNodes: TreeNode[]; } type TreeContextMenuActionsResolver = (ctx: TreeContextMenuActionsContext) => TreeContextMenuItem[] | null | undefined; export type { FlatRow as F, TreeNode as T, TreeItemId as a, TreeRowSlot as b, TreeContextMenuSlot as c, TreeContextMenuActionsResolver as d, TreeRowRenderProps as e, TreeContextMenuItem as f, TreeContextMenuAction as g, TreeContextMenuActionsContext as h };