import { useState } from "react"; import type { TreeNode, NodeIcon } from "./tree"; import { type ViewState, isHidden, isEffectivelyHidden, } from "./viewState"; const ICONS: Record = { figure: "▦", axes: "▢", trace: "∿", dataset: "⋯", }; function EyeIcon({ open }: { open: boolean }) { return ( ); } function SoloIcon() { return ( ); } function NodeRow({ node, depth, expanded, toggle, selectedId, onSelect, viewState, onToggleHidden, onIsolate, }: { node: TreeNode; depth: number; expanded: Set; toggle: (id: string) => void; selectedId: string | null; onSelect: (id: string) => void; viewState: ViewState; onToggleHidden: (id: string) => void; onIsolate: (id: string) => void; }) { const hasChildren = node.children.length > 0; const isOpen = expanded.has(node.id); const isSelected = selectedId === node.id; const hasControls = node.icon === "axes" || node.icon === "trace"; const ownHidden = isHidden(viewState, node.id); const dimmed = isEffectivelyHidden(viewState, node.id); const cls = [ "tree-row", isSelected ? "selected" : "", dimmed ? "dimmed" : "", ownHidden ? "el-hidden" : "", ] .filter(Boolean) .join(" "); return ( <>
onSelect(node.id)} role="treeitem" aria-selected={isSelected} aria-expanded={hasChildren ? isOpen : undefined} > { e.stopPropagation(); if (hasChildren) toggle(node.id); }} > {hasChildren ? (isOpen ? "▾" : "▸") : ""} {ICONS[node.icon]} {node.label} {hasControls && ( )}
{hasChildren && isOpen && node.children.map(child => ( ))} ); } export function ObjectTree({ root, selectedId, onSelect, viewState, onToggleHidden, onIsolate, }: { root: TreeNode; selectedId: string | null; onSelect: (id: string) => void; viewState: ViewState; onToggleHidden: (id: string) => void; onIsolate: (id: string) => void; }) { // Expand the figure and its axes by default. const [expanded, setExpanded] = useState>(() => { const s = new Set([root.id]); for (const axes of root.children) s.add(axes.id); return s; }); const toggle = (id: string) => setExpanded(prev => { const next = new Set(prev); if (next.has(id)) next.delete(id); else next.add(id); return next; }); return (
); }