@ii_elif_ii/ui-node-tree 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/index.ts","../src/components/node-tree.tsx","../src/utils/cn.ts","../src/components/tree-connections.tsx","../src/components/tree-renderer.tsx","../src/hooks/use-node-tree-layout.ts"],"sourcesContent":["export { NodeTree } from \"./components/node-tree\";\nexport type {\r\n NodeFrameProps,\r\n NodeTreeAnimationOptions,\r\n NodeTreeClassNameOptions,\r\n NodeTreeConnectionOptions,\r\n NodeTreeFrameOptions,\n NodeTreeLayoutOptions,\n NodeTreeProps,\n TreeNodeChildren,\n TreeNode,\n TreeNodeEdge,\n TreeNodeRenderContext,\n} from \"./types\";\n","import * as React from \"react\";\nimport \"../node-tree.css\";\nimport { cn } from \"../utils/cn\";\nimport { TreeConnections } from \"./tree-connections\";\nimport { TreeRenderer } from \"./tree-renderer\";\nimport { useNodeTreeLayout } from \"../hooks/use-node-tree-layout\";\nimport type { AlignAxis, NodeTreeProps } from \"../types\";\n\r\nconst NodeTree = React.forwardRef<HTMLDivElement, NodeTreeProps>(\r\n (\r\n {\r\n className,\r\n nodeTree,\r\n layout,\r\n connection,\r\n animation,\r\n nodeFrame,\r\n debug = false,\r\n style,\r\n ...props\r\n },\r\n ref,\r\n ) => {\r\n const containerRef = React.useRef<HTMLDivElement | null>(null);\r\n const nodeRefs = React.useRef(new Map<string, HTMLDivElement>());\r\n const registerNode = React.useCallback(\r\n (id: string, element: HTMLDivElement | null) => {\r\n const registry = nodeRefs.current;\r\n if (element) {\r\n registry.set(id, element);\r\n } else {\r\n registry.delete(id);\r\n }\r\n },\r\n [],\r\n );\r\n\r\n const resolvedAlign = layout?.align ?? \"center\";\r\n const resolvedDirection = layout?.direction ?? \"down\";\r\n const resolvedRootLayout = layout?.root ?? \"stack\";\r\n const resolvedPaddingContainer = layout?.containerPadding ?? 128;\r\n const resolvedPadding = layout?.padding ?? 64;\r\n const resolvedGap = layout?.gap ?? 64;\r\n const resolvedStrokeColor = connection?.color ?? \"rgba(255,255,255)\";\r\n const resolvedStrokeWidth = connection?.width ?? 1;\r\n const resolvedAnimationDurationMs = animation?.durationMs ?? 2000;\r\n const resolvedNodeFrameStyle = nodeFrame?.style;\r\n\r\n const { doneNodes, layoutState } = useNodeTreeLayout({\r\n nodeTree,\r\n direction: resolvedDirection,\r\n gap: resolvedGap,\r\n padding: resolvedPadding,\r\n animationSpeed: resolvedAnimationDurationMs,\r\n debug,\r\n containerRef,\r\n nodeRefs,\r\n });\r\n\r\n const flowDown = resolvedDirection === \"down\";\r\n const alignValue = resolvedAlign;\r\n const alignX: AlignAxis =\r\n typeof alignValue === \"string\" ? alignValue : alignValue.x;\r\n const alignY: AlignAxis =\r\n typeof alignValue === \"string\" ? \"start\" : alignValue.y;\r\n const resolvedConnectionOpacity = connection?.opacity ?? (debug ? 1 : 0.1);\r\n\r\n return (\r\n <div\r\n ref={ref}\r\n className={cn(\"unt-tree-root-container\", className?.root)}\r\n style={style}\r\n {...props}\r\n >\r\n <div\r\n ref={containerRef}\r\n className={cn(\"unt-tree-canvas\", className?.canvas)}\r\n style={{ padding: resolvedPaddingContainer }}\r\n >\r\n <TreeConnections\r\n layoutState={layoutState}\r\n debug={debug}\r\n strokeColor={resolvedStrokeColor}\r\n strokeWidth={resolvedStrokeWidth}\r\n opacity={resolvedConnectionOpacity}\r\n className={className?.connections}\r\n />\r\n <TreeRenderer\r\n nodeTree={nodeTree}\r\n rootLayout={resolvedRootLayout}\r\n flowDown={flowDown}\r\n alignX={alignX}\r\n alignY={alignY}\r\n gap={resolvedGap}\r\n debug={debug}\r\n layoutState={layoutState}\r\n doneNodes={doneNodes}\r\n registerNode={registerNode}\r\n rendererClassName={className?.renderer}\r\n nodeFrameClassName={className?.frame}\r\n nodeFrameStyle={resolvedNodeFrameStyle}\r\n />\r\n </div>\r\n </div>\r\n );\r\n },\r\n);\r\n\r\nNodeTree.displayName = \"NodeTree\";\r\n\r\nexport { NodeTree };\r\n","import { clsx, type ClassValue } from \"clsx\";\r\n\r\nexport function cn(...inputs: ClassValue[]) {\r\n return clsx(inputs);\r\n}\r\n","import * as React from \"react\";\nimport { cn } from \"../utils/cn\";\nimport type { NodeTreeLayoutState } from \"../types\";\n\r\ntype TreeConnectionsProps = {\r\n layoutState: NodeTreeLayoutState;\r\n debug: boolean;\r\n strokeColor: string;\r\n strokeWidth: number;\r\n opacity: number;\r\n className?: string;\r\n};\r\n\r\nexport function TreeConnections({\r\n layoutState,\r\n debug,\r\n strokeColor,\r\n strokeWidth,\r\n opacity,\r\n className,\r\n}: TreeConnectionsProps) {\r\n if (!layoutState.svgBounds) {\r\n return null;\r\n }\r\n\r\n return (\r\n <svg\r\n className={cn(\"unt-tree-connections\", className)}\r\n width={layoutState.svgBounds.width}\r\n height={layoutState.svgBounds.height}\r\n viewBox={`0 0 ${layoutState.svgBounds.width} ${layoutState.svgBounds.height}`}\r\n style={{\r\n left: layoutState.svgBounds.offsetX,\r\n top: layoutState.svgBounds.offsetY,\r\n opacity,\r\n }}\r\n >\r\n {layoutState.segments.map((segment) => {\r\n const debugPalette = [\r\n \"#22d3ee\",\r\n \"#a855f7\",\r\n \"#f59e0b\",\r\n \"#10b981\",\r\n \"#f97316\",\r\n \"#38bdf8\",\r\n ];\r\n const lineColor = debug\r\n ? debugPalette[segment.colorIndex % debugPalette.length]\r\n : strokeColor;\r\n return (\r\n <line\r\n key={`${segment.x1}-${segment.y1}-${segment.x2}-${segment.y2}-${segment.delay}`}\r\n x1={segment.x1 - layoutState.svgBounds!.offsetX}\r\n y1={segment.y1 - layoutState.svgBounds!.offsetY}\r\n x2={segment.x2 - layoutState.svgBounds!.offsetX}\r\n y2={segment.y2 - layoutState.svgBounds!.offsetY}\r\n className=\"node-line\"\r\n style={{\r\n strokeDasharray: segment.length,\r\n strokeDashoffset: segment.length,\r\n animationDelay: `${segment.delay}s`,\r\n animationDuration: `${segment.duration}s`,\r\n }}\r\n stroke={lineColor}\r\n strokeWidth={strokeWidth}\r\n strokeLinecap=\"round\"\r\n />\r\n );\r\n })}\r\n </svg>\r\n );\r\n}\r\n","import * as React from \"react\";\nimport { cn } from \"../utils/cn\";\nimport type {\n AlignAxis,\n NodeFrameProps,\n NodeTreeLayoutState,\n TreeNode,\n} from \"../types\";\n\r\ntype TreeRendererProps = {\r\n nodeTree: TreeNode[];\n rootLayout: \"stack\" | \"row\";\r\n flowDown: boolean;\r\n alignX: AlignAxis;\r\n alignY: AlignAxis;\r\n gap: number;\r\n debug: boolean;\r\n layoutState: NodeTreeLayoutState;\r\n doneNodes: Set<string>;\r\n registerNode: (id: string, element: HTMLDivElement | null) => void;\r\n rendererClassName?: string;\r\n nodeFrameClassName?: string;\r\n nodeFrameStyle?: React.CSSProperties;\r\n};\r\n\r\nfunction axisToFlexAlign(axis: AlignAxis): React.CSSProperties[\"alignItems\"] {\r\n if (axis === \"start\") {\r\n return \"flex-start\";\r\n }\r\n if (axis === \"end\") {\r\n return \"flex-end\";\r\n }\r\n return \"center\";\r\n}\r\n\r\nfunction axisToFlexJustify(axis: AlignAxis): React.CSSProperties[\"justifyContent\"] {\r\n if (axis === \"start\") {\r\n return \"flex-start\";\r\n }\r\n if (axis === \"end\") {\r\n return \"flex-end\";\r\n }\r\n return \"center\";\r\n}\r\n\r\nfunction NodeFrame({ node, className, onRef, children, ...props }: NodeFrameProps) {\r\n return (\r\n <div\r\n ref={(element) => {\r\n onRef(node.id, element);\r\n }}\r\n className={cn(\"unt-tree-node-hit\", className)}\r\n data-nodeframe\r\n data-viewport-no-pan\r\n {...props}\r\n >\r\n {children}\r\n </div>\r\n );\r\n}\r\n\r\nfunction renderTreeNode({\r\n node,\r\n index,\r\n parentId,\r\n depth,\r\n path,\r\n flowDown,\r\n alignX,\r\n alignY,\r\n gap,\r\n debug,\r\n layoutState,\r\n doneNodes,\r\n registerNode,\r\n nodeFrameClassName,\r\n nodeFrameStyle,\r\n}: {\r\n node: TreeNode;\n index: number;\r\n parentId?: string;\r\n depth: number;\r\n path: Set<string>;\r\n flowDown: boolean;\r\n alignX: AlignAxis;\r\n alignY: AlignAxis;\r\n gap: number;\r\n debug: boolean;\r\n layoutState: NodeTreeLayoutState;\r\n doneNodes: Set<string>;\r\n registerNode: (id: string, element: HTMLDivElement | null) => void;\r\n nodeFrameClassName?: string;\r\n nodeFrameStyle?: React.CSSProperties;\r\n}): React.ReactNode {\r\n const stackUnder = !flowDown && node.children?.layout === \"stack\";\r\n if (path.has(node.id)) {\r\n return null;\r\n }\r\n\r\n path.add(node.id);\r\n const childrenLayoutIsStack = node.children?.layout === \"stack\" || !flowDown;\r\n const childCount = node.children?.nodes.length ?? 0;\r\n const isLeaf = childCount === 0;\r\n const pathIds = [...path];\r\n const childrenContent =\r\n node.children?.nodes && node.children.nodes.length > 0 ? (\r\n <div\r\n className=\"unt-tree-children\"\r\n style={{\r\n display: \"flex\",\r\n flexShrink: 0,\r\n flexDirection: childrenLayoutIsStack ? \"column\" : \"row\",\r\n alignItems: axisToFlexAlign(childrenLayoutIsStack ? alignX : alignY),\r\n justifyContent: axisToFlexJustify(childrenLayoutIsStack ? alignY : alignX),\r\n gap,\r\n marginTop: flowDown || stackUnder ? gap : 0,\r\n marginLeft: flowDown\r\n ? node.children?.layout === \"stack\"\r\n ? gap\r\n : 0\r\n : stackUnder\r\n ? gap / 2\r\n : gap,\r\n }}\r\n >\r\n {node.children.nodes.map((child, childIndex) =>\r\n renderTreeNode({\r\n node: child,\r\n index: childIndex,\r\n parentId: node.id,\r\n depth: depth + 1,\r\n path,\r\n flowDown,\r\n alignX,\r\n alignY,\r\n gap,\r\n debug,\r\n layoutState,\r\n doneNodes,\r\n registerNode,\r\n nodeFrameClassName,\r\n nodeFrameStyle,\r\n }),\r\n )}\r\n </div>\r\n ) : null;\r\n path.delete(node.id);\r\n\r\n return (\r\n <div\r\n key={`${node.id}-${index}`}\r\n className=\"unt-tree-node-wrap\"\r\n style={{\r\n display: \"flex\",\r\n position: \"relative\",\r\n flexDirection: flowDown || stackUnder ? \"column\" : \"row\",\r\n alignItems: axisToFlexAlign(flowDown ? alignX : alignY),\r\n justifyContent: axisToFlexJustify(flowDown ? alignY : alignX),\r\n }}\r\n >\r\n <NodeFrame\r\n node={node}\r\n className={cn(\"node-enter unt-tree-node-frame\", nodeFrameClassName)}\r\n style={{\r\n justifyContent: axisToFlexJustify(alignX),\r\n animationDuration: `${layoutState.nodeAnimDuration}s`,\r\n animationDelay: `${\r\n layoutState.nodeDelays.get(node.id) ?? depth * 0.08 + index * 0.04\r\n }s`,\r\n ...nodeFrameStyle,\r\n }}\r\n onRef={registerNode}\r\n >\r\n {debug ? (\r\n <div\r\n className={cn(\r\n \"unt-tree-debug-badge\",\r\n `unt-tree-debug-badge--${depth % 6}`,\r\n )}\r\n >\r\n <div>{`DEPTH: ${depth}`}</div>\r\n <div>{`PARENT-ID: ${parentId ?? \"root\"}`}</div>\r\n <div>{`NODE-ID: ${node.id}`}</div>\r\n <div>{`C-LAYOUT: ${node.children?.layout ?? \"N/A\"}`}</div>\r\n </div>\r\n ) : null}\r\n {node.render({\r\n node,\r\n index,\r\n depth,\r\n parentId,\r\n path: pathIds,\r\n isLeaf,\r\n childCount,\r\n isNodeAnimationDone: doneNodes.has(node.id),\r\n })}\r\n </NodeFrame>\r\n\r\n {childrenContent}\r\n </div>\r\n );\r\n}\r\n\r\nexport function TreeRenderer({\r\n nodeTree,\r\n rootLayout,\r\n flowDown,\r\n alignX,\r\n alignY,\r\n gap,\r\n debug,\r\n layoutState,\r\n doneNodes,\r\n registerNode,\r\n rendererClassName,\r\n nodeFrameClassName,\r\n nodeFrameStyle,\r\n}: TreeRendererProps) {\r\n const rootLayoutRow = rootLayout === \"row\";\r\n return (\r\n <section\r\n className={cn(\"unt-tree-renderer\", rendererClassName)}\r\n style={{\r\n gap,\r\n display: \"flex\",\r\n width: \"100%\",\r\n overflow: \"visible\",\r\n position: \"relative\",\r\n zIndex: 10,\r\n flexDirection: rootLayoutRow ? \"row\" : \"column\",\r\n alignItems: axisToFlexAlign(rootLayoutRow ? alignY : alignX),\r\n justifyContent: axisToFlexJustify(rootLayoutRow ? alignX : alignY),\r\n }}\r\n >\r\n {nodeTree.map((node, index) =>\r\n renderTreeNode({\r\n node,\r\n index,\r\n depth: 0,\r\n path: new Set<string>(),\r\n flowDown,\r\n alignX,\r\n alignY,\r\n gap,\r\n debug,\r\n layoutState,\r\n doneNodes,\r\n registerNode,\r\n nodeFrameClassName,\r\n nodeFrameStyle,\r\n }),\r\n )}\r\n </section>\r\n );\r\n}\r\n","import * as React from \"react\";\nimport type {\n NodeTreeLayoutState,\n TreeNode,\n TreeNodeEdge,\n} from \"../types\";\n\ntype EdgeGeometry = {\n edge: TreeNodeEdge;\n fromX: number;\n fromY: number;\n fromBottom: number;\n fromCenterX: number;\n toX: number;\n toY: number;\n toLeft: number;\n toCenterY: number;\n};\n\ntype UseNodeTreeLayoutParams = {\n nodeTree: TreeNode[];\n direction: \"down\" | \"right\";\n gap: number;\n padding: number;\n animationSpeed: number;\n debug: boolean;\n containerRef: React.RefObject<HTMLDivElement | null>;\n nodeRefs: React.MutableRefObject<Map<string, HTMLDivElement>>;\n};\n\nconst EMPTY_LAYOUT: NodeTreeLayoutState = {\n segments: [],\n nodeDelays: new Map(),\n nodeAnimDuration: 0.42,\n animationTotal: 0,\n svgBounds: null,\n};\n\nfunction collectEdges(nodes: TreeNode[]) {\n const edges: TreeNodeEdge[] = [];\n const visiting = new Set<string>();\n const visit = (node: TreeNode) => {\n if (visiting.has(node.id)) {\n return;\n }\n visiting.add(node.id);\n if (node.children?.nodes && node.children.nodes.length > 0) {\n node.children.nodes.forEach((child, index) => {\n const key = `${node.id}=>${child.id}`;\n edges.push({\n key,\n from: node.id,\n to: child.id,\n index,\n count: node.children?.nodes.length ?? 1,\n });\n visit(child);\n });\n }\n visiting.delete(node.id);\n };\n\n nodes.forEach(visit);\n return edges;\n}\n\nfunction collectDescendants(nodes: TreeNode[]) {\n const map = new Map<string, string[]>();\n const visiting = new Set<string>();\n const visit = (node: TreeNode): string[] => {\n if (visiting.has(node.id)) {\n return [];\n }\n visiting.add(node.id);\n const descendants: string[] = [];\n node.children?.nodes.forEach((child) => {\n descendants.push(child.id);\n descendants.push(...visit(child));\n });\n map.set(node.id, descendants);\n visiting.delete(node.id);\n return descendants;\n };\n nodes.forEach(visit);\n return map;\n}\n\nexport function useNodeTreeLayout({\n nodeTree,\n direction,\n gap,\n padding,\n animationSpeed,\n debug,\n containerRef,\n nodeRefs,\n}: UseNodeTreeLayoutParams) {\n const [layoutState, setLayoutState] =\n React.useState<NodeTreeLayoutState>(EMPTY_LAYOUT);\n const [doneNodes, setDoneNodes] = React.useState<Set<string>>(\n () => new Set(),\n );\n const doneNodesRef = React.useRef<Set<string>>(new Set());\n const edges = React.useMemo(() => collectEdges(nodeTree), [nodeTree]);\n const descendantMap = React.useMemo(\n () => collectDescendants(nodeTree),\n [nodeTree],\n );\n\n const totalAnimationSec = Math.max(0.1, animationSpeed / 1000);\n\n const drawConnections = React.useCallback(() => {\n const container = containerRef.current;\n if (!container) {\n return;\n }\n\n const flowDown = direction === \"down\";\n\n const getRelativeRect = (element: HTMLElement) => {\n let left = 0;\n let top = 0;\n let current: HTMLElement | null = element;\n while (current && current !== container) {\n left += current.offsetLeft;\n top += current.offsetTop;\n current = current.offsetParent as HTMLElement | null;\n }\n return {\n left,\n top,\n right: left + element.offsetWidth,\n bottom: top + element.offsetHeight,\n width: element.offsetWidth,\n height: element.offsetHeight,\n };\n };\n\n const rectMap = new Map<string, ReturnType<typeof getRelativeRect>>();\n nodeRefs.current.forEach((el, id) => {\n rectMap.set(id, getRelativeRect(el));\n });\n\n const nextSegments: NodeTreeLayoutState[\"segments\"] = [];\n const nextNodeDelays = new Map<string, number>();\n const baseSecondsPerPixel = 1 / 900;\n const baseNodeAnimDuration = 0.42;\n const edgeColorIndex = debug ? new Map<string, number>() : null;\n const edgeData = new Map<string, EdgeGeometry>();\n\n edges.forEach((edge) => {\n const fromRect = rectMap.get(edge.from);\n const toRect = rectMap.get(edge.to);\n if (!fromRect || !toRect) {\n return;\n }\n\n const fromX = flowDown ? fromRect.left + fromRect.width / 2 : fromRect.right;\n const fromY = flowDown\n ? fromRect.bottom\n : fromRect.top + fromRect.height / 2;\n const toX = flowDown ? toRect.left + toRect.width / 2 : toRect.left;\n const toY = flowDown ? toRect.top : toRect.top + toRect.height / 2;\n\n edgeData.set(edge.key, {\n edge,\n fromX,\n fromY,\n fromBottom: fromRect.bottom,\n fromCenterX: fromRect.left + fromRect.width / 2,\n toX,\n toY,\n toLeft: toRect.left,\n toCenterY: toRect.top + toRect.height / 2,\n });\n });\n\n const pushSegment = (\n x1: number,\n y1: number,\n x2: number,\n y2: number,\n depth: number,\n delay: number,\n colorIndex: number,\n order: number,\n ) => {\n const length = Math.hypot(x2 - x1, y2 - y1);\n const duration = Math.max(0.05, length * baseSecondsPerPixel);\n nextSegments.push({\n x1,\n y1,\n x2,\n y2,\n length,\n depth,\n delay,\n duration,\n colorIndex,\n order,\n });\n return duration;\n };\n\n const visit = (node: TreeNode, depth: number, nodeDelay: number) => {\n const existing = nextNodeDelays.get(node.id) ?? 0;\n const resolvedDelay = Math.max(existing, nodeDelay);\n nextNodeDelays.set(node.id, resolvedDelay);\n\n const childEdges =\n node.children?.nodes\n .map((child) => edgeData.get(`${node.id}=>${child.id}`))\n .filter((edge): edge is EdgeGeometry => Boolean(edge)) ?? [];\n const stackLayout = node.children?.layout === \"stack\";\n const descendantIds =\n flowDown && stackLayout ? (descendantMap.get(node.id) ?? []) : [];\n const descendantLefts =\n flowDown && stackLayout\n ? descendantIds\n .map((id) => rectMap.get(id))\n .filter((rect): rect is NonNullable<typeof rect> => Boolean(rect))\n .map((rect) => rect.left)\n : [];\n const descendantMinLeft =\n descendantLefts.length > 0 ? Math.min(...descendantLefts) : undefined;\n const gutterX =\n flowDown && stackLayout\n ? (descendantMinLeft ??\n (childEdges.length > 0\n ? Math.min(...childEdges.map((edge) => edge.toLeft))\n : 0)) -\n gap / 2\n : 0;\n const gutterXRight =\n !flowDown && stackLayout\n ? (childEdges.length > 0\n ? Math.min(...childEdges.map((edge) => edge.toLeft))\n : 0) -\n gap / 2\n : 0;\n\n const orderedChildren =\n node.children?.nodes\n .map((child) => {\n const edge = edgeData.get(`${node.id}=>${child.id}`);\n if (!edge) {\n return null;\n }\n const dx = edge.toX - edge.fromX;\n const dy = edge.toY - edge.fromY;\n const length = Math.hypot(dx, dy);\n return { child, edge, length, toX: edge.toX };\n })\n .filter(\n (entry): entry is NonNullable<typeof entry> => Boolean(entry),\n ) ?? [];\n\n if (debug) {\n orderedChildren.sort((a, b) => {\n if (a.length !== b.length) {\n return a.length - b.length;\n }\n return a.toX - b.toX;\n });\n }\n\n orderedChildren.forEach((entry, index) => {\n const { child, edge } = entry;\n const edgeKey = edge.edge.key;\n let colorIndex = 0;\n if (edgeColorIndex) {\n if (!edgeColorIndex.has(edgeKey)) {\n edgeColorIndex.set(edgeKey, edgeColorIndex.size);\n }\n colorIndex = edgeColorIndex.get(edgeKey) ?? 0;\n }\n const order = orderedChildren.length - 1 - index;\n const edgeDelay = resolvedDelay + baseNodeAnimDuration + index * 0.04;\n let totalDuration = 0;\n if (flowDown && stackLayout) {\n const baseDrop = Math.max(12, gap / 2);\n const targetY = edge.toCenterY;\n const midY =\n edge.fromY + Math.min(baseDrop, (targetY - edge.fromY) * 0.6);\n totalDuration += pushSegment(\n edge.fromX,\n edge.fromY,\n edge.fromX,\n midY,\n depth,\n edgeDelay,\n colorIndex,\n order,\n );\n totalDuration += pushSegment(\n edge.fromX,\n midY,\n gutterX,\n midY,\n depth,\n edgeDelay + totalDuration,\n colorIndex,\n order,\n );\n totalDuration += pushSegment(\n gutterX,\n midY,\n gutterX,\n targetY,\n depth,\n edgeDelay + totalDuration,\n colorIndex,\n order,\n );\n totalDuration += pushSegment(\n gutterX,\n targetY,\n edge.toLeft,\n targetY,\n depth,\n edgeDelay + totalDuration,\n colorIndex,\n order,\n );\n } else if (!flowDown && stackLayout) {\n const targetY = edge.toCenterY;\n const baseDrop = Math.max(12, gap / 2);\n const midY =\n edge.fromBottom +\n Math.min(baseDrop, (targetY - edge.fromBottom) * 0.6);\n totalDuration += pushSegment(\n edge.fromCenterX,\n edge.fromBottom,\n edge.fromCenterX,\n midY,\n depth,\n edgeDelay,\n colorIndex,\n order,\n );\n totalDuration += pushSegment(\n edge.fromCenterX,\n midY,\n gutterXRight,\n midY,\n depth,\n edgeDelay + totalDuration,\n colorIndex,\n order,\n );\n totalDuration += pushSegment(\n gutterXRight,\n midY,\n gutterXRight,\n targetY,\n depth,\n edgeDelay + totalDuration,\n colorIndex,\n order,\n );\n totalDuration += pushSegment(\n gutterXRight,\n targetY,\n edge.toLeft,\n targetY,\n depth,\n edgeDelay + totalDuration,\n colorIndex,\n order,\n );\n } else if (flowDown) {\n const midY = edge.fromY + (edge.toY - edge.fromY) * 0.5;\n totalDuration += pushSegment(\n edge.fromX,\n edge.fromY,\n edge.fromX,\n midY,\n depth,\n edgeDelay,\n colorIndex,\n order,\n );\n totalDuration += pushSegment(\n edge.fromX,\n midY,\n edge.toX,\n midY,\n depth,\n edgeDelay + totalDuration,\n colorIndex,\n order,\n );\n totalDuration += pushSegment(\n edge.toX,\n midY,\n edge.toX,\n edge.toY,\n depth,\n edgeDelay + totalDuration,\n colorIndex,\n order,\n );\n } else {\n const midX = edge.fromX + (edge.toX - edge.fromX) * 0.5;\n totalDuration += pushSegment(\n edge.fromX,\n edge.fromY,\n midX,\n edge.fromY,\n depth,\n edgeDelay,\n colorIndex,\n order,\n );\n totalDuration += pushSegment(\n midX,\n edge.fromY,\n midX,\n edge.toY,\n depth,\n edgeDelay + totalDuration,\n colorIndex,\n order,\n );\n totalDuration += pushSegment(\n midX,\n edge.toY,\n edge.toX,\n edge.toY,\n depth,\n edgeDelay + totalDuration,\n colorIndex,\n order,\n );\n }\n visit(child, depth + 1, edgeDelay + totalDuration);\n });\n };\n\n nodeTree.forEach((node) => visit(node, 0, 0));\n\n if (nextSegments.length === 0) {\n setLayoutState((prev) => ({\n ...prev,\n segments: [],\n svgBounds: null,\n animationTotal: 0,\n }));\n setDoneNodes(new Set());\n doneNodesRef.current = new Set();\n return;\n }\n\n let minX = Infinity;\n let minY = Infinity;\n let maxX = -Infinity;\n let maxY = -Infinity;\n nextSegments.forEach((segment) => {\n minX = Math.min(minX, segment.x1, segment.x2);\n minY = Math.min(minY, segment.y1, segment.y2);\n maxX = Math.max(maxX, segment.x1, segment.x2);\n maxY = Math.max(maxY, segment.y1, segment.y2);\n });\n\n if (\n !Number.isFinite(minX) ||\n !Number.isFinite(minY) ||\n !Number.isFinite(maxX) ||\n !Number.isFinite(maxY)\n ) {\n return;\n }\n\n const width = Math.max(1, maxX - minX + padding * 2);\n const height = Math.max(1, maxY - minY + padding * 2);\n const offsetX = minX - padding;\n const offsetY = minY - padding;\n\n const maxLineEnd = Math.max(\n 0,\n ...nextSegments.map((segment) => segment.delay + segment.duration),\n );\n const maxNodeEnd =\n Math.max(0, ...Array.from(nextNodeDelays.values())) + baseNodeAnimDuration;\n const animationMax = Math.max(maxLineEnd, maxNodeEnd);\n const scale = animationMax > 0 ? totalAnimationSec / animationMax : 1;\n const scaledSegments = nextSegments\n .map((segment) => ({\n ...segment,\n delay: segment.delay * scale,\n duration: segment.duration * scale,\n }))\n .sort((a, b) => a.order - b.order);\n const scaledNodeDelays = new Map<string, number>();\n nextNodeDelays.forEach((value, key) => {\n scaledNodeDelays.set(key, value * scale);\n });\n\n setLayoutState({\n segments: scaledSegments,\n nodeDelays: scaledNodeDelays,\n nodeAnimDuration: baseNodeAnimDuration * scale,\n animationTotal: animationMax * scale,\n svgBounds: { width, height, offsetX, offsetY },\n });\n setDoneNodes(new Set());\n doneNodesRef.current = new Set();\n }, [\n animationSpeed,\n containerRef,\n debug,\n descendantMap,\n direction,\n edges,\n gap,\n nodeRefs,\n nodeTree,\n padding,\n totalAnimationSec,\n ]);\n\n React.useLayoutEffect(() => {\n const rafId = requestAnimationFrame(drawConnections);\n return () => cancelAnimationFrame(rafId);\n }, [drawConnections, nodeTree]);\n\n React.useEffect(() => {\n if (layoutState.animationTotal <= 0 || layoutState.nodeDelays.size === 0) {\n return;\n }\n\n const entries = Array.from(layoutState.nodeDelays.entries())\n .map(([id, delay]) => ({\n id,\n end: delay + layoutState.nodeAnimDuration,\n }))\n .sort((a, b) => a.end - b.end);\n\n doneNodesRef.current = new Set();\n setDoneNodes(new Set());\n\n const start = performance.now();\n let rafId = 0;\n let index = 0;\n\n const tick = () => {\n const elapsed = (performance.now() - start) / 1000;\n let updated = false;\n\n while (index < entries.length && elapsed >= entries[index].end) {\n doneNodesRef.current.add(entries[index].id);\n index += 1;\n updated = true;\n }\n\n if (updated) {\n setDoneNodes(new Set(doneNodesRef.current));\n }\n\n if (index < entries.length) {\n rafId = requestAnimationFrame(tick);\n }\n };\n\n rafId = requestAnimationFrame(tick);\n return () => cancelAnimationFrame(rafId);\n }, [\n layoutState.animationTotal,\n layoutState.nodeAnimDuration,\n layoutState.nodeDelays,\n ]);\n\n return { doneNodes, layoutState };\n}\n"],"mappings":"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","names":["React","import_jsx_runtime","import_jsx_runtime"]}
package/dist/index.css ADDED
@@ -0,0 +1,87 @@
1
+ /* src/node-tree.css */
2
+ @keyframes unt-node-enter {
3
+ 0% {
4
+ opacity: 0;
5
+ }
6
+ 100% {
7
+ opacity: 1;
8
+ }
9
+ }
10
+ .unt-tree-root-container {
11
+ position: relative;
12
+ width: 100%;
13
+ height: 100%;
14
+ min-height: 0;
15
+ overflow: hidden;
16
+ }
17
+ .unt-tree-canvas {
18
+ position: relative;
19
+ }
20
+ .unt-tree-node-hit {
21
+ cursor: auto;
22
+ }
23
+ .unt-tree-node-frame {
24
+ position: relative;
25
+ display: flex;
26
+ border: 1px solid rgba(255, 255, 255, 0.2);
27
+ padding: 1rem;
28
+ }
29
+ .unt-tree-debug-badge {
30
+ position: absolute;
31
+ top: 0.5rem;
32
+ left: 0.5rem;
33
+ z-index: 10;
34
+ padding: 0.25rem 0.5rem;
35
+ font-size: 0.75rem;
36
+ line-height: 1rem;
37
+ }
38
+ .unt-tree-debug-badge--0 {
39
+ background: #a7f3d0;
40
+ color: #042f2e;
41
+ }
42
+ .unt-tree-debug-badge--1 {
43
+ background: #bae6fd;
44
+ color: #082f49;
45
+ }
46
+ .unt-tree-debug-badge--2 {
47
+ background: #fde68a;
48
+ color: #451a03;
49
+ }
50
+ .unt-tree-debug-badge--3 {
51
+ background: #fecdd3;
52
+ color: #4c0519;
53
+ }
54
+ .unt-tree-debug-badge--4 {
55
+ background: #d9f99d;
56
+ color: #1a2e05;
57
+ }
58
+ .unt-tree-debug-badge--5 {
59
+ background: #ddd6fe;
60
+ color: #2e1065;
61
+ }
62
+ .unt-tree-connections {
63
+ pointer-events: none;
64
+ position: absolute;
65
+ inset: 0;
66
+ z-index: 0;
67
+ }
68
+ .node-enter {
69
+ animation-name: unt-node-enter;
70
+ animation-timing-function: ease-out;
71
+ animation-fill-mode: both;
72
+ }
73
+ @keyframes unt-line-draw {
74
+ 0% {
75
+ opacity: 0.2;
76
+ }
77
+ 100% {
78
+ stroke-dashoffset: 0;
79
+ opacity: 1;
80
+ }
81
+ }
82
+ .node-line {
83
+ animation-name: unt-line-draw;
84
+ animation-timing-function: ease-out;
85
+ animation-fill-mode: both;
86
+ }
87
+ /*# sourceMappingURL=index.css.map */
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/node-tree.css"],"sourcesContent":["@keyframes unt-node-enter {\r\n 0% {\r\n opacity: 0;\r\n }\r\n 100% {\r\n opacity: 1;\r\n }\r\n}\r\n\r\n.unt-tree-root-container {\r\n position: relative;\r\n width: 100%;\r\n height: 100%;\r\n min-height: 0;\r\n overflow: hidden;\r\n}\r\n\r\n.unt-tree-canvas {\r\n position: relative;\r\n}\r\n\r\n.unt-tree-node-hit {\r\n cursor: auto;\r\n}\r\n\r\n.unt-tree-node-frame {\r\n position: relative;\r\n display: flex;\r\n border: 1px solid rgba(255, 255, 255, 0.2);\r\n padding: 1rem;\r\n}\r\n\r\n.unt-tree-debug-badge {\r\n position: absolute;\r\n top: 0.5rem;\r\n left: 0.5rem;\r\n z-index: 10;\r\n padding: 0.25rem 0.5rem;\r\n font-size: 0.75rem;\r\n line-height: 1rem;\r\n}\r\n\r\n.unt-tree-debug-badge--0 {\r\n background: #a7f3d0;\r\n color: #042f2e;\r\n}\r\n\r\n.unt-tree-debug-badge--1 {\r\n background: #bae6fd;\r\n color: #082f49;\r\n}\r\n\r\n.unt-tree-debug-badge--2 {\r\n background: #fde68a;\r\n color: #451a03;\r\n}\r\n\r\n.unt-tree-debug-badge--3 {\r\n background: #fecdd3;\r\n color: #4c0519;\r\n}\r\n\r\n.unt-tree-debug-badge--4 {\r\n background: #d9f99d;\r\n color: #1a2e05;\r\n}\r\n\r\n.unt-tree-debug-badge--5 {\r\n background: #ddd6fe;\r\n color: #2e1065;\r\n}\r\n\r\n.unt-tree-connections {\r\n pointer-events: none;\r\n position: absolute;\r\n inset: 0;\r\n z-index: 0;\r\n}\r\n\r\n.node-enter {\r\n animation-name: unt-node-enter;\r\n animation-timing-function: ease-out;\r\n animation-fill-mode: both;\r\n}\r\n\r\n@keyframes unt-line-draw {\r\n 0% {\r\n opacity: 0.2;\r\n }\r\n 100% {\r\n stroke-dashoffset: 0;\r\n opacity: 1;\r\n }\r\n}\r\n\r\n.node-line {\r\n animation-name: unt-line-draw;\r\n animation-timing-function: ease-out;\r\n animation-fill-mode: both;\r\n}\r\n"],"mappings":";AAAA,WAAW;AACT;AACE,aAAS;AACX;AACA;AACE,aAAS;AACX;AACF;AAEA,CAAC;AACC,YAAU;AACV,SAAO;AACP,UAAQ;AACR,cAAY;AACZ,YAAU;AACZ;AAEA,CAAC;AACC,YAAU;AACZ;AAEA,CAAC;AACC,UAAQ;AACV;AAEA,CAAC;AACC,YAAU;AACV,WAAS;AACT,UAAQ,IAAI,MAAM,KAAK,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE;AACtC,WAAS;AACX;AAEA,CAAC;AACC,YAAU;AACV,OAAK;AACL,QAAM;AACN,WAAS;AACT,WAAS,QAAQ;AACjB,aAAW;AACX,eAAa;AACf;AAEA,CAAC;AACC,cAAY;AACZ,SAAO;AACT;AAEA,CAAC;AACC,cAAY;AACZ,SAAO;AACT;AAEA,CAAC;AACC,cAAY;AACZ,SAAO;AACT;AAEA,CAAC;AACC,cAAY;AACZ,SAAO;AACT;AAEA,CAAC;AACC,cAAY;AACZ,SAAO;AACT;AAEA,CAAC;AACC,cAAY;AACZ,SAAO;AACT;AAEA,CAAC;AACC,kBAAgB;AAChB,YAAU;AACV,SAAO;AACP,WAAS;AACX;AAEA,CAAC;AACC,kBAAgB;AAChB,6BAA2B;AAC3B,uBAAqB;AACvB;AAEA,WAAW;AACT;AACE,aAAS;AACX;AACA;AACE,uBAAmB;AACnB,aAAS;AACX;AACF;AAEA,CAAC;AACC,kBAAgB;AAChB,6BAA2B;AAC3B,uBAAqB;AACvB;","names":[]}
@@ -0,0 +1,120 @@
1
+ import * as React from 'react';
2
+
3
+ /**
4
+ * Runtime info provided to each node render function.
5
+ * This enables render logic based on position, hierarchy, and animation state.
6
+ */
7
+ interface TreeNodeRenderContext<TData = unknown> {
8
+ /** The current node being rendered. */
9
+ node: TreeNode<TData>;
10
+ /** Index of this node within its current siblings array. */
11
+ index: number;
12
+ /** Depth from root (root = 0). */
13
+ depth: number;
14
+ /** Parent node id, or undefined for root nodes. */
15
+ parentId?: string;
16
+ /** Ordered ancestor path ending with the current node id. */
17
+ path: readonly string[];
18
+ /** True when the current node has no children. */
19
+ isLeaf: boolean;
20
+ /** Number of direct children for the current node. */
21
+ childCount: number;
22
+ /** True when this node's enter animation has completed. */
23
+ isNodeAnimationDone: boolean;
24
+ }
25
+ interface TreeNodeChildren<TData = unknown> {
26
+ /** Layout for the child group. */
27
+ layout?: "stack" | "row";
28
+ /** Child nodes under this node. */
29
+ nodes: TreeNode<TData>[];
30
+ }
31
+ type TreeNode<TData = unknown> = {
32
+ /** Unique node identifier. */
33
+ id: string;
34
+ /** Optional payload for consumer-defined node data. */
35
+ data?: TData;
36
+ /** Render callback for this node. */
37
+ render: (context: TreeNodeRenderContext<TData>) => React.ReactNode;
38
+ /** Optional child group. */
39
+ children?: TreeNodeChildren<TData>;
40
+ };
41
+ type TreeNodeEdge = {
42
+ key: string;
43
+ from: string;
44
+ to: string;
45
+ index: number;
46
+ count: number;
47
+ };
48
+ type NodeTreeAlign = "center" | "start" | "end" | {
49
+ x: "center" | "start" | "end";
50
+ y: "center" | "start" | "end";
51
+ };
52
+ interface NodeTreeLayoutOptions {
53
+ /** Horizontal/vertical alignment. String form applies to x with y defaulting to "start". @default "center" */
54
+ align?: NodeTreeAlign;
55
+ /** Overall flow direction for child placement. @default "down" */
56
+ direction?: "down" | "right";
57
+ /** Layout for top-level nodes. @default "stack" */
58
+ root?: "stack" | "row";
59
+ /** Spacing between nodes. @default 64 */
60
+ gap?: number;
61
+ /** Extra padding around connection bounds. @default 64 */
62
+ padding?: number;
63
+ /** Padding around the entire tree container. @default 128 */
64
+ containerPadding?: number;
65
+ }
66
+ interface NodeTreeConnectionOptions {
67
+ /** Line stroke color. @default "rgba(255,255,255)" */
68
+ color?: string;
69
+ /** Line stroke width in px. @default 1 */
70
+ width?: number;
71
+ /** Line opacity (0 to 1). @default 1 when debug=true, otherwise 0.1 */
72
+ opacity?: number;
73
+ }
74
+ interface NodeTreeAnimationOptions {
75
+ /** Total animation time in ms (all nodes/lines complete within this duration). @default 2000 */
76
+ durationMs?: number;
77
+ }
78
+ interface NodeTreeClassNameOptions {
79
+ /** Class name for the root wrapper element. */
80
+ root?: string;
81
+ /** Class name for the inner canvas container. */
82
+ canvas?: string;
83
+ /** Class name for the renderer section. */
84
+ renderer?: string;
85
+ /** Class name for each node frame wrapper. */
86
+ frame?: string;
87
+ /** Class name for the SVG connections layer. */
88
+ connections?: string;
89
+ }
90
+ interface NodeTreeFrameOptions {
91
+ /** Extra inline styles applied to each node frame wrapper. */
92
+ style?: React.CSSProperties;
93
+ }
94
+ interface NodeTreeProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "className"> {
95
+ /** Root nodes to render. */
96
+ nodeTree: TreeNode[];
97
+ /** Slot-based class names for internal elements. */
98
+ className?: NodeTreeClassNameOptions;
99
+ /** Grouped layout options. */
100
+ layout?: NodeTreeLayoutOptions;
101
+ /** Grouped connection line options. */
102
+ connection?: NodeTreeConnectionOptions;
103
+ /** Grouped animation options. */
104
+ animation?: NodeTreeAnimationOptions;
105
+ /** Grouped node frame options. */
106
+ nodeFrame?: NodeTreeFrameOptions;
107
+ /** Show debug overlay badges. @default false */
108
+ debug?: boolean;
109
+ }
110
+ interface NodeFrameProps extends React.HTMLAttributes<HTMLDivElement> {
111
+ /** Node associated with this frame element. */
112
+ node: TreeNode;
113
+ /** Ref registry hook used internally for layout measurements. */
114
+ onRef: (id: string, element: HTMLDivElement | null) => void;
115
+ children: React.ReactNode;
116
+ }
117
+
118
+ declare const NodeTree: React.ForwardRefExoticComponent<NodeTreeProps & React.RefAttributes<HTMLDivElement>>;
119
+
120
+ export { type NodeFrameProps, NodeTree, type NodeTreeAnimationOptions, type NodeTreeClassNameOptions, type NodeTreeConnectionOptions, type NodeTreeFrameOptions, type NodeTreeLayoutOptions, type NodeTreeProps, type TreeNode, type TreeNodeChildren, type TreeNodeEdge, type TreeNodeRenderContext };
@@ -0,0 +1,120 @@
1
+ import * as React from 'react';
2
+
3
+ /**
4
+ * Runtime info provided to each node render function.
5
+ * This enables render logic based on position, hierarchy, and animation state.
6
+ */
7
+ interface TreeNodeRenderContext<TData = unknown> {
8
+ /** The current node being rendered. */
9
+ node: TreeNode<TData>;
10
+ /** Index of this node within its current siblings array. */
11
+ index: number;
12
+ /** Depth from root (root = 0). */
13
+ depth: number;
14
+ /** Parent node id, or undefined for root nodes. */
15
+ parentId?: string;
16
+ /** Ordered ancestor path ending with the current node id. */
17
+ path: readonly string[];
18
+ /** True when the current node has no children. */
19
+ isLeaf: boolean;
20
+ /** Number of direct children for the current node. */
21
+ childCount: number;
22
+ /** True when this node's enter animation has completed. */
23
+ isNodeAnimationDone: boolean;
24
+ }
25
+ interface TreeNodeChildren<TData = unknown> {
26
+ /** Layout for the child group. */
27
+ layout?: "stack" | "row";
28
+ /** Child nodes under this node. */
29
+ nodes: TreeNode<TData>[];
30
+ }
31
+ type TreeNode<TData = unknown> = {
32
+ /** Unique node identifier. */
33
+ id: string;
34
+ /** Optional payload for consumer-defined node data. */
35
+ data?: TData;
36
+ /** Render callback for this node. */
37
+ render: (context: TreeNodeRenderContext<TData>) => React.ReactNode;
38
+ /** Optional child group. */
39
+ children?: TreeNodeChildren<TData>;
40
+ };
41
+ type TreeNodeEdge = {
42
+ key: string;
43
+ from: string;
44
+ to: string;
45
+ index: number;
46
+ count: number;
47
+ };
48
+ type NodeTreeAlign = "center" | "start" | "end" | {
49
+ x: "center" | "start" | "end";
50
+ y: "center" | "start" | "end";
51
+ };
52
+ interface NodeTreeLayoutOptions {
53
+ /** Horizontal/vertical alignment. String form applies to x with y defaulting to "start". @default "center" */
54
+ align?: NodeTreeAlign;
55
+ /** Overall flow direction for child placement. @default "down" */
56
+ direction?: "down" | "right";
57
+ /** Layout for top-level nodes. @default "stack" */
58
+ root?: "stack" | "row";
59
+ /** Spacing between nodes. @default 64 */
60
+ gap?: number;
61
+ /** Extra padding around connection bounds. @default 64 */
62
+ padding?: number;
63
+ /** Padding around the entire tree container. @default 128 */
64
+ containerPadding?: number;
65
+ }
66
+ interface NodeTreeConnectionOptions {
67
+ /** Line stroke color. @default "rgba(255,255,255)" */
68
+ color?: string;
69
+ /** Line stroke width in px. @default 1 */
70
+ width?: number;
71
+ /** Line opacity (0 to 1). @default 1 when debug=true, otherwise 0.1 */
72
+ opacity?: number;
73
+ }
74
+ interface NodeTreeAnimationOptions {
75
+ /** Total animation time in ms (all nodes/lines complete within this duration). @default 2000 */
76
+ durationMs?: number;
77
+ }
78
+ interface NodeTreeClassNameOptions {
79
+ /** Class name for the root wrapper element. */
80
+ root?: string;
81
+ /** Class name for the inner canvas container. */
82
+ canvas?: string;
83
+ /** Class name for the renderer section. */
84
+ renderer?: string;
85
+ /** Class name for each node frame wrapper. */
86
+ frame?: string;
87
+ /** Class name for the SVG connections layer. */
88
+ connections?: string;
89
+ }
90
+ interface NodeTreeFrameOptions {
91
+ /** Extra inline styles applied to each node frame wrapper. */
92
+ style?: React.CSSProperties;
93
+ }
94
+ interface NodeTreeProps extends Omit<React.HTMLAttributes<HTMLDivElement>, "className"> {
95
+ /** Root nodes to render. */
96
+ nodeTree: TreeNode[];
97
+ /** Slot-based class names for internal elements. */
98
+ className?: NodeTreeClassNameOptions;
99
+ /** Grouped layout options. */
100
+ layout?: NodeTreeLayoutOptions;
101
+ /** Grouped connection line options. */
102
+ connection?: NodeTreeConnectionOptions;
103
+ /** Grouped animation options. */
104
+ animation?: NodeTreeAnimationOptions;
105
+ /** Grouped node frame options. */
106
+ nodeFrame?: NodeTreeFrameOptions;
107
+ /** Show debug overlay badges. @default false */
108
+ debug?: boolean;
109
+ }
110
+ interface NodeFrameProps extends React.HTMLAttributes<HTMLDivElement> {
111
+ /** Node associated with this frame element. */
112
+ node: TreeNode;
113
+ /** Ref registry hook used internally for layout measurements. */
114
+ onRef: (id: string, element: HTMLDivElement | null) => void;
115
+ children: React.ReactNode;
116
+ }
117
+
118
+ declare const NodeTree: React.ForwardRefExoticComponent<NodeTreeProps & React.RefAttributes<HTMLDivElement>>;
119
+
120
+ export { type NodeFrameProps, NodeTree, type NodeTreeAnimationOptions, type NodeTreeClassNameOptions, type NodeTreeConnectionOptions, type NodeTreeFrameOptions, type NodeTreeLayoutOptions, type NodeTreeProps, type TreeNode, type TreeNodeChildren, type TreeNodeEdge, type TreeNodeRenderContext };