import React from 'react'; import { toggleExpandedIds } from '../../../utils/toggleExpandedIds'; import { TreeItemRow } from './TreeItemRow'; export interface TreeItemNode { readonly id: TId; readonly label: React.ReactNode; readonly icon?: React.ReactNode; readonly children?: readonly TreeItemNode[]; readonly disabled?: boolean; readonly meta?: React.ReactNode; readonly actions?: React.ReactNode; } export interface TreeItemRenderProps { readonly node: TreeItemNode; readonly depth: number; readonly selected: boolean; readonly expanded: boolean; readonly hasChildren: boolean; } export interface TreeViewProps { readonly nodes: readonly TreeItemNode[]; readonly selectedId?: TId; readonly expandedIds?: readonly TId[]; readonly defaultExpandedIds?: readonly TId[]; readonly onSelect?: (id: TId) => void; readonly onExpandedChange?: (ids: readonly TId[]) => void; readonly renderItem?: (props: TreeItemRenderProps) => React.ReactNode; readonly expansionIndicator?: 'chevron' | 'folder'; readonly className?: string; readonly style?: React.CSSProperties; readonly ariaLabel?: string; } /*** * Render the standalone browser TreeView artifact without React Native runtime dependencies. * @config expansionIndicator Use `chevron` beside custom node icons, or `folder` (default) for * built-in folder/file indicators. Expansion is leading and independent from row selection. */ export function TreeView({ nodes, selectedId, expandedIds: controlledExpandedIds, defaultExpandedIds, onSelect, onExpandedChange, renderItem, expansionIndicator = 'folder', className, style, ariaLabel = 'Tree', }: TreeViewProps) { const [internalExpandedIds, setInternalExpandedIds] = React.useState( defaultExpandedIds ?? [], ); const isControlled = controlledExpandedIds !== undefined; const expandedIds = isControlled ? controlledExpandedIds : internalExpandedIds; const handleToggleExpand = React.useCallback( (id: TId) => { const nextExpandedIds = toggleExpandedIds(expandedIds, id); if (!isControlled) setInternalExpandedIds(nextExpandedIds); onExpandedChange?.(nextExpandedIds); }, [expandedIds, isControlled, onExpandedChange], ); return (
{nodes.map((node) => ( ))}
); } const TREE_STYLE = { display: 'flex', flexDirection: 'column', minWidth: 0, } as const satisfies React.CSSProperties;