@hlang-tech/editor-ui 0.2.2 → 0.4.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.
package/lib/index.mjs.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/tokens/tokens.ts","../src/tokens/theme.ts","../src/tokens/ThemeProvider.tsx","../src/nodes/SignalBar.tsx","../src/nodes/PortRow.tsx","../src/nodes/NodeBodySlot.tsx","../src/live/LiveSignalContext.tsx","../src/live/live-signal-store.ts","../src/nodes/AssetNode.tsx","../src/nodes/PillNode.tsx","../src/icons/node-icons.tsx","../src/panels/DiagnosticBadge.tsx","../src/nodes/NodeInteractionContext.tsx","../src/nodes/HlangNode.tsx","../src/edges/FlowEdge.tsx","../src/nodes/flow-types.ts","../src/shell/EditorShell.tsx","../src/toolbar/Toolbar.tsx","../src/toolbar/ToolCluster.tsx","../src/canvas/CanvasChrome.tsx","../src/canvas/CanvasDock.tsx","../src/canvas/EmptyState.tsx","../src/panels/InspectorPanel.tsx","../src/schema/param-field.ts","../src/hooks/useNodeParams.ts","../src/panels/ParamForm.tsx","../src/panels/OutlineTree.tsx","../src/panels/PreviewPanel.tsx","../src/panels/RailTabs.tsx","../src/panels/AssetGrid.tsx","../src/panels/PositionPanel.tsx","../src/command-palette/NodeSearch.tsx","../src/command-palette/useNodeSearch.ts","../src/command-palette/fuzzy.ts","../src/command-palette/node-search-model.ts","../src/command-palette/useNodeSearchTriggers.ts","../src/hooks/useEditorHotkeys.ts","../src/context-menu/NodeContextMenu.tsx","../src/context-menu/useNodeContextMenu.ts","../src/overlays/Cheatsheet.tsx","../src/overlays/Toast.tsx","../src/hooks/useLiveSignals.ts"],"sourcesContent":["/**\n * Typed accessors for the design tokens. This module only NAMES the CSS custom\n * properties declared in `tokens.css` — it never duplicates their values, so\n * there is a single source of truth. Components reference tokens through here\n * (e.g. `KIND_TOKEN[node.kind]`) instead of hardcoding hex values.\n */\n\nimport type { NodeKind } from '@hlang-tech/editor-core';\n\n/** The full set of token custom-property names (without the leading `--`). */\nexport const TOKEN_NAMES = [\n 'hl-void',\n 'hl-void-2',\n 'hl-surface',\n 'hl-surface-2',\n 'hl-line',\n 'hl-line-strong',\n 'hl-silver',\n 'hl-silver-hi',\n 'hl-silver-lo',\n 'hl-spark',\n 'hl-r',\n 'hl-t',\n 'hl-w',\n 'hl-error',\n 'hl-ink',\n 'hl-ink-2',\n 'hl-ink-3',\n 'hl-font-ui',\n 'hl-font-mono',\n 'hl-r-sm',\n 'hl-r-md',\n 'hl-r-lg',\n 'hl-r-pill',\n 'hl-shadow-node',\n 'hl-shadow-glass',\n 'hl-glow-silver',\n 'hl-ease',\n] as const;\n\n/** A token name (without `--`), e.g. `'hl-silver'`. */\nexport type TokenName = (typeof TOKEN_NAMES)[number];\n\n/** `var(--<name>)` reference string for a token. */\nexport function tokenVar(name: TokenName): string {\n return `var(--${name})`;\n}\n\n/** Maps a node kind to its color-temperature token reference. */\nexport const KIND_TOKEN: Record<NodeKind, string> = {\n R: 'var(--hl-r)',\n T: 'var(--hl-t)',\n W: 'var(--hl-w)',\n};\n\n/** Human-readable role label per node kind (used in node headers). */\nexport const KIND_ROLE: Record<NodeKind, string> = {\n R: 'source',\n T: 'transform',\n W: 'sink',\n};\n","/**\n * Theming: a host overrides any subset of tokens by producing a CSS-variable\n * style object with `createTheme(...)` and applying it (via\n * `EditorUIThemeProvider` or directly on a wrapper element). Zero-runtime and\n * SSR-safe — it is just inline custom properties.\n */\n\nimport type { CSSProperties } from 'react';\nimport type { TokenName } from './tokens';\n\n/**\n * A partial override map from token name to CSS value. Values may be\n * `undefined` (treated as \"not overridden\") so callers can pass conditional\n * overrides without pre-filtering.\n */\nexport type ThemeOverride = Partial<Record<TokenName, string | undefined>>;\n\n/**\n * Build a style object that overrides the given tokens as inline custom\n * properties. Apply it to a wrapping element to re-theme everything beneath.\n *\n * ```ts\n * <div style={createTheme({ 'hl-silver': '#d8dce4' })}> … </div>\n * ```\n */\nexport function createTheme(overrides: ThemeOverride): CSSProperties {\n // CSS custom properties are typed via an index signature on CSSProperties,\n // so a plain string map of `--*` keys is structurally a CSSProperties.\n const style: CSSProperties & Record<`--${string}`, string> = {};\n for (const [name, value] of Object.entries(overrides)) {\n if (value !== undefined) {\n style[`--${name}`] = value;\n }\n }\n return style;\n}\n","/**\n * `EditorUIThemeProvider` — applies a token override to its subtree by wrapping\n * children in an element carrying the inline custom properties from\n * `createTheme`. Import `@hlang-tech/editor-ui/tokens.css` once at the app root\n * for the base tokens; use this provider only to override.\n */\n\nimport type { ReactElement, ReactNode, CSSProperties } from 'react';\nimport { createTheme } from './theme';\nimport type { ThemeOverride } from './theme';\n\nexport interface EditorUIThemeProviderProps {\n readonly theme?: ThemeOverride;\n readonly className?: string;\n readonly style?: CSSProperties;\n readonly children: ReactNode;\n}\n\nexport function EditorUIThemeProvider({\n theme,\n className,\n style,\n children,\n}: EditorUIThemeProviderProps): ReactElement {\n const themeStyle = theme ? createTheme(theme) : undefined;\n return (\n <div className={className} style={{ ...themeStyle, ...style }}>\n {children}\n </div>\n );\n}\n","/**\n * The thin, kind-tinted bar across the top of a node — the node's kind\n * expressed with restraint (no large color fills). Reads `--hl-kind` set by the\n * node's kind class.\n */\n\nimport type { ReactElement } from 'react';\n\nexport function SignalBar(): ReactElement {\n return <div className=\"hl-signal\" aria-hidden=\"true\" />;\n}\n","/**\n * A single port row: a React Flow `Handle` anchored to this row (so it centers\n * on its own label, never drifting) plus the port's mono label. Renders the\n * live/value distinction (filled vs hollow handle) and the error hue.\n */\n\nimport type { ReactElement } from 'react';\nimport { Handle, Position } from '@xyflow/react';\nimport type { PortDescriptor } from '@hlang-tech/editor-core';\n\nexport interface PortRowProps {\n readonly port: PortDescriptor;\n}\n\nexport function PortRow({ port }: PortRowProps): ReactElement {\n const isInput = port.direction === 'I';\n const side = isInput ? 'target' : 'source';\n // Ports are RxJS streams by default; a `value` port only emits on change.\n const isLive = port.stream !== 'value';\n const rowClass = `hl-port${port.isError ? ' is-error' : ''}`;\n const handleClass = `hl-handle${isLive ? ' is-live' : ''}`;\n\n return (\n <li className={rowClass}>\n <Handle\n type={side}\n position={isInput ? Position.Left : Position.Right}\n id={port.id}\n className={handleClass}\n isConnectable\n />\n <span className=\"hl-port-label\">{port.isError ? 'error' : port.name}</span>\n </li>\n );\n}\n","/**\n * The node-body extension point. In M-UI-1 this renders nothing (generic nodes\n * stay clean R/T/W cards). M-UI-5 wires it to the NodeBodyRegistry so a host\n * application can render custom content — image/video previews, inline\n * widgets — per node `code`/`kind` without editor-ui knowing anything about it.\n */\n\nimport type { ReactElement, ReactNode } from 'react';\nimport type { EditorNode } from '@hlang-tech/editor-core';\n\nexport interface NodeBodySlotProps {\n readonly node: EditorNode;\n /** Custom body content, resolved by the host/registry. Empty renders nothing. */\n readonly children?: ReactNode;\n}\n\nexport function NodeBodySlot({ children }: NodeBodySlotProps): ReactElement | null {\n if (children === undefined || children === null || children === false) {\n return null;\n }\n return <div className=\"hl-body\">{children}</div>;\n}\n","/**\n * React glue for the LiveSignalStore. A single store instance is provided via\n * context; node/edge components subscribe to their own id through\n * `useNodeLiveState` / `useEdgeFlowing` (each returns a primitive, so only the\n * components whose state actually flips re-render — no global DOM scanning).\n */\n\nimport { createContext, useContext, useMemo, useSyncExternalStore } from 'react';\nimport type { ReactElement, ReactNode } from 'react';\nimport { LiveSignalStore } from './live-signal-store';\nimport type { NodeLiveState } from './live-signal-store';\n\nconst LiveSignalContext = createContext<LiveSignalStore | null>(null);\n\nexport interface LiveSignalProviderProps {\n /** Optional external store; a fresh one is created if omitted. */\n readonly store?: LiveSignalStore;\n readonly children: ReactNode;\n}\n\nexport function LiveSignalProvider({ store, children }: LiveSignalProviderProps): ReactElement {\n const value = useMemo(() => store ?? new LiveSignalStore(), [store]);\n return <LiveSignalContext.Provider value={value}>{children}</LiveSignalContext.Provider>;\n}\n\n/** Access the live store, or `null` when there is no provider (visuals off). */\nexport function useLiveSignalStore(): LiveSignalStore | null {\n return useContext(LiveSignalContext);\n}\n\n/** Subscribe to a single node's live state. Idle when no store is present. */\nexport function useNodeLiveState(nodeId: string): NodeLiveState {\n const store = useContext(LiveSignalContext);\n return useSyncExternalStore(\n onChange => (store === null ? () => undefined : store.subscribeNode(nodeId, onChange)),\n () => (store === null ? 'idle' : store.getNodeState(nodeId)),\n () => 'idle',\n );\n}\n\n/** Subscribe to a single edge's flowing state. False when no store is present. */\nexport function useEdgeFlowing(edgeId: string): boolean {\n const store = useContext(LiveSignalContext);\n return useSyncExternalStore(\n onChange => (store === null ? () => undefined : store.subscribeEdge(edgeId, onChange)),\n () => (store === null ? false : store.isEdgeFlowing(edgeId)),\n () => false,\n );\n}\n","/**\n * `LiveSignalStore` — the source of truth for a running graph's live visual\n * state. It ingests activity/error signals, decays activity over a short\n * window, and lets node/edge components subscribe to THEIR OWN id only.\n *\n * Design rationale (industrial-grade, no tricks):\n * - No global DOM scanning and no dependency on React Flow's private CSS\n * classes. Components read their state by id through `useSyncExternalStore`,\n * so only the components whose state actually flips re-render.\n * - Edge \"flowing\" state is computed from an injected edge index, not by\n * reaching into another layer's model at paint time.\n * - A single rAF loop advances decay and notifies only changed ids.\n */\n\n/** Live state of a node during execution. */\nexport type NodeLiveState = 'idle' | 'active' | 'error';\n\n/** How long a node/edge stays \"active\" after its last emission (ms). */\nconst ACTIVE_WINDOW_MS = 700;\n\ntype Listener = () => void;\n\n/** Composite key for a specific output port on a node. */\nfunction portKey(nodeId: string, portId: string): string {\n return `${nodeId}@${portId}`;\n}\n\n/** Minimal edge shape the store needs to map a source-port pulse to edges. */\nexport interface EdgeIndexEntry {\n readonly id: string;\n readonly sourceNodeId: string;\n readonly sourcePortId: string;\n readonly isError: boolean;\n}\n\n/** Injected clock + scheduler so the store is deterministic and testable. */\nexport interface LiveSignalStoreDeps {\n now(): number;\n schedule(cb: () => void): number;\n cancel(handle: number): void;\n}\n\nconst defaultDeps: LiveSignalStoreDeps = {\n now: () => (typeof performance !== 'undefined' ? performance.now() : Date.now()),\n schedule: cb =>\n typeof requestAnimationFrame !== 'undefined'\n ? requestAnimationFrame(cb)\n : // `window.setTimeout` returns a numeric handle (the DOM overload),\n // unlike the Node overload's `Timeout` object — this store deals in\n // numeric handles because it runs in the browser.\n window.setTimeout(cb, 16),\n cancel: h =>\n typeof cancelAnimationFrame !== 'undefined'\n ? cancelAnimationFrame(h)\n : window.clearTimeout(h),\n};\n\nexport class LiveSignalStore {\n private readonly deps: LiveSignalStoreDeps;\n /** nodeId -> last-active timestamp. */\n private readonly nodeActiveAt = new Map<string, number>();\n /** nodeId set that errored during this run. */\n private readonly erroredNodes = new Set<string>();\n /** edgeId -> last-flowing timestamp. */\n private readonly edgeFlowAt = new Map<string, number>();\n /** Per-id listeners. */\n private readonly nodeListeners = new Map<string, Set<Listener>>();\n private readonly edgeListeners = new Map<string, Set<Listener>>();\n /** Snapshot of last-emitted state per id, so we only notify on real change. */\n private readonly lastNodeState = new Map<string, NodeLiveState>();\n private readonly lastEdgeFlowing = new Map<string, boolean>();\n /** Edges sourced by a given (nodeId@portId), for pulse -> edge mapping. */\n private edgesBySourcePort = new Map<string, EdgeIndexEntry[]>();\n private rafHandle: number | null = null;\n private running = false;\n\n constructor(deps: LiveSignalStoreDeps = defaultDeps) {\n this.deps = deps;\n }\n\n /** Provide the current edge index (call whenever edges change). */\n setEdgeIndex(edges: readonly EdgeIndexEntry[]): void {\n const next = new Map<string, EdgeIndexEntry[]>();\n for (const edge of edges) {\n const key = portKey(edge.sourceNodeId, edge.sourcePortId);\n const list = next.get(key);\n if (list === undefined) {\n next.set(key, [edge]);\n } else {\n list.push(edge);\n }\n }\n this.edgesBySourcePort = next;\n }\n\n /** Record a node emitting on an output port (drives node + edge activity). */\n markActivity(nodeId: string, portId: string): void {\n const t = this.deps.now();\n this.nodeActiveAt.set(nodeId, t);\n const edges = this.edgesBySourcePort.get(portKey(nodeId, portId));\n if (edges !== undefined) {\n for (const edge of edges) {\n this.edgeFlowAt.set(edge.id, t);\n }\n }\n this.ensureLoop();\n }\n\n /** Record a node erroring (sticky for the run). */\n markError(nodeId: string): void {\n this.erroredNodes.add(nodeId);\n this.ensureLoop();\n }\n\n /** Clear all live state (on stop/teardown) and notify everyone. */\n reset(): void {\n this.nodeActiveAt.clear();\n this.erroredNodes.clear();\n this.edgeFlowAt.clear();\n this.stopLoop();\n this.flushNotifications();\n }\n\n /** Subscribe to a single node's live state. */\n subscribeNode(nodeId: string, listener: Listener): () => void {\n return this.subscribe(this.nodeListeners, nodeId, listener);\n }\n\n /** Subscribe to a single edge's flowing state. */\n subscribeEdge(edgeId: string, listener: Listener): () => void {\n return this.subscribe(this.edgeListeners, edgeId, listener);\n }\n\n /** Current live state of a node. */\n getNodeState(nodeId: string): NodeLiveState {\n if (this.erroredNodes.has(nodeId)) {\n return 'error';\n }\n const at = this.nodeActiveAt.get(nodeId);\n if (at !== undefined && this.deps.now() - at <= ACTIVE_WINDOW_MS) {\n return 'active';\n }\n return 'idle';\n }\n\n /** Whether an edge is currently flowing. */\n isEdgeFlowing(edgeId: string): boolean {\n const at = this.edgeFlowAt.get(edgeId);\n return at !== undefined && this.deps.now() - at <= ACTIVE_WINDOW_MS;\n }\n\n private subscribe(\n registry: Map<string, Set<Listener>>,\n id: string,\n listener: Listener,\n ): () => void {\n const set = registry.get(id) ?? new Set<Listener>();\n set.add(listener);\n registry.set(id, set);\n return () => {\n set.delete(listener);\n if (set.size === 0) {\n registry.delete(id);\n }\n };\n }\n\n private ensureLoop(): void {\n if (this.running) {\n this.flushNotifications();\n return;\n }\n this.running = true;\n const step = (): void => {\n const stillLive = this.flushNotifications();\n if (stillLive) {\n this.rafHandle = this.deps.schedule(step);\n } else {\n this.running = false;\n this.rafHandle = null;\n }\n };\n this.rafHandle = this.deps.schedule(step);\n }\n\n private stopLoop(): void {\n if (this.rafHandle !== null) {\n this.deps.cancel(this.rafHandle);\n this.rafHandle = null;\n }\n this.running = false;\n }\n\n /**\n * Recompute every subscribed id's state, notify only those that changed, and\n * report whether anything is still within its active window (so the loop can\n * stop when the graph goes quiet).\n */\n private flushNotifications(): boolean {\n let anyLive = false;\n\n for (const [nodeId, listeners] of this.nodeListeners) {\n const state = this.getNodeState(nodeId);\n if (state !== 'idle') {\n anyLive = anyLive || state === 'active';\n }\n if (this.lastNodeState.get(nodeId) !== state) {\n this.lastNodeState.set(nodeId, state);\n for (const listener of listeners) {\n listener();\n }\n }\n }\n\n for (const [edgeId, listeners] of this.edgeListeners) {\n const flowing = this.isEdgeFlowing(edgeId);\n anyLive = anyLive || flowing;\n if (this.lastEdgeFlowing.get(edgeId) !== flowing) {\n this.lastEdgeFlowing.set(edgeId, flowing);\n for (const listener of listeners) {\n listener();\n }\n }\n }\n\n return anyLive;\n }\n}\n","/**\n * `AssetNode` — a source node dressed as a real image asset.\n *\n * Architecturally this is just an R node: to the runtime it has output ports and\n * emits its image (its `params.imageUrl`). editor-ui is free to DRESS it as a\n * framed photograph — a frosted-glass card whose hero is the image itself — with\n * no change to the input/output contract. This is the layering: the bottom is an\n * input→output DAG; this layer decides what the node looks like.\n *\n * Ports are reused verbatim (PortRow → React Flow Handle), so wiring behaves\n * exactly like any other node; the output handle rides the image's right edge.\n */\n\nimport type { ReactElement } from 'react';\nimport type { EditorNode } from '@hlang-tech/editor-core';\nimport { PortRow } from './PortRow';\nimport { useNodeLiveState } from '../live/LiveSignalContext';\nimport './AssetNode.css';\n\nexport interface AssetNodeChromeProps {\n readonly node: EditorNode;\n readonly selected?: boolean;\n}\n\n/** Read a string param, or undefined. */\nfunction stringParam(node: EditorNode, key: string): string | undefined {\n const v = node.params[key];\n return typeof v === 'string' ? v : undefined;\n}\n\nexport function AssetNodeChrome({ node, selected }: AssetNodeChromeProps): ReactElement {\n const imageUrl = stringParam(node, 'imageUrl') ?? '';\n const caption = stringParam(node, 'caption') ?? node.name;\n const role = stringParam(node, 'role'); // optional semantic role (e.g. Character)\n const live = useNodeLiveState(node.id);\n // An asset is a clean source: expose only its data output(s). The `@node/error`\n // port still exists in the model, but drawing it on the photo would be visual\n // clutter (nover hides plumbing) — error wiring is an advanced affordance.\n const outputs = node.ports.filter(p => p.direction === 'O' && !p.isError);\n\n const className = [\n 'hl-asset',\n selected ? 'is-selected' : '',\n live === 'active' ? 'is-active' : '',\n live === 'error' ? 'is-live-error' : '',\n ]\n .filter(Boolean)\n .join(' ');\n\n return (\n <div className={className} data-kind={node.kind}>\n <div className=\"hl-asset-frame\">\n {imageUrl.length > 0 ? (\n <img className=\"hl-asset-img\" src={imageUrl} alt={caption} draggable={false} />\n ) : (\n <div className=\"hl-asset-placeholder\" aria-hidden />\n )}\n <div className=\"hl-asset-scrim\" />\n <div className=\"hl-asset-caption\">\n <span className=\"hl-asset-name\">{caption}</span>\n {role !== undefined && <span className=\"hl-asset-role hl-mono\">{role}</span>}\n </div>\n </div>\n {/* Output ports ride the right edge; hidden until hover/select via CSS. */}\n <ul className=\"hl-asset-ports\">\n {outputs.map(port => (\n <PortRow key={port.id} port={port} />\n ))}\n </ul>\n </div>\n );\n}\n","/**\n * `PillNode` — the default dressing for a non-asset node: a nover-style capsule.\n *\n * To the runtime this is still an ordinary R/T/W node with ports; editor-ui just\n * dresses it as a rounded pill — a kind-tinted domain dot, the name, and a\n * status dot — with the ports HIDDEN at rest and revealed on hover/selection.\n * The picture, not the plumbing. The verbose port-board (`NodeChrome`) remains\n * available as an \"expanded\" view for later.\n *\n * Ports reuse `PortRow` (so wiring is identical); the pill styles the handles\n * to ride its left/right edges as small silver dots.\n */\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport type { ReactElement, KeyboardEvent } from 'react';\nimport type { EditorNode } from '@hlang-tech/editor-core';\nimport { PortRow } from './PortRow';\nimport { NodeIcon } from '../icons/node-icons';\nimport { DiagnosticBadge } from '../panels/DiagnosticBadge';\nimport { useNodeLiveState } from '../live/LiveSignalContext';\nimport { useNodeInteraction } from './NodeInteractionContext';\nimport './PillNode.css';\n\n/** Max gap (ms) between two clicks on the node name to count as a double-click. */\nconst DOUBLE_CLICK_MS = 320;\n\nexport interface PillNodeChromeProps {\n readonly node: EditorNode;\n readonly selected?: boolean;\n}\n\nexport function PillNodeChrome({ node, selected }: PillNodeChromeProps): ReactElement {\n const live = useNodeLiveState(node.id);\n const interaction = useNodeInteraction();\n const diagnostic = interaction.diagnosticFor(node.id);\n\n // Inline rename: double-click the name to edit; Enter/blur commits, Esc cancels.\n const [editing, setEditing] = useState(false);\n const [draft, setDraft] = useState(node.name);\n const inputRef = useRef<HTMLInputElement>(null);\n useEffect(() => {\n if (editing) {\n setDraft(node.name);\n // Focus + select on next tick so the input exists.\n requestAnimationFrame(() => inputRef.current?.select());\n }\n }, [editing, node.name]);\n const commit = useCallback((): void => {\n setEditing(false);\n interaction.rename(node.id, draft);\n }, [interaction, node.id, draft]);\n const onKeyDown = useCallback(\n (e: KeyboardEvent<HTMLInputElement>): void => {\n if (e.key === 'Enter') {\n e.preventDefault();\n commit();\n } else if (e.key === 'Escape') {\n e.preventDefault();\n setEditing(false);\n }\n },\n [commit],\n );\n\n // React Flow's node-drag pointer handler swallows the browser's native\n // dblclick on a node child, so detect a double-click manually from two rapid\n // clicks (which RF does not block). 320ms window.\n const lastClick = useRef(0);\n const onNameClick = useCallback((): void => {\n const now = performance.now();\n if (now - lastClick.current < DOUBLE_CLICK_MS) {\n setEditing(true);\n lastClick.current = 0;\n } else {\n lastClick.current = now;\n }\n }, []);\n\n // Data ports only; the error port exists in the model but isn't drawn on the\n // resting pill (advanced affordance — keeps the capsule clean).\n const inputs = node.ports.filter(p => p.direction === 'I' && !p.isError);\n const outputs = node.ports.filter(p => p.direction === 'O' && !p.isError);\n\n const className = [\n 'hl-pill',\n `hl-pill-${node.kind.toLowerCase()}`,\n selected ? 'is-selected' : '',\n live === 'active' ? 'is-active' : '',\n live === 'error' ? 'is-live-error' : '',\n diagnostic?.severity === 'error' ? 'has-diag-error' : '',\n diagnostic?.severity === 'warning' ? 'has-diag-warning' : '',\n ]\n .filter(Boolean)\n .join(' ');\n\n return (\n <div className={className} data-kind={node.kind}>\n {/* Domain bead: a kind-tinted disc carrying the node's per-type icon. */}\n <span className=\"hl-pill-dot\" aria-hidden>\n <NodeIcon code={node.code} kind={node.kind} size={13} />\n </span>\n {editing ? (\n <input\n ref={inputRef}\n className=\"hl-pill-rename nodrag\"\n value={draft}\n onChange={e => setDraft(e.target.value)}\n onKeyDown={onKeyDown}\n onBlur={commit}\n spellCheck={false}\n aria-label=\"Rename node\"\n />\n ) : (\n <span\n className=\"hl-pill-name\"\n onClick={() => {\n // The name covers most of the capsule, so it behaves like the node:\n // the click also reaches React Flow (which selects the node) and a\n // press here drags the node. React Flow swallows the native dblclick\n // on a node child, so a double-click is detected from two rapid\n // clicks; it is the only rename path.\n onNameClick();\n }}\n title=\"Double-click to rename\"\n >\n {node.name}\n </span>\n )}\n {/* Edit-time diagnostic badge (independent of the runtime error channel). */}\n {diagnostic !== undefined && (\n <DiagnosticBadge diagnostic={diagnostic} variant=\"hl-pill-diag\" size={12} />\n )}\n {/* Status dot — lit when the node is active during a run. */}\n <span className=\"hl-pill-status\" aria-hidden />\n\n {/* Ports ride the capsule edges; hidden until hover/select. */}\n <ul className=\"hl-pill-ports hl-in\">\n {inputs.map(port => (\n <PortRow key={port.id} port={port} />\n ))}\n </ul>\n <ul className=\"hl-pill-ports hl-out\">\n {outputs.map(port => (\n <PortRow key={port.id} port={port} />\n ))}\n </ul>\n </div>\n );\n}\n","/**\n * Per-type node icons. A small registry mapping a node `code` to a crisp\n * line-glyph (1.5px stroke, currentColor), with a kind fallback (R/T/W). Used\n * by the outline tree and the node chrome so every node reads by its ROLE, not\n * a generic letter — the difference between a tool and a spreadsheet.\n *\n * Icons are inline SVG (not emoji) for a premium, monochrome, scalable look;\n * they inherit `color` so callers tint them by kind or silver.\n */\n\nimport type { ReactElement } from 'react';\nimport type { NodeKind } from '@hlang-tech/editor-core';\n\ninterface IconProps {\n readonly size?: number;\n}\n\n/** Common svg wrapper: currentColor stroke, no fill, round joins. */\nfunction svg(size: number, children: ReactElement | readonly ReactElement[]): ReactElement {\n return (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={1.6}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden\n >\n {children}\n </svg>\n );\n}\n\n/** Icon builders keyed by node code. */\nconst BY_CODE: Record<string, (s: number) => ReactElement> = {\n 'image-source': s => svg(s, [\n <rect key=\"r\" x=\"3\" y=\"4\" width=\"18\" height=\"16\" rx=\"2.5\" />,\n <circle key=\"c\" cx=\"8.5\" cy=\"9\" r=\"1.6\" />,\n <path key=\"p\" d=\"M4 17l5-5 4 4 3-2 4 4\" />,\n ]),\n 'text-source': s => svg(s, [<path key=\"p\" d=\"M5 6h14M12 6v12M9 18h6\" />]),\n 'interval-source': s => svg(s, [\n <circle key=\"c\" cx=\"12\" cy=\"12\" r=\"8\" />,\n <path key=\"h\" d=\"M12 8v4l3 2\" />,\n ]),\n 'range-source': s => svg(s, [\n <path key=\"l\" d=\"M4 12h16\" />,\n <circle key=\"a\" cx=\"6\" cy=\"12\" r=\"2\" />,\n <circle key=\"b\" cx=\"18\" cy=\"12\" r=\"2\" />,\n ]),\n 'constant-source': s => svg(s, [<path key=\"p\" d=\"M6 12h12M9 8l-3 4 3 4M15 8l3 4-3 4\" />]),\n 'map-scale': s => svg(s, [\n <path key=\"a\" d=\"M4 20V8l8-4\" />,\n <path key=\"b\" d=\"M4 8l8 4 8-4M12 12v8\" />,\n ]),\n uppercase: s => svg(s, [<path key=\"p\" d=\"M5 18L9 6l4 12M6.5 14h5M15 10v8M15 10c3 0 3 4 0 4\" />]),\n 'filter-threshold': s => svg(s, [<path key=\"p\" d=\"M4 5h16l-6 7v6l-4-2v-4z\" />]),\n 'scan-sum': s => svg(s, [<path key=\"p\" d=\"M17 6H7l6 6-6 6h10\" />]),\n delay: s => svg(s, [\n <circle key=\"c\" cx=\"12\" cy=\"13\" r=\"7\" />,\n <path key=\"h\" d=\"M12 10v3l2 2M9 3h6\" />,\n ]),\n merge: s => svg(s, [<path key=\"p\" d=\"M6 5v4c0 3 3 3 6 3s6 0 6-3V5M12 12v7\" />]),\n 'console-sink': s => svg(s, [\n <rect key=\"r\" x=\"4\" y=\"5\" width=\"16\" height=\"12\" rx=\"2\" />,\n <path key=\"p\" d=\"M8 10l2.5 2L8 14M13 14h3\" />,\n ]),\n 'collect-sink': s => svg(s, [\n <path key=\"p\" d=\"M4 7h16M4 12h16M4 17h10\" />,\n ]),\n};\n\n/** Fallback glyph per kind when a code has no specific icon. */\nconst BY_KIND: Record<NodeKind, (s: number) => ReactElement> = {\n R: s => svg(s, [<path key=\"p\" d=\"M8 5l10 7-10 7z\" />]), // source ▷ (play)\n T: s => svg(s, [<path key=\"p\" d=\"M4 8h6l4 8h6M14 8h6M4 16h6\" />]), // transform\n W: s => svg(s, [\n <path key=\"p\" d=\"M5 4h11l3 3v13H5z\" />,\n <path key=\"q\" d=\"M9 4v5h6\" />,\n ]), // sink (save)\n};\n\nexport interface NodeIconProps extends IconProps {\n readonly code: string;\n readonly kind: NodeKind;\n}\n\n/** Render the icon for a node, by code (then kind fallback). */\nexport function NodeIcon({ code, kind, size = 15 }: NodeIconProps): ReactElement {\n const build = BY_CODE[code] ?? BY_KIND[kind];\n return build(size);\n}\n\n// ---------------------------------------------------------------------------\n// Control glyphs — crisp line icons for the outline's visible/lock affordances.\n// Kept in the same registry so every glyph shares one stroke language. Unlike\n// emoji, these stay legible at small sizes and against dark/dim rows.\n// ---------------------------------------------------------------------------\n\n/** Open eye — layer visible. */\nexport function EyeIcon({ size = 14 }: IconProps): ReactElement {\n return svg(size, [\n <path key=\"p\" d=\"M2 12s3.5-6.5 10-6.5S22 12 22 12s-3.5 6.5-10 6.5S2 12 2 12z\" />,\n <circle key=\"c\" cx=\"12\" cy=\"12\" r=\"2.6\" />,\n ]);\n}\n\n/** Eye with a slash — layer hidden. Always reads clearly, even on a dim row. */\nexport function EyeOffIcon({ size = 14 }: IconProps): ReactElement {\n return svg(size, [\n <path key=\"p\" d=\"M2 12s3.5-6.5 10-6.5c1.7 0 3.2.45 4.5 1.1M22 12s-3.5 6.5-10 6.5c-1.7 0-3.2-.45-4.5-1.1\" />,\n <path key=\"e\" d=\"M9.9 9.9a2.6 2.6 0 003.7 3.7\" />,\n <path key=\"s\" d=\"M3 3l18 18\" />,\n ]);\n}\n\n/** Open padlock — layer unlocked (editable). */\nexport function UnlockIcon({ size = 14 }: IconProps): ReactElement {\n return svg(size, [\n <rect key=\"r\" x=\"5\" y=\"11\" width=\"14\" height=\"9\" rx=\"2\" />,\n <path key=\"s\" d=\"M8 11V7a4 4 0 017.9-1\" />,\n ]);\n}\n\n/** Closed padlock — layer locked (pinned, not draggable). */\nexport function LockIcon({ size = 14 }: IconProps): ReactElement {\n return svg(size, [\n <rect key=\"r\" x=\"5\" y=\"11\" width=\"14\" height=\"9\" rx=\"2\" />,\n <path key=\"s\" d=\"M8 11V7a4 4 0 018 0v4\" />,\n ]);\n}\n\n/** Warning triangle — a predictive edit-time diagnostic. */\nexport function WarningIcon({ size = 13 }: IconProps): ReactElement {\n return svg(size, [\n <path key=\"t\" d=\"M12 4l9 15H3z\" />,\n <path key=\"b\" d=\"M12 10v4\" />,\n <path key=\"d\" d=\"M12 17v.5\" />,\n ]);\n}\n\n/** Error circle — a hard, runtime-fatal edit-time diagnostic. */\nexport function ErrorIcon({ size = 13 }: IconProps): ReactElement {\n return svg(size, [\n <circle key=\"c\" cx=\"12\" cy=\"12\" r=\"9\" />,\n <path key=\"b\" d=\"M12 7v6\" />,\n <path key=\"d\" d=\"M12 16v.5\" />,\n ]);\n}\n","/**\n * `DiagnosticBadge` — a single edit-time diagnostic marker (error/warning icon +\n * tooltip), shared by the node chrome and the outline so the severity→icon and\n * severity→class mapping lives in ONE place. `variant` only sets the wrapper\n * class prefix so each host can size/position it via its own CSS.\n */\n\nimport type { ReactElement } from 'react';\nimport type { Diagnostic } from '@hlang-tech/editor-core';\nimport { ErrorIcon, WarningIcon } from '../icons/node-icons';\n\nexport interface DiagnosticBadgeProps {\n readonly diagnostic: Diagnostic;\n /** Class-prefix so hosts style it in context (e.g. 'hl-pill-diag'). */\n readonly variant: string;\n readonly size?: number;\n}\n\nexport function DiagnosticBadge({ diagnostic, variant, size = 12 }: DiagnosticBadgeProps): ReactElement {\n return (\n <span\n className={`${variant} hl-diag-${diagnostic.severity}`}\n title={diagnostic.message}\n aria-label={`${diagnostic.severity}: ${diagnostic.message}`}\n >\n {diagnostic.severity === 'error' ? <ErrorIcon size={size} /> : <WarningIcon size={size} />}\n </span>\n );\n}\n","/**\n * `NodeInteractionContext` — optional per-node interaction wiring supplied by the\n * host (diagnostics to badge, rename to commit). Node chrome reads it to render a\n * diagnostic badge and to support inline rename, but degrades gracefully to a\n * plain, read-only node when no provider is present — so editor-ui stays usable\n * without the full editor wiring.\n */\n\nimport { createContext, useContext } from 'react';\nimport type { ReactElement, ReactNode } from 'react';\nimport type { Diagnostic, NodeId } from '@hlang-tech/editor-core';\n\nexport interface NodeInteraction {\n /** The most severe diagnostic on a node, or undefined. */\n diagnosticFor(id: NodeId): Diagnostic | undefined;\n /** Commit a rename (host routes it through the command service). */\n rename(id: NodeId, name: string): void;\n}\n\nconst NoopInteraction: NodeInteraction = {\n diagnosticFor: () => undefined,\n rename: () => undefined,\n};\n\nconst NodeInteractionCtx = createContext<NodeInteraction>(NoopInteraction);\n\nexport interface NodeInteractionProviderProps {\n readonly value: NodeInteraction;\n readonly children: ReactNode;\n}\n\nexport function NodeInteractionProvider({\n value,\n children,\n}: NodeInteractionProviderProps): ReactElement {\n return <NodeInteractionCtx.Provider value={value}>{children}</NodeInteractionCtx.Provider>;\n}\n\nexport function useNodeInteraction(): NodeInteraction {\n return useContext(NodeInteractionCtx);\n}\n","/**\n * The R/T/W node component. A near-monochrome glass card whose personality\n * comes from a thin kind-tinted signal bar and glowing ports; body content is\n * an extension point (empty for generic nodes). Ports are laid out in two\n * columns — inputs (I) left, outputs (O) right — each Handle anchored to its\n * own row so the `@node/error` port never drifts. W nodes render no error port\n * because their descriptor has none.\n */\n\nimport type { ReactElement, ReactNode } from 'react';\nimport type { NodeProps } from '@xyflow/react';\nimport type { HlangRFNode } from '@hlang-tech/editor-react';\nimport type { EditorNode } from '@hlang-tech/editor-core';\nimport { KIND_ROLE } from '../tokens/tokens';\nimport { SignalBar } from './SignalBar';\nimport { PortRow } from './PortRow';\nimport { NodeBodySlot } from './NodeBodySlot';\nimport { useNodeLiveState } from '../live/LiveSignalContext';\nimport { AssetNodeChrome } from './AssetNode';\nimport { PillNodeChrome } from './PillNode';\nimport './HlangNode.css';\n\n/** Presentational node chrome, decoupled from React Flow for easy testing. */\nexport interface NodeChromeProps {\n readonly node: EditorNode;\n readonly selected?: boolean;\n readonly body?: ReactNode;\n}\n\nexport function NodeChrome({ node, selected, body }: NodeChromeProps): ReactElement {\n const inputs = node.ports.filter(p => p.direction === 'I');\n const outputs = node.ports.filter(p => p.direction === 'O');\n const live = useNodeLiveState(node.id);\n const className = [\n 'hl-node',\n `hl-${node.kind.toLowerCase()}`,\n selected ? 'is-selected' : '',\n live === 'active' ? 'is-active' : '',\n live === 'error' ? 'is-live-error' : '',\n ]\n .filter(Boolean)\n .join(' ');\n\n return (\n <div className={className} data-kind={node.kind}>\n <SignalBar />\n <header className=\"hl-head\">\n <span className=\"hl-kind\">{node.kind}</span>\n <span className=\"hl-name\">{node.name}</span>\n <span className=\"hl-role\">{KIND_ROLE[node.kind]}</span>\n </header>\n <NodeBodySlot node={node}>{body}</NodeBodySlot>\n <div className=\"hl-ports\">\n <ul className=\"hl-col hl-in\">\n {inputs.map(port => (\n <PortRow key={port.id} port={port} />\n ))}\n </ul>\n <ul className=\"hl-col hl-out\">\n {outputs.map(port => (\n <PortRow key={port.id} port={port} />\n ))}\n </ul>\n </div>\n </div>\n );\n}\n\n/**\n * The React Flow node component. Reads everything from `data.editorNode`, then\n * DISPATCHES to the right dressing — all in editor-ui, with no change to the\n * runtime (every case is just a node with ports):\n * - an image asset (params.imageUrl) → {@link AssetNodeChrome} (framed photo)\n * - anything else → {@link PillNodeChrome} (nover capsule)\n * The verbose port-board {@link NodeChrome} stays available as a future\n * \"expanded\" view.\n */\nexport function HlangNode({ data, selected }: NodeProps<HlangRFNode>): ReactElement {\n const node = data.editorNode;\n if (typeof node.params.imageUrl === 'string' && node.params.imageUrl.length > 0) {\n return <AssetNodeChrome node={node} selected={selected} />;\n }\n return <PillNodeChrome node={node} selected={selected} />;\n}\n","/**\n * The signature edge: a connection rendered as a living stream. A base bezier\n * conduit plus a silver overlay that marches from output (O) to input (I) —\n * exactly what an hlang RxJS port does; a cold spark lights it while flowing.\n *\n * When the SOURCE node carries a semantic `role` param (e.g. Character,\n * Background), a small glass label pill rides the edge midpoint — naming what\n * the connection carries, the way nover labels its wires. The role is read from\n * the source node's params (no change to editor-react's edge data).\n */\n\nimport type { ReactElement } from 'react';\nimport { BaseEdge, EdgeLabelRenderer, getBezierPath, useInternalNode } from '@xyflow/react';\nimport type { EdgeProps } from '@xyflow/react';\nimport type { HlangRFEdge } from '@hlang-tech/editor-react';\nimport { useEdgeFlowing } from '../live/LiveSignalContext';\nimport './FlowEdge.css';\n\n/** Read a string `role` param off the source node, if any. */\nfunction useSourceRole(sourceId: string): string | undefined {\n const node = useInternalNode(sourceId);\n const editorNode = (node?.data as { editorNode?: { params?: Record<string, unknown> } } | undefined)\n ?.editorNode;\n const role = editorNode?.params?.role;\n return typeof role === 'string' && role.length > 0 ? role : undefined;\n}\n\nexport function FlowEdge(props: EdgeProps<HlangRFEdge>): ReactElement {\n const { id, source, sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, data } =\n props;\n const [path] = getBezierPath({\n sourceX,\n sourceY,\n sourcePosition,\n targetX,\n targetY,\n targetPosition,\n });\n // Bias the semantic label toward the TARGET (0.62 along the run), off the\n // source card into open canvas — the geometric midpoint of a short edge lands\n // on the source node and gets clipped. Labels name what a wire carries; they\n // must stay legible, not tuck behind a photo.\n const t = 0.62;\n const labelX = sourceX + (targetX - sourceX) * t;\n const labelY = sourceY + (targetY - sourceY) * t;\n\n const isError = data?.isError ?? false;\n const isValue = data?.stream === 'value';\n const flowing = useEdgeFlowing(id);\n const role = useSourceRole(source);\n const className = [\n 'hl-edge',\n isError ? 'is-error' : '',\n isValue ? 'is-value' : 'is-live',\n flowing ? 'is-flowing' : '',\n ]\n .filter(Boolean)\n .join(' ');\n\n return (\n <>\n <g className={className}>\n <BaseEdge id={id} path={path} className=\"hl-edge-base\" />\n <path d={path} className=\"hl-edge-flow\" />\n </g>\n {role !== undefined && (\n <EdgeLabelRenderer>\n <div\n className=\"hl-edge-label hl-mono\"\n style={{ transform: `translate(-50%, -50%) translate(${String(labelX)}px, ${String(labelY)}px)` }}\n >\n {role}\n </div>\n </EdgeLabelRenderer>\n )}\n </>\n );\n}\n","/**\n * One-line React Flow wiring: `createHlangFlowTypes()` returns the `nodeTypes`\n * and `edgeTypes` maps to spread onto `<ReactFlow>`, binding hlang's R/T/W node\n * kinds to `HlangNode` and the default edge to the flowing `FlowEdge`.\n *\n * ```tsx\n * const { nodeTypes, edgeTypes } = createHlangFlowTypes();\n * <ReactFlow nodeTypes={nodeTypes} edgeTypes={edgeTypes} {...useHlangFlow(core)} />\n * ```\n */\n\nimport type { EdgeTypes, NodeTypes } from '@xyflow/react';\nimport { HlangNode } from './HlangNode';\nimport { FlowEdge } from '../edges/FlowEdge';\n\nexport interface HlangFlowTypes {\n readonly nodeTypes: NodeTypes;\n readonly edgeTypes: EdgeTypes;\n}\n\n// React Flow's `NodeTypes`/`EdgeTypes` are keyed to the BASE node/edge props\n// (data: Record<string, unknown>), while our components declare the specific\n// `HlangRFNode`/`HlangRFEdge` data shape. The two are runtime-compatible — our\n// components only read fields that exist on the base type plus our own data —\n// but not structurally assignable, a well-known React Flow typing friction.\n// We narrow the entries to the registry types at this single boundary.\nconst nodeComponent = HlangNode as NodeTypes[string];\nconst edgeComponent = FlowEdge as EdgeTypes[string];\n\n/** Build the React Flow node/edge type maps for the hlang editor. */\nexport function createHlangFlowTypes(): HlangFlowTypes {\n return {\n nodeTypes: { R: nodeComponent, T: nodeComponent, W: nodeComponent },\n edgeTypes: { default: edgeComponent },\n };\n}\n","/**\n * `EditorShell` — composes the editor's regions (top toolbar, left panel,\n * center canvas, right inspector) as a CSS grid. It holds NO graph logic; a\n * host slots children into named regions. Left/right panels are collapsible via\n * UI-only props (collapse state is presentation, never part of the graph).\n */\n\nimport type { ReactElement, ReactNode } from 'react';\nimport './EditorShell.css';\n\nexport interface EditorShellProps {\n /** Top toolbar region. */\n readonly toolbar?: ReactNode;\n /** Left region (node palette / outline). */\n readonly left?: ReactNode;\n /** Right region (inspector). */\n readonly right?: ReactNode;\n /** Center region — required; the host renders <ReactFlow> + <CanvasChrome>. */\n readonly canvas: ReactNode;\n /** Optional footer region (e.g. an output/console strip). */\n readonly footer?: ReactNode;\n readonly leftCollapsed?: boolean;\n readonly rightCollapsed?: boolean;\n}\n\nexport function EditorShell({\n toolbar,\n left,\n right,\n canvas,\n footer,\n leftCollapsed = false,\n rightCollapsed = false,\n}: EditorShellProps): ReactElement {\n const className = [\n 'hl-shell',\n leftCollapsed ? 'hl-left-collapsed' : '',\n rightCollapsed ? 'hl-right-collapsed' : '',\n ]\n .filter(Boolean)\n .join(' ');\n\n return (\n <div className={className}>\n {toolbar !== undefined && <div className=\"hl-region-toolbar\">{toolbar}</div>}\n <div className=\"hl-region-body\">\n {left !== undefined && !leftCollapsed && (\n <aside className=\"hl-region-left\">{left}</aside>\n )}\n <main className=\"hl-region-canvas\">{canvas}</main>\n {right !== undefined && !rightCollapsed && (\n <aside className=\"hl-region-right\">{right}</aside>\n )}\n </div>\n {footer !== undefined && <div className=\"hl-region-footer\">{footer}</div>}\n </div>\n );\n}\n","/**\n * The top toolbar: a thin glass bar with a brand wordmark on the left and an\n * action cluster on the right. `Toolbar` is the presentational container;\n * `UndoRedo` and `RunButton` are the standard actions wired to editor-core via\n * editor-react hooks. Hosts may pass extra actions through `actions`.\n */\n\nimport type { ReactElement, ReactNode } from 'react';\nimport type { EditorCore } from '@hlang-tech/editor-core';\nimport { useHistory } from '@hlang-tech/editor-react';\nimport './Toolbar.css';\n\nexport interface ToolbarProps {\n /** Brand/title shown on the left. Defaults to a generic wordmark. */\n readonly title?: ReactNode;\n /** Centre slot — a tool cluster (add/frame/view), absolutely centred. */\n readonly center?: ReactNode;\n /** Action nodes rendered on the right (e.g. <UndoRedo/>, <RunButton/>). */\n readonly actions?: ReactNode;\n}\n\nexport function Toolbar({ title, center, actions }: ToolbarProps): ReactElement {\n return (\n <header className=\"hl-toolbar\">\n <div className=\"hl-toolbar-brand\">\n {title ?? (\n <>\n <span className=\"hl-toolbar-glyph\" aria-hidden=\"true\" />\n <span className=\"hl-toolbar-wordmark\">hlang</span>\n </>\n )}\n </div>\n {center !== undefined && <div className=\"hl-toolbar-center\">{center}</div>}\n <div className=\"hl-toolbar-actions\">{actions}</div>\n </header>\n );\n}\n\nexport interface UndoRedoProps {\n readonly core: EditorCore;\n}\n\nexport function UndoRedo({ core }: UndoRedoProps): ReactElement {\n const history = useHistory(core);\n return (\n <>\n <button\n type=\"button\"\n className=\"hl-toolbar-btn\"\n onClick={() => history.undo()}\n disabled={!history.canUndo}\n title=\"Undo (⌘Z)\"\n >\n Undo\n </button>\n <button\n type=\"button\"\n className=\"hl-toolbar-btn\"\n onClick={() => history.redo()}\n disabled={!history.canRedo}\n title=\"Redo (⌘⇧Z)\"\n >\n Redo\n </button>\n </>\n );\n}\n\nexport interface RunButtonProps {\n /**\n * Invoked when clicked. This is a toggle: when `running` is true the button\n * shows a Stop affordance, and the host is expected to stop the execution.\n */\n readonly onRun: () => void;\n /** Whether an execution is currently in progress. */\n readonly running?: boolean;\n readonly runLabel?: string;\n readonly stopLabel?: string;\n}\n\nexport function RunButton({\n onRun,\n running = false,\n runLabel = 'Run',\n stopLabel = 'Stop',\n}: RunButtonProps): ReactElement {\n return (\n <button\n type=\"button\"\n className={`hl-toolbar-btn hl-toolbar-run${running ? ' is-running' : ''}`}\n onClick={onRun}\n aria-pressed={running}\n >\n <span\n className={`hl-toolbar-run-icon${running ? ' is-stop' : ''}`}\n aria-hidden=\"true\"\n />\n {running ? stopLabel : runLabel}\n </button>\n );\n}\n\n/** A compact read-only stat pill (e.g. a node/vertex count) for the top bar. */\nexport function ToolbarStat({ label, value }: { readonly label?: string; readonly value: ReactNode }): ReactElement {\n return (\n <span className=\"hl-toolbar-stat hl-mono\" title={label}>\n {value}\n </span>\n );\n}\n\n/** A secondary ghost button for the top bar (e.g. Invite). Presentational. */\nexport function ToolbarGhostButton({\n children,\n onClick,\n title,\n}: {\n readonly children: ReactNode;\n readonly onClick?: () => void;\n readonly title?: string;\n}): ReactElement {\n return (\n <button type=\"button\" className=\"hl-toolbar-btn\" onClick={onClick} title={title}>\n {children}\n </button>\n );\n}\n","/**\n * `ToolCluster` — the centred group of canvas tools in the top bar (nover-style):\n * a row of icon buttons with optional separators, in the black/silver glass\n * language. Purely presentational: the host supplies the items and their\n * actions. Kept generic (no business/media concepts) so it stays an editor-ui\n * primitive — a \"frame\", \"add\", or \"view\" tool is just an item with an icon.\n */\n\nimport type { ReactElement, ReactNode } from 'react';\nimport './ToolCluster.css';\n\nexport interface ToolItem {\n readonly id: string;\n readonly icon: ReactNode;\n readonly title: string;\n readonly onClick?: () => void;\n readonly active?: boolean;\n readonly disabled?: boolean;\n /** Draw a thin divider before this item. */\n readonly separatorBefore?: boolean;\n}\n\nexport interface ToolClusterProps {\n readonly items: readonly ToolItem[];\n}\n\nexport function ToolCluster({ items }: ToolClusterProps): ReactElement {\n return (\n <div className=\"hl-toolcluster\" role=\"toolbar\" aria-label=\"Canvas tools\">\n {items.map(item => (\n <span key={item.id} className=\"hl-toolcluster-slot\">\n {item.separatorBefore === true && <span className=\"hl-toolcluster-sep\" aria-hidden />}\n <button\n type=\"button\"\n className={'hl-toolcluster-btn' + (item.active === true ? ' is-active' : '')}\n onClick={item.onClick}\n disabled={item.disabled}\n title={item.title}\n aria-label={item.title}\n aria-pressed={item.active}\n >\n {item.icon}\n </button>\n </span>\n ))}\n </div>\n );\n}\n","/**\n * `CanvasChrome` — themed React Flow canvas furniture. Now just the dotted\n * background: React Flow's default MiniMap and Controls are intentionally NOT\n * rendered — a creation studio replaces them with our own centred `CanvasDock`\n * (pan/zoom/add) so the canvas isn't cluttered with a stock topology-editor\n * toolbar. Rendered as children of <ReactFlow>.\n */\n\nimport type { ReactElement } from 'react';\nimport { Background, BackgroundVariant } from '@xyflow/react';\nimport './CanvasChrome.css';\n\nexport interface CanvasChromeProps {\n readonly background?: boolean;\n}\n\nexport function CanvasChrome({ background = true }: CanvasChromeProps): ReactElement {\n return <>{background && <Background variant={BackgroundVariant.Dots} gap={26} size={1} color=\"#242830\" />}</>;\n}\n","/**\n * `CanvasDock` — the centred, bottom-of-canvas floating toolbar of a creation\n * studio: pointer/pan mode, add-node, and zoom controls, in the black/silver\n * glass language. It replaces React Flow's default corner Controls + MiniMap\n * with one calm, centred dock.\n *\n * Presentation only: it renders buttons and the current zoom %, and calls back\n * to the host for every action. It holds no React Flow or graph state — the host\n * wires the callbacks to `useReactFlow()` (zoom/fit) and the node search (add).\n */\n\nimport type { ReactElement } from 'react';\nimport './CanvasDock.css';\n\n/** Interaction mode the canvas is in — left-drag selects, or left-drag pans. */\nexport type CanvasMode = 'select' | 'pan';\n\nexport interface CanvasDockProps {\n /** Current zoom as a fraction (1 = 100%). */\n readonly zoom: number;\n readonly onZoomIn: () => void;\n readonly onZoomOut: () => void;\n readonly onFitView: () => void;\n /** Open the node search to add a node. */\n readonly onAdd: () => void;\n /** Current interaction mode + setter (left-drag selects vs pans). */\n readonly mode: CanvasMode;\n readonly onModeChange: (mode: CanvasMode) => void;\n /** Undo/redo — colocated with the canvas tools rather than the top bar. */\n readonly onUndo: () => void;\n readonly onRedo: () => void;\n readonly canUndo: boolean;\n readonly canRedo: boolean;\n}\n\nfunction CursorIcon(): ReactElement {\n return (\n <svg width={16} height={16} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={1.6} strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"M5 3l6 16 2-6 6-2z\" />\n </svg>\n );\n}\nfunction HandIcon(): ReactElement {\n return (\n <svg width={16} height={16} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={1.6} strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"M8 12V6a1.5 1.5 0 013 0v5m0-1V5a1.5 1.5 0 013 0v6m0-1V6.5a1.5 1.5 0 013 0V13c0 3.5-2 6-5.5 6H12c-2 0-3-.8-4.2-2.5L5 12.5c-.7-1 .6-2.3 1.6-1.6z\" />\n </svg>\n );\n}\nfunction PlusIcon(): ReactElement {\n return (\n <svg width={17} height={17} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={1.7} strokeLinecap=\"round\" aria-hidden>\n <path d=\"M12 5v14M5 12h14\" />\n </svg>\n );\n}\nfunction FitIcon(): ReactElement {\n return (\n <svg width={15} height={15} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={1.6} strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"M4 9V4h5M20 9V4h-5M4 15v5h5M20 15v5h-5\" />\n </svg>\n );\n}\nfunction UndoIcon(): ReactElement {\n return (\n <svg width={15} height={15} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={1.6} strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"M9 7L4 12l5 5M4 12h11a5 5 0 010 10h-1\" />\n </svg>\n );\n}\nfunction RedoIcon(): ReactElement {\n return (\n <svg width={15} height={15} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={1.6} strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"M15 7l5 5-5 5M20 12H9a5 5 0 000 10h1\" />\n </svg>\n );\n}\n\nexport function CanvasDock({\n zoom,\n onZoomIn,\n onZoomOut,\n onFitView,\n onAdd,\n mode,\n onModeChange,\n onUndo,\n onRedo,\n canUndo,\n canRedo,\n}: CanvasDockProps): ReactElement {\n const pct = `${String(Math.round(zoom * 100))}%`;\n return (\n <div className=\"hl-dock\" role=\"toolbar\" aria-label=\"Canvas tools\">\n <button\n className=\"hl-dock-btn\"\n onClick={onUndo}\n disabled={!canUndo}\n title=\"Undo (⌘Z)\"\n aria-label=\"Undo\"\n >\n <UndoIcon />\n </button>\n <button\n className=\"hl-dock-btn\"\n onClick={onRedo}\n disabled={!canRedo}\n title=\"Redo (⌘⇧Z)\"\n aria-label=\"Redo\"\n >\n <RedoIcon />\n </button>\n <span className=\"hl-dock-sep\" aria-hidden />\n <button\n className={'hl-dock-btn' + (mode === 'select' ? ' is-active' : '')}\n onClick={() => onModeChange('select')}\n title=\"Select (V)\"\n aria-pressed={mode === 'select'}\n >\n <CursorIcon />\n </button>\n <button\n className={'hl-dock-btn' + (mode === 'pan' ? ' is-active' : '')}\n onClick={() => onModeChange('pan')}\n title=\"Pan (Space)\"\n aria-pressed={mode === 'pan'}\n >\n <HandIcon />\n </button>\n <button className=\"hl-dock-btn hl-dock-add\" onClick={onAdd} title=\"Add node\">\n <PlusIcon />\n </button>\n\n <span className=\"hl-dock-sep\" aria-hidden />\n\n <button className=\"hl-dock-btn\" onClick={onZoomOut} title=\"Zoom out\" aria-label=\"Zoom out\">\n <span className=\"hl-dock-glyph\">−</span>\n </button>\n <button className=\"hl-dock-zoom hl-mono\" onClick={onFitView} title=\"Fit view\">\n {pct}\n </button>\n <button className=\"hl-dock-btn\" onClick={onZoomIn} title=\"Zoom in\" aria-label=\"Zoom in\">\n <span className=\"hl-dock-glyph\">+</span>\n </button>\n <button className=\"hl-dock-btn hl-dock-fit\" onClick={onFitView} title=\"Fit view\" aria-label=\"Fit view\">\n <FitIcon />\n </button>\n </div>\n );\n}\n","/**\n * `EmptyState` — a quiet, centered hint shown over an empty canvas. Purely\n * presentational; the host decides when to render it (e.g. when the graph has\n * no nodes). Non-interactive so it never blocks canvas gestures.\n */\n\nimport type { ReactElement, ReactNode } from 'react';\nimport './EmptyState.css';\n\nexport interface EmptyStateProps {\n readonly title?: ReactNode;\n readonly hint?: ReactNode;\n}\n\nexport function EmptyState({\n title = 'An empty canvas.',\n hint = 'add a source · wire it to a sink · run',\n}: EmptyStateProps): ReactElement {\n return (\n <div className=\"hl-empty\" aria-hidden=\"true\">\n <p className=\"hl-empty-title\">{title}</p>\n <p className=\"hl-empty-hint\">{hint}</p>\n </div>\n );\n}\n","/**\n * `InspectorPanel` — the right-hand property inspector. It follows selection:\n * with exactly one node selected it shows that node's identity plus a\n * schema-driven parameter form (edits commit undoable UpdateParamsCommands);\n * otherwise it shows an empty/summary state. This is the unified control center\n * (nover.studio's model) over hlang's headless core.\n */\n\nimport type { ReactElement, ReactNode } from 'react';\nimport type { EditorCore } from '@hlang-tech/editor-core';\nimport { useSelection } from '@hlang-tech/editor-react';\nimport { KIND_ROLE } from '../tokens/tokens';\nimport { deriveParamSchema } from '../schema/param-field';\nimport { useNodeParams } from '../hooks/useNodeParams';\nimport { ParamForm } from './ParamForm';\nimport './InspectorPanel.css';\n\nexport interface InspectorPanelProps {\n readonly core: EditorCore;\n /** Shown when no single node is selected. */\n readonly emptyState?: ReactNode;\n}\n\nexport function InspectorPanel({ core, emptyState }: InspectorPanelProps): ReactElement {\n const selection = useSelection(core);\n const selectedNodes = selection.selectedNodes;\n const singleId = selectedNodes.length === 1 ? selectedNodes[0] : undefined;\n const params = useNodeParams(core, singleId);\n const node = params.node;\n\n if (node === undefined) {\n return (\n <div className=\"hl-inspector hl-inspector-empty\">\n {emptyState ?? (\n <div className=\"hl-inspector-blank\">\n <span className=\"hl-inspector-blank-badge\" aria-hidden />\n <p className=\"hl-inspector-blank-title\">\n {selectedNodes.length > 1 ? `${String(selectedNodes.length)} nodes selected` : 'Nothing selected'}\n </p>\n <p className=\"hl-inspector-hint\">\n {selectedNodes.length > 1\n ? 'Select a single node to edit its parameters.'\n : 'Pick a node on the canvas or in the outline to inspect and tune it.'}\n </p>\n </div>\n )}\n </div>\n );\n }\n\n const descriptor = core.registry.get(node.code);\n const fields = descriptor === undefined ? [] : deriveParamSchema(descriptor, node);\n const imageUrl =\n typeof node.params.imageUrl === 'string' && node.params.imageUrl.length > 0\n ? node.params.imageUrl\n : undefined;\n\n return (\n <div className=\"hl-inspector\">\n {/* A preview thumbnail grounds the header: the asset's image, or a\n kind-tinted medallion for other nodes. */}\n <div className={`hl-inspector-preview hl-${node.kind.toLowerCase()}`}>\n {imageUrl !== undefined ? (\n <img className=\"hl-inspector-preview-img\" src={imageUrl} alt={node.name} />\n ) : (\n <span className=\"hl-inspector-preview-badge hl-mono\">{node.kind}</span>\n )}\n </div>\n <header className=\"hl-inspector-head\">\n <span className={`hl-inspector-kind hl-${node.kind.toLowerCase()}`}>{node.kind}</span>\n <div className=\"hl-inspector-titles\">\n <span className=\"hl-inspector-name\">{node.name}</span>\n <span className=\"hl-inspector-role hl-mono\">\n {node.code} · {KIND_ROLE[node.kind]}\n </span>\n </div>\n </header>\n\n <section className=\"hl-inspector-section\">\n <h3 className=\"hl-inspector-section-title\">Parameters</h3>\n {fields.length === 0 ? (\n <p className=\"hl-inspector-hint\">This node has no parameters.</p>\n ) : (\n <ParamForm\n fields={fields}\n onCommit={(key, value) => params.setParam(key, value)}\n />\n )}\n </section>\n\n <section className=\"hl-inspector-section\">\n <h3 className=\"hl-inspector-section-title\">Ports</h3>\n <ul className=\"hl-inspector-ports\">\n {node.ports.map(port => (\n <li\n key={port.id}\n className={`hl-inspector-port${port.isError ? ' is-error' : ''}`}\n >\n <span className={`hl-port-dot hl-dir-${port.direction.toLowerCase()}`} />\n <span className=\"hl-mono\">{port.name}</span>\n <span className=\"hl-inspector-port-dir hl-mono\">{port.direction}</span>\n </li>\n ))}\n </ul>\n </section>\n </div>\n );\n}\n","/**\n * Schema-driven property editing. A node's editable parameters are derived into\n * a strongly-typed `ParamField[]` (zero `any`), which the inspector renders as\n * form controls. Field types are inferred from each default value's runtime\n * type — the only metadata a `NodeDescriptor` carries today (`defaultParams`).\n */\n\nimport type { NodeDescriptor, EditorNode, ParamValue } from '@hlang-tech/editor-core';\n\n/** Common fields on every derived form field. */\nexport interface ParamFieldBase {\n readonly key: string;\n readonly label: string;\n readonly disabled?: boolean;\n}\n\n/** A discriminated union of the built-in form field types (zero `any`). */\nexport type ParamField =\n | (ParamFieldBase & { readonly type: 'text'; readonly value: string })\n | (ParamFieldBase & { readonly type: 'textarea'; readonly value: string })\n | (ParamFieldBase & { readonly type: 'number'; readonly value: number })\n | (ParamFieldBase & { readonly type: 'toggle'; readonly value: boolean })\n | (ParamFieldBase & {\n readonly type: 'custom';\n readonly fieldType: string;\n readonly value: ParamValue;\n });\n\n/** Turn a param key like `maxTokens` / `hack_send` into a readable label. */\nfunction humanizeKey(key: string): string {\n const spaced = key\n .replace(/[_-]+/g, ' ')\n .replace(/([a-z0-9])([A-Z])/g, '$1 $2')\n .trim();\n return spaced.charAt(0).toUpperCase() + spaced.slice(1);\n}\n\n/** Infer a field from a key and its current value. */\nfunction fieldFor(key: string, value: ParamValue): ParamField {\n const label = humanizeKey(key);\n if (typeof value === 'boolean') {\n return { key, label, type: 'toggle', value };\n }\n if (typeof value === 'number') {\n return { key, label, type: 'number', value };\n }\n if (typeof value === 'string') {\n // Multi-line strings (e.g. code / prompts) get a textarea.\n const type = value.includes('\\n') ? 'textarea' : 'text';\n return { key, label, type, value };\n }\n // Arrays, nested objects, null — surface via the custom control registry.\n return { key, label, type: 'custom', fieldType: 'json', value };\n}\n\n/**\n * Derive the ordered form schema for a node. Keys come from the descriptor's\n * `defaultParams` (the canonical param set); current values come from the live\n * node, falling back to the default.\n */\nexport function deriveParamSchema(\n descriptor: NodeDescriptor,\n node: EditorNode,\n): readonly ParamField[] {\n const fields: ParamField[] = [];\n for (const key of Object.keys(descriptor.defaultParams)) {\n const current = key in node.params ? node.params[key] : descriptor.defaultParams[key];\n fields.push(fieldFor(key, current ?? null));\n }\n return fields;\n}\n","/**\n * `useNodeParams` — reactively read a node's params and commit edits through the\n * command service (so every change is undoable). Re-reads on the `nodeChanged`\n * event via a version counter (the same pattern editor-react's selectors use).\n */\n\nimport { useCallback, useMemo, useRef, useSyncExternalStore } from 'react';\nimport type { EditorCore, EditorNode, NodeId, ParamBag, ParamValue } from '@hlang-tech/editor-core';\nimport { UpdateParamsCommand } from '@hlang-tech/editor-core';\n\nexport interface NodeParamsHandle {\n /** The node, or undefined if it no longer exists. */\n readonly node: EditorNode | undefined;\n /** Set a single param, committing an undoable UpdateParamsCommand. */\n setParam(key: string, value: ParamValue): void;\n /** Replace the whole param bag, committing an undoable UpdateParamsCommand. */\n setParams(next: ParamBag): void;\n}\n\nexport function useNodeParams(core: EditorCore, nodeId: NodeId | undefined): NodeParamsHandle {\n const versionRef = useRef(0);\n\n const subscribe = useCallback(\n (onStoreChange: () => void): (() => void) => {\n const disposable = core.events.on('nodeChanged', event => {\n if (nodeId !== undefined && event.node.id === nodeId) {\n versionRef.current += 1;\n onStoreChange();\n }\n });\n return (): void => {\n disposable.dispose();\n };\n },\n [core, nodeId],\n );\n\n const getSnapshot = useCallback((): number => versionRef.current, []);\n const version = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n\n const setParams = useCallback(\n (next: ParamBag): void => {\n if (nodeId === undefined) {\n return;\n }\n core.commands.execute(new UpdateParamsCommand(nodeId, next));\n },\n [core, nodeId],\n );\n\n const setParam = useCallback(\n (key: string, value: ParamValue): void => {\n if (nodeId === undefined) {\n return;\n }\n const node = core.model.getNode(nodeId);\n if (node === undefined) {\n return;\n }\n setParams({ ...node.params, [key]: value });\n },\n [core, nodeId, setParams],\n );\n\n return useMemo<NodeParamsHandle>(\n () => ({\n node: nodeId === undefined ? undefined : core.model.getNode(nodeId),\n setParam,\n setParams,\n }),\n // `version` re-reads the node after each nodeChanged for this id.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [core, nodeId, version, setParam, setParams],\n );\n}\n","/**\n * `ParamForm` — renders a derived `ParamField[]` as compact, pro-tool form\n * controls. Text/number inputs commit on blur or Enter (not per keystroke, so\n * one edit is one undo entry); toggles commit immediately. `custom` fields are\n * a placeholder until the ParamFieldRegistry lands (M-UI-5).\n */\n\nimport { useState } from 'react';\nimport type { ReactElement } from 'react';\nimport type { ParamValue } from '@hlang-tech/editor-core';\nimport type { ParamField } from '../schema/param-field';\nimport './ParamForm.css';\n\nexport interface ParamFormProps {\n readonly fields: readonly ParamField[];\n /** Commit a single field's new value (undoable, handled by the caller). */\n readonly onCommit: (key: string, value: ParamValue) => void;\n}\n\nexport function ParamForm({ fields, onCommit }: ParamFormProps): ReactElement {\n return (\n <div className=\"hl-form\">\n {fields.map(field => (\n <FieldRow key={field.key} field={field} onCommit={onCommit} />\n ))}\n </div>\n );\n}\n\nfunction FieldRow({\n field,\n onCommit,\n}: {\n field: ParamField;\n onCommit: (key: string, value: ParamValue) => void;\n}): ReactElement {\n return (\n <label className=\"hl-field\">\n <span className=\"hl-field-label\">{field.label}</span>\n <FieldControl field={field} onCommit={onCommit} />\n </label>\n );\n}\n\nfunction FieldControl({\n field,\n onCommit,\n}: {\n field: ParamField;\n onCommit: (key: string, value: ParamValue) => void;\n}): ReactElement {\n switch (field.type) {\n case 'toggle':\n return (\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={field.value}\n className={`hl-toggle${field.value ? ' is-on' : ''}`}\n disabled={field.disabled}\n onClick={() => onCommit(field.key, !field.value)}\n >\n <span className=\"hl-toggle-knob\" />\n </button>\n );\n case 'number':\n return <NumberControl field={field} onCommit={onCommit} />;\n case 'textarea':\n return <TextControl field={field} onCommit={onCommit} multiline />;\n case 'text':\n return <TextControl field={field} onCommit={onCommit} />;\n case 'custom':\n return (\n <span className=\"hl-field-custom hl-mono\" title={field.fieldType}>\n {describeCustom(field.value)}\n </span>\n );\n }\n}\n\nfunction TextControl({\n field,\n onCommit,\n multiline = false,\n}: {\n field: ParamField & { type: 'text' | 'textarea' };\n onCommit: (key: string, value: ParamValue) => void;\n multiline?: boolean;\n}): ReactElement {\n const [draft, setDraft] = useState(field.value);\n const commit = (): void => {\n if (draft !== field.value) {\n onCommit(field.key, draft);\n }\n };\n const shared = {\n className: 'hl-input',\n value: draft,\n disabled: field.disabled,\n spellCheck: false,\n onBlur: commit,\n };\n if (multiline) {\n return (\n <textarea\n {...shared}\n rows={4}\n onChange={e => setDraft(e.target.value)}\n />\n );\n }\n return (\n <input\n {...shared}\n type=\"text\"\n onChange={e => setDraft(e.target.value)}\n onKeyDown={e => {\n if (e.key === 'Enter') {\n e.currentTarget.blur();\n }\n }}\n />\n );\n}\n\nfunction NumberControl({\n field,\n onCommit,\n}: {\n field: ParamField & { type: 'number' };\n onCommit: (key: string, value: ParamValue) => void;\n}): ReactElement {\n const [draft, setDraft] = useState(String(field.value));\n const commit = (): void => {\n const parsed = Number(draft);\n if (!Number.isNaN(parsed) && parsed !== field.value) {\n onCommit(field.key, parsed);\n }\n };\n return (\n <input\n className=\"hl-input hl-mono\"\n type=\"number\"\n inputMode=\"decimal\"\n value={draft}\n disabled={field.disabled}\n onChange={e => setDraft(e.target.value)}\n onBlur={commit}\n onKeyDown={e => {\n if (e.key === 'Enter') {\n e.currentTarget.blur();\n }\n }}\n />\n );\n}\n\nfunction describeCustom(value: ParamValue): string {\n if (Array.isArray(value)) {\n return `[${String(value.length)} items]`;\n }\n if (value === null) {\n return 'null';\n }\n if (typeof value === 'object') {\n return '{…}';\n }\n return String(value);\n}\n","/**\n * `OutlineTree` — the left-rail outline: a two-level GROUPING, not a tree.\n *\n * hlang's graph is a DAG (R/T/W nodes, O->I edges, T<->T feedback allowed), so\n * there is no parent/child hierarchy to render. Instead we group by weakly-\n * connected component (`GraphTopology.components()`): each component is one\n * expandable \"Flow N\" container, and its member nodes are listed FLAT — they are\n * peers. The real relationships between nodes (edges, fan-in/out) are shown on\n * the canvas, never faked here as nesting. So: the outline expresses BELONGING\n * (which Flow a node is in); the canvas expresses DATA FLOW.\n *\n * Rows carry per-type icons, a diagnostic marker, hover-revealed visible/lock\n * controls, and a solid silver highlight when selected. Clicking a node selects\n * and focuses it. Visibility/lock are per-node view state via `useViewState`.\n */\n\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport type { ReactElement } from 'react';\nimport type { EditorCore, EditorNode, NodeId, TopologyComponent } from '@hlang-tech/editor-core';\nimport { GraphTopology } from '@hlang-tech/editor-core';\nimport { useSelection, useViewState, useDiagnostics } from '@hlang-tech/editor-react';\nimport { NodeIcon, EyeIcon, EyeOffIcon, LockIcon, UnlockIcon } from '../icons/node-icons';\nimport { DiagnosticBadge } from './DiagnosticBadge';\nimport './OutlineTree.css';\n\nexport interface OutlineTreeProps {\n readonly core: EditorCore;\n readonly onFocus?: (id: NodeId) => void;\n}\n\n/**\n * Reactively derive the graph's weakly-connected components from the LIVE model.\n * Rebuilding a GraphTopology from scratch each change is cheap for editor-sized\n * graphs and — crucially — timing-proof: a bulk `model.restore` (which emits no\n * per-node events) is picked up by the mount effect, and normal edits by the\n * structural-event subscription. This avoids the stale-empty-index bug.\n */\nfunction useTopologyComponents(core: EditorCore): readonly TopologyComponent[] {\n const [tick, setTick] = useState(0);\n const bump = useCallback((): void => setTick(t => t + 1), []);\n\n useEffect(() => {\n // Normal edits fire structural events.\n const kinds = ['nodeAdded', 'nodeRemoved', 'nodeChanged', 'edgeAdded', 'edgeRemoved'] as const;\n const disposers = kinds.map(k => core.events.on(k, bump));\n // Bulk loads (restore) emit no events — recompute once now that the host's\n // mount effect has populated the model.\n bump();\n return () => {\n for (const d of disposers) {\n d.dispose();\n }\n };\n }, [core, bump]);\n\n return useMemo(() => {\n void tick;\n const topo = new GraphTopology();\n topo.reset(core.model.getNodes(), core.model.getEdges());\n return topo.components();\n }, [core, tick]);\n}\n\nexport function OutlineTree({ core, onFocus }: OutlineTreeProps): ReactElement {\n const components = useTopologyComponents(core);\n const selection = useSelection(core);\n const viewState = useViewState(core);\n const diagnostics = useDiagnostics(core);\n const [collapsed, setCollapsed] = useState<ReadonlySet<string>>(new Set());\n\n // Rebuild the id->node map whenever the component set changes (which happens\n // on any graph change). `components` identity is the change signal.\n const nodeById = useMemo(() => {\n const m = new Map<NodeId, EditorNode>();\n for (const n of core.model.getNodes()) {\n m.set(n.id, n);\n }\n return m;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [core, components]);\n\n const toggleGroup = useCallback((id: string): void => {\n setCollapsed(prev => {\n const next = new Set(prev);\n if (next.has(id)) {\n next.delete(id);\n } else {\n next.add(id);\n }\n return next;\n });\n }, []);\n\n const select = useCallback(\n (id: NodeId): void => {\n selection.selectNodes([id], 'replace');\n onFocus?.(id);\n },\n [selection, onFocus],\n );\n\n if (components.length === 0) {\n return <p className=\"hl-outline-empty hl-mono\">no layers yet</p>;\n }\n\n // Order groups largest-first for a stable, sensible reading order.\n const groups = [...components].sort((a, b) => b.nodeIds.size - a.nodeIds.size);\n\n return (\n <div className=\"hl-outline\" role=\"tree\" aria-label=\"Outline\">\n {groups.map((group, gi) => {\n const members = [...group.nodeIds]\n .map(id => nodeById.get(id))\n .filter((n): n is EditorNode => n !== undefined);\n const open = !collapsed.has(group.id);\n const groupName = `Flow ${String(gi + 1)}`;\n return (\n <div key={group.id} className=\"hl-outline-group\" role=\"treeitem\" aria-expanded={open}>\n <button\n className=\"hl-outline-grouphead\"\n onClick={() => toggleGroup(group.id)}\n >\n <span className={'hl-outline-caret' + (open ? ' is-open' : '')} aria-hidden>\n ▸\n </span>\n <span className=\"hl-outline-groupname\">{groupName}</span>\n <span className=\"hl-outline-count hl-mono\">{group.nodeIds.size}</span>\n </button>\n {open && (\n <ul className=\"hl-outline-members\">\n {members.map(node => {\n const active = selection.isSelected(node.id);\n const isHidden = viewState.isHidden(node.id);\n const isLocked = viewState.isLocked(node.id);\n const hasImage =\n typeof node.params.imageUrl === 'string' && node.params.imageUrl.length > 0;\n return (\n <li key={node.id}>\n <div\n className={\n 'hl-outline-row' +\n (active ? ' is-active' : '') +\n (isHidden ? ' is-hidden' : '') +\n (isLocked ? ' is-locked' : '')\n }\n >\n <button className=\"hl-outline-main\" onClick={() => select(node.id)}>\n <span\n className={`hl-outline-icon hl-kind-${node.kind.toLowerCase()}`}\n aria-hidden\n >\n {hasImage ? (\n <img\n className=\"hl-outline-thumb\"\n src={node.params.imageUrl as string}\n alt=\"\"\n />\n ) : (\n <NodeIcon code={node.code} kind={node.kind} size={13} />\n )}\n </span>\n <span className=\"hl-outline-name\">{node.name}</span>\n {/* Edit-time diagnostic marker (error/warning). */}\n {(() => {\n const diag = diagnostics.worstOf(node.id);\n return diag === undefined ? null : (\n <DiagnosticBadge diagnostic={diag} variant=\"hl-outline-diag\" size={11} />\n );\n })()}\n {/* Persistent status glyphs: only shown when a flag is\n ON, so a hidden/locked layer stays legible at rest\n (not just on hover). */}\n {isLocked && (\n <span className=\"hl-outline-badge\" aria-hidden>\n <LockIcon size={11} />\n </span>\n )}\n {isHidden && (\n <span className=\"hl-outline-badge\" aria-hidden>\n <EyeOffIcon size={11} />\n </span>\n )}\n </button>\n <span className=\"hl-outline-controls\">\n <button\n className={'hl-outline-ctl' + (isHidden ? ' is-active-ctl' : '')}\n onClick={() => viewState.toggleHidden(node.id)}\n aria-label={isHidden ? 'Show layer' : 'Hide layer'}\n title={isHidden ? 'Show' : 'Hide'}\n >\n {isHidden ? <EyeOffIcon /> : <EyeIcon />}\n </button>\n <button\n className={'hl-outline-ctl' + (isLocked ? ' is-active-ctl' : '')}\n onClick={() => viewState.toggleLocked(node.id)}\n aria-label={isLocked ? 'Unlock layer' : 'Lock layer'}\n title={isLocked ? 'Unlock' : 'Lock'}\n >\n {isLocked ? <LockIcon /> : <UnlockIcon />}\n </button>\n </span>\n </div>\n </li>\n );\n })}\n </ul>\n )}\n </div>\n );\n })}\n </div>\n );\n}\n","/**\n * `PreviewPanel` — a framed preview of a result image. Generic: the host passes\n * an image URL + title (and optional status), and it renders a glass-framed\n * hero card. In the creator flow this is the \"output\" of the graph — the render\n * — completing the素材→intent→result narrative. editor-ui only draws it; what\n * the image IS (a render, a still, a mock) is the host's business.\n */\n\nimport type { ReactElement } from 'react';\nimport './PreviewPanel.css';\n\nexport interface PreviewPanelProps {\n readonly imageUrl?: string;\n readonly title?: string;\n readonly status?: string;\n}\n\nexport function PreviewPanel({ imageUrl, title = 'Preview', status }: PreviewPanelProps): ReactElement {\n return (\n <section className=\"hl-preview\" aria-label=\"Preview\">\n <div className=\"hl-preview-head\">\n <span className=\"hl-preview-title\">{title}</span>\n {status !== undefined && <span className=\"hl-preview-status hl-mono\">{status}</span>}\n </div>\n <div className=\"hl-preview-frame\">\n {imageUrl !== undefined && imageUrl.length > 0 ? (\n <img className=\"hl-preview-img\" src={imageUrl} alt={title} draggable={false} />\n ) : (\n <div className=\"hl-preview-placeholder hl-mono\">no output yet</div>\n )}\n </div>\n </section>\n );\n}\n","/**\n * `RailTabs` — the segmented tab strip at the top of a side rail (Outline /\n * Insert / Assets, nover-style), in the black/silver glass language. Purely\n * presentational and generic: the host supplies the tab ids/labels and owns the\n * active state, so this is an editor-ui primitive with no coupling to what the\n * tabs contain.\n */\n\nimport type { ReactElement } from 'react';\nimport './RailTabs.css';\n\nexport interface RailTab {\n readonly id: string;\n readonly label: string;\n}\n\nexport interface RailTabsProps {\n readonly tabs: readonly RailTab[];\n readonly active: string;\n readonly onChange: (id: string) => void;\n}\n\nexport function RailTabs({ tabs, active, onChange }: RailTabsProps): ReactElement {\n return (\n <div className=\"hl-railtabs\" role=\"tablist\">\n {tabs.map(tab => (\n <button\n key={tab.id}\n role=\"tab\"\n aria-selected={tab.id === active}\n className={'hl-railtab' + (tab.id === active ? ' is-active' : '')}\n onClick={() => onChange(tab.id)}\n >\n {tab.label}\n </button>\n ))}\n </div>\n );\n}\n","/**\n * `AssetGrid` — a thumbnail grid of render results / source images (the nover\n * \"Renders\" / \"Assets\" panel). Purely presentational: the host supplies image\n * URLs; clicking one calls back. editor-ui stays generic — an \"asset\" here is\n * just an image with an id, no media/model business concept.\n */\n\nimport type { ReactElement } from 'react';\nimport './AssetGrid.css';\n\nexport interface AssetItem {\n readonly id: string;\n readonly url: string;\n readonly label?: string;\n}\n\nexport interface AssetGridProps {\n readonly items: readonly AssetItem[];\n readonly onSelect?: (id: string) => void;\n /** Shown when there are no assets yet. */\n readonly emptyHint?: string;\n}\n\nexport function AssetGrid({ items, onSelect, emptyHint = 'No assets yet' }: AssetGridProps): ReactElement {\n if (items.length === 0) {\n return <p className=\"hl-assetgrid-empty hl-mono\">{emptyHint}</p>;\n }\n return (\n <div className=\"hl-assetgrid\">\n {items.map(item => (\n <button\n key={item.id}\n className=\"hl-assetgrid-cell\"\n onClick={() => onSelect?.(item.id)}\n title={item.label}\n >\n <img className=\"hl-assetgrid-img\" src={item.url} alt={item.label ?? ''} loading=\"lazy\" />\n </button>\n ))}\n </div>\n );\n}\n","/**\n * `PositionPanel` — the \"Position\" section of the inspector (nover-style): a\n * 3×2 align cluster, the selected node's X/Y, and a Pin toggle. Generic geometry\n * only — alignment/coordinates carry no media/model concept, so this belongs in\n * editor-ui. All moves go through the command service (undoable) via `useRename`-\n * style command execution; nothing mutates the model directly.\n *\n * With a single selected node it shows and edits that node's position. With\n * multiple, the align actions distribute them against their common bounding box.\n */\n\nimport { useCallback, useEffect, useReducer } from 'react';\nimport type { ReactElement } from 'react';\nimport type { EditorCore, EditorNode } from '@hlang-tech/editor-core';\nimport { MoveNodeCommand } from '@hlang-tech/editor-core';\nimport { useSelection } from '@hlang-tech/editor-react';\nimport './PositionPanel.css';\n\nexport interface PositionPanelProps {\n readonly core: EditorCore;\n /**\n * Optional LIVE position reader (canvas coords) for a node. A drag commits to\n * the model only on drag-stop, so to show X/Y updating DURING a drag the host\n * supplies the canvas's in-flight position (e.g. React Flow's node.position).\n * When omitted, the committed model position is shown. Keeping this a callback\n * means editor-ui never imports React Flow — the binding stays in the host.\n */\n readonly livePosition?: (id: string) => { x: number; y: number } | undefined;\n}\n\ntype Align = 'left' | 'hcenter' | 'right' | 'top' | 'vcenter' | 'bottom';\n\nfunction selectedNodes(core: EditorCore): EditorNode[] {\n const ids = core.selection.getSelectedNodes();\n const out: EditorNode[] = [];\n for (const id of ids) {\n const n = core.model.getNode(id);\n if (n !== undefined) {\n out.push(n);\n }\n }\n return out;\n}\n\nexport function PositionPanel({ core, livePosition }: PositionPanelProps): ReactElement {\n // Re-render on selection change (enabled-state) AND on node change — a drag\n // commits a MoveNodeCommand which emits `nodeChanged`. During a drag, the host\n // re-renders us every frame (its live node list updates), so reading\n // `livePosition` here reflects the in-flight position continuously.\n useSelection(core);\n const [, bump] = useReducer((n: number) => n + 1, 0);\n useEffect(() => {\n const kinds = ['nodeChanged', 'nodeAdded', 'nodeRemoved'] as const;\n const disposers = kinds.map(k => core.events.on(k, bump));\n return () => {\n for (const d of disposers) {\n d.dispose();\n }\n };\n }, [core]);\n\n const nodes = selectedNodes(core);\n const single = nodes.length === 1 ? nodes[0] : undefined;\n // The displayed position prefers the live canvas position (updates mid-drag),\n // falling back to the committed model position.\n const shownPos =\n single !== undefined ? (livePosition?.(single.id) ?? single.position) : undefined;\n\n const moveAll = useCallback(\n (fn: (n: EditorNode) => { x: number; y: number }): void => {\n const targets = selectedNodes(core);\n if (targets.length === 0) {\n return;\n }\n core.history.transact('Align', () => {\n for (const n of targets) {\n core.commands.execute(new MoveNodeCommand(n.id, fn(n)));\n }\n });\n },\n [core],\n );\n\n const align = useCallback(\n (kind: Align): void => {\n const targets = selectedNodes(core);\n if (targets.length === 0) {\n return;\n }\n const xs = targets.map(n => n.position.x);\n const ys = targets.map(n => n.position.y);\n const minX = Math.min(...xs);\n const maxX = Math.max(...xs);\n const minY = Math.min(...ys);\n const maxY = Math.max(...ys);\n const cx = (minX + maxX) / 2;\n const cy = (minY + maxY) / 2;\n moveAll(n => {\n switch (kind) {\n case 'left':\n return { x: minX, y: n.position.y };\n case 'hcenter':\n return { x: cx, y: n.position.y };\n case 'right':\n return { x: maxX, y: n.position.y };\n case 'top':\n return { x: n.position.x, y: minY };\n case 'vcenter':\n return { x: n.position.x, y: cy };\n case 'bottom':\n return { x: n.position.x, y: maxY };\n }\n });\n },\n [core, moveAll],\n );\n\n const setCoord = useCallback(\n (axis: 'x' | 'y', value: number): void => {\n if (single === undefined || Number.isNaN(value)) {\n return;\n }\n const next = axis === 'x' ? { x: value, y: single.position.y } : { x: single.position.x, y: value };\n core.commands.execute(new MoveNodeCommand(single.id, next));\n },\n [core, single],\n );\n\n const disabled = nodes.length === 0;\n const alignButtons: readonly { kind: Align; label: string; d: string }[] = [\n { kind: 'left', label: 'Align left', d: 'M5 4v16M9 8h8M9 16h5' },\n { kind: 'hcenter', label: 'Align centre', d: 'M12 4v16M8 9h8M9 15h6' },\n { kind: 'right', label: 'Align right', d: 'M19 4v16M7 8h8M12 16h3' },\n { kind: 'top', label: 'Align top', d: 'M4 5h16M8 9v8M16 9v5' },\n { kind: 'vcenter', label: 'Align middle', d: 'M4 12h16M9 8v8M15 9v6' },\n { kind: 'bottom', label: 'Align bottom', d: 'M4 19h16M8 7v8M16 12v3' },\n ];\n\n return (\n <section className=\"hl-position\">\n <h3 className=\"hl-position-title hl-mono\">Position</h3>\n <div className=\"hl-position-align\" role=\"group\" aria-label=\"Align\">\n {alignButtons.map(b => (\n <button\n key={b.kind}\n className=\"hl-position-alignbtn\"\n onClick={() => align(b.kind)}\n disabled={disabled}\n title={b.label}\n aria-label={b.label}\n >\n <svg width={16} height={16} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={1.6} strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d={b.d} />\n </svg>\n </button>\n ))}\n </div>\n <div className=\"hl-position-coords\">\n <label className=\"hl-position-field\">\n <input\n type=\"number\"\n className=\"hl-position-input hl-mono\"\n value={shownPos !== undefined ? Math.round(shownPos.x) : ''}\n disabled={single === undefined}\n onChange={e => setCoord('x', Number(e.target.value))}\n aria-label=\"X position\"\n />\n <span className=\"hl-position-axis hl-mono\">X</span>\n </label>\n <label className=\"hl-position-field\">\n <input\n type=\"number\"\n className=\"hl-position-input hl-mono\"\n value={shownPos !== undefined ? Math.round(shownPos.y) : ''}\n disabled={single === undefined}\n onChange={e => setCoord('y', Number(e.target.value))}\n aria-label=\"Y position\"\n />\n <span className=\"hl-position-axis hl-mono\">Y</span>\n </label>\n </div>\n </section>\n );\n}\n","/**\n * `NodeSearch` — the floating command palette for creating nodes by fuzzy\n * search. Rendered when the controller is open; anchored at the trigger point.\n *\n * Presentation only: it owns the query string, keyboard navigation, and match\n * highlighting, and delegates ranking + creation to the `NodeSearchController`.\n * Deep-space glass panel, electric-blue accent, kind-tinted result chips.\n */\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport type { ReactElement, KeyboardEvent } from 'react';\nimport type { NodeKind } from '@hlang-tech/editor-core';\nimport type { NodeSearchController, NodeSearchResultView } from './useNodeSearch';\nimport type { FuzzyMatch } from './fuzzy';\nimport './NodeSearch.css';\n\n/** Panel width, used to keep the panel on-screen near the right/bottom edges. */\nconst PANEL_WIDTH = 320;\nconst PANEL_MAX_HEIGHT = 360;\n\nexport interface NodeSearchProps {\n readonly controller: NodeSearchController;\n}\n\nexport function NodeSearch({ controller }: NodeSearchProps): ReactElement | null {\n const { state } = controller;\n const [query, setQuery] = useState('');\n const [active, setActive] = useState(0);\n const inputRef = useRef<HTMLInputElement>(null);\n\n // Reset the query and focus the input each time the palette opens.\n const isOpen = state !== undefined;\n useEffect(() => {\n if (isOpen) {\n setQuery('');\n setActive(0);\n inputRef.current?.focus();\n }\n }, [isOpen]);\n\n const results = useMemo(\n () => (state !== undefined ? controller.results(query) : []),\n [controller, state, query],\n );\n\n // Keep the active index within bounds as results shrink/grow.\n const clampedActive = results.length === 0 ? 0 : Math.min(active, results.length - 1);\n\n const choose = useCallback(\n (view: NodeSearchResultView | undefined): void => {\n if (view !== undefined) {\n controller.commit(view);\n }\n },\n [controller],\n );\n\n const onKeyDown = useCallback(\n (event: KeyboardEvent<HTMLInputElement>): void => {\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n setActive(i => (results.length === 0 ? 0 : (i + 1) % results.length));\n break;\n case 'ArrowUp':\n event.preventDefault();\n setActive(i => (results.length === 0 ? 0 : (i - 1 + results.length) % results.length));\n break;\n case 'Enter':\n event.preventDefault();\n choose(results[clampedActive]);\n break;\n case 'Escape':\n event.preventDefault();\n controller.close();\n break;\n default:\n break;\n }\n },\n [results, clampedActive, choose, controller],\n );\n\n if (state === undefined) {\n return null;\n }\n\n const style = clampToViewport(state.screen.x, state.screen.y);\n const connectMode = state.pending !== undefined;\n\n return (\n <>\n <div\n className=\"hl-node-search-scrim\"\n onPointerDown={() => {\n controller.close();\n }}\n />\n <div className=\"hl-node-search\" style={style} role=\"dialog\" aria-label=\"Create node\">\n <div className=\"hl-node-search-field\">\n <span className=\"hl-node-search-glyph\" aria-hidden>\n {connectMode ? '⤳' : '+'}\n </span>\n <input\n ref={inputRef}\n className=\"hl-node-search-input\"\n value={query}\n placeholder={connectMode ? 'connect to…' : 'search nodes…'}\n onChange={e => {\n setQuery(e.target.value);\n setActive(0);\n }}\n onKeyDown={onKeyDown}\n aria-label=\"Search nodes\"\n autoComplete=\"off\"\n spellCheck={false}\n />\n </div>\n <ul className=\"hl-node-search-list\" role=\"listbox\">\n {results.length === 0 && (\n <li className=\"hl-node-search-empty hl-mono\">no matching nodes</li>\n )}\n {results.map((view, index) => {\n const descriptor = view.result.value;\n const kind = descriptor.kind;\n return (\n <li\n key={descriptor.code}\n role=\"option\"\n aria-selected={index === clampedActive}\n className={\n 'hl-node-search-item' + (index === clampedActive ? ' is-active' : '')\n }\n onPointerEnter={() => setActive(index)}\n onPointerDown={e => {\n e.preventDefault();\n choose(view);\n }}\n >\n <span\n className={`hl-node-search-kind hl-mono hl-kind-${kind.toLowerCase() as Lowercase<NodeKind>}`}\n >\n {kind}\n </span>\n <span className=\"hl-node-search-label\">\n {highlight(descriptor.displayName, view.result.match)}\n </span>\n {view.connectPortId !== undefined && (\n <span className=\"hl-node-search-port hl-mono\">{view.connectPortId}</span>\n )}\n </li>\n );\n })}\n </ul>\n </div>\n </>\n );\n}\n\n/** Render a label with the fuzzy-matched characters emphasized. */\nfunction highlight(text: string, match: FuzzyMatch): readonly ReactElement[] {\n const hit = new Set(match.positions);\n const chars = Array.from(text);\n return chars.map((ch, i) =>\n hit.has(i) ? (\n <mark key={i} className=\"hl-node-search-hit\">\n {ch}\n </mark>\n ) : (\n <span key={i}>{ch}</span>\n ),\n );\n}\n\n/** Keep the panel within the viewport when opened near an edge. */\nfunction clampToViewport(x: number, y: number): { left: number; top: number } {\n const maxLeft = Math.max(8, window.innerWidth - PANEL_WIDTH - 8);\n const maxTop = Math.max(8, window.innerHeight - PANEL_MAX_HEIGHT - 8);\n return {\n left: Math.min(Math.max(8, x), maxLeft),\n top: Math.min(Math.max(8, y), maxTop),\n };\n}\n","/**\n * `useNodeSearch` — palette state + commit logic for creating nodes by search.\n *\n * The palette can open in two modes:\n * - blank: create a free-standing node at a point (canvas double-click, `/`).\n * - from a released connection: create a node AND wire the dangling link to a\n * compatible port on it, as ONE undoable step.\n *\n * All mutation goes through the core command service; connection legality and\n * edge ids come from the core (validator + id generator). This hook holds no\n * graph rules of its own.\n */\n\nimport { useCallback, useMemo, useState } from 'react';\nimport type { EditorCore, NodeDescriptor, Point } from '@hlang-tech/editor-core';\nimport { AddNodeCommand, ConnectCommand } from '@hlang-tech/editor-core';\nimport {\n searchNodes,\n connectableCandidates,\n} from './node-search-model';\nimport type {\n PendingConnection,\n NodeSearchResult,\n} from './node-search-model';\n\n/** Where and how the palette is currently open. */\nexport interface NodeSearchState {\n /** Screen-space anchor for rendering the floating panel. */\n readonly screen: Point;\n /** Flow-space position where the created node will be placed. */\n readonly flow: Point;\n /** Set when opened by releasing a dangling connection. */\n readonly pending?: PendingConnection;\n}\n\n/** The palette controller returned by the hook. */\nexport interface NodeSearchController {\n /** Current open state, or `undefined` when closed. */\n readonly state: NodeSearchState | undefined;\n /** Open the palette to create a free-standing node. */\n openBlank(screen: Point, flow: Point): void;\n /** Open the palette to complete a released connection. */\n openFromConnection(screen: Point, flow: Point, pending: PendingConnection): void;\n /** Close the palette without creating anything. */\n close(): void;\n /**\n * Rank registry descriptors for the current query and open mode. In blank\n * mode every node is offered; in connection mode only nodes that can legally\n * complete the pending link are offered.\n */\n results(query: string): readonly NodeSearchResultView[];\n /** Create the chosen node (and wire the pending link, if any), then close. */\n commit(result: NodeSearchResultView): void;\n}\n\n/**\n * A ranked result as the palette renders it: the fuzzy match plus, in\n * connection mode, the port on the new node that completes the link.\n */\nexport interface NodeSearchResultView {\n readonly result: NodeSearchResult;\n /** Present only in connection mode. */\n readonly connectPortId?: string;\n}\n\nexport function useNodeSearch(core: EditorCore): NodeSearchController {\n const [state, setState] = useState<NodeSearchState | undefined>(undefined);\n\n const openBlank = useCallback((screen: Point, flow: Point): void => {\n setState({ screen, flow });\n }, []);\n\n const openFromConnection = useCallback(\n (screen: Point, flow: Point, pending: PendingConnection): void => {\n setState({ screen, flow, pending });\n },\n [],\n );\n\n const close = useCallback((): void => {\n setState(undefined);\n }, []);\n\n const descriptors = core.registry.list();\n\n const results = useCallback(\n (query: string): readonly NodeSearchResultView[] => {\n if (state?.pending !== undefined) {\n return connectableCandidates(\n query,\n descriptors,\n state.pending,\n core.validator,\n ).map(entry => ({ result: entry.candidate, connectPortId: entry.connectPortId }));\n }\n return searchNodes(query, descriptors).map(result => ({ result }));\n },\n [state, descriptors, core],\n );\n\n const commit = useCallback(\n (view: NodeSearchResultView): void => {\n if (state === undefined) {\n return;\n }\n const descriptor: NodeDescriptor = view.result.value;\n const node = core.registry.createNode(descriptor.code, state.flow);\n\n if (state.pending !== undefined && view.connectPortId !== undefined) {\n const pending = state.pending;\n const connectPortId = view.connectPortId;\n // Create the node and wire the released link as one undoable step.\n core.history.transact('Create & Connect Node', () => {\n core.commands.execute(new AddNodeCommand(node));\n const edgeId = core.idGenerator.nextEdgeId();\n const newEndpoint = { nodeId: node.id, portId: connectPortId };\n const [source, target] =\n pending.direction === 'from-source'\n ? [pending.fromEndpoint, newEndpoint]\n : [newEndpoint, pending.fromEndpoint];\n core.commands.execute(new ConnectCommand(edgeId, source, target));\n });\n } else {\n core.commands.execute(new AddNodeCommand(node));\n }\n setState(undefined);\n },\n [state, core],\n );\n\n return useMemo(\n () => ({ state, openBlank, openFromConnection, close, results, commit }),\n [state, openBlank, openFromConnection, close, results, commit],\n );\n}\n","/**\n * Small, dependency-free fuzzy matcher for the node search palette. Pure\n * functions — the only logic in editor-ui that carries its own unit tests\n * (behavior, not pixels). Ranks candidates by subsequence match quality:\n * contiguous and word-boundary matches score higher, earlier matches score\n * higher, shorter targets break ties.\n */\n\n/** A scored match with the matched character positions (for highlighting). */\nexport interface FuzzyMatch {\n readonly score: number;\n readonly positions: readonly number[];\n}\n\n/**\n * Score `query` against `target` as a case-insensitive subsequence match.\n * Returns `null` when `target` does not contain `query` as a subsequence.\n * An empty query matches everything with score 0 (stable, no reordering).\n */\nexport function fuzzyScore(query: string, target: string): FuzzyMatch | null {\n if (query.length === 0) {\n return { score: 0, positions: [] };\n }\n const q = query.toLowerCase();\n const t = target.toLowerCase();\n\n const positions: number[] = [];\n let score = 0;\n let qi = 0;\n let prevMatch = -2;\n\n for (let ti = 0; ti < t.length && qi < q.length; ti += 1) {\n if (t[ti] !== q[qi]) {\n continue;\n }\n positions.push(ti);\n\n // Base point for a matched character.\n let point = 1;\n // Contiguous with the previous matched char.\n if (ti === prevMatch + 1) {\n point += 3;\n }\n // At a word boundary (start, or after a separator / camelCase hump).\n if (ti === 0 || isBoundary(target, ti)) {\n point += 2;\n }\n // Earlier matches are slightly preferred.\n point += Math.max(0, 2 - ti * 0.05);\n\n score += point;\n prevMatch = ti;\n qi += 1;\n }\n\n if (qi < q.length) {\n return null; // not a full subsequence\n }\n\n // Prefer shorter targets when scores are otherwise close.\n score -= target.length * 0.01;\n return { score, positions };\n}\n\nfunction isBoundary(target: string, index: number): boolean {\n const prev = target[index - 1];\n const cur = target[index];\n if (prev === undefined || cur === undefined) {\n return false;\n }\n const isSep = /[\\s\\-_./]/.test(prev);\n const isCamel = prev === prev.toLowerCase() && cur === cur.toUpperCase();\n return isSep || isCamel;\n}\n\n/** A candidate to rank, carrying an opaque payload of type `T`. */\nexport interface FuzzyCandidate<T> {\n readonly text: string;\n readonly value: T;\n}\n\n/** A ranked result: the candidate plus its match. */\nexport interface FuzzyResult<T> {\n readonly value: T;\n readonly text: string;\n readonly match: FuzzyMatch;\n}\n\n/**\n * Rank candidates against a query, best first. Non-matching candidates are\n * dropped. With an empty query, candidates are returned in their original order.\n */\nexport function fuzzyRank<T>(\n query: string,\n candidates: readonly FuzzyCandidate<T>[],\n): readonly FuzzyResult<T>[] {\n const results: FuzzyResult<T>[] = [];\n for (const candidate of candidates) {\n const match = fuzzyScore(query, candidate.text);\n if (match !== null) {\n results.push({ value: candidate.value, text: candidate.text, match });\n }\n }\n if (query.length === 0) {\n return results;\n }\n return results.sort((a, b) => b.match.score - a.match.score);\n}\n","/**\n * Pure model behind the node-search palette. No React, no DOM.\n *\n * Two responsibilities:\n * 1. Turn the design-time registry into fuzzy-searchable candidates and rank\n * them against a query (`descriptorCandidates` + `searchNodes`).\n * 2. When the palette is opened by releasing a dangling connection into empty\n * space, offer ONLY nodes that can legally complete that connection, and\n * remember which port on each closes it (`connectableCandidates`). The\n * legality decision is delegated to the core `IConnectionValidator` — this\n * module never re-encodes hlang's connection rules.\n */\n\nimport type {\n NodeDescriptor,\n PortDescriptor,\n Endpoint,\n IConnectionValidator,\n} from '@hlang-tech/editor-core';\nimport { fuzzyRank } from './fuzzy';\nimport type { FuzzyCandidate, FuzzyResult } from './fuzzy';\n\n/** A registry descriptor made searchable, keyed by its display name. */\nexport type NodeCandidate = FuzzyCandidate<NodeDescriptor>;\n\n/** A ranked search result carrying the matched descriptor. */\nexport type NodeSearchResult = FuzzyResult<NodeDescriptor>;\n\n/** Build fuzzy candidates from registry descriptors (display-name keyed). */\nexport function descriptorCandidates(\n descriptors: readonly NodeDescriptor[],\n): readonly NodeCandidate[] {\n return descriptors.map(descriptor => ({ text: descriptor.displayName, value: descriptor }));\n}\n\n/** Rank descriptors against `query`, best first (empty query keeps order). */\nexport function searchNodes(\n query: string,\n descriptors: readonly NodeDescriptor[],\n): readonly NodeSearchResult[] {\n return fuzzyRank(query, descriptorCandidates(descriptors));\n}\n\n/**\n * A connection left dangling in empty space. `fromEndpoint` is the port the\n * user dragged from and `fromPort` its resolved descriptor; `direction` says\n * whether that endpoint is the connection's source (an output, needing a\n * target) or its target (an input, needing a source). The palette will create a\n * node and wire the missing side.\n */\nexport interface PendingConnection {\n readonly fromEndpoint: Endpoint;\n /** Descriptor of the port the drag started from (resolved from the model). */\n readonly fromPort: PortDescriptor;\n readonly direction: 'from-source' | 'from-target';\n}\n\n/**\n * A search result augmented with the specific port on the candidate node that\n * would complete a pending connection.\n */\nexport interface ConnectableResult {\n readonly candidate: NodeSearchResult;\n /** The port id on the (future) new node that closes the connection. */\n readonly connectPortId: string;\n}\n\n/**\n * Filter and rank descriptors to those that can legally complete `pending`,\n * annotating each with the completing port. Legality is decided by the core\n * validator's model-free `canLink` (direction + DTO): for a dangling source we\n * ask canLink(danglingSource, candidatePort); for a dangling target we ask\n * canLink(candidatePort, danglingTarget). No graph model is consulted, because\n * the candidate node does not exist yet — legality here is purely a property of\n * the two ports.\n */\nexport function connectableCandidates(\n query: string,\n descriptors: readonly NodeDescriptor[],\n pending: PendingConnection,\n validator: IConnectionValidator,\n): readonly ConnectableResult[] {\n const ranked = searchNodes(query, descriptors);\n const out: ConnectableResult[] = [];\n\n for (const result of ranked) {\n const port = firstCompletingPort(result.value.ports, pending, validator);\n if (port !== undefined) {\n out.push({ candidate: result, connectPortId: port });\n }\n }\n return out;\n}\n\n/**\n * Find the first port on `ports` that legally completes `pending`, or\n * `undefined` if none do. For a dangling source (output) we look for an input\n * on the candidate; for a dangling target (input), an output.\n */\nfunction firstCompletingPort(\n ports: readonly PortDescriptor[],\n pending: PendingConnection,\n validator: IConnectionValidator,\n): string | undefined {\n for (const port of ports) {\n const ok =\n pending.direction === 'from-source'\n ? validator.canLink(pending.fromPort, port).ok\n : validator.canLink(port, pending.fromPort).ok;\n if (ok) {\n return port.id;\n }\n }\n return undefined;\n}\n","/**\n * `useNodeSearchTriggers` — bridge React Flow gestures to the node-search\n * palette. Returns handlers to spread onto `<ReactFlow>`:\n *\n * - `onConnectStart` / `onConnectEnd`: when a link is dragged from a port and\n * released into empty space (not onto a handle), open the palette pre-filtered\n * to nodes that can complete that connection.\n * - `onPaneClick`: two clicks on the empty pane within `doubleClickMs` open a\n * blank palette. We use React Flow's first-class `onPaneClick` (which fires\n * only for the pane, never for nodes/edges/handles) rather than a raw DOM\n * double-click, so this never reaches into React Flow's internal markup.\n *\n * Screen→flow coordinate conversion uses the React Flow instance, so created\n * nodes land under the pointer regardless of pan/zoom. This hook must be used\n * within a `ReactFlowProvider` (React Flow's own requirement for `useReactFlow`).\n */\n\nimport { useCallback, useRef } from 'react';\nimport { useReactFlow } from '@xyflow/react';\nimport type {\n OnConnectStart,\n OnConnectEnd,\n OnConnectStartParams,\n FinalConnectionState,\n} from '@xyflow/react';\nimport type { MouseEvent as ReactMouseEvent } from 'react';\nimport type { EditorCore, PortDescriptor } from '@hlang-tech/editor-core';\nimport type { NodeSearchController } from './useNodeSearch';\nimport type { PendingConnection } from './node-search-model';\n\n/** Max gap between two pane clicks to count as a double-click. */\nconst DEFAULT_DOUBLE_CLICK_MS = 350;\n\n/** Options for the trigger hook (injectable clock keeps it deterministic). */\nexport interface NodeSearchTriggerOptions {\n /** Double-click detection window in ms. Defaults to 350. */\n readonly doubleClickMs?: number;\n /** Monotonic clock in ms. Defaults to `performance.now`. */\n readonly now?: () => number;\n}\n\n/** Handlers to spread onto the `<ReactFlow>` element. */\nexport interface NodeSearchTriggers {\n readonly onConnectStart: OnConnectStart;\n readonly onConnectEnd: OnConnectEnd;\n /** Attach to `<ReactFlow onPaneClick>`; a rapid second click opens the palette. */\n onPaneClick(event: ReactMouseEvent): void;\n}\n\nexport function useNodeSearchTriggers(\n core: EditorCore,\n search: NodeSearchController,\n options: NodeSearchTriggerOptions = {},\n): NodeSearchTriggers {\n const flow = useReactFlow();\n const doubleClickMs = options.doubleClickMs ?? DEFAULT_DOUBLE_CLICK_MS;\n const now = options.now ?? defaultNow;\n\n // Remember the endpoint a connection drag started from, so connect-end can\n // build the pending connection when it lands in empty space.\n const startRef = useRef<OnConnectStartParams | null>(null);\n // Timestamp of the last pane click, for double-click detection.\n const lastPaneClickRef = useRef<number>(Number.NEGATIVE_INFINITY);\n\n const onConnectStart = useCallback<OnConnectStart>((_event, params) => {\n startRef.current = params;\n }, []);\n\n const onConnectEnd = useCallback<OnConnectEnd>(\n (event, connectionState: FinalConnectionState) => {\n const start = startRef.current;\n startRef.current = null;\n // Only act when the drag ended in empty space (no destination node/handle).\n if (connectionState.toNode !== null || start === null) {\n return;\n }\n if (start.nodeId === null || start.handleId === null || start.handleType === null) {\n return;\n }\n const point = pointerOf(event);\n if (point === null) {\n return;\n }\n // Resolve the descriptor of the port the drag started from; the palette\n // needs it to decide which node types can complete the connection.\n const fromPort = resolvePort(core, start.nodeId, start.handleId);\n if (fromPort === undefined) {\n return;\n }\n const pending: PendingConnection = {\n fromEndpoint: { nodeId: start.nodeId, portId: start.handleId },\n fromPort,\n // A drag from a 'source' (output) handle needs a target node; a drag\n // from a 'target' (input) handle needs a source node.\n direction: start.handleType === 'source' ? 'from-source' : 'from-target',\n };\n search.openFromConnection(\n point,\n flow.screenToFlowPosition(point),\n pending,\n );\n },\n [core, flow, search],\n );\n\n const onPaneClick = useCallback(\n (event: ReactMouseEvent): void => {\n const t = now();\n const isDouble = t - lastPaneClickRef.current <= doubleClickMs;\n lastPaneClickRef.current = t;\n if (!isDouble) {\n return;\n }\n lastPaneClickRef.current = Number.NEGATIVE_INFINITY; // consume the pair\n const screen = { x: event.clientX, y: event.clientY };\n search.openBlank(screen, flow.screenToFlowPosition(screen));\n },\n [flow, search, doubleClickMs, now],\n );\n\n return { onConnectStart, onConnectEnd, onPaneClick };\n}\n\nfunction defaultNow(): number {\n return performance.now();\n}\n\n/** Resolve a port descriptor by node id + port id from the graph model. */\nfunction resolvePort(\n core: EditorCore,\n nodeId: string,\n portId: string,\n): PortDescriptor | undefined {\n const node = core.model.getNode(nodeId);\n return node?.ports.find(port => port.id === portId);\n}\n\n/** Extract client pointer coords from a mouse or touch connect-end event. */\nfunction pointerOf(event: MouseEvent | TouchEvent): { x: number; y: number } | null {\n if ('clientX' in event) {\n return { x: event.clientX, y: event.clientY };\n }\n const touch = event.changedTouches[0];\n return touch ? { x: touch.clientX, y: touch.clientY } : null;\n}\n","/**\n * `useEditorHotkeys` — global keyboard shortcuts for the editor canvas:\n *\n * ⌘/Ctrl+Z undo ⌘/Ctrl+Shift+Z, ⌘/Ctrl+Y redo\n * ⌘/Ctrl+C copy ⌘/Ctrl+V paste ⌘/Ctrl+X cut ⌘/Ctrl+D duplicate\n * Delete / Backspace delete\n *\n * Clipboard actions run through `useClipboard`; undo/redo drive the history\n * service. Every action is a proper command, so it is itself undoable. The\n * listener is on `window` but SUPPRESSED while a text input / textarea /\n * contenteditable is focused, so typing never triggers a canvas action.\n *\n * When the editor is one part of a larger page, pass `scope`: shortcuts then\n * fire only for keystrokes whose target is inside that element, and every other\n * keystroke (copying page text, Backspace in a page control) is left untouched.\n */\n\nimport { useEffect } from 'react';\nimport type { RefObject } from 'react';\nimport type { EditorCore } from '@hlang-tech/editor-core';\nimport { useClipboard } from '@hlang-tech/editor-react';\n\n/** True when focus is in an editable field, where shortcuts must NOT fire. */\nexport function isEditableTarget(target: EventTarget | null): boolean {\n if (!(target instanceof HTMLElement)) {\n return false;\n }\n const tag = target.tagName;\n return tag === 'INPUT' || tag === 'TEXTAREA' || target.isContentEditable;\n}\n\nexport interface EditorHotkeysOptions {\n /**\n * The element that owns the shortcuts. When given, only keystrokes whose\n * target is inside it are handled; while it is not mounted, none are.\n * Omit it when the editor fills the page.\n */\n readonly scope?: RefObject<HTMLElement | null>;\n}\n\n/** True when `scope` is unset, or when the event's target is inside it. */\nfunction withinScope(target: EventTarget | null, scope: EditorHotkeysOptions['scope']): boolean {\n if (scope === undefined) {\n return true;\n }\n const root = scope.current;\n return root !== null && target instanceof Node && root.contains(target);\n}\n\nexport function useEditorHotkeys(core: EditorCore, options: EditorHotkeysOptions = {}): void {\n const clipboard = useClipboard(core);\n const { scope } = options;\n\n useEffect(() => {\n const onKeyDown = (event: KeyboardEvent): void => {\n if (!withinScope(event.target, scope) || isEditableTarget(event.target)) {\n return;\n }\n const mod = event.metaKey || event.ctrlKey;\n\n // Undo / redo. Redo accepts ⌘⇧Z (Mac) and ⌘Y (Windows) conventions.\n if (mod && !event.altKey) {\n const key = event.key.toLowerCase();\n if (key === 'z' && !event.shiftKey) {\n event.preventDefault();\n core.history.undo();\n return;\n }\n if ((key === 'z' && event.shiftKey) || key === 'y') {\n event.preventDefault();\n core.history.redo();\n return;\n }\n }\n\n if (mod && !event.shiftKey && !event.altKey) {\n const key = event.key.toLowerCase();\n if (key === 'c') {\n event.preventDefault();\n clipboard.copy();\n return;\n }\n if (key === 'x') {\n event.preventDefault();\n clipboard.cut();\n return;\n }\n if (key === 'v') {\n event.preventDefault();\n clipboard.paste();\n return;\n }\n if (key === 'd') {\n event.preventDefault();\n clipboard.duplicate();\n return;\n }\n if (key === 'a') {\n // Select all nodes. Going through core.selection reflects onto the\n // canvas via the derived `selected` flag + selectionChanged reconcile.\n event.preventDefault();\n core.selection.selectNodes(\n core.model.getNodes().map(n => n.id),\n 'replace',\n );\n return;\n }\n }\n\n if (event.key === 'Delete' || event.key === 'Backspace') {\n event.preventDefault();\n clipboard.remove();\n }\n };\n\n window.addEventListener('keydown', onKeyDown);\n return (): void => {\n window.removeEventListener('keydown', onKeyDown);\n };\n }, [core, clipboard, scope]);\n}\n","/**\n * `NodeContextMenu` — the right-click menu for a node. A black/silver glass\n * panel matching the command palette's material and dismissal, listing actions\n * the consumer supplies (duplicate/copy/cut/paste/delete/hide/lock). Presentation\n * only: each item carries its own `onSelect`; this component owns positioning,\n * keyboard navigation, and dismissal.\n */\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport type { ReactElement, ReactNode, KeyboardEvent } from 'react';\nimport type { NodeContextMenuController } from './useNodeContextMenu';\nimport './NodeContextMenu.css';\n\nconst PANEL_WIDTH = 208;\nconst ITEM_HEIGHT = 34;\n/** Keep the menu this many px inside each viewport edge. */\nconst VIEWPORT_MARGIN = 8;\n/** Extra vertical padding added to the estimated menu height. */\nconst MENU_VPAD = 12;\n\n/** One menu row. A separator is a bare `{ separator: true }`. */\nexport interface ContextMenuItem {\n readonly id: string;\n readonly label: string;\n /** Optional keyboard-shortcut hint shown right-aligned (e.g. \"⌘D\"). */\n readonly shortcut?: string;\n /** Optional leading glyph. */\n readonly icon?: ReactNode;\n /** Destructive styling (e.g. Delete). */\n readonly danger?: boolean;\n /** Disabled rows are shown dim and are not selectable. */\n readonly disabled?: boolean;\n readonly onSelect: () => void;\n}\n\nexport interface NodeContextMenuProps {\n readonly controller: NodeContextMenuController;\n /** Build the items for the targeted node id (recomputed on open). */\n readonly items: (nodeId: string) => readonly ContextMenuItem[];\n}\n\nexport function NodeContextMenu({ controller, items }: NodeContextMenuProps): ReactElement | null {\n const { state } = controller;\n const [active, setActive] = useState(0);\n const menuRef = useRef<HTMLDivElement>(null);\n\n const isOpen = state !== undefined;\n useEffect(() => {\n if (isOpen) {\n setActive(0);\n menuRef.current?.focus();\n }\n }, [isOpen]);\n\n const rows = useMemo(\n () => (state !== undefined ? items(state.nodeId) : []),\n [items, state],\n );\n\n // Indices that can actually be selected (skip disabled rows).\n const enabledIndices = useMemo(\n () => rows.map((r, i) => (r.disabled ? -1 : i)).filter(i => i >= 0),\n [rows],\n );\n\n const move = useCallback(\n (delta: number): void => {\n if (enabledIndices.length === 0) {\n return;\n }\n setActive(current => {\n const pos = enabledIndices.indexOf(current);\n const nextPos =\n pos === -1\n ? 0\n : (pos + delta + enabledIndices.length) % enabledIndices.length;\n return enabledIndices[nextPos] ?? current;\n });\n },\n [enabledIndices],\n );\n\n const choose = useCallback(\n (item: ContextMenuItem | undefined): void => {\n if (item === undefined || item.disabled) {\n return;\n }\n item.onSelect();\n controller.close();\n },\n [controller],\n );\n\n const onKeyDown = useCallback(\n (event: KeyboardEvent<HTMLDivElement>): void => {\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n move(1);\n break;\n case 'ArrowUp':\n event.preventDefault();\n move(-1);\n break;\n case 'Enter':\n event.preventDefault();\n choose(rows[active]);\n break;\n case 'Escape':\n event.preventDefault();\n controller.close();\n break;\n default:\n break;\n }\n },\n [move, choose, rows, active, controller],\n );\n\n if (state === undefined) {\n return null;\n }\n\n const style = clampToViewport(state.screen.x, state.screen.y, rows.length);\n\n return (\n <>\n <div\n className=\"hl-ctx-scrim\"\n onPointerDown={() => {\n controller.close();\n }}\n onContextMenu={e => {\n // A right-click on the scrim dismisses rather than opening the OS menu.\n e.preventDefault();\n controller.close();\n }}\n />\n <div\n ref={menuRef}\n className=\"hl-ctx-menu\"\n style={style}\n role=\"menu\"\n aria-label=\"Node actions\"\n tabIndex={-1}\n onKeyDown={onKeyDown}\n >\n {rows.map((item, index) => (\n <button\n key={item.id}\n type=\"button\"\n role=\"menuitem\"\n disabled={item.disabled}\n className={\n 'hl-ctx-item' +\n (item.danger === true ? ' is-danger' : '') +\n (index === active ? ' is-active' : '')\n }\n onPointerEnter={() => !item.disabled && setActive(index)}\n onPointerDown={e => {\n e.preventDefault();\n choose(item);\n }}\n >\n <span className=\"hl-ctx-item-icon\" aria-hidden>\n {item.icon}\n </span>\n <span className=\"hl-ctx-item-label\">{item.label}</span>\n {item.shortcut !== undefined && (\n <span className=\"hl-ctx-item-key hl-mono\">{item.shortcut}</span>\n )}\n </button>\n ))}\n </div>\n </>\n );\n}\n\n/** Keep the menu within the viewport near an edge. */\nfunction clampToViewport(x: number, y: number, rowCount: number): { left: number; top: number } {\n const height = Math.max(ITEM_HEIGHT, rowCount * ITEM_HEIGHT + MENU_VPAD);\n const maxLeft = Math.max(VIEWPORT_MARGIN, window.innerWidth - PANEL_WIDTH - VIEWPORT_MARGIN);\n const maxTop = Math.max(VIEWPORT_MARGIN, window.innerHeight - height - VIEWPORT_MARGIN);\n return {\n left: Math.min(Math.max(VIEWPORT_MARGIN, x), maxLeft),\n top: Math.min(Math.max(VIEWPORT_MARGIN, y), maxTop),\n };\n}\n","/**\n * `useNodeContextMenu` — controller for the right-click node menu. Holds only\n * where the menu is open and which node it targets; the menu ITEMS (labels,\n * shortcuts, actions) are assembled by the consumer from clipboard/view-state\n * actions, so this hook carries no graph rules.\n */\n\nimport { useCallback, useMemo, useState } from 'react';\nimport type { NodeId, Point } from '@hlang-tech/editor-core';\n\n/** Where the menu is open and which node it targets. */\nexport interface NodeContextMenuState {\n /** Screen-space anchor (the click point). */\n readonly screen: Point;\n /** The node the menu acts on. */\n readonly nodeId: NodeId;\n}\n\nexport interface NodeContextMenuController {\n readonly state: NodeContextMenuState | undefined;\n /** Open the menu for a node at a screen point. */\n openForNode(screen: Point, nodeId: NodeId): void;\n close(): void;\n}\n\nexport function useNodeContextMenu(): NodeContextMenuController {\n const [state, setState] = useState<NodeContextMenuState | undefined>(undefined);\n\n const openForNode = useCallback((screen: Point, nodeId: NodeId): void => {\n setState({ screen, nodeId });\n }, []);\n\n const close = useCallback((): void => {\n setState(undefined);\n }, []);\n\n return useMemo(() => ({ state, openForNode, close }), [state, openForNode, close]);\n}\n","/**\n * `Cheatsheet` — a keyboard-shortcut reference in the black/silver glass\n * language. Toggled by the host (typically the `?` key). Presentation only: it\n * takes an `open` flag and an `onClose`, and renders a grouped list of the\n * editor's shortcuts so they are discoverable, not memorized.\n */\n\nimport { useEffect, useRef } from 'react';\nimport type { ReactElement } from 'react';\nimport './Cheatsheet.css';\n\nexport interface ShortcutRow {\n readonly keys: string;\n readonly label: string;\n}\nexport interface ShortcutGroup {\n readonly title: string;\n readonly rows: readonly ShortcutRow[];\n}\n\nexport interface CheatsheetProps {\n readonly open: boolean;\n readonly onClose: () => void;\n /** Groups to display; a sensible default set is used when omitted. */\n readonly groups?: readonly ShortcutGroup[];\n}\n\nconst DEFAULT_GROUPS: readonly ShortcutGroup[] = [\n {\n title: 'Edit',\n rows: [\n { keys: '⌘Z', label: 'Undo' },\n { keys: '⌘⇧Z / ⌘Y', label: 'Redo' },\n { keys: '⌘C', label: 'Copy' },\n { keys: '⌘X', label: 'Cut' },\n { keys: '⌘V', label: 'Paste (at cursor)' },\n { keys: '⌘D', label: 'Duplicate' },\n { keys: '⌫', label: 'Delete' },\n ],\n },\n {\n title: 'Select & navigate',\n rows: [\n { keys: '⌘A', label: 'Select all' },\n { keys: 'Drag', label: 'Box-select (left drag)' },\n { keys: 'Middle / Right drag', label: 'Pan' },\n { keys: 'Space + drag', label: 'Pan' },\n { keys: 'Double-click name', label: 'Rename node' },\n ],\n },\n {\n title: 'Build',\n rows: [\n { keys: 'Double-click canvas', label: 'Search & create node' },\n { keys: 'Drag port to empty', label: 'Create & connect' },\n { keys: 'Drop node on wire', label: 'Insert inline (if compatible)' },\n { keys: 'Drag edge end', label: 'Reconnect' },\n { keys: '?', label: 'This cheatsheet' },\n ],\n },\n];\n\nexport function Cheatsheet({ open, onClose, groups = DEFAULT_GROUPS }: CheatsheetProps): ReactElement | null {\n const dialogRef = useRef<HTMLDivElement>(null);\n useEffect(() => {\n if (!open) {\n return;\n }\n // Move focus into the dialog on open (a11y — keyboard/SR users get an anchor,\n // matching the NodeContextMenu pattern).\n dialogRef.current?.focus();\n const onKey = (e: KeyboardEvent): void => {\n if (e.key === 'Escape') {\n onClose();\n }\n };\n window.addEventListener('keydown', onKey);\n return (): void => window.removeEventListener('keydown', onKey);\n }, [open, onClose]);\n\n if (!open) {\n return null;\n }\n\n return (\n <>\n <div className=\"hl-cheat-scrim\" onPointerDown={onClose} />\n <div\n ref={dialogRef}\n className=\"hl-cheat\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Keyboard shortcuts\"\n tabIndex={-1}\n >\n <div className=\"hl-cheat-head\">\n <span className=\"hl-cheat-title\">Shortcuts</span>\n <button className=\"hl-cheat-close\" onClick={onClose} aria-label=\"Close\">\n ✕\n </button>\n </div>\n <div className=\"hl-cheat-grid\">\n {groups.map(group => (\n <section key={group.title} className=\"hl-cheat-group\">\n <h3 className=\"hl-cheat-group-title hl-mono\">{group.title}</h3>\n <ul className=\"hl-cheat-rows\">\n {group.rows.map(row => (\n // A row is a binding: one action can have several (two ways to pan),\n // so neither the label nor the keys alone identify it.\n <li key={`${row.keys}\\u0000${row.label}`} className=\"hl-cheat-row\">\n <span className=\"hl-cheat-label\">{row.label}</span>\n <kbd className=\"hl-cheat-keys hl-mono\">{row.keys}</kbd>\n </li>\n ))}\n </ul>\n </section>\n ))}\n </div>\n </div>\n </>\n );\n}\n","/**\n * `ToastProvider` / `useToast` — lightweight transient notifications in the\n * black/silver glass language. A host wraps the app once; any component calls\n * `useToast().show('Copied 3 nodes')` for a brief confirmation. Presentation\n * only: it holds a small queue that auto-dismisses.\n */\n\nimport { createContext, useCallback, useContext, useMemo, useRef, useState } from 'react';\nimport type { ReactElement, ReactNode } from 'react';\nimport './Toast.css';\n\ninterface ToastItem {\n readonly id: number;\n readonly message: string;\n}\n\nexport interface ToastApi {\n show(message: string): void;\n}\n\nconst ToastCtx = createContext<ToastApi>({ show: () => undefined });\n\nexport interface ToastProviderProps {\n readonly children: ReactNode;\n /** Auto-dismiss delay in ms (default 2200). */\n readonly duration?: number;\n}\n\nexport function ToastProvider({ children, duration = 2200 }: ToastProviderProps): ReactElement {\n const [items, setItems] = useState<readonly ToastItem[]>([]);\n const seq = useRef(0);\n\n const show = useCallback(\n (message: string): void => {\n seq.current += 1;\n const id = seq.current;\n setItems(prev => [...prev, { id, message }]);\n // Timers are a UI concern; Date/setTimeout are fine in the browser layer.\n setTimeout(() => {\n setItems(prev => prev.filter(t => t.id !== id));\n }, duration);\n },\n [duration],\n );\n\n const api = useMemo<ToastApi>(() => ({ show }), [show]);\n\n return (\n <ToastCtx.Provider value={api}>\n {children}\n <div className=\"hl-toast-stack\" aria-live=\"polite\">\n {items.map(t => (\n <div key={t.id} className=\"hl-toast\">\n {t.message}\n </div>\n ))}\n </div>\n </ToastCtx.Provider>\n );\n}\n\nexport function useToast(): ToastApi {\n return useContext(ToastCtx);\n}\n","/**\n * `useLiveSignals` — feed a running flow's activity/error signals into the\n * LiveSignalStore, which node/edge components subscribe to by id. No global DOM\n * access and no dependency on React Flow's private structure: the store is the\n * single source of truth and components read their own state (see\n * `LiveSignalContext`). Must be used within a `<LiveSignalProvider>`.\n */\n\nimport { useEffect } from 'react';\nimport type { EditorCore } from '@hlang-tech/editor-core';\nimport type { IExecutionHandle } from '@hlang-tech/editor-core';\nimport { useLiveSignalStore } from '../live/LiveSignalContext';\nimport type { EdgeIndexEntry, LiveSignalStore } from '../live/live-signal-store';\n\n/**\n * Drive live visuals from an execution handle. Pass the handle returned by\n * `core.execution.run(...)`; pass `undefined` to clear. Keeps the store's edge\n * index in sync with the model so a source-port pulse lights the right edges.\n *\n * The store is taken from `<LiveSignalProvider>` context; pass `explicitStore`\n * when the feeding component sits at or above the provider (so it and the\n * subscribing components share one store).\n */\nexport function useLiveSignals(\n core: EditorCore,\n handle: IExecutionHandle | undefined,\n explicitStore?: LiveSignalStore,\n): void {\n const contextStore = useLiveSignalStore();\n const store = explicitStore ?? contextStore;\n\n // Keep the edge index current whenever the graph changes.\n useEffect(() => {\n if (store === null) {\n return;\n }\n const syncEdges = (): void => {\n const entries: EdgeIndexEntry[] = core.model.getEdges().map(edge => ({\n id: edge.id,\n sourceNodeId: edge.source.nodeId,\n sourcePortId: edge.source.portId,\n isError: edge.source.portId === '@node/error',\n }));\n store.setEdgeIndex(entries);\n };\n syncEdges();\n const added = core.events.on('edgeAdded', syncEdges);\n const removed = core.events.on('edgeRemoved', syncEdges);\n return (): void => {\n added.dispose();\n removed.dispose();\n };\n }, [core, store]);\n\n // Subscribe to the running handle's signals and feed the store.\n useEffect(() => {\n if (store === null) {\n return;\n }\n if (handle === undefined) {\n store.reset();\n return;\n }\n const activitySub = handle.onActivity(e => store.markActivity(e.nodeId, e.portId));\n const errorSub = handle.onError(e => store.markError(e.nodeId));\n return (): void => {\n activitySub.dispose();\n errorSub.dispose();\n store.reset();\n };\n }, [store, handle]);\n}\n"],"mappings":"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","names":["jsx","jsx","jsx","jsx","jsx","jsxs","jsx","jsx","createContext","useContext","jsx","jsx","jsxs","jsx","jsxs","jsx","jsxs","jsx","jsxs","Fragment","jsx","jsxs","jsx","jsxs","Fragment","jsx","jsx","jsxs","jsx","jsxs","useCallback","useMemo","useRef","useSyncExternalStore","useState","jsx","jsxs","useState","jsx","jsxs","selectedNodes","useCallback","useEffect","useMemo","useState","useSelection","jsx","jsxs","useState","useCallback","useEffect","useMemo","useSelection","jsx","jsxs","jsx","jsx","useCallback","useEffect","useSelection","jsx","jsxs","useSelection","useEffect","useCallback","useCallback","useEffect","useMemo","useRef","useState","Fragment","jsx","jsxs","useState","useRef","useEffect","useMemo","useCallback","useCallback","useMemo","useState","useState","useCallback","useMemo","useCallback","useRef","useEffect","useCallback","useEffect","useMemo","useRef","useState","Fragment","jsx","jsxs","PANEL_WIDTH","useState","useRef","useEffect","useMemo","useCallback","clampToViewport","useCallback","useMemo","useState","useEffect","useRef","Fragment","jsx","jsxs","useRef","useEffect","createContext","useCallback","useContext","useMemo","useRef","useState","jsx","jsxs","createContext","useState","useRef","useCallback","useMemo","useContext","useEffect","useEffect"]}
1
+ {"version":3,"sources":["../src/tokens/tokens.ts","../src/tokens/theme.ts","../src/tokens/ThemeProvider.tsx","../src/nodes/SignalBar.tsx","../src/nodes/PortRow.tsx","../src/nodes/NodeBodySlot.tsx","../src/live/LiveSignalContext.tsx","../src/live/live-signal-store.ts","../src/live/LivePulse.tsx","../src/nodes/AssetNode.tsx","../src/nodes/PillNode.tsx","../src/icons/node-icons.tsx","../src/panels/DiagnosticBadge.tsx","../src/nodes/NodeInteractionContext.tsx","../src/nodes/HlangNode.tsx","../src/edges/FlowEdge.tsx","../src/edges/self-loop.ts","../src/edges/edge-bounds.ts","../src/nodes/flow-types.ts","../src/shell/EditorShell.tsx","../src/shell/FooterResizer.tsx","../src/shell/useFooterResize.ts","../src/shell/footer-size.ts","../src/toolbar/Toolbar.tsx","../src/toolbar/ToolCluster.tsx","../src/canvas/CanvasChrome.tsx","../src/canvas/CanvasDock.tsx","../src/canvas/EmptyState.tsx","../src/panels/InspectorPanel.tsx","../src/schema/param-field.ts","../src/hooks/useNodeParams.ts","../src/hooks/useEdgeBounds.ts","../src/panels/ParamForm.tsx","../src/panels/ConnectionInspector.tsx","../src/live/format.ts","../src/live/preview.ts","../src/live/RunTraceContext.tsx","../src/panels/NodeRunStats.tsx","../src/panels/OutlineTree.tsx","../src/panels/PreviewPanel.tsx","../src/panels/RailTabs.tsx","../src/panels/AssetGrid.tsx","../src/panels/PositionPanel.tsx","../src/command-palette/NodeSearch.tsx","../src/command-palette/useNodeSearch.ts","../src/command-palette/fuzzy.ts","../src/command-palette/node-search-model.ts","../src/command-palette/useNodeSearchTriggers.ts","../src/hooks/useEditorHotkeys.ts","../src/context-menu/NodeContextMenu.tsx","../src/context-menu/useNodeContextMenu.ts","../src/overlays/Cheatsheet.tsx","../src/overlays/Toast.tsx","../src/hooks/useLiveSignals.ts","../src/live/run-trace.ts","../src/hooks/useRunTrace.ts","../src/hooks/useFollowScroll.ts","../src/panels/RunLog.tsx"],"sourcesContent":["/**\n * Typed accessors for the design tokens. This module only NAMES the CSS custom\n * properties declared in `tokens.css` — it never duplicates their values, so\n * there is a single source of truth. Components reference tokens through here\n * (e.g. `KIND_TOKEN[node.kind]`) instead of hardcoding hex values.\n */\n\nimport type { NodeKind } from '@hlang-tech/editor-core';\n\n/** The full set of token custom-property names (without the leading `--`). */\nexport const TOKEN_NAMES = [\n 'hl-void',\n 'hl-void-2',\n 'hl-surface',\n 'hl-surface-2',\n 'hl-line',\n 'hl-line-strong',\n 'hl-silver',\n 'hl-silver-hi',\n 'hl-silver-lo',\n 'hl-glass',\n 'hl-glass-2',\n 'hl-glass-blur',\n 'hl-glass-sat',\n 'hl-glass-edge',\n 'hl-glass-edge-hi',\n 'hl-spark',\n 'hl-r',\n 'hl-t',\n 'hl-w',\n 'hl-error',\n 'hl-warning',\n 'hl-ink',\n 'hl-ink-2',\n 'hl-ink-3',\n 'hl-font-ui',\n 'hl-font-mono',\n 'hl-r-sm',\n 'hl-r-md',\n 'hl-r-lg',\n 'hl-r-pill',\n 'hl-shadow-node',\n 'hl-shadow-glass',\n 'hl-glow-silver',\n 'hl-ease',\n 'hl-activity',\n 'hl-cost',\n] as const;\n\n/** A token name (without `--`), e.g. `'hl-silver'`. */\nexport type TokenName = (typeof TOKEN_NAMES)[number];\n\n/** `var(--<name>)` reference string for a token. */\nexport function tokenVar(name: TokenName): string {\n return `var(--${name})`;\n}\n\n/** Maps a node kind to its color-temperature token reference. */\nexport const KIND_TOKEN: Record<NodeKind, string> = {\n R: 'var(--hl-r)',\n T: 'var(--hl-t)',\n W: 'var(--hl-w)',\n};\n\n/** Human-readable role label per node kind (used in node headers). */\nexport const KIND_ROLE: Record<NodeKind, string> = {\n R: 'source',\n T: 'transform',\n W: 'sink',\n};\n","/**\n * Theming: a host overrides any subset of tokens by producing a CSS-variable\n * style object with `createTheme(...)` and applying it (via\n * `EditorUIThemeProvider` or directly on a wrapper element). Zero-runtime and\n * SSR-safe — it is just inline custom properties.\n */\n\nimport type { CSSProperties } from 'react';\nimport type { TokenName } from './tokens';\n\n/**\n * A partial override map from token name to CSS value. Values may be\n * `undefined` (treated as \"not overridden\") so callers can pass conditional\n * overrides without pre-filtering.\n */\nexport type ThemeOverride = Partial<Record<TokenName, string | undefined>>;\n\n/**\n * Build a style object that overrides the given tokens as inline custom\n * properties. Apply it to a wrapping element to re-theme everything beneath.\n *\n * ```ts\n * <div style={createTheme({ 'hl-silver': '#d8dce4' })}> … </div>\n * ```\n */\nexport function createTheme(overrides: ThemeOverride): CSSProperties {\n // CSS custom properties are typed via an index signature on CSSProperties,\n // so a plain string map of `--*` keys is structurally a CSSProperties.\n const style: CSSProperties & Record<`--${string}`, string> = {};\n for (const [name, value] of Object.entries(overrides)) {\n if (value !== undefined) {\n style[`--${name}`] = value;\n }\n }\n return style;\n}\n","/**\n * `EditorUIThemeProvider` — applies a token override to its subtree by wrapping\n * children in an element carrying the inline custom properties from\n * `createTheme`. Import `@hlang-tech/editor-ui/tokens.css` once at the app root\n * for the base tokens; use this provider only to override.\n */\n\nimport type { ReactElement, ReactNode, CSSProperties } from 'react';\nimport { createTheme } from './theme';\nimport type { ThemeOverride } from './theme';\n\nexport interface EditorUIThemeProviderProps {\n readonly theme?: ThemeOverride;\n readonly className?: string;\n readonly style?: CSSProperties;\n readonly children: ReactNode;\n}\n\nexport function EditorUIThemeProvider({\n theme,\n className,\n style,\n children,\n}: EditorUIThemeProviderProps): ReactElement {\n const themeStyle = theme ? createTheme(theme) : undefined;\n return (\n <div className={className} style={{ ...themeStyle, ...style }}>\n {children}\n </div>\n );\n}\n","/**\n * The thin, kind-tinted bar across the top of a node — the node's kind\n * expressed with restraint (no large color fills). Reads `--hl-kind` set by the\n * node's kind class.\n */\n\nimport type { ReactElement } from 'react';\n\nexport function SignalBar(): ReactElement {\n return <div className=\"hl-signal\" aria-hidden=\"true\" />;\n}\n","/**\n * A single port row: a React Flow `Handle` anchored to this row (so it centers\n * on its own label, never drifting) plus the port's mono label. Renders the\n * live/value distinction (filled vs hollow handle) and the error hue.\n */\n\nimport type { ReactElement } from 'react';\nimport { Handle, Position } from '@xyflow/react';\nimport type { PortDescriptor } from '@hlang-tech/editor-core';\n\nexport interface PortRowProps {\n readonly port: PortDescriptor;\n}\n\nexport function PortRow({ port }: PortRowProps): ReactElement {\n const isInput = port.direction === 'I';\n const side = isInput ? 'target' : 'source';\n // Ports are RxJS streams by default; a `value` port only emits on change.\n const isLive = port.stream !== 'value';\n const rowClass = `hl-port${port.isError ? ' is-error' : ''}`;\n const handleClass = `hl-handle${isLive ? ' is-live' : ''}`;\n\n return (\n <li className={rowClass}>\n <Handle\n type={side}\n position={isInput ? Position.Left : Position.Right}\n id={port.id}\n className={handleClass}\n isConnectable\n />\n <span className=\"hl-port-label\">{port.isError ? 'error' : port.name}</span>\n </li>\n );\n}\n","/**\n * The node-body extension point. In M-UI-1 this renders nothing (generic nodes\n * stay clean R/T/W cards). M-UI-5 wires it to the NodeBodyRegistry so a host\n * application can render custom content — image/video previews, inline\n * widgets — per node `code`/`kind` without editor-ui knowing anything about it.\n */\n\nimport type { ReactElement, ReactNode } from 'react';\nimport type { EditorNode } from '@hlang-tech/editor-core';\n\nexport interface NodeBodySlotProps {\n readonly node: EditorNode;\n /** Custom body content, resolved by the host/registry. Empty renders nothing. */\n readonly children?: ReactNode;\n}\n\nexport function NodeBodySlot({ children }: NodeBodySlotProps): ReactElement | null {\n if (children === undefined || children === null || children === false) {\n return null;\n }\n return <div className=\"hl-body\">{children}</div>;\n}\n","/**\n * React glue for the LiveSignalStore. A single store instance is provided via\n * context; node/edge components subscribe to their own id through\n * `useNodeLiveState` / `useEdgeFlowing` (each returns a primitive, so only the\n * components whose state actually flips re-render — no global DOM scanning).\n */\n\nimport { createContext, useContext, useMemo, useSyncExternalStore } from 'react';\nimport type { ReactElement, ReactNode } from 'react';\nimport { LiveSignalStore } from './live-signal-store';\nimport type { NodeLiveState } from './live-signal-store';\n\nconst LiveSignalContext = createContext<LiveSignalStore | null>(null);\n\nexport interface LiveSignalProviderProps {\n /** Optional external store; a fresh one is created if omitted. */\n readonly store?: LiveSignalStore;\n readonly children: ReactNode;\n}\n\nexport function LiveSignalProvider({ store, children }: LiveSignalProviderProps): ReactElement {\n const value = useMemo(() => store ?? new LiveSignalStore(), [store]);\n return <LiveSignalContext.Provider value={value}>{children}</LiveSignalContext.Provider>;\n}\n\n/** Access the live store, or `null` when there is no provider (visuals off). */\nexport function useLiveSignalStore(): LiveSignalStore | null {\n return useContext(LiveSignalContext);\n}\n\n/** Subscribe to a single node's live state. Idle when no store is present. */\nexport function useNodeLiveState(nodeId: string): NodeLiveState {\n const store = useContext(LiveSignalContext);\n return useSyncExternalStore(\n onChange => (store === null ? () => undefined : store.subscribeNode(nodeId, onChange)),\n () => (store === null ? 'idle' : store.getNodeState(nodeId)),\n () => 'idle',\n );\n}\n\n/** How many messages a node has handled or sent this run; it changes each time the node runs. */\nexport function useNodePulse(nodeId: string): number {\n const store = useContext(LiveSignalContext);\n return useSyncExternalStore(\n onChange => (store === null ? () => undefined : store.subscribeNode(nodeId, onChange)),\n () => (store === null ? 0 : store.getNodePulse(nodeId)),\n () => 0,\n );\n}\n\n/** How many messages an edge has carried this run. */\nexport function useEdgePulse(edgeId: string): number {\n const store = useContext(LiveSignalContext);\n return useSyncExternalStore(\n onChange => (store === null ? () => undefined : store.subscribeEdge(edgeId, onChange)),\n () => (store === null ? 0 : store.getEdgePulse(edgeId)),\n () => 0,\n );\n}\n\n/** Subscribe to a single edge's flowing state. False when no store is present. */\nexport function useEdgeFlowing(edgeId: string): boolean {\n const store = useContext(LiveSignalContext);\n return useSyncExternalStore(\n onChange => (store === null ? () => undefined : store.subscribeEdge(edgeId, onChange)),\n () => (store === null ? false : store.isEdgeFlowing(edgeId)),\n () => false,\n );\n}\n","/**\n * `LiveSignalStore` — the source of truth for a running graph's live visual\n * state. It ingests activity/error signals, decays activity over a short\n * window, and lets node/edge components subscribe to THEIR OWN id only.\n *\n * Design rationale (industrial-grade, no tricks):\n * - No global DOM scanning and no dependency on React Flow's private CSS\n * classes. Components read their state by id through `useSyncExternalStore`,\n * so only the components whose state actually flips re-render.\n * - Edge \"flowing\" state is computed from an injected edge index, not by\n * reaching into another layer's model at paint time.\n * - A single rAF loop advances decay and notifies only changed ids, once per\n * frame however many signals arrived in it.\n */\n\n/** Live state of a node during execution. */\nexport type NodeLiveState = 'idle' | 'active' | 'error' | 'finished';\n\n/** How long a node/edge stays \"active\" after its last emission (ms). */\nconst ACTIVE_WINDOW_MS = 700;\n\ntype Listener = () => void;\n\n/** Composite key for a specific output port on a node. */\nfunction portKey(nodeId: string, portId: string): string {\n return `${nodeId}@${portId}`;\n}\n\n/**\n * Minimal edge shape the store needs to map a signal to edges. With its\n * target, a delivery lights exactly the edge that carried it.\n */\nexport interface EdgeIndexEntry {\n readonly id: string;\n readonly sourceNodeId: string;\n readonly sourcePortId: string;\n readonly targetNodeId?: string;\n readonly targetPortId?: string;\n readonly isError: boolean;\n}\n\n/** A message delivered on one connection: its source ran and sent it, its target ran to handle it. */\nexport interface DeliverySignal {\n readonly sourceNodeId: string;\n readonly sourcePortId: string;\n readonly targetNodeId: string;\n readonly targetPortId: string;\n}\n\nfunction connectionKey(sourceNodeId: string, sourcePortId: string, targetNodeId: string, targetPortId: string): string {\n return `${portKey(sourceNodeId, sourcePortId)}->${portKey(targetNodeId, targetPortId)}`;\n}\n\n/** Injected clock + scheduler so the store is deterministic and testable. */\nexport interface LiveSignalStoreDeps {\n now(): number;\n schedule(cb: () => void): number;\n cancel(handle: number): void;\n}\n\n/** The browser's clock and frame scheduler, with fallbacks outside a browser. */\nexport const defaultLiveDeps: LiveSignalStoreDeps = {\n now: () => (typeof performance !== 'undefined' ? performance.now() : Date.now()),\n schedule: cb =>\n typeof requestAnimationFrame !== 'undefined'\n ? requestAnimationFrame(cb)\n : // `window.setTimeout` returns a numeric handle (the DOM overload),\n // unlike the Node overload's `Timeout` object — this store deals in\n // numeric handles because it runs in the browser.\n window.setTimeout(cb, 16),\n cancel: h =>\n typeof cancelAnimationFrame !== 'undefined'\n ? cancelAnimationFrame(h)\n : window.clearTimeout(h),\n};\n\nexport class LiveSignalStore {\n private readonly deps: LiveSignalStoreDeps;\n /** nodeId -> last-active timestamp. */\n private readonly nodeActiveAt = new Map<string, number>();\n /** nodeId set that errored during this run. */\n private readonly erroredNodes = new Set<string>();\n /** nodeId set that finished during this run (RFC 0001). */\n private readonly finishedNodes = new Set<string>();\n /** edgeId -> last-flowing timestamp. */\n private readonly edgeFlowAt = new Map<string, number>();\n /** Per-id listeners. */\n private readonly nodeListeners = new Map<string, Set<Listener>>();\n private readonly edgeListeners = new Map<string, Set<Listener>>();\n /** Snapshot of last-emitted state per id, so we only notify on real change. */\n private readonly lastNodeState = new Map<string, NodeLiveState>();\n private readonly lastEdgeFlowing = new Map<string, boolean>();\n /** Edges sourced by a given (nodeId@portId), for pulse -> edge mapping. */\n private edgesBySourcePort = new Map<string, EdgeIndexEntry[]>();\n /** Edges by the connection they carry (source port -> target port). */\n private edgesByConnection = new Map<string, EdgeIndexEntry[]>();\n /** How many messages each node has handled or sent, and each edge carried, this run. */\n private readonly nodePulse = new Map<string, number>();\n private readonly edgePulse = new Map<string, number>();\n /** The pulse counts last notified, so a new message notifies even while the state stays active. */\n private readonly lastNodePulse = new Map<string, number>();\n private readonly lastEdgePulse = new Map<string, number>();\n private rafHandle: number | null = null;\n private running = false;\n\n constructor(deps: LiveSignalStoreDeps = defaultLiveDeps) {\n this.deps = deps;\n }\n\n /** Provide the current edge index (call whenever edges change). */\n setEdgeIndex(edges: readonly EdgeIndexEntry[]): void {\n const next = new Map<string, EdgeIndexEntry[]>();\n for (const edge of edges) {\n const key = portKey(edge.sourceNodeId, edge.sourcePortId);\n const list = next.get(key);\n if (list === undefined) {\n next.set(key, [edge]);\n } else {\n list.push(edge);\n }\n }\n this.edgesBySourcePort = next;\n const byConnection = new Map<string, EdgeIndexEntry[]>();\n for (const edge of edges) {\n if (edge.targetNodeId !== undefined && edge.targetPortId !== undefined) {\n const key = connectionKey(edge.sourceNodeId, edge.sourcePortId, edge.targetNodeId, edge.targetPortId);\n byConnection.set(key, [...(byConnection.get(key) ?? []), edge]);\n }\n }\n this.edgesByConnection = byConnection;\n }\n\n /**\n * Record a message delivered on a connection, when it happens: its source\n * and its target each pulse once (each ran), and so does the edge that\n * carried it, and only that edge. Subscribers are notified on the next\n * frame, once however many messages arrived in it.\n */\n markDelivery(signal: DeliverySignal): void {\n const t = this.deps.now();\n for (const nodeId of [signal.sourceNodeId, signal.targetNodeId]) {\n this.nodeActiveAt.set(nodeId, t);\n this.nodePulse.set(nodeId, this.getNodePulse(nodeId) + 1);\n }\n const key = connectionKey(signal.sourceNodeId, signal.sourcePortId, signal.targetNodeId, signal.targetPortId);\n for (const edge of this.edgesByConnection.get(key) ?? []) {\n this.edgeFlowAt.set(edge.id, t);\n this.edgePulse.set(edge.id, this.getEdgePulse(edge.id) + 1);\n }\n this.ensureLoop();\n }\n\n /** How many messages a node has handled or sent this run; it changes each time the node runs. */\n getNodePulse(nodeId: string): number {\n return this.nodePulse.get(nodeId) ?? 0;\n }\n\n /** How many messages an edge has carried this run. */\n getEdgePulse(edgeId: string): number {\n return this.edgePulse.get(edgeId) ?? 0;\n }\n\n /** Record a node emitting on an output port (drives node + edge activity). */\n markActivity(nodeId: string, portId: string): void {\n const t = this.deps.now();\n this.nodeActiveAt.set(nodeId, t);\n const edges = this.edgesBySourcePort.get(portKey(nodeId, portId));\n if (edges !== undefined) {\n for (const edge of edges) {\n this.edgeFlowAt.set(edge.id, t);\n }\n }\n this.ensureLoop();\n }\n\n /** Record a node finishing (RFC 0001): shown once its last flash has faded. */\n markFinished(nodeId: string): void {\n this.finishedNodes.add(nodeId);\n this.ensureLoop();\n }\n\n /** Record a node erroring (sticky for the run). */\n markError(nodeId: string): void {\n this.erroredNodes.add(nodeId);\n this.ensureLoop();\n }\n\n /** Clear all live state (on stop/teardown) and notify everyone. */\n reset(): void {\n this.nodeActiveAt.clear();\n this.erroredNodes.clear();\n this.finishedNodes.clear();\n this.edgeFlowAt.clear();\n this.nodePulse.clear();\n this.edgePulse.clear();\n this.stopLoop();\n this.flushNotifications();\n }\n\n /** Subscribe to a single node's live state. */\n subscribeNode(nodeId: string, listener: Listener): () => void {\n return this.subscribe(this.nodeListeners, nodeId, listener);\n }\n\n /** Subscribe to a single edge's flowing state. */\n subscribeEdge(edgeId: string, listener: Listener): () => void {\n return this.subscribe(this.edgeListeners, edgeId, listener);\n }\n\n /** Current live state of a node. */\n getNodeState(nodeId: string): NodeLiveState {\n if (this.erroredNodes.has(nodeId)) {\n return 'error';\n }\n const at = this.nodeActiveAt.get(nodeId);\n if (at !== undefined && this.deps.now() - at <= ACTIVE_WINDOW_MS) {\n return 'active';\n }\n return this.finishedNodes.has(nodeId) ? 'finished' : 'idle';\n }\n\n /** Whether an edge is currently flowing. */\n isEdgeFlowing(edgeId: string): boolean {\n const at = this.edgeFlowAt.get(edgeId);\n return at !== undefined && this.deps.now() - at <= ACTIVE_WINDOW_MS;\n }\n\n private subscribe(\n registry: Map<string, Set<Listener>>,\n id: string,\n listener: Listener,\n ): () => void {\n const set = registry.get(id) ?? new Set<Listener>();\n set.add(listener);\n registry.set(id, set);\n return () => {\n set.delete(listener);\n if (set.size === 0) {\n registry.delete(id);\n }\n };\n }\n\n /**\n * Arms the frame loop if it is not running. Signals only record state; the\n * next frame notifies, so a burst of signals costs one pass over the\n * subscribers per frame, not one per signal, and every change shows within a\n * frame.\n */\n private ensureLoop(): void {\n if (this.running) {\n return;\n }\n this.running = true;\n const step = (): void => {\n const stillLive = this.flushNotifications();\n if (stillLive) {\n this.rafHandle = this.deps.schedule(step);\n } else {\n this.running = false;\n this.rafHandle = null;\n }\n };\n this.rafHandle = this.deps.schedule(step);\n }\n\n private stopLoop(): void {\n if (this.rafHandle !== null) {\n this.deps.cancel(this.rafHandle);\n this.rafHandle = null;\n }\n this.running = false;\n }\n\n /**\n * Recompute every subscribed id's state, notify only those that changed, and\n * report whether anything is still within its active window (so the loop can\n * stop when the graph goes quiet).\n */\n private flushNotifications(): boolean {\n let anyLive = false;\n\n for (const [nodeId, listeners] of this.nodeListeners) {\n const state = this.getNodeState(nodeId);\n if (state !== 'idle') {\n anyLive = anyLive || state === 'active';\n }\n const pulse = this.getNodePulse(nodeId);\n if (this.lastNodeState.get(nodeId) !== state || this.lastNodePulse.get(nodeId) !== pulse) {\n this.lastNodeState.set(nodeId, state);\n this.lastNodePulse.set(nodeId, pulse);\n for (const listener of listeners) {\n listener();\n }\n }\n }\n\n for (const [edgeId, listeners] of this.edgeListeners) {\n const flowing = this.isEdgeFlowing(edgeId);\n anyLive = anyLive || flowing;\n const pulse = this.getEdgePulse(edgeId);\n if (this.lastEdgeFlowing.get(edgeId) !== flowing || this.lastEdgePulse.get(edgeId) !== pulse) {\n this.lastEdgeFlowing.set(edgeId, flowing);\n this.lastEdgePulse.set(edgeId, pulse);\n for (const listener of listeners) {\n listener();\n }\n }\n }\n\n return anyLive;\n }\n}\n","/**\n * `LivePulse` — one flash on a node each time it runs during a live run. The\n * pulse count from the live store keys the element, so every new count\n * mounts a fresh element and its CSS animation plays once: the node flashes\n * exactly as often as it actually ran (per frame at most). Place it as the\n * first child of a node's rounded, positioned root.\n */\n\nimport type { ReactElement } from 'react';\nimport { useNodePulse } from './LiveSignalContext';\n\nexport function LivePulse({ nodeId }: { readonly nodeId: string }): ReactElement | null {\n const pulse = useNodePulse(nodeId);\n return pulse === 0 ? null : <span key={pulse} className=\"hl-live-pulse\" aria-hidden=\"true\" />;\n}\n","/**\n * `AssetNode` — a source node dressed as a real image asset.\n *\n * Architecturally this is just an R node: to the runtime it has output ports and\n * emits its image (its `params.imageUrl`). editor-ui is free to DRESS it as a\n * framed photograph — a frosted-glass card whose hero is the image itself — with\n * no change to the input/output contract. This is the layering: the bottom is an\n * input→output DAG; this layer decides what the node looks like.\n *\n * Ports are reused verbatim (PortRow → React Flow Handle), so wiring behaves\n * exactly like any other node; the output handle rides the image's right edge.\n */\n\nimport type { ReactElement } from 'react';\nimport type { EditorNode } from '@hlang-tech/editor-core';\nimport { PortRow } from './PortRow';\nimport { useNodeLiveState } from '../live/LiveSignalContext';\nimport { LivePulse } from '../live/LivePulse';\nimport './AssetNode.css';\n\nexport interface AssetNodeChromeProps {\n readonly node: EditorNode;\n readonly selected?: boolean;\n}\n\n/** Read a string param, or undefined. */\nfunction stringParam(node: EditorNode, key: string): string | undefined {\n const v = node.params[key];\n return typeof v === 'string' ? v : undefined;\n}\n\nexport function AssetNodeChrome({ node, selected }: AssetNodeChromeProps): ReactElement {\n const imageUrl = stringParam(node, 'imageUrl') ?? '';\n const caption = stringParam(node, 'caption') ?? node.name;\n const role = stringParam(node, 'role'); // optional semantic role (e.g. Character)\n const live = useNodeLiveState(node.id);\n // An asset is a clean source: expose only its data output(s). The `@node/error`\n // port still exists in the model, but drawing it on the photo would be visual\n // clutter (nover hides plumbing) — error wiring is an advanced affordance.\n const outputs = node.ports.filter(p => p.direction === 'O' && !p.isError);\n\n const className = [\n 'hl-asset',\n selected ? 'is-selected' : '',\n live === 'active' ? 'is-active' : '',\n live === 'error' ? 'is-live-error' : '',\n live === 'finished' ? 'is-finished' : '',\n ]\n .filter(Boolean)\n .join(' ');\n\n return (\n <div className={className} data-kind={node.kind}>\n <LivePulse nodeId={node.id} />\n <div className=\"hl-asset-frame\">\n {imageUrl.length > 0 ? (\n <img className=\"hl-asset-img\" src={imageUrl} alt={caption} draggable={false} />\n ) : (\n <div className=\"hl-asset-placeholder\" aria-hidden />\n )}\n <div className=\"hl-asset-scrim\" />\n <div className=\"hl-asset-caption\">\n <span className=\"hl-asset-name\">{caption}</span>\n {role !== undefined && <span className=\"hl-asset-role hl-mono\">{role}</span>}\n </div>\n </div>\n {/* Output ports ride the right edge; hidden until hover/select via CSS. */}\n <ul className=\"hl-asset-ports\">\n {outputs.map(port => (\n <PortRow key={port.id} port={port} />\n ))}\n </ul>\n </div>\n );\n}\n","/**\n * `PillNode` — the default dressing for a non-asset node: a nover-style capsule.\n *\n * To the runtime this is still an ordinary R/T/W node with ports; editor-ui just\n * dresses it as a rounded pill — a kind-tinted domain dot, the name, and a\n * status dot — with the ports HIDDEN at rest and revealed on hover/selection.\n * The picture, not the plumbing. The verbose port-board (`NodeChrome`) remains\n * available as an \"expanded\" view for later.\n *\n * Ports reuse `PortRow` (so wiring is identical); the pill styles the handles\n * to ride its left/right edges as small silver dots.\n */\n\nimport { useCallback, useEffect, useRef, useState } from 'react';\nimport type { ReactElement, KeyboardEvent } from 'react';\nimport type { EditorNode } from '@hlang-tech/editor-core';\nimport { PortRow } from './PortRow';\nimport { NodeIcon } from '../icons/node-icons';\nimport { DiagnosticBadge } from '../panels/DiagnosticBadge';\nimport { useNodeLiveState } from '../live/LiveSignalContext';\nimport { LivePulse } from '../live/LivePulse';\nimport { useNodeInteraction } from './NodeInteractionContext';\nimport './PillNode.css';\n\n/** Max gap (ms) between two clicks on the node name to count as a double-click. */\nconst DOUBLE_CLICK_MS = 320;\n\nexport interface PillNodeChromeProps {\n readonly node: EditorNode;\n readonly selected?: boolean;\n}\n\nexport function PillNodeChrome({ node, selected }: PillNodeChromeProps): ReactElement {\n const live = useNodeLiveState(node.id);\n const interaction = useNodeInteraction();\n const diagnostic = interaction.diagnosticFor(node.id);\n\n // Inline rename: double-click the name to edit; Enter/blur commits, Esc cancels.\n const [editing, setEditing] = useState(false);\n const [draft, setDraft] = useState(node.name);\n const inputRef = useRef<HTMLInputElement>(null);\n useEffect(() => {\n if (editing) {\n setDraft(node.name);\n // Focus + select on next tick so the input exists.\n requestAnimationFrame(() => inputRef.current?.select());\n }\n }, [editing, node.name]);\n const commit = useCallback((): void => {\n setEditing(false);\n interaction.rename(node.id, draft);\n }, [interaction, node.id, draft]);\n const onKeyDown = useCallback(\n (e: KeyboardEvent<HTMLInputElement>): void => {\n if (e.key === 'Enter') {\n e.preventDefault();\n commit();\n } else if (e.key === 'Escape') {\n e.preventDefault();\n setEditing(false);\n }\n },\n [commit],\n );\n\n // React Flow's node-drag pointer handler swallows the browser's native\n // dblclick on a node child, so detect a double-click manually from two rapid\n // clicks (which RF does not block). 320ms window.\n const lastClick = useRef(0);\n const onNameClick = useCallback((): void => {\n const now = performance.now();\n if (now - lastClick.current < DOUBLE_CLICK_MS) {\n setEditing(true);\n lastClick.current = 0;\n } else {\n lastClick.current = now;\n }\n }, []);\n\n // Data ports only; the error port exists in the model but isn't drawn on the\n // resting pill (advanced affordance — keeps the capsule clean).\n const inputs = node.ports.filter(p => p.direction === 'I' && !p.isError);\n const outputs = node.ports.filter(p => p.direction === 'O' && !p.isError);\n\n const className = [\n 'hl-pill',\n `hl-pill-${node.kind.toLowerCase()}`,\n selected ? 'is-selected' : '',\n live === 'active' ? 'is-active' : '',\n live === 'error' ? 'is-live-error' : '',\n live === 'finished' ? 'is-finished' : '',\n diagnostic?.severity === 'error' ? 'has-diag-error' : '',\n diagnostic?.severity === 'warning' ? 'has-diag-warning' : '',\n ]\n .filter(Boolean)\n .join(' ');\n\n return (\n <div className={className} data-kind={node.kind}>\n <LivePulse nodeId={node.id} />\n {/* Domain bead: a kind-tinted disc carrying the node's per-type icon. */}\n <span className=\"hl-pill-dot\" aria-hidden>\n <NodeIcon code={node.code} kind={node.kind} size={13} />\n </span>\n {editing ? (\n <input\n ref={inputRef}\n className=\"hl-pill-rename nodrag\"\n value={draft}\n onChange={e => setDraft(e.target.value)}\n onKeyDown={onKeyDown}\n onBlur={commit}\n spellCheck={false}\n aria-label=\"Rename node\"\n />\n ) : (\n <span\n className=\"hl-pill-name\"\n onClick={() => {\n // The name covers most of the capsule, so it behaves like the node:\n // the click also reaches React Flow (which selects the node) and a\n // press here drags the node. React Flow swallows the native dblclick\n // on a node child, so a double-click is detected from two rapid\n // clicks; it is the only rename path.\n onNameClick();\n }}\n title=\"Double-click to rename\"\n >\n {node.name}\n </span>\n )}\n {/* Edit-time diagnostic badge (independent of the runtime error channel). */}\n {diagnostic !== undefined && (\n <DiagnosticBadge diagnostic={diagnostic} variant=\"hl-pill-diag\" size={12} />\n )}\n {/* Status dot — lit when the node is active during a run. */}\n <span className=\"hl-pill-status\" aria-hidden />\n\n {/* Ports ride the capsule edges; hidden until hover/select. */}\n <ul className=\"hl-pill-ports hl-in\">\n {inputs.map(port => (\n <PortRow key={port.id} port={port} />\n ))}\n </ul>\n <ul className=\"hl-pill-ports hl-out\">\n {outputs.map(port => (\n <PortRow key={port.id} port={port} />\n ))}\n </ul>\n </div>\n );\n}\n","/**\n * Per-type node icons. A small registry mapping a node `code` to a crisp\n * line-glyph (1.5px stroke, currentColor), with a kind fallback (R/T/W). Used\n * by the outline tree and the node chrome so every node reads by its ROLE, not\n * a generic letter — the difference between a tool and a spreadsheet.\n *\n * Icons are inline SVG (not emoji) for a premium, monochrome, scalable look;\n * they inherit `color` so callers tint them by kind or silver.\n */\n\nimport type { ReactElement } from 'react';\nimport type { NodeKind } from '@hlang-tech/editor-core';\n\ninterface IconProps {\n readonly size?: number;\n}\n\n/** Common svg wrapper: currentColor stroke, no fill, round joins. */\nfunction svg(size: number, children: ReactElement | readonly ReactElement[]): ReactElement {\n return (\n <svg\n width={size}\n height={size}\n viewBox=\"0 0 24 24\"\n fill=\"none\"\n stroke=\"currentColor\"\n strokeWidth={1.6}\n strokeLinecap=\"round\"\n strokeLinejoin=\"round\"\n aria-hidden\n >\n {children}\n </svg>\n );\n}\n\n/** Icon builders keyed by node code. */\nconst BY_CODE: Record<string, (s: number) => ReactElement> = {\n 'image-source': s => svg(s, [\n <rect key=\"r\" x=\"3\" y=\"4\" width=\"18\" height=\"16\" rx=\"2.5\" />,\n <circle key=\"c\" cx=\"8.5\" cy=\"9\" r=\"1.6\" />,\n <path key=\"p\" d=\"M4 17l5-5 4 4 3-2 4 4\" />,\n ]),\n 'text-source': s => svg(s, [<path key=\"p\" d=\"M5 6h14M12 6v12M9 18h6\" />]),\n 'interval-source': s => svg(s, [\n <circle key=\"c\" cx=\"12\" cy=\"12\" r=\"8\" />,\n <path key=\"h\" d=\"M12 8v4l3 2\" />,\n ]),\n 'range-source': s => svg(s, [\n <path key=\"l\" d=\"M4 12h16\" />,\n <circle key=\"a\" cx=\"6\" cy=\"12\" r=\"2\" />,\n <circle key=\"b\" cx=\"18\" cy=\"12\" r=\"2\" />,\n ]),\n 'constant-source': s => svg(s, [<path key=\"p\" d=\"M6 12h12M9 8l-3 4 3 4M15 8l3 4-3 4\" />]),\n 'map-scale': s => svg(s, [\n <path key=\"a\" d=\"M4 20V8l8-4\" />,\n <path key=\"b\" d=\"M4 8l8 4 8-4M12 12v8\" />,\n ]),\n uppercase: s => svg(s, [<path key=\"p\" d=\"M5 18L9 6l4 12M6.5 14h5M15 10v8M15 10c3 0 3 4 0 4\" />]),\n 'filter-threshold': s => svg(s, [<path key=\"p\" d=\"M4 5h16l-6 7v6l-4-2v-4z\" />]),\n 'scan-sum': s => svg(s, [<path key=\"p\" d=\"M17 6H7l6 6-6 6h10\" />]),\n delay: s => svg(s, [\n <circle key=\"c\" cx=\"12\" cy=\"13\" r=\"7\" />,\n <path key=\"h\" d=\"M12 10v3l2 2M9 3h6\" />,\n ]),\n merge: s => svg(s, [<path key=\"p\" d=\"M6 5v4c0 3 3 3 6 3s6 0 6-3V5M12 12v7\" />]),\n 'console-sink': s => svg(s, [\n <rect key=\"r\" x=\"4\" y=\"5\" width=\"16\" height=\"12\" rx=\"2\" />,\n <path key=\"p\" d=\"M8 10l2.5 2L8 14M13 14h3\" />,\n ]),\n 'collect-sink': s => svg(s, [\n <path key=\"p\" d=\"M4 7h16M4 12h16M4 17h10\" />,\n ]),\n};\n\n/** Fallback glyph per kind when a code has no specific icon. */\nconst BY_KIND: Record<NodeKind, (s: number) => ReactElement> = {\n R: s => svg(s, [<path key=\"p\" d=\"M8 5l10 7-10 7z\" />]), // source ▷ (play)\n T: s => svg(s, [<path key=\"p\" d=\"M4 8h6l4 8h6M14 8h6M4 16h6\" />]), // transform\n W: s => svg(s, [\n <path key=\"p\" d=\"M5 4h11l3 3v13H5z\" />,\n <path key=\"q\" d=\"M9 4v5h6\" />,\n ]), // sink (save)\n};\n\nexport interface NodeIconProps extends IconProps {\n readonly code: string;\n readonly kind: NodeKind;\n}\n\n/** Render the icon for a node, by code (then kind fallback). */\nexport function NodeIcon({ code, kind, size = 15 }: NodeIconProps): ReactElement {\n const build = BY_CODE[code] ?? BY_KIND[kind];\n return build(size);\n}\n\n// ---------------------------------------------------------------------------\n// Control glyphs — crisp line icons for the outline's visible/lock affordances.\n// Kept in the same registry so every glyph shares one stroke language. Unlike\n// emoji, these stay legible at small sizes and against dark/dim rows.\n// ---------------------------------------------------------------------------\n\n/** Open eye — layer visible. */\nexport function EyeIcon({ size = 14 }: IconProps): ReactElement {\n return svg(size, [\n <path key=\"p\" d=\"M2 12s3.5-6.5 10-6.5S22 12 22 12s-3.5 6.5-10 6.5S2 12 2 12z\" />,\n <circle key=\"c\" cx=\"12\" cy=\"12\" r=\"2.6\" />,\n ]);\n}\n\n/** Eye with a slash — layer hidden. Always reads clearly, even on a dim row. */\nexport function EyeOffIcon({ size = 14 }: IconProps): ReactElement {\n return svg(size, [\n <path key=\"p\" d=\"M2 12s3.5-6.5 10-6.5c1.7 0 3.2.45 4.5 1.1M22 12s-3.5 6.5-10 6.5c-1.7 0-3.2-.45-4.5-1.1\" />,\n <path key=\"e\" d=\"M9.9 9.9a2.6 2.6 0 003.7 3.7\" />,\n <path key=\"s\" d=\"M3 3l18 18\" />,\n ]);\n}\n\n/** Open padlock — layer unlocked (editable). */\nexport function UnlockIcon({ size = 14 }: IconProps): ReactElement {\n return svg(size, [\n <rect key=\"r\" x=\"5\" y=\"11\" width=\"14\" height=\"9\" rx=\"2\" />,\n <path key=\"s\" d=\"M8 11V7a4 4 0 017.9-1\" />,\n ]);\n}\n\n/** Closed padlock — layer locked (pinned, not draggable). */\nexport function LockIcon({ size = 14 }: IconProps): ReactElement {\n return svg(size, [\n <rect key=\"r\" x=\"5\" y=\"11\" width=\"14\" height=\"9\" rx=\"2\" />,\n <path key=\"s\" d=\"M8 11V7a4 4 0 018 0v4\" />,\n ]);\n}\n\n/** Warning triangle — a predictive edit-time diagnostic. */\nexport function WarningIcon({ size = 13 }: IconProps): ReactElement {\n return svg(size, [\n <path key=\"t\" d=\"M12 4l9 15H3z\" />,\n <path key=\"b\" d=\"M12 10v4\" />,\n <path key=\"d\" d=\"M12 17v.5\" />,\n ]);\n}\n\n/** Error circle — a hard, runtime-fatal edit-time diagnostic. */\nexport function ErrorIcon({ size = 13 }: IconProps): ReactElement {\n return svg(size, [\n <circle key=\"c\" cx=\"12\" cy=\"12\" r=\"9\" />,\n <path key=\"b\" d=\"M12 7v6\" />,\n <path key=\"d\" d=\"M12 16v.5\" />,\n ]);\n}\n","/**\n * `DiagnosticBadge` — a single edit-time diagnostic marker (error/warning icon +\n * tooltip), shared by the node chrome and the outline so the severity→icon and\n * severity→class mapping lives in ONE place. `variant` only sets the wrapper\n * class prefix so each host can size/position it via its own CSS.\n */\n\nimport type { ReactElement } from 'react';\nimport type { Diagnostic } from '@hlang-tech/editor-core';\nimport { ErrorIcon, WarningIcon } from '../icons/node-icons';\n\nexport interface DiagnosticBadgeProps {\n readonly diagnostic: Diagnostic;\n /** Class-prefix so hosts style it in context (e.g. 'hl-pill-diag'). */\n readonly variant: string;\n readonly size?: number;\n}\n\nexport function DiagnosticBadge({ diagnostic, variant, size = 12 }: DiagnosticBadgeProps): ReactElement {\n return (\n <span\n className={`${variant} hl-diag-${diagnostic.severity}`}\n title={diagnostic.message}\n aria-label={`${diagnostic.severity}: ${diagnostic.message}`}\n >\n {diagnostic.severity === 'error' ? <ErrorIcon size={size} /> : <WarningIcon size={size} />}\n </span>\n );\n}\n","/**\n * `NodeInteractionContext` — optional per-node interaction wiring supplied by the\n * host (diagnostics to badge, rename to commit). Node chrome reads it to render a\n * diagnostic badge and to support inline rename, but degrades gracefully to a\n * plain, read-only node when no provider is present — so editor-ui stays usable\n * without the full editor wiring.\n */\n\nimport { createContext, useContext } from 'react';\nimport type { ReactElement, ReactNode } from 'react';\nimport type { Diagnostic, NodeId } from '@hlang-tech/editor-core';\n\nexport interface NodeInteraction {\n /** The most severe diagnostic on a node, or undefined. */\n diagnosticFor(id: NodeId): Diagnostic | undefined;\n /** Commit a rename (host routes it through the command service). */\n rename(id: NodeId, name: string): void;\n}\n\nconst NoopInteraction: NodeInteraction = {\n diagnosticFor: () => undefined,\n rename: () => undefined,\n};\n\nconst NodeInteractionCtx = createContext<NodeInteraction>(NoopInteraction);\n\nexport interface NodeInteractionProviderProps {\n readonly value: NodeInteraction;\n readonly children: ReactNode;\n}\n\nexport function NodeInteractionProvider({\n value,\n children,\n}: NodeInteractionProviderProps): ReactElement {\n return <NodeInteractionCtx.Provider value={value}>{children}</NodeInteractionCtx.Provider>;\n}\n\nexport function useNodeInteraction(): NodeInteraction {\n return useContext(NodeInteractionCtx);\n}\n","/**\n * The R/T/W node component. A near-monochrome glass card whose personality\n * comes from a thin kind-tinted signal bar and glowing ports; body content is\n * an extension point (empty for generic nodes). Ports are laid out in two\n * columns — inputs (I) left, outputs (O) right — each Handle anchored to its\n * own row so the `@node/error` port never drifts. W nodes render no error port\n * because their descriptor has none.\n */\n\nimport type { ReactElement, ReactNode } from 'react';\nimport type { NodeProps } from '@xyflow/react';\nimport type { HlangRFNode } from '@hlang-tech/editor-react';\nimport type { EditorNode } from '@hlang-tech/editor-core';\nimport { KIND_ROLE } from '../tokens/tokens';\nimport { SignalBar } from './SignalBar';\nimport { PortRow } from './PortRow';\nimport { NodeBodySlot } from './NodeBodySlot';\nimport { useNodeLiveState } from '../live/LiveSignalContext';\nimport { LivePulse } from '../live/LivePulse';\nimport { AssetNodeChrome } from './AssetNode';\nimport { PillNodeChrome } from './PillNode';\nimport './HlangNode.css';\n\n/** Presentational node chrome, decoupled from React Flow for easy testing. */\nexport interface NodeChromeProps {\n readonly node: EditorNode;\n readonly selected?: boolean;\n readonly body?: ReactNode;\n}\n\nexport function NodeChrome({ node, selected, body }: NodeChromeProps): ReactElement {\n const inputs = node.ports.filter(p => p.direction === 'I');\n const outputs = node.ports.filter(p => p.direction === 'O');\n const live = useNodeLiveState(node.id);\n const className = [\n 'hl-node',\n `hl-${node.kind.toLowerCase()}`,\n selected ? 'is-selected' : '',\n live === 'active' ? 'is-active' : '',\n live === 'error' ? 'is-live-error' : '',\n live === 'finished' ? 'is-finished' : '',\n ]\n .filter(Boolean)\n .join(' ');\n\n return (\n <div className={className} data-kind={node.kind}>\n <LivePulse nodeId={node.id} />\n <SignalBar />\n <header className=\"hl-head\">\n <span className=\"hl-kind\">{node.kind}</span>\n <span className=\"hl-name\">{node.name}</span>\n <span className=\"hl-role\">{KIND_ROLE[node.kind]}</span>\n </header>\n <NodeBodySlot node={node}>{body}</NodeBodySlot>\n <div className=\"hl-ports\">\n <ul className=\"hl-col hl-in\">\n {inputs.map(port => (\n <PortRow key={port.id} port={port} />\n ))}\n </ul>\n <ul className=\"hl-col hl-out\">\n {outputs.map(port => (\n <PortRow key={port.id} port={port} />\n ))}\n </ul>\n </div>\n </div>\n );\n}\n\n/**\n * The React Flow node component. Reads everything from `data.editorNode`, then\n * DISPATCHES to the right dressing — all in editor-ui, with no change to the\n * runtime (every case is just a node with ports):\n * - an image asset (params.imageUrl) → {@link AssetNodeChrome} (framed photo)\n * - anything else → {@link PillNodeChrome} (nover capsule)\n * The verbose port-board {@link NodeChrome} stays available as a future\n * \"expanded\" view.\n */\nexport function HlangNode({ data, selected }: NodeProps<HlangRFNode>): ReactElement {\n const node = data.editorNode;\n if (typeof node.params.imageUrl === 'string' && node.params.imageUrl.length > 0) {\n return <AssetNodeChrome node={node} selected={selected} />;\n }\n return <PillNodeChrome node={node} selected={selected} />;\n}\n","/**\n * The signature edge: a connection rendered as a living stream. A base bezier\n * conduit (or, from a node back into itself, a loop routed around the node) plus a silver overlay that marches from output (O) to input (I) —\n * exactly what an hlang RxJS port does; a cold spark lights it while flowing.\n *\n * When the SOURCE node carries a semantic `role` param (e.g. Character,\n * Background), a small glass label pill rides the edge midpoint — naming what\n * the connection carries, the way nover labels its wires. The role is read from\n * the source node's params (no change to editor-react's edge data).\n */\n\nimport type { ReactElement } from 'react';\nimport { BaseEdge, EdgeLabelRenderer, getBezierPath, useInternalNode } from '@xyflow/react';\nimport type { EdgeProps } from '@xyflow/react';\nimport type { HlangRFEdge, HlangRFNode } from '@hlang-tech/editor-react';\nimport { useEdgeFlowing, useEdgePulse } from '../live/LiveSignalContext';\nimport { selfLoopPath } from './self-loop';\nimport { capacityLabel } from './edge-bounds';\nimport './FlowEdge.css';\n\n/** A string `role` param on the source node, if any. */\nfunction roleOf(node: HlangRFNode | undefined): string | undefined {\n const role = node?.data.editorNode.params.role;\n return typeof role === 'string' && role.length > 0 ? role : undefined;\n}\n\nexport function FlowEdge(props: EdgeProps<HlangRFEdge>): ReactElement {\n const { id, source, target, sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, data, selected } =\n props;\n const sourceNode = useInternalNode<HlangRFNode>(source);\n const role = roleOf(sourceNode);\n // An edge from a node back into itself (a Transform's iteration) is routed\n // around that node once it has been measured; any other edge is a curve.\n const width = sourceNode?.measured.width;\n const height = sourceNode?.measured.height;\n const loop =\n source === target && sourceNode !== undefined && width !== undefined && height !== undefined\n ? selfLoopPath({\n source: { x: sourceX, y: sourceY },\n target: { x: targetX, y: targetY },\n node: { ...sourceNode.internals.positionAbsolute, width, height },\n })\n : undefined;\n const [curve] = getBezierPath({\n sourceX,\n sourceY,\n sourcePosition,\n targetX,\n targetY,\n targetPosition,\n });\n const path = loop?.path ?? curve;\n // Bias the semantic label toward the TARGET (0.62 along the run), off the\n // source card into open canvas — the geometric midpoint of a short edge lands\n // on the source node and gets clipped. Labels name what a wire carries; they\n // must stay legible, not tuck behind a photo. A self-loop's label sits under\n // its node.\n const t = 0.62;\n const labelX = loop?.labelX ?? sourceX + (targetX - sourceX) * t;\n const labelY = loop?.labelY ?? sourceY + (targetY - sourceY) * t;\n // A bounded connection carries its capacity in FBP notation, nearer its\n // source than the role label (or, on a loop, at the loop's label point).\n const capacity = capacityLabel(data ?? {});\n const capacityX = loop?.labelX ?? sourceX + (targetX - sourceX) * 0.38;\n const capacityY = loop?.labelY ?? sourceY + (targetY - sourceY) * 0.38;\n\n const isError = data?.isError ?? false;\n const isValue = data?.stream === 'value';\n const flowing = useEdgeFlowing(id);\n // One flash per message this edge carried; a new count mounts a new path, so it plays once.\n const pulse = useEdgePulse(id);\n const className = [\n 'hl-edge',\n isError ? 'is-error' : '',\n isValue ? 'is-value' : 'is-live',\n flowing ? 'is-flowing' : '',\n selected === true ? 'is-selected' : '',\n ]\n .filter(Boolean)\n .join(' ');\n\n return (\n <>\n <g className={className}>\n <BaseEdge id={id} path={path} className=\"hl-edge-base\" />\n <path d={path} className=\"hl-edge-flow\" />\n {pulse > 0 && <path key={pulse} d={path} className=\"hl-edge-pulse\" />}\n </g>\n {capacity !== undefined && (\n <EdgeLabelRenderer>\n <div\n className={`hl-edge-capacity hl-mono${data?.overflow === 'drop-oldest' ? ' is-lossy' : ''}`}\n style={{ transform: `translate(-50%, -50%) translate(${String(capacityX)}px, ${String(capacityY)}px)` }}\n >\n {capacity}\n </div>\n </EdgeLabelRenderer>\n )}\n {role !== undefined && (\n <EdgeLabelRenderer>\n <div\n className=\"hl-edge-label hl-mono\"\n style={{ transform: `translate(-50%, -50%) translate(${String(labelX)}px, ${String(labelY)}px)` }}\n >\n {role}\n </div>\n </EdgeLabelRenderer>\n )}\n </>\n );\n}\n","/**\n * The route of an edge from a node back into the same node: a Transform fed\n * by its own output (iteration). A curve between two handles on opposite\n * sides of one node would cut across it; instead the edge leaves the output\n * to the right, runs under the node and comes up on the left into the input,\n * with rounded corners, as node editors route an edge that goes backwards\n * (n8n's back edges). Pure geometry, so the edge component only draws it.\n */\n\nexport interface Point {\n readonly x: number;\n readonly y: number;\n}\n\nexport interface Rect {\n readonly x: number;\n readonly y: number;\n readonly width: number;\n readonly height: number;\n}\n\nexport interface SelfLoopInput {\n /** The output handle (on the node's right side) and the input handle (on its left). */\n readonly source: Point;\n readonly target: Point;\n /** The node, in the same coordinates. */\n readonly node: Rect;\n /** How far the route keeps from the node. Default `SELF_LOOP_CLEARANCE`. */\n readonly clearance?: number;\n /** The corner radius, reduced where a segment is too short. Default `SELF_LOOP_RADIUS`. */\n readonly radius?: number;\n}\n\nexport interface SelfLoop {\n /** SVG path data. */\n readonly path: string;\n /** Where a label sits: the middle of the run under the node. */\n readonly labelX: number;\n readonly labelY: number;\n}\n\n/** The design system's distance between a self-loop and its node, in flow units. */\nexport const SELF_LOOP_CLEARANCE = 28;\n/** The design system's corner radius for a self-loop, in flow units. */\nexport const SELF_LOOP_RADIUS = 16;\n\nfunction format(value: number): string {\n return String(Math.round(value * 100) / 100);\n}\n\nfunction distance(a: Point, b: Point): number {\n return Math.abs(a.x - b.x) + Math.abs(a.y - b.y);\n}\n\n/** A point `length` from `from` towards `to` (the segments are horizontal or vertical). */\nfunction toward(from: Point, to: Point, length: number): Point {\n const span = distance(from, to);\n const share = span === 0 ? 0 : length / span;\n return { x: from.x + (to.x - from.x) * share, y: from.y + (to.y - from.y) * share };\n}\n\nexport function selfLoopPath(input: SelfLoopInput): SelfLoop {\n const clearance = input.clearance ?? SELF_LOOP_CLEARANCE;\n const radius = input.radius ?? SELF_LOOP_RADIUS;\n const { source, target, node } = input;\n const right = Math.max(source.x, node.x + node.width) + clearance;\n const left = Math.min(target.x, node.x) - clearance;\n const below = node.y + node.height + clearance;\n\n // Start, the four corners of the route, end.\n const points: readonly Point[] = [\n source,\n { x: right, y: source.y },\n { x: right, y: below },\n { x: left, y: below },\n { x: left, y: target.y },\n target,\n ];\n const parts = [`M ${format(source.x)} ${format(source.y)}`];\n for (let i = 1; i < points.length - 1; i += 1) {\n const before = points[i - 1] ?? source;\n const corner = points[i] ?? source;\n const after = points[i + 1] ?? target;\n const r = Math.min(radius, distance(before, corner) / 2, distance(corner, after) / 2);\n if (r <= 0) {\n parts.push(`L ${format(corner.x)} ${format(corner.y)}`);\n continue;\n }\n const enter = toward(corner, before, r);\n const leave = toward(corner, after, r);\n parts.push(\n `L ${format(enter.x)} ${format(enter.y)} Q ${format(corner.x)} ${format(corner.y)} ${format(leave.x)} ${format(leave.y)}`,\n );\n }\n parts.push(`L ${format(target.x)} ${format(target.y)}`);\n return { path: parts.join(' '), labelX: (right + left) / 2, labelY: below };\n}\n","/**\n * A connection's bounds (RFC 0001) as the editor shows and edits them: the\n * fields of the inspector's Connection section, the bounds a change to one of\n * them makes, and the label a bounded edge carries.\n */\n\nimport type { EdgeBounds, ParamValue } from '@hlang-tech/editor-core';\nimport type { ParamField } from '../schema/param-field';\n\n/** The capacity a connection gets when it is first bounded: JavaFBP's production default. */\nexport const DEFAULT_EDGE_CAPACITY = 10;\n\n/** The inspector's fields for a connection with `bounds`. */\nexport function boundsFields(bounds: EdgeBounds): ParamField[] {\n const bounded = bounds.capacity !== undefined;\n return [\n { key: 'bounded', label: 'Bounded', type: 'toggle', value: bounded },\n { key: 'capacity', label: 'Capacity', type: 'number', value: bounds.capacity ?? DEFAULT_EDGE_CAPACITY, disabled: !bounded },\n {\n key: 'dropOldest',\n label: 'Drop oldest when full',\n type: 'toggle',\n value: bounds.overflow === 'drop-oldest',\n disabled: !bounded,\n },\n ];\n}\n\n/** The bounds after the inspector's field `key` is set to `value`. */\nexport function nextBounds(bounds: EdgeBounds, key: string, value: ParamValue): EdgeBounds {\n const { capacity, overflow } = bounds;\n if (key === 'bounded') {\n return value === true ? { capacity: capacity ?? DEFAULT_EDGE_CAPACITY } : {};\n }\n if (capacity === undefined) {\n return {};\n }\n const keep = overflow === undefined ? {} : { overflow };\n if (key === 'capacity') {\n if (typeof value !== 'number' || Number.isNaN(value)) {\n return bounds;\n }\n return { capacity: Math.max(1, Math.round(value)), ...keep };\n }\n if (key === 'dropOldest') {\n return value === true ? { capacity, overflow: 'drop-oldest' } : { capacity };\n }\n return bounds;\n}\n\n/** A bounded edge's label, in FBP notation: `[4]`; `undefined` when unbounded. */\nexport function capacityLabel(bounds: EdgeBounds): string | undefined {\n if (bounds.capacity === undefined) {\n return undefined;\n }\n const label = `[${String(bounds.capacity)}]`;\n return bounds.overflow === 'drop-oldest' ? `${label} drop oldest` : label;\n}\n","/**\n * One-line React Flow wiring: `createHlangFlowTypes()` returns the `nodeTypes`\n * and `edgeTypes` maps to spread onto `<ReactFlow>`, binding hlang's R/T/W node\n * kinds to `HlangNode` and the default edge to the flowing `FlowEdge`.\n *\n * ```tsx\n * const { nodeTypes, edgeTypes } = createHlangFlowTypes();\n * <ReactFlow nodeTypes={nodeTypes} edgeTypes={edgeTypes} {...useHlangFlow(core)} />\n * ```\n */\n\nimport type { EdgeTypes, NodeTypes } from '@xyflow/react';\nimport { HlangNode } from './HlangNode';\nimport { FlowEdge } from '../edges/FlowEdge';\n\nexport interface HlangFlowTypes {\n readonly nodeTypes: NodeTypes;\n readonly edgeTypes: EdgeTypes;\n}\n\n// The registry entries for the hlang node and edge components.\nconst nodeComponent: NodeTypes[string] = HlangNode;\nconst edgeComponent: EdgeTypes[string] = FlowEdge;\n\n/** Build the React Flow node/edge type maps for the hlang editor. */\nexport function createHlangFlowTypes(): HlangFlowTypes {\n return {\n nodeTypes: { R: nodeComponent, T: nodeComponent, W: nodeComponent },\n edgeTypes: { default: edgeComponent },\n };\n}\n","/**\n * `EditorShell` — composes the editor's regions (top toolbar, left panel,\n * center canvas, right inspector, footer). It holds NO graph logic; a host\n * slots children into named regions. Left/right panels are collapsible via\n * UI-only props, and the footer can be made resizable (presentation state,\n * never part of the graph).\n */\n\nimport { useEffect, useId, useRef } from 'react';\nimport type { ReactElement, ReactNode, RefObject } from 'react';\nimport { FooterResizer } from './FooterResizer';\nimport { useFooterResize } from './useFooterResize';\nimport type { FooterResizeOptions } from './useFooterResize';\nimport './EditorShell.css';\n\nexport interface EditorShellProps {\n /** Top toolbar region. */\n readonly toolbar?: ReactNode;\n /** Left region (node palette / outline). */\n readonly left?: ReactNode;\n /** Right region (inspector). */\n readonly right?: ReactNode;\n /** Center region — required; the host renders <ReactFlow> + <CanvasChrome>. */\n readonly canvas: ReactNode;\n /** Optional footer region (e.g. an output/console strip). */\n readonly footer?: ReactNode;\n /**\n * Makes the footer resizable: its top edge can be dragged, moved with the\n * keyboard, and double-clicked to collapse it. Without it the footer takes\n * its content's height.\n */\n readonly footerResize?: FooterResizeOptions & {\n /** The accessible name of the footer's resize handle. Default \"Resize the panel\". */\n readonly label?: string;\n };\n readonly leftCollapsed?: boolean;\n readonly rightCollapsed?: boolean;\n}\n\nexport function EditorShell({\n toolbar,\n left,\n right,\n canvas,\n footer,\n footerResize,\n leftCollapsed = false,\n rightCollapsed = false,\n}: EditorShellProps): ReactElement {\n const shellRef = useRef<HTMLDivElement>(null);\n const toolbarRef = useRef<HTMLDivElement>(null);\n const className = [\n 'hl-shell',\n leftCollapsed ? 'hl-left-collapsed' : '',\n rightCollapsed ? 'hl-right-collapsed' : '',\n ]\n .filter(Boolean)\n .join(' ');\n\n return (\n <div className={className} ref={shellRef}>\n {toolbar !== undefined && (\n <div className=\"hl-region-toolbar\" ref={toolbarRef}>\n {toolbar}\n </div>\n )}\n <div className=\"hl-region-body\">\n {left !== undefined && !leftCollapsed && (\n <aside className=\"hl-region-left\">{left}</aside>\n )}\n <main className=\"hl-region-canvas\">{canvas}</main>\n {right !== undefined && !rightCollapsed && (\n <aside className=\"hl-region-right\">{right}</aside>\n )}\n </div>\n {footer !== undefined &&\n (footerResize === undefined ? (\n <div className=\"hl-region-footer\">{footer}</div>\n ) : (\n <ResizableFooter options={footerResize} shellRef={shellRef} toolbarRef={toolbarRef}>\n {footer}\n </ResizableFooter>\n ))}\n </div>\n );\n}\n\nfunction ResizableFooter({\n options,\n shellRef,\n toolbarRef,\n children,\n}: {\n readonly options: NonNullable<EditorShellProps['footerResize']>;\n readonly shellRef: RefObject<HTMLDivElement | null>;\n readonly toolbarRef: RefObject<HTMLDivElement | null>;\n readonly children: ReactNode;\n}): ReactElement {\n const resize = useFooterResize(options);\n const id = useId();\n const { measure } = resize;\n\n // The footer may take what the toolbar leaves, less the canvas's minimum;\n // re-measured whenever the editor or its toolbar changes size.\n useEffect(() => {\n const shell = shellRef.current;\n if (shell === null) {\n return;\n }\n const update = (): void => {\n measure(shell.clientHeight - (toolbarRef.current?.offsetHeight ?? 0));\n };\n update();\n const observer = new ResizeObserver(update);\n observer.observe(shell);\n if (toolbarRef.current !== null) {\n observer.observe(toolbarRef.current);\n }\n return (): void => {\n observer.disconnect();\n };\n }, [measure, shellRef, toolbarRef]);\n\n return (\n <div\n id={id}\n className={`hl-region-footer is-resizable${resize.dragging ? ' is-resizing' : ''}`}\n style={{ height: resize.height }}\n >\n <FooterResizer resize={resize} controls={id} label={options.label ?? 'Resize the panel'} />\n {children}\n </div>\n );\n}\n","/**\n * `FooterResizer` — the grab handle on a resizable footer's top edge. Drag it\n * with a mouse, a finger or a pen; with focus, the arrow keys move it (Shift\n * for larger steps), Home and End go to the smallest and largest heights, and\n * Enter or a double click collapses the footer and opens it again. It is a\n * focusable ARIA `separator` that reports the footer's height.\n */\n\nimport type { KeyboardEvent, PointerEvent, ReactElement } from 'react';\nimport type { FooterResize } from './useFooterResize';\n\nexport interface FooterResizerProps {\n readonly resize: FooterResize;\n /** The id of the footer the handle resizes. */\n readonly controls: string;\n /** Its accessible name. */\n readonly label: string;\n}\n\nexport function FooterResizer({ resize, controls, label }: FooterResizerProps): ReactElement {\n const onPointerDown = (event: PointerEvent<HTMLDivElement>): void => {\n // A mouse drags with its main button only; touch and pen always drag.\n if (event.pointerType === 'mouse' && event.button !== 0) {\n return;\n }\n event.preventDefault();\n event.currentTarget.setPointerCapture(event.pointerId);\n resize.startDrag(event.clientY);\n };\n const onPointerMove = (event: PointerEvent<HTMLDivElement>): void => {\n if (event.currentTarget.hasPointerCapture(event.pointerId)) {\n resize.drag(event.clientY);\n }\n };\n const onPointerEnd = (event: PointerEvent<HTMLDivElement>): void => {\n if (event.currentTarget.hasPointerCapture(event.pointerId)) {\n event.currentTarget.releasePointerCapture(event.pointerId);\n }\n resize.endDrag();\n };\n const onKeyDown = (event: KeyboardEvent<HTMLDivElement>): void => {\n if (resize.keyDown(event.key, event.shiftKey)) {\n event.preventDefault();\n }\n };\n\n return (\n <div\n role=\"separator\"\n aria-orientation=\"horizontal\"\n aria-label={label}\n aria-controls={controls}\n aria-valuemin={resize.bounds.min}\n aria-valuemax={resize.bounds.max}\n aria-valuenow={resize.height}\n tabIndex={0}\n className={`hl-footer-resizer${resize.dragging ? ' is-dragging' : ''}`}\n onPointerDown={onPointerDown}\n onPointerMove={onPointerMove}\n onPointerUp={onPointerEnd}\n onPointerCancel={onPointerEnd}\n onLostPointerCapture={() => {\n resize.endDrag();\n }}\n onDoubleClick={() => {\n resize.toggle();\n }}\n onKeyDown={onKeyDown}\n />\n );\n}\n","/**\n * `useFooterResize` — the state of a footer whose top edge the user drags, or\n * moves with the keyboard, to make it taller or shorter. It takes only what it\n * reads (a pointer's `clientY`, a key), so `FooterResizer` adapts the browser's\n * events to it and the behavior is testable without a browser.\n *\n * The height the user asked for is kept apart from the height shown: when the\n * editor gets shorter the footer shrinks to fit, and when it grows back the\n * footer returns to the asked-for height.\n */\n\nimport { useCallback, useMemo, useRef, useState } from 'react';\nimport { clampFooter, footerBounds, resizeByKey, toggleCollapsed } from './footer-size';\nimport type { FooterBounds } from './footer-size';\n\n/** How a resizable footer behaves. */\nexport interface FooterResizeOptions {\n /** Its height when the editor opens, in pixels. */\n readonly defaultHeight: number;\n /** Its height when collapsed: its own header, so it can always be grabbed and opened again. */\n readonly minHeight: number;\n /** The height the canvas always keeps. Default `DEFAULT_MIN_CANVAS_HEIGHT`. */\n readonly minCanvasHeight?: number;\n}\n\n/** The canvas height a footer never takes away, unless a host sets another. */\nexport const DEFAULT_MIN_CANVAS_HEIGHT = 160;\n\nexport interface FooterResize {\n /** The height to render. */\n readonly height: number;\n readonly bounds: FooterBounds;\n readonly dragging: boolean;\n /** Tells the hook how many pixels the toolbar leaves for the canvas and the footer. */\n readonly measure: (available: number) => void;\n readonly startDrag: (clientY: number) => void;\n readonly drag: (clientY: number) => void;\n readonly endDrag: () => void;\n /** Applies a key pressed on the edge; returns whether the key resized the footer. */\n readonly keyDown: (key: string, shift: boolean) => boolean;\n /** Collapses the footer, or opens it again to the height it had. */\n readonly toggle: () => void;\n}\n\nexport function useFooterResize(options: FooterResizeOptions): FooterResize {\n const { defaultHeight, minHeight } = options;\n const minCanvasHeight = options.minCanvasHeight ?? DEFAULT_MIN_CANVAS_HEIGHT;\n // Unknown until measured (e.g. while rendering on a server): the default fits.\n const [available, setAvailable] = useState<number | null>(null);\n const [preferred, setPreferred] = useState(defaultHeight);\n const [restore, setRestore] = useState(defaultHeight);\n const [dragging, setDragging] = useState(false);\n const dragStart = useRef<{ readonly clientY: number; readonly height: number } | null>(null);\n\n const bounds = useMemo<FooterBounds>(\n () =>\n available === null\n ? { min: minHeight, max: Math.max(minHeight, defaultHeight) }\n : footerBounds({ available, minHeight, minCanvasHeight }),\n [available, minHeight, minCanvasHeight, defaultHeight],\n );\n const height = clampFooter(preferred, bounds);\n\n /** Sets the height the user asked for; an open height is also the one to reopen to. */\n const choose = useCallback(\n (next: number): void => {\n setPreferred(next);\n if (next > bounds.min) {\n setRestore(next);\n }\n },\n [bounds.min],\n );\n\n const measure = useCallback((next: number): void => {\n setAvailable(next);\n }, []);\n\n const startDrag = useCallback(\n (clientY: number): void => {\n dragStart.current = { clientY, height };\n setDragging(true);\n },\n [height],\n );\n\n const drag = useCallback(\n (clientY: number): void => {\n const start = dragStart.current;\n if (start === null) {\n return;\n }\n choose(clampFooter(start.height + (start.clientY - clientY), bounds));\n },\n [bounds, choose],\n );\n\n const endDrag = useCallback((): void => {\n dragStart.current = null;\n setDragging(false);\n }, []);\n\n const toggle = useCallback((): void => {\n const next = toggleCollapsed({ height, restore }, bounds);\n setPreferred(next.height);\n setRestore(next.restore);\n }, [height, restore, bounds]);\n\n const keyDown = useCallback(\n (key: string, shift: boolean): boolean => {\n if (key === 'Enter') {\n toggle();\n return true;\n }\n const next = resizeByKey(height, key, shift, bounds);\n if (next === undefined) {\n return false;\n }\n choose(next);\n return true;\n },\n [height, bounds, choose, toggle],\n );\n\n return { height, bounds, dragging, measure, startDrag, drag, endDrag, keyDown, toggle };\n}\n","/**\n * The size rules of the editor's resizable footer (its console): how tall it\n * may be, and how the keyboard and a double click change it. Pure, so the\n * pointer and keyboard handling in `useFooterResize` stays a thin layer.\n */\n\n/** How far one arrow key press moves the footer edge, in pixels; Shift moves four times as far. */\nexport const FOOTER_KEY_STEP = 16;\n\nexport interface FooterBounds {\n readonly min: number;\n readonly max: number;\n}\n\n/**\n * The heights the footer may take in an editor with `available` pixels below\n * its toolbar: at least `minHeight` (its header alone, collapsed), and at most\n * what leaves the canvas `minCanvasHeight`.\n */\nexport function footerBounds(options: {\n readonly available: number;\n readonly minHeight: number;\n readonly minCanvasHeight: number;\n}): FooterBounds {\n const { available, minHeight, minCanvasHeight } = options;\n return { min: minHeight, max: Math.max(minHeight, available - minCanvasHeight) };\n}\n\n/** `height` held within `bounds`, in whole pixels. */\nexport function clampFooter(height: number, bounds: FooterBounds): number {\n return Math.round(Math.min(bounds.max, Math.max(bounds.min, height)));\n}\n\n/** The height after pressing `key` on the footer edge, or `undefined` for a key that does nothing. */\nexport function resizeByKey(height: number, key: string, shift: boolean, bounds: FooterBounds): number | undefined {\n const step = FOOTER_KEY_STEP * (shift ? 4 : 1);\n switch (key) {\n case 'ArrowUp':\n return clampFooter(height + step, bounds);\n case 'ArrowDown':\n return clampFooter(height - step, bounds);\n case 'Home':\n return bounds.min;\n case 'End':\n return bounds.max;\n default:\n return undefined;\n }\n}\n\n/** The footer's height and the height to return to when it is opened again. */\nexport interface FooterSize {\n readonly height: number;\n readonly restore: number;\n}\n\n/** Collapses an open footer (remembering its height), or opens a collapsed one to that height. */\nexport function toggleCollapsed(size: FooterSize, bounds: FooterBounds): FooterSize {\n if (size.height > bounds.min) {\n return { height: bounds.min, restore: size.height };\n }\n return { height: clampFooter(size.restore, bounds), restore: size.restore };\n}\n","/**\n * The top toolbar: a thin glass bar with a brand wordmark on the left and an\n * action cluster on the right. `Toolbar` is the presentational container;\n * `UndoRedo` and `RunButton` are the standard actions wired to editor-core via\n * editor-react hooks. Hosts may pass extra actions through `actions`.\n */\n\nimport type { ReactElement, ReactNode } from 'react';\nimport type { EditorCore } from '@hlang-tech/editor-core';\nimport { useHistory } from '@hlang-tech/editor-react';\nimport './Toolbar.css';\n\nexport interface ToolbarProps {\n /** Brand/title shown on the left. Defaults to a generic wordmark. */\n readonly title?: ReactNode;\n /** Centre slot — a tool cluster (add/frame/view), absolutely centred. */\n readonly center?: ReactNode;\n /** Action nodes rendered on the right (e.g. <UndoRedo/>, <RunButton/>). */\n readonly actions?: ReactNode;\n}\n\nexport function Toolbar({ title, center, actions }: ToolbarProps): ReactElement {\n return (\n <header className=\"hl-toolbar\">\n <div className=\"hl-toolbar-brand\">\n {title ?? (\n <>\n <span className=\"hl-toolbar-glyph\" aria-hidden=\"true\" />\n <span className=\"hl-toolbar-wordmark\">hlang</span>\n </>\n )}\n </div>\n {center !== undefined && <div className=\"hl-toolbar-center\">{center}</div>}\n <div className=\"hl-toolbar-actions\">{actions}</div>\n </header>\n );\n}\n\nexport interface UndoRedoProps {\n readonly core: EditorCore;\n}\n\nexport function UndoRedo({ core }: UndoRedoProps): ReactElement {\n const history = useHistory(core);\n return (\n <>\n <button\n type=\"button\"\n className=\"hl-toolbar-btn\"\n onClick={() => history.undo()}\n disabled={!history.canUndo}\n title=\"Undo (⌘Z)\"\n >\n Undo\n </button>\n <button\n type=\"button\"\n className=\"hl-toolbar-btn\"\n onClick={() => history.redo()}\n disabled={!history.canRedo}\n title=\"Redo (⌘⇧Z)\"\n >\n Redo\n </button>\n </>\n );\n}\n\nexport interface RunButtonProps {\n /**\n * Invoked when clicked. This is a toggle: when `running` is true the button\n * shows a Stop affordance, and the host is expected to stop the execution.\n */\n readonly onRun: () => void;\n /** Whether an execution is currently in progress. */\n readonly running?: boolean;\n readonly runLabel?: string;\n readonly stopLabel?: string;\n}\n\nexport function RunButton({\n onRun,\n running = false,\n runLabel = 'Run',\n stopLabel = 'Stop',\n}: RunButtonProps): ReactElement {\n return (\n <button\n type=\"button\"\n className={`hl-toolbar-btn hl-toolbar-run${running ? ' is-running' : ''}`}\n onClick={onRun}\n aria-pressed={running}\n >\n <span\n className={`hl-toolbar-run-icon${running ? ' is-stop' : ''}`}\n aria-hidden=\"true\"\n />\n {running ? stopLabel : runLabel}\n </button>\n );\n}\n\n/** A compact read-only stat pill (e.g. a node/vertex count) for the top bar. */\nexport function ToolbarStat({ label, value }: { readonly label?: string; readonly value: ReactNode }): ReactElement {\n return (\n <span className=\"hl-toolbar-stat hl-mono\" title={label}>\n {value}\n </span>\n );\n}\n\n/** A secondary ghost button for the top bar (e.g. Invite). Presentational. */\nexport function ToolbarGhostButton({\n children,\n onClick,\n title,\n}: {\n readonly children: ReactNode;\n readonly onClick?: () => void;\n readonly title?: string;\n}): ReactElement {\n return (\n <button type=\"button\" className=\"hl-toolbar-btn\" onClick={onClick} title={title}>\n {children}\n </button>\n );\n}\n","/**\n * `ToolCluster` — the centred group of canvas tools in the top bar (nover-style):\n * a row of icon buttons with optional separators, in the black/silver glass\n * language. Purely presentational: the host supplies the items and their\n * actions. Kept generic (no business/media concepts) so it stays an editor-ui\n * primitive — a \"frame\", \"add\", or \"view\" tool is just an item with an icon.\n */\n\nimport type { ReactElement, ReactNode } from 'react';\nimport './ToolCluster.css';\n\nexport interface ToolItem {\n readonly id: string;\n readonly icon: ReactNode;\n readonly title: string;\n readonly onClick?: () => void;\n readonly active?: boolean;\n readonly disabled?: boolean;\n /** Draw a thin divider before this item. */\n readonly separatorBefore?: boolean;\n}\n\nexport interface ToolClusterProps {\n readonly items: readonly ToolItem[];\n}\n\nexport function ToolCluster({ items }: ToolClusterProps): ReactElement {\n return (\n <div className=\"hl-toolcluster\" role=\"toolbar\" aria-label=\"Canvas tools\">\n {items.map(item => (\n <span key={item.id} className=\"hl-toolcluster-slot\">\n {item.separatorBefore === true && <span className=\"hl-toolcluster-sep\" aria-hidden />}\n <button\n type=\"button\"\n className={'hl-toolcluster-btn' + (item.active === true ? ' is-active' : '')}\n onClick={item.onClick}\n disabled={item.disabled}\n title={item.title}\n aria-label={item.title}\n aria-pressed={item.active}\n >\n {item.icon}\n </button>\n </span>\n ))}\n </div>\n );\n}\n","/**\n * `CanvasChrome` — themed React Flow canvas furniture. Now just the dotted\n * background: React Flow's default MiniMap and Controls are intentionally NOT\n * rendered — a creation studio replaces them with our own centred `CanvasDock`\n * (pan/zoom/add) so the canvas isn't cluttered with a stock topology-editor\n * toolbar. Rendered as children of <ReactFlow>.\n */\n\nimport type { ReactElement } from 'react';\nimport { Background, BackgroundVariant } from '@xyflow/react';\nimport './CanvasChrome.css';\n\nexport interface CanvasChromeProps {\n readonly background?: boolean;\n}\n\nexport function CanvasChrome({ background = true }: CanvasChromeProps): ReactElement {\n return <>{background && <Background variant={BackgroundVariant.Dots} gap={26} size={1} color=\"#242830\" />}</>;\n}\n","/**\n * `CanvasDock` — the centred, bottom-of-canvas floating toolbar of a creation\n * studio: pointer/pan mode, add-node, and zoom controls, in the black/silver\n * glass language. It replaces React Flow's default corner Controls + MiniMap\n * with one calm, centred dock.\n *\n * Presentation only: it renders buttons and the current zoom %, and calls back\n * to the host for every action. It holds no React Flow or graph state — the host\n * wires the callbacks to `useReactFlow()` (zoom/fit) and the node search (add).\n */\n\nimport type { ReactElement } from 'react';\nimport './CanvasDock.css';\n\n/** Interaction mode the canvas is in — left-drag selects, or left-drag pans. */\nexport type CanvasMode = 'select' | 'pan';\n\nexport interface CanvasDockProps {\n /** Current zoom as a fraction (1 = 100%). */\n readonly zoom: number;\n readonly onZoomIn: () => void;\n readonly onZoomOut: () => void;\n readonly onFitView: () => void;\n /** Open the node search to add a node. */\n readonly onAdd: () => void;\n /** Current interaction mode + setter (left-drag selects vs pans). */\n readonly mode: CanvasMode;\n readonly onModeChange: (mode: CanvasMode) => void;\n /** Undo/redo — colocated with the canvas tools rather than the top bar. */\n readonly onUndo: () => void;\n readonly onRedo: () => void;\n readonly canUndo: boolean;\n readonly canRedo: boolean;\n}\n\nfunction CursorIcon(): ReactElement {\n return (\n <svg width={16} height={16} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={1.6} strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"M5 3l6 16 2-6 6-2z\" />\n </svg>\n );\n}\nfunction HandIcon(): ReactElement {\n return (\n <svg width={16} height={16} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={1.6} strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"M8 12V6a1.5 1.5 0 013 0v5m0-1V5a1.5 1.5 0 013 0v6m0-1V6.5a1.5 1.5 0 013 0V13c0 3.5-2 6-5.5 6H12c-2 0-3-.8-4.2-2.5L5 12.5c-.7-1 .6-2.3 1.6-1.6z\" />\n </svg>\n );\n}\nfunction PlusIcon(): ReactElement {\n return (\n <svg width={17} height={17} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={1.7} strokeLinecap=\"round\" aria-hidden>\n <path d=\"M12 5v14M5 12h14\" />\n </svg>\n );\n}\nfunction FitIcon(): ReactElement {\n return (\n <svg width={15} height={15} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={1.6} strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"M4 9V4h5M20 9V4h-5M4 15v5h5M20 15v5h-5\" />\n </svg>\n );\n}\nfunction UndoIcon(): ReactElement {\n return (\n <svg width={15} height={15} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={1.6} strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"M9 7L4 12l5 5M4 12h11a5 5 0 010 10h-1\" />\n </svg>\n );\n}\nfunction RedoIcon(): ReactElement {\n return (\n <svg width={15} height={15} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={1.6} strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d=\"M15 7l5 5-5 5M20 12H9a5 5 0 000 10h1\" />\n </svg>\n );\n}\n\nexport function CanvasDock({\n zoom,\n onZoomIn,\n onZoomOut,\n onFitView,\n onAdd,\n mode,\n onModeChange,\n onUndo,\n onRedo,\n canUndo,\n canRedo,\n}: CanvasDockProps): ReactElement {\n const pct = `${String(Math.round(zoom * 100))}%`;\n return (\n <div className=\"hl-dock\" role=\"toolbar\" aria-label=\"Canvas tools\">\n <button\n className=\"hl-dock-btn\"\n onClick={onUndo}\n disabled={!canUndo}\n title=\"Undo (⌘Z)\"\n aria-label=\"Undo\"\n >\n <UndoIcon />\n </button>\n <button\n className=\"hl-dock-btn\"\n onClick={onRedo}\n disabled={!canRedo}\n title=\"Redo (⌘⇧Z)\"\n aria-label=\"Redo\"\n >\n <RedoIcon />\n </button>\n <span className=\"hl-dock-sep\" aria-hidden />\n <button\n className={'hl-dock-btn' + (mode === 'select' ? ' is-active' : '')}\n onClick={() => onModeChange('select')}\n title=\"Select (V)\"\n aria-pressed={mode === 'select'}\n >\n <CursorIcon />\n </button>\n <button\n className={'hl-dock-btn' + (mode === 'pan' ? ' is-active' : '')}\n onClick={() => onModeChange('pan')}\n title=\"Pan (Space)\"\n aria-pressed={mode === 'pan'}\n >\n <HandIcon />\n </button>\n <button className=\"hl-dock-btn hl-dock-add\" onClick={onAdd} title=\"Add node\">\n <PlusIcon />\n </button>\n\n <span className=\"hl-dock-sep\" aria-hidden />\n\n <button className=\"hl-dock-btn\" onClick={onZoomOut} title=\"Zoom out\" aria-label=\"Zoom out\">\n <span className=\"hl-dock-glyph\">−</span>\n </button>\n <button className=\"hl-dock-zoom hl-mono\" onClick={onFitView} title=\"Fit view\">\n {pct}\n </button>\n <button className=\"hl-dock-btn\" onClick={onZoomIn} title=\"Zoom in\" aria-label=\"Zoom in\">\n <span className=\"hl-dock-glyph\">+</span>\n </button>\n <button className=\"hl-dock-btn hl-dock-fit\" onClick={onFitView} title=\"Fit view\" aria-label=\"Fit view\">\n <FitIcon />\n </button>\n </div>\n );\n}\n","/**\n * `EmptyState` — a quiet, centered hint shown over an empty canvas. Purely\n * presentational; the host decides when to render it (e.g. when the graph has\n * no nodes). Non-interactive so it never blocks canvas gestures.\n */\n\nimport type { ReactElement, ReactNode } from 'react';\nimport './EmptyState.css';\n\nexport interface EmptyStateProps {\n readonly title?: ReactNode;\n readonly hint?: ReactNode;\n}\n\nexport function EmptyState({\n title = 'An empty canvas.',\n hint = 'add a source · wire it to a sink · run',\n}: EmptyStateProps): ReactElement {\n return (\n <div className=\"hl-empty\" aria-hidden=\"true\">\n <p className=\"hl-empty-title\">{title}</p>\n <p className=\"hl-empty-hint\">{hint}</p>\n </div>\n );\n}\n","/**\n * `InspectorPanel` — the right-hand property inspector. It follows selection:\n * with exactly one node selected it shows that node's identity plus a\n * schema-driven parameter form (edits commit undoable UpdateParamsCommands);\n * with exactly one connection selected, the connection and its back-pressure;\n * otherwise it shows an empty/summary state. This is the unified control center\n * (nover.studio's model) over hlang's headless core.\n */\n\nimport type { ReactElement, ReactNode } from 'react';\nimport type { EditorCore } from '@hlang-tech/editor-core';\nimport { useSelection } from '@hlang-tech/editor-react';\nimport { KIND_ROLE } from '../tokens/tokens';\nimport { deriveParamSchema } from '../schema/param-field';\nimport { useNodeParams } from '../hooks/useNodeParams';\nimport { ConnectionInspector } from './ConnectionInspector';\nimport { NodeRunStats } from './NodeRunStats';\nimport { ParamForm } from './ParamForm';\nimport './InspectorPanel.css';\n\nexport interface InspectorPanelProps {\n readonly core: EditorCore;\n /** Shown when no single node is selected. */\n readonly emptyState?: ReactNode;\n}\n\nexport function InspectorPanel({ core, emptyState }: InspectorPanelProps): ReactElement {\n const selection = useSelection(core);\n const selectedNodes = selection.selectedNodes;\n const singleId = selectedNodes.length === 1 ? selectedNodes[0] : undefined;\n const params = useNodeParams(core, singleId);\n const node = params.node;\n\n const singleEdgeId =\n selectedNodes.length === 0 && selection.selectedEdges.length === 1 ? selection.selectedEdges[0] : undefined;\n if (node === undefined && singleEdgeId !== undefined) {\n return <ConnectionInspector core={core} edgeId={singleEdgeId} />;\n }\n\n if (node === undefined) {\n return (\n <div className=\"hl-inspector hl-inspector-empty\">\n {emptyState ?? (\n <div className=\"hl-inspector-blank\">\n <span className=\"hl-inspector-blank-badge\" aria-hidden />\n <p className=\"hl-inspector-blank-title\">\n {selectedNodes.length > 1 ? `${String(selectedNodes.length)} nodes selected` : 'Nothing selected'}\n </p>\n <p className=\"hl-inspector-hint\">\n {selectedNodes.length > 1\n ? 'Select a single node to edit its parameters.'\n : 'Pick a node or a connection on the canvas to inspect and tune it.'}\n </p>\n </div>\n )}\n </div>\n );\n }\n\n const descriptor = core.registry.get(node.code);\n const fields = descriptor === undefined ? [] : deriveParamSchema(descriptor, node);\n const imageUrl =\n typeof node.params.imageUrl === 'string' && node.params.imageUrl.length > 0\n ? node.params.imageUrl\n : undefined;\n\n return (\n <div className=\"hl-inspector\">\n {/* A preview thumbnail grounds the header: the asset's image, or a\n kind-tinted medallion for other nodes. */}\n <div className={`hl-inspector-preview hl-${node.kind.toLowerCase()}`}>\n {imageUrl !== undefined ? (\n <img className=\"hl-inspector-preview-img\" src={imageUrl} alt={node.name} />\n ) : (\n <span className=\"hl-inspector-preview-badge hl-mono\">{node.kind}</span>\n )}\n </div>\n <header className=\"hl-inspector-head\">\n <span className={`hl-inspector-kind hl-${node.kind.toLowerCase()}`}>{node.kind}</span>\n <div className=\"hl-inspector-titles\">\n <span className=\"hl-inspector-name\">{node.name}</span>\n <span className=\"hl-inspector-role hl-mono\">\n {node.code} · {KIND_ROLE[node.kind]}\n </span>\n </div>\n </header>\n\n <section className=\"hl-inspector-section\">\n <h3 className=\"hl-inspector-section-title\">Parameters</h3>\n {fields.length === 0 ? (\n <p className=\"hl-inspector-hint\">This node has no parameters.</p>\n ) : (\n <ParamForm\n fields={fields}\n onCommit={(key, value) => params.setParam(key, value)}\n />\n )}\n </section>\n\n <NodeRunStats nodeId={node.id} />\n\n <section className=\"hl-inspector-section\">\n <h3 className=\"hl-inspector-section-title\">Ports</h3>\n <ul className=\"hl-inspector-ports\">\n {node.ports.map(port => (\n <li\n key={port.id}\n className={`hl-inspector-port${port.isError ? ' is-error' : ''}`}\n >\n <span className={`hl-port-dot hl-dir-${port.direction.toLowerCase()}`} />\n <span className=\"hl-mono\">{port.name}</span>\n <span className=\"hl-inspector-port-dir hl-mono\">{port.direction}</span>\n </li>\n ))}\n </ul>\n </section>\n </div>\n );\n}\n","/**\n * Schema-driven property editing. A node's editable parameters are derived into\n * a strongly-typed `ParamField[]` (zero `any`), which the inspector renders as\n * form controls. Field types are inferred from each default value's runtime\n * type — the only metadata a `NodeDescriptor` carries today (`defaultParams`).\n */\n\nimport type { NodeDescriptor, EditorNode, ParamValue } from '@hlang-tech/editor-core';\n\n/** Common fields on every derived form field. */\nexport interface ParamFieldBase {\n readonly key: string;\n readonly label: string;\n readonly disabled?: boolean;\n}\n\n/** A discriminated union of the built-in form field types (zero `any`). */\nexport type ParamField =\n | (ParamFieldBase & { readonly type: 'text'; readonly value: string })\n | (ParamFieldBase & { readonly type: 'textarea'; readonly value: string })\n | (ParamFieldBase & { readonly type: 'number'; readonly value: number })\n | (ParamFieldBase & { readonly type: 'toggle'; readonly value: boolean })\n | (ParamFieldBase & {\n readonly type: 'custom';\n readonly fieldType: string;\n readonly value: ParamValue;\n });\n\n/** Turn a param key like `maxTokens` / `hack_send` into a readable label. */\nfunction humanizeKey(key: string): string {\n const spaced = key\n .replace(/[_-]+/g, ' ')\n .replace(/([a-z0-9])([A-Z])/g, '$1 $2')\n .trim();\n return spaced.charAt(0).toUpperCase() + spaced.slice(1);\n}\n\n/** Infer a field from a key and its current value. */\nfunction fieldFor(key: string, value: ParamValue): ParamField {\n const label = humanizeKey(key);\n if (typeof value === 'boolean') {\n return { key, label, type: 'toggle', value };\n }\n if (typeof value === 'number') {\n return { key, label, type: 'number', value };\n }\n if (typeof value === 'string') {\n // Multi-line strings (e.g. code / prompts) get a textarea.\n const type = value.includes('\\n') ? 'textarea' : 'text';\n return { key, label, type, value };\n }\n // Arrays, nested objects, null — surface via the custom control registry.\n return { key, label, type: 'custom', fieldType: 'json', value };\n}\n\n/**\n * Derive the ordered form schema for a node. Keys come from the descriptor's\n * `defaultParams` (the canonical param set); current values come from the live\n * node, falling back to the default.\n */\nexport function deriveParamSchema(\n descriptor: NodeDescriptor,\n node: EditorNode,\n): readonly ParamField[] {\n const fields: ParamField[] = [];\n for (const key of Object.keys(descriptor.defaultParams)) {\n const current = key in node.params ? node.params[key] : descriptor.defaultParams[key];\n fields.push(fieldFor(key, current ?? null));\n }\n return fields;\n}\n","/**\n * `useNodeParams` — reactively read a node's params and commit edits through the\n * command service (so every change is undoable). Re-reads on the `nodeChanged`\n * event via a version counter (the same pattern editor-react's selectors use).\n */\n\nimport { useCallback, useMemo, useRef, useSyncExternalStore } from 'react';\nimport type { EditorCore, EditorNode, NodeId, ParamBag, ParamValue } from '@hlang-tech/editor-core';\nimport { UpdateParamsCommand } from '@hlang-tech/editor-core';\n\nexport interface NodeParamsHandle {\n /** The node, or undefined if it no longer exists. */\n readonly node: EditorNode | undefined;\n /** Set a single param, committing an undoable UpdateParamsCommand. */\n setParam(key: string, value: ParamValue): void;\n /** Replace the whole param bag, committing an undoable UpdateParamsCommand. */\n setParams(next: ParamBag): void;\n}\n\nexport function useNodeParams(core: EditorCore, nodeId: NodeId | undefined): NodeParamsHandle {\n const versionRef = useRef(0);\n\n const subscribe = useCallback(\n (onStoreChange: () => void): (() => void) => {\n const disposable = core.events.on('nodeChanged', event => {\n if (nodeId !== undefined && event.node.id === nodeId) {\n versionRef.current += 1;\n onStoreChange();\n }\n });\n return (): void => {\n disposable.dispose();\n };\n },\n [core, nodeId],\n );\n\n const getSnapshot = useCallback((): number => versionRef.current, []);\n const version = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n\n const setParams = useCallback(\n (next: ParamBag): void => {\n if (nodeId === undefined) {\n return;\n }\n core.commands.execute(new UpdateParamsCommand(nodeId, next));\n },\n [core, nodeId],\n );\n\n const setParam = useCallback(\n (key: string, value: ParamValue): void => {\n if (nodeId === undefined) {\n return;\n }\n const node = core.model.getNode(nodeId);\n if (node === undefined) {\n return;\n }\n setParams({ ...node.params, [key]: value });\n },\n [core, nodeId, setParams],\n );\n\n return useMemo<NodeParamsHandle>(\n () => ({\n node: nodeId === undefined ? undefined : core.model.getNode(nodeId),\n setParam,\n setParams,\n }),\n // `version` re-reads the node after each nodeChanged for this id.\n // eslint-disable-next-line react-hooks/exhaustive-deps\n [core, nodeId, version, setParam, setParams],\n );\n}\n","/**\n * `useEdgeBounds` — one connection and its bounds (RFC 0001), kept current\n * as commands change it, with a setter that commits an undoable\n * `SetEdgeBoundsCommand`.\n */\n\nimport { useCallback, useSyncExternalStore } from 'react';\nimport { SetEdgeBoundsCommand } from '@hlang-tech/editor-core';\nimport type { EdgeBounds, EdgeId, EditorCore, EditorEdge } from '@hlang-tech/editor-core';\n\nexport interface EdgeBoundsHandle {\n /** The edge, or undefined if it no longer exists. */\n readonly edge: EditorEdge | undefined;\n /** Bound the connection, or unbound it, as one undoable step. */\n readonly setBounds: (bounds: EdgeBounds) => void;\n}\n\nexport function useEdgeBounds(core: EditorCore, edgeId: EdgeId | undefined): EdgeBoundsHandle {\n const subscribe = useCallback(\n (onStoreChange: () => void): (() => void) => {\n const changed = core.events.on('edgeChanged', event => {\n if (event.edge.id === edgeId) {\n onStoreChange();\n }\n });\n const removed = core.events.on('edgeRemoved', event => {\n if (event.edgeId === edgeId) {\n onStoreChange();\n }\n });\n return (): void => {\n changed.dispose();\n removed.dispose();\n };\n },\n [core, edgeId],\n );\n // The model replaces an edge object whenever it changes, so the object\n // itself is a stable snapshot.\n const getSnapshot = useCallback(\n (): EditorEdge | undefined => (edgeId === undefined ? undefined : core.model.getEdge(edgeId)),\n [core, edgeId],\n );\n const edge = useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n\n const setBounds = useCallback(\n (bounds: EdgeBounds): void => {\n if (edgeId !== undefined) {\n core.commands.execute(new SetEdgeBoundsCommand(edgeId, bounds));\n }\n },\n [core, edgeId],\n );\n\n return { edge, setBounds };\n}\n","/**\n * `ParamForm` — renders a derived `ParamField[]` as compact, pro-tool form\n * controls. Text/number inputs commit on blur or Enter (not per keystroke, so\n * one edit is one undo entry); toggles commit immediately. `custom` fields are\n * a placeholder until the ParamFieldRegistry lands (M-UI-5).\n */\n\nimport { useState } from 'react';\nimport type { ReactElement } from 'react';\nimport type { ParamValue } from '@hlang-tech/editor-core';\nimport type { ParamField } from '../schema/param-field';\nimport './ParamForm.css';\n\nexport interface ParamFormProps {\n readonly fields: readonly ParamField[];\n /** Commit a single field's new value (undoable, handled by the caller). */\n readonly onCommit: (key: string, value: ParamValue) => void;\n}\n\nexport function ParamForm({ fields, onCommit }: ParamFormProps): ReactElement {\n return (\n <div className=\"hl-form\">\n {fields.map(field => (\n <FieldRow key={field.key} field={field} onCommit={onCommit} />\n ))}\n </div>\n );\n}\n\nfunction FieldRow({\n field,\n onCommit,\n}: {\n field: ParamField;\n onCommit: (key: string, value: ParamValue) => void;\n}): ReactElement {\n return (\n <label className=\"hl-field\">\n <span className=\"hl-field-label\">{field.label}</span>\n <FieldControl field={field} onCommit={onCommit} />\n </label>\n );\n}\n\nfunction FieldControl({\n field,\n onCommit,\n}: {\n field: ParamField;\n onCommit: (key: string, value: ParamValue) => void;\n}): ReactElement {\n switch (field.type) {\n case 'toggle':\n return (\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={field.value}\n className={`hl-toggle${field.value ? ' is-on' : ''}`}\n disabled={field.disabled}\n onClick={() => onCommit(field.key, !field.value)}\n >\n <span className=\"hl-toggle-knob\" />\n </button>\n );\n case 'number':\n return <NumberControl field={field} onCommit={onCommit} />;\n case 'textarea':\n return <TextControl field={field} onCommit={onCommit} multiline />;\n case 'text':\n return <TextControl field={field} onCommit={onCommit} />;\n case 'custom':\n return (\n <span className=\"hl-field-custom hl-mono\" title={field.fieldType}>\n {describeCustom(field.value)}\n </span>\n );\n }\n}\n\nfunction TextControl({\n field,\n onCommit,\n multiline = false,\n}: {\n field: ParamField & { type: 'text' | 'textarea' };\n onCommit: (key: string, value: ParamValue) => void;\n multiline?: boolean;\n}): ReactElement {\n const [draft, setDraft] = useState(field.value);\n const commit = (): void => {\n if (draft !== field.value) {\n onCommit(field.key, draft);\n }\n };\n const shared = {\n className: 'hl-input',\n value: draft,\n disabled: field.disabled,\n spellCheck: false,\n onBlur: commit,\n };\n if (multiline) {\n return (\n <textarea\n {...shared}\n rows={4}\n onChange={e => setDraft(e.target.value)}\n />\n );\n }\n return (\n <input\n {...shared}\n type=\"text\"\n onChange={e => setDraft(e.target.value)}\n onKeyDown={e => {\n if (e.key === 'Enter') {\n e.currentTarget.blur();\n }\n }}\n />\n );\n}\n\nfunction NumberControl({\n field,\n onCommit,\n}: {\n field: ParamField & { type: 'number' };\n onCommit: (key: string, value: ParamValue) => void;\n}): ReactElement {\n const [draft, setDraft] = useState(String(field.value));\n const commit = (): void => {\n const parsed = Number(draft);\n if (!Number.isNaN(parsed) && parsed !== field.value) {\n onCommit(field.key, parsed);\n }\n };\n return (\n <input\n className=\"hl-input hl-mono\"\n type=\"number\"\n inputMode=\"decimal\"\n value={draft}\n disabled={field.disabled}\n onChange={e => setDraft(e.target.value)}\n onBlur={commit}\n onKeyDown={e => {\n if (e.key === 'Enter') {\n e.currentTarget.blur();\n }\n }}\n />\n );\n}\n\nfunction describeCustom(value: ParamValue): string {\n if (Array.isArray(value)) {\n return `[${String(value.length)} items]`;\n }\n if (value === null) {\n return 'null';\n }\n if (typeof value === 'object') {\n return '{…}';\n }\n return String(value);\n}\n","/**\n * `ConnectionInspector` — the inspector for one selected connection: where it\n * runs from and to, and its back-pressure (RFC 0001): whether it is bounded,\n * its capacity, and whether a full connection drops its oldest message.\n * Changes are undoable commands.\n */\n\nimport type { ReactElement } from 'react';\nimport type { EdgeId, EditorCore, Endpoint } from '@hlang-tech/editor-core';\nimport { boundsFields, nextBounds } from '../edges/edge-bounds';\nimport { useEdgeBounds } from '../hooks/useEdgeBounds';\nimport { ParamForm } from './ParamForm';\n\nexport function ConnectionInspector({ core, edgeId }: { readonly core: EditorCore; readonly edgeId: EdgeId }): ReactElement | null {\n const { edge, setBounds } = useEdgeBounds(core, edgeId);\n if (edge === undefined) {\n return null;\n }\n const end = (endpoint: Endpoint): string => `${core.model.getNode(endpoint.nodeId)?.name ?? endpoint.nodeId}.${endpoint.portId}`;\n return (\n <div className=\"hl-inspector\">\n <header className=\"hl-inspector-head\">\n <span className=\"hl-inspector-kind hl-connection\">→</span>\n <div className=\"hl-inspector-titles\">\n <span className=\"hl-inspector-name\">Connection</span>\n <span className=\"hl-inspector-role hl-mono\">\n {end(edge.source)} → {end(edge.target)}\n </span>\n </div>\n </header>\n <section className=\"hl-inspector-section\">\n <h3 className=\"hl-inspector-section-title\">Back-pressure</h3>\n <p className=\"hl-inspector-hint hl-inspector-note\">\n A bounded connection holds at most its capacity, counting the message being worked on. A sender to a full connection\n waits, unless it drops its oldest waiting message.\n </p>\n <ParamForm\n fields={boundsFields(edge)}\n onCommit={(key, value) => {\n setBounds(nextBounds(edge, key, value));\n }}\n />\n </section>\n </div>\n );\n}\n","/** Short, aligned text for the times the run views show. */\n\n/** How long a delivery took: `<0.01 ms`, `0.12 ms`, `4.6 ms`, `42 ms`, `1.52 s`. */\nexport function formatDuration(ms: number): string {\n if (ms === 0) {\n return '0 ms';\n }\n if (ms < 0.01) {\n return '<0.01 ms';\n }\n if (ms < 1) {\n return `${ms.toFixed(2)} ms`;\n }\n if (ms < 10) {\n return `${ms.toFixed(1)} ms`;\n }\n if (ms < 1000) {\n return `${Math.round(ms).toString()} ms`;\n }\n return `${(ms / 1000).toFixed(2)} s`;\n}\n\n/** When something happened, in seconds since the run started: `0.013s`. */\nexport function formatElapsed(ms: number): string {\n return `${(ms / 1000).toFixed(3)}s`;\n}\n","/**\n * `previewValue` — a short, single-line text for any value a node sends, for\n * the run log and the inspector. Messages are `unknown`: they can be huge,\n * cyclic, class instances, or objects whose getters throw, so the preview\n * never throws, never prints a function's source, and is cut to a limit.\n */\n\n/** The longest preview, in characters, unless a caller asks for another. */\nexport const PREVIEW_LENGTH = 120;\n\nconst CIRCULAR = '[Circular]';\n\n/** A function by its name only: its source is never printed. */\nfunction functionPreview(value: { readonly name: string }): string {\n return `ƒ ${value.name === '' ? 'anonymous' : value.name}`;\n}\n\nfunction bigintPreview(value: bigint): string {\n return `${value.toString()}n`;\n}\n\n/** The name of a value's class, or `Object` for a plain or prototype-less object. */\nfunction className(value: object): string {\n const prototype: unknown = Object.getPrototypeOf(value);\n if (prototype === null || prototype === Object.prototype) {\n return 'Object';\n }\n const name: unknown = typeof prototype === 'object' && 'constructor' in prototype ? prototype.constructor : undefined;\n return typeof name === 'function' && name.name !== '' ? name.name : 'Object';\n}\n\n/** What a nested value becomes inside the JSON of an object or array. */\nfunction nestedPreview(value: unknown): unknown {\n if (typeof value === 'bigint') {\n return bigintPreview(value);\n }\n if (typeof value === 'function') {\n return functionPreview(value);\n }\n if (typeof value === 'symbol') {\n return value.toString();\n }\n if (value instanceof Error) {\n return `${value.name}: ${value.message}`;\n }\n if (value instanceof Map || value instanceof Set) {\n return `${value instanceof Map ? 'Map' : 'Set'}(${String(value.size)})`;\n }\n return value;\n}\n\n/** Compact JSON of an object or array, with cycles, bigints and functions made printable. */\nfunction json(value: object): string | undefined {\n // The objects from the root to the one being serialized: a value already\n // among them is a cycle. (A value seen elsewhere is merely shared.)\n const ancestors: unknown[] = [];\n return JSON.stringify(value, function replace(this: unknown, _key: string, nested: unknown): unknown {\n while (ancestors.length > 0 && ancestors[ancestors.length - 1] !== this) {\n ancestors.pop();\n }\n if (typeof nested === 'object' && nested !== null) {\n if (ancestors.includes(nested)) {\n return CIRCULAR;\n }\n ancestors.push(nested);\n }\n return nestedPreview(nested);\n });\n}\n\nfunction fullPreview(value: unknown): string {\n switch (typeof value) {\n case 'string':\n return JSON.stringify(value);\n case 'bigint':\n case 'function':\n case 'symbol': {\n const preview = nestedPreview(value);\n return typeof preview === 'string' ? preview : String(preview);\n }\n case 'object':\n break;\n default:\n return String(value);\n }\n if (value === null) {\n return 'null';\n }\n if (value instanceof Error || value instanceof Map || value instanceof Set) {\n return String(nestedPreview(value));\n }\n if (value instanceof Date) {\n return Number.isNaN(value.getTime()) ? 'Invalid Date' : value.toISOString();\n }\n const name = Array.isArray(value) ? 'Array' : className(value);\n let body: string | undefined;\n try {\n body = json(value);\n } catch {\n // A getter that throws, or a toJSON that does: name the value instead.\n return name;\n }\n if (body === undefined) {\n return name;\n }\n return name === 'Object' || name === 'Array' ? body : `${name} ${body}`;\n}\n\n/** A single-line preview of `value`, at most `maxLength` characters. */\nexport function previewValue(value: unknown, maxLength: number = PREVIEW_LENGTH): string {\n const preview = fullPreview(value);\n return preview.length <= maxLength ? preview : `${preview.slice(0, maxLength - 1)}…`;\n}\n","/**\n * React glue for `RunTrace`. A host provides one trace for the editor; the run\n * log and the inspector read it through `useRunTraceVersion`, which changes at\n * most once per frame, so a busy flow costs one render per frame.\n */\n\nimport { createContext, useContext, useSyncExternalStore } from 'react';\nimport type { ReactElement, ReactNode } from 'react';\nimport type { RunTrace } from './run-trace';\n\nconst RunTraceContext = createContext<RunTrace | null>(null);\n\nexport interface RunTraceProviderProps {\n readonly trace: RunTrace;\n readonly children: ReactNode;\n}\n\nexport function RunTraceProvider({ trace, children }: RunTraceProviderProps): ReactElement {\n return <RunTraceContext.Provider value={trace}>{children}</RunTraceContext.Provider>;\n}\n\n/** The trace, or `null` when there is no provider (run views stay hidden). */\nexport function useRunTraceStore(): RunTrace | null {\n return useContext(RunTraceContext);\n}\n\n/** Re-renders the caller when the trace changes; returns its version (0 without a trace). */\nexport function useRunTraceVersion(trace: RunTrace | null): number {\n return useSyncExternalStore(\n onChange => (trace === null ? () => undefined : trace.subscribe(onChange)),\n () => (trace === null ? 0 : trace.getVersion()),\n () => 0,\n );\n}\n","/**\n * `NodeRunStats` — what one node did in the current run: messages in and out,\n * errors, the average and longest time it spent on a message, and the latest\n * values. Shown in the inspector when the host provides a `RunTrace`.\n */\n\nimport type { ReactElement } from 'react';\nimport { formatDuration } from '../live/format';\nimport { previewValue } from '../live/preview';\nimport { useRunTraceStore, useRunTraceVersion } from '../live/RunTraceContext';\n\nexport function NodeRunStats({ nodeId }: { readonly nodeId: string }): ReactElement | null {\n const trace = useRunTraceStore();\n useRunTraceVersion(trace);\n if (trace === null) {\n return null;\n }\n const stats = trace.statsOf(nodeId);\n return (\n <section className=\"hl-inspector-section\">\n <h3 className=\"hl-inspector-section-title\">Run</h3>\n {stats === undefined ? (\n <p className=\"hl-inspector-hint hl-runstats-hint\">No activity in this run.</p>\n ) : (\n <dl className=\"hl-runstats\">\n <div className=\"hl-runstats-cell\">\n <dt>In</dt>\n <dd className=\"hl-mono\">{stats.received}</dd>\n </div>\n <div className=\"hl-runstats-cell\">\n <dt>Out</dt>\n <dd className=\"hl-mono\">{stats.sent}</dd>\n </div>\n <div className={`hl-runstats-cell${stats.errors > 0 ? ' is-error' : ''}`}>\n <dt>Errors</dt>\n <dd className=\"hl-mono\">{stats.errors}</dd>\n </div>\n <div className=\"hl-runstats-cell\">\n <dt>Avg</dt>\n <dd className=\"hl-mono\">{stats.received === 0 ? '—' : formatDuration(stats.totalMs / stats.received)}</dd>\n </div>\n <div className=\"hl-runstats-cell\">\n <dt>Max</dt>\n <dd className=\"hl-mono\">{stats.received === 0 ? '—' : formatDuration(stats.maxMs)}</dd>\n </div>\n {stats.dropped > 0 && (\n <div className=\"hl-runstats-cell is-warning\">\n <dt>Dropped</dt>\n <dd className=\"hl-mono\">{stats.dropped}</dd>\n </div>\n )}\n {stats.finished && (\n <div className=\"hl-runstats-cell is-done\">\n <dt>State</dt>\n <dd>Finished</dd>\n </div>\n )}\n {stats.received > 0 && (\n <div className=\"hl-runstats-cell is-wide\">\n <dt>Last in</dt>\n <dd className=\"hl-mono\">{previewValue(stats.lastReceived)}</dd>\n </div>\n )}\n {stats.sent > 0 && (\n <div className=\"hl-runstats-cell is-wide\">\n <dt>Last out</dt>\n <dd className=\"hl-mono\">{previewValue(stats.lastSent)}</dd>\n </div>\n )}\n </dl>\n )}\n </section>\n );\n}\n","/**\n * `OutlineTree` — the left-rail outline: a two-level GROUPING, not a tree.\n *\n * hlang's graph is a DAG (R/T/W nodes, O->I edges, T<->T feedback allowed), so\n * there is no parent/child hierarchy to render. Instead we group by weakly-\n * connected component (`GraphTopology.components()`): each component is one\n * expandable \"Flow N\" container, and its member nodes are listed FLAT — they are\n * peers. The real relationships between nodes (edges, fan-in/out) are shown on\n * the canvas, never faked here as nesting. So: the outline expresses BELONGING\n * (which Flow a node is in); the canvas expresses DATA FLOW.\n *\n * Rows carry per-type icons, a diagnostic marker, hover-revealed visible/lock\n * controls, and a solid silver highlight when selected. Clicking a node selects\n * and focuses it. Visibility/lock are per-node view state via `useViewState`.\n */\n\nimport { useCallback, useEffect, useMemo, useState } from 'react';\nimport type { ReactElement } from 'react';\nimport type { EditorCore, EditorNode, NodeId, TopologyComponent } from '@hlang-tech/editor-core';\nimport { GraphTopology } from '@hlang-tech/editor-core';\nimport { useSelection, useViewState, useDiagnostics } from '@hlang-tech/editor-react';\nimport { NodeIcon, EyeIcon, EyeOffIcon, LockIcon, UnlockIcon } from '../icons/node-icons';\nimport { DiagnosticBadge } from './DiagnosticBadge';\nimport './OutlineTree.css';\n\nexport interface OutlineTreeProps {\n readonly core: EditorCore;\n readonly onFocus?: (id: NodeId) => void;\n}\n\n/**\n * Reactively derive the graph's weakly-connected components from the LIVE model.\n * Rebuilding a GraphTopology from scratch each change is cheap for editor-sized\n * graphs and — crucially — timing-proof: a bulk `model.restore` (which emits no\n * per-node events) is picked up by the mount effect, and normal edits by the\n * structural-event subscription. This avoids the stale-empty-index bug.\n */\nfunction useTopologyComponents(core: EditorCore): readonly TopologyComponent[] {\n const [tick, setTick] = useState(0);\n const bump = useCallback((): void => setTick(t => t + 1), []);\n\n useEffect(() => {\n // Normal edits fire structural events.\n const kinds = ['nodeAdded', 'nodeRemoved', 'nodeChanged', 'edgeAdded', 'edgeRemoved'] as const;\n const disposers = kinds.map(k => core.events.on(k, bump));\n // Bulk loads (restore) emit no events — recompute once now that the host's\n // mount effect has populated the model.\n bump();\n return () => {\n for (const d of disposers) {\n d.dispose();\n }\n };\n }, [core, bump]);\n\n return useMemo(() => {\n void tick;\n const topo = new GraphTopology();\n topo.reset(core.model.getNodes(), core.model.getEdges());\n return topo.components();\n }, [core, tick]);\n}\n\nexport function OutlineTree({ core, onFocus }: OutlineTreeProps): ReactElement {\n const components = useTopologyComponents(core);\n const selection = useSelection(core);\n const viewState = useViewState(core);\n const diagnostics = useDiagnostics(core);\n const [collapsed, setCollapsed] = useState<ReadonlySet<string>>(new Set());\n\n // Rebuild the id->node map whenever the component set changes (which happens\n // on any graph change). `components` identity is the change signal.\n const nodeById = useMemo(() => {\n const m = new Map<NodeId, EditorNode>();\n for (const n of core.model.getNodes()) {\n m.set(n.id, n);\n }\n return m;\n // eslint-disable-next-line react-hooks/exhaustive-deps\n }, [core, components]);\n\n const toggleGroup = useCallback((id: string): void => {\n setCollapsed(prev => {\n const next = new Set(prev);\n if (next.has(id)) {\n next.delete(id);\n } else {\n next.add(id);\n }\n return next;\n });\n }, []);\n\n const select = useCallback(\n (id: NodeId): void => {\n selection.selectNodes([id], 'replace');\n onFocus?.(id);\n },\n [selection, onFocus],\n );\n\n if (components.length === 0) {\n return <p className=\"hl-outline-empty hl-mono\">no layers yet</p>;\n }\n\n // Order groups largest-first for a stable, sensible reading order.\n const groups = [...components].sort((a, b) => b.nodeIds.size - a.nodeIds.size);\n\n return (\n <div className=\"hl-outline\" role=\"tree\" aria-label=\"Outline\">\n {groups.map((group, gi) => {\n const members = [...group.nodeIds]\n .map(id => nodeById.get(id))\n .filter((n): n is EditorNode => n !== undefined);\n const open = !collapsed.has(group.id);\n const groupName = `Flow ${String(gi + 1)}`;\n return (\n <div key={group.id} className=\"hl-outline-group\" role=\"treeitem\" aria-expanded={open}>\n <button\n className=\"hl-outline-grouphead\"\n onClick={() => toggleGroup(group.id)}\n >\n <span className={'hl-outline-caret' + (open ? ' is-open' : '')} aria-hidden>\n ▸\n </span>\n <span className=\"hl-outline-groupname\">{groupName}</span>\n <span className=\"hl-outline-count hl-mono\">{group.nodeIds.size}</span>\n </button>\n {open && (\n <ul className=\"hl-outline-members\">\n {members.map(node => {\n const active = selection.isSelected(node.id);\n const isHidden = viewState.isHidden(node.id);\n const isLocked = viewState.isLocked(node.id);\n const { imageUrl } = node.params;\n const thumbnail = typeof imageUrl === 'string' && imageUrl.length > 0 ? imageUrl : undefined;\n return (\n <li key={node.id}>\n <div\n className={\n 'hl-outline-row' +\n (active ? ' is-active' : '') +\n (isHidden ? ' is-hidden' : '') +\n (isLocked ? ' is-locked' : '')\n }\n >\n <button className=\"hl-outline-main\" onClick={() => select(node.id)}>\n <span\n className={`hl-outline-icon hl-kind-${node.kind.toLowerCase()}`}\n aria-hidden\n >\n {thumbnail !== undefined ? (\n <img\n className=\"hl-outline-thumb\"\n src={thumbnail}\n alt=\"\"\n />\n ) : (\n <NodeIcon code={node.code} kind={node.kind} size={13} />\n )}\n </span>\n <span className=\"hl-outline-name\">{node.name}</span>\n {/* Edit-time diagnostic marker (error/warning). */}\n {(() => {\n const diag = diagnostics.worstOf(node.id);\n return diag === undefined ? null : (\n <DiagnosticBadge diagnostic={diag} variant=\"hl-outline-diag\" size={11} />\n );\n })()}\n {/* Persistent status glyphs: only shown when a flag is\n ON, so a hidden/locked layer stays legible at rest\n (not just on hover). */}\n {isLocked && (\n <span className=\"hl-outline-badge\" aria-hidden>\n <LockIcon size={11} />\n </span>\n )}\n {isHidden && (\n <span className=\"hl-outline-badge\" aria-hidden>\n <EyeOffIcon size={11} />\n </span>\n )}\n </button>\n <span className=\"hl-outline-controls\">\n <button\n className={'hl-outline-ctl' + (isHidden ? ' is-active-ctl' : '')}\n onClick={() => viewState.toggleHidden(node.id)}\n aria-label={isHidden ? 'Show layer' : 'Hide layer'}\n title={isHidden ? 'Show' : 'Hide'}\n >\n {isHidden ? <EyeOffIcon /> : <EyeIcon />}\n </button>\n <button\n className={'hl-outline-ctl' + (isLocked ? ' is-active-ctl' : '')}\n onClick={() => viewState.toggleLocked(node.id)}\n aria-label={isLocked ? 'Unlock layer' : 'Lock layer'}\n title={isLocked ? 'Unlock' : 'Lock'}\n >\n {isLocked ? <LockIcon /> : <UnlockIcon />}\n </button>\n </span>\n </div>\n </li>\n );\n })}\n </ul>\n )}\n </div>\n );\n })}\n </div>\n );\n}\n","/**\n * `PreviewPanel` — a framed preview of a result image. Generic: the host passes\n * an image URL + title (and optional status), and it renders a glass-framed\n * hero card. In the creator flow this is the \"output\" of the graph — the render\n * — completing the素材→intent→result narrative. editor-ui only draws it; what\n * the image IS (a render, a still, a mock) is the host's business.\n */\n\nimport type { ReactElement } from 'react';\nimport './PreviewPanel.css';\n\nexport interface PreviewPanelProps {\n readonly imageUrl?: string;\n readonly title?: string;\n readonly status?: string;\n}\n\nexport function PreviewPanel({ imageUrl, title = 'Preview', status }: PreviewPanelProps): ReactElement {\n return (\n <section className=\"hl-preview\" aria-label=\"Preview\">\n <div className=\"hl-preview-head\">\n <span className=\"hl-preview-title\">{title}</span>\n {status !== undefined && <span className=\"hl-preview-status hl-mono\">{status}</span>}\n </div>\n <div className=\"hl-preview-frame\">\n {imageUrl !== undefined && imageUrl.length > 0 ? (\n <img className=\"hl-preview-img\" src={imageUrl} alt={title} draggable={false} />\n ) : (\n <div className=\"hl-preview-placeholder hl-mono\">no output yet</div>\n )}\n </div>\n </section>\n );\n}\n","/**\n * `RailTabs` — the segmented tab strip at the top of a side rail (Outline /\n * Insert / Assets, nover-style), in the black/silver glass language. Purely\n * presentational and generic: the host supplies the tab ids/labels and owns the\n * active state, so this is an editor-ui primitive with no coupling to what the\n * tabs contain.\n */\n\nimport type { ReactElement } from 'react';\nimport './RailTabs.css';\n\nexport interface RailTab {\n readonly id: string;\n readonly label: string;\n}\n\nexport interface RailTabsProps {\n readonly tabs: readonly RailTab[];\n readonly active: string;\n readonly onChange: (id: string) => void;\n}\n\nexport function RailTabs({ tabs, active, onChange }: RailTabsProps): ReactElement {\n return (\n <div className=\"hl-railtabs\" role=\"tablist\">\n {tabs.map(tab => (\n <button\n key={tab.id}\n role=\"tab\"\n aria-selected={tab.id === active}\n className={'hl-railtab' + (tab.id === active ? ' is-active' : '')}\n onClick={() => onChange(tab.id)}\n >\n {tab.label}\n </button>\n ))}\n </div>\n );\n}\n","/**\n * `AssetGrid` — a thumbnail grid of render results / source images (the nover\n * \"Renders\" / \"Assets\" panel). Purely presentational: the host supplies image\n * URLs; clicking one calls back. editor-ui stays generic — an \"asset\" here is\n * just an image with an id, no media/model business concept.\n */\n\nimport type { ReactElement } from 'react';\nimport './AssetGrid.css';\n\nexport interface AssetItem {\n readonly id: string;\n readonly url: string;\n readonly label?: string;\n}\n\nexport interface AssetGridProps {\n readonly items: readonly AssetItem[];\n readonly onSelect?: (id: string) => void;\n /** Shown when there are no assets yet. */\n readonly emptyHint?: string;\n}\n\nexport function AssetGrid({ items, onSelect, emptyHint = 'No assets yet' }: AssetGridProps): ReactElement {\n if (items.length === 0) {\n return <p className=\"hl-assetgrid-empty hl-mono\">{emptyHint}</p>;\n }\n return (\n <div className=\"hl-assetgrid\">\n {items.map(item => (\n <button\n key={item.id}\n className=\"hl-assetgrid-cell\"\n onClick={() => onSelect?.(item.id)}\n title={item.label}\n >\n <img className=\"hl-assetgrid-img\" src={item.url} alt={item.label ?? ''} loading=\"lazy\" />\n </button>\n ))}\n </div>\n );\n}\n","/**\n * `PositionPanel` — the \"Position\" section of the inspector (nover-style): a\n * 3×2 align cluster, the selected node's X/Y, and a Pin toggle. Generic geometry\n * only — alignment/coordinates carry no media/model concept, so this belongs in\n * editor-ui. All moves go through the command service (undoable) via `useRename`-\n * style command execution; nothing mutates the model directly.\n *\n * With a single selected node it shows and edits that node's position. With\n * multiple, the align actions distribute them against their common bounding box.\n */\n\nimport { useCallback, useEffect, useReducer } from 'react';\nimport type { ReactElement } from 'react';\nimport type { EditorCore, EditorNode } from '@hlang-tech/editor-core';\nimport { MoveNodeCommand } from '@hlang-tech/editor-core';\nimport { useSelection } from '@hlang-tech/editor-react';\nimport './PositionPanel.css';\n\nexport interface PositionPanelProps {\n readonly core: EditorCore;\n /**\n * Optional LIVE position reader (canvas coords) for a node. A drag commits to\n * the model only on drag-stop, so to show X/Y updating DURING a drag the host\n * supplies the canvas's in-flight position (e.g. React Flow's node.position).\n * When omitted, the committed model position is shown. Keeping this a callback\n * means editor-ui never imports React Flow — the binding stays in the host.\n */\n readonly livePosition?: (id: string) => { x: number; y: number } | undefined;\n}\n\ntype Align = 'left' | 'hcenter' | 'right' | 'top' | 'vcenter' | 'bottom';\n\nfunction selectedNodes(core: EditorCore): EditorNode[] {\n const ids = core.selection.getSelectedNodes();\n const out: EditorNode[] = [];\n for (const id of ids) {\n const n = core.model.getNode(id);\n if (n !== undefined) {\n out.push(n);\n }\n }\n return out;\n}\n\nexport function PositionPanel({ core, livePosition }: PositionPanelProps): ReactElement {\n // Re-render on selection change (enabled-state) AND on node change — a drag\n // commits a MoveNodeCommand which emits `nodeChanged`. During a drag, the host\n // re-renders us every frame (its live node list updates), so reading\n // `livePosition` here reflects the in-flight position continuously.\n useSelection(core);\n const [, bump] = useReducer((n: number) => n + 1, 0);\n useEffect(() => {\n const kinds = ['nodeChanged', 'nodeAdded', 'nodeRemoved'] as const;\n const disposers = kinds.map(k => core.events.on(k, bump));\n return () => {\n for (const d of disposers) {\n d.dispose();\n }\n };\n }, [core]);\n\n const nodes = selectedNodes(core);\n const single = nodes.length === 1 ? nodes[0] : undefined;\n // The displayed position prefers the live canvas position (updates mid-drag),\n // falling back to the committed model position.\n const shownPos =\n single !== undefined ? (livePosition?.(single.id) ?? single.position) : undefined;\n\n const moveAll = useCallback(\n (fn: (n: EditorNode) => { x: number; y: number }): void => {\n const targets = selectedNodes(core);\n if (targets.length === 0) {\n return;\n }\n core.history.transact('Align', () => {\n for (const n of targets) {\n core.commands.execute(new MoveNodeCommand(n.id, fn(n)));\n }\n });\n },\n [core],\n );\n\n const align = useCallback(\n (kind: Align): void => {\n const targets = selectedNodes(core);\n if (targets.length === 0) {\n return;\n }\n const xs = targets.map(n => n.position.x);\n const ys = targets.map(n => n.position.y);\n const minX = Math.min(...xs);\n const maxX = Math.max(...xs);\n const minY = Math.min(...ys);\n const maxY = Math.max(...ys);\n const cx = (minX + maxX) / 2;\n const cy = (minY + maxY) / 2;\n moveAll(n => {\n switch (kind) {\n case 'left':\n return { x: minX, y: n.position.y };\n case 'hcenter':\n return { x: cx, y: n.position.y };\n case 'right':\n return { x: maxX, y: n.position.y };\n case 'top':\n return { x: n.position.x, y: minY };\n case 'vcenter':\n return { x: n.position.x, y: cy };\n case 'bottom':\n return { x: n.position.x, y: maxY };\n }\n });\n },\n [core, moveAll],\n );\n\n const setCoord = useCallback(\n (axis: 'x' | 'y', value: number): void => {\n if (single === undefined || Number.isNaN(value)) {\n return;\n }\n const next = axis === 'x' ? { x: value, y: single.position.y } : { x: single.position.x, y: value };\n core.commands.execute(new MoveNodeCommand(single.id, next));\n },\n [core, single],\n );\n\n const disabled = nodes.length === 0;\n const alignButtons: readonly { kind: Align; label: string; d: string }[] = [\n { kind: 'left', label: 'Align left', d: 'M5 4v16M9 8h8M9 16h5' },\n { kind: 'hcenter', label: 'Align centre', d: 'M12 4v16M8 9h8M9 15h6' },\n { kind: 'right', label: 'Align right', d: 'M19 4v16M7 8h8M12 16h3' },\n { kind: 'top', label: 'Align top', d: 'M4 5h16M8 9v8M16 9v5' },\n { kind: 'vcenter', label: 'Align middle', d: 'M4 12h16M9 8v8M15 9v6' },\n { kind: 'bottom', label: 'Align bottom', d: 'M4 19h16M8 7v8M16 12v3' },\n ];\n\n return (\n <section className=\"hl-position\">\n <h3 className=\"hl-position-title hl-mono\">Position</h3>\n <div className=\"hl-position-align\" role=\"group\" aria-label=\"Align\">\n {alignButtons.map(b => (\n <button\n key={b.kind}\n className=\"hl-position-alignbtn\"\n onClick={() => align(b.kind)}\n disabled={disabled}\n title={b.label}\n aria-label={b.label}\n >\n <svg width={16} height={16} viewBox=\"0 0 24 24\" fill=\"none\" stroke=\"currentColor\" strokeWidth={1.6} strokeLinecap=\"round\" strokeLinejoin=\"round\" aria-hidden>\n <path d={b.d} />\n </svg>\n </button>\n ))}\n </div>\n <div className=\"hl-position-coords\">\n <label className=\"hl-position-field\">\n <input\n type=\"number\"\n className=\"hl-position-input hl-mono\"\n value={shownPos !== undefined ? Math.round(shownPos.x) : ''}\n disabled={single === undefined}\n onChange={e => setCoord('x', Number(e.target.value))}\n aria-label=\"X position\"\n />\n <span className=\"hl-position-axis hl-mono\">X</span>\n </label>\n <label className=\"hl-position-field\">\n <input\n type=\"number\"\n className=\"hl-position-input hl-mono\"\n value={shownPos !== undefined ? Math.round(shownPos.y) : ''}\n disabled={single === undefined}\n onChange={e => setCoord('y', Number(e.target.value))}\n aria-label=\"Y position\"\n />\n <span className=\"hl-position-axis hl-mono\">Y</span>\n </label>\n </div>\n </section>\n );\n}\n","/**\n * `NodeSearch` — the floating command palette for creating nodes by fuzzy\n * search. Rendered when the controller is open; anchored at the trigger point.\n *\n * Presentation only: it owns the query string, keyboard navigation, and match\n * highlighting, and delegates ranking + creation to the `NodeSearchController`.\n * Deep-space glass panel, electric-blue accent, kind-tinted result chips.\n */\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport type { ReactElement, KeyboardEvent } from 'react';\nimport type { NodeSearchController, NodeSearchResultView } from './useNodeSearch';\nimport type { FuzzyMatch } from './fuzzy';\nimport './NodeSearch.css';\n\n/** Panel width, used to keep the panel on-screen near the right/bottom edges. */\nconst PANEL_WIDTH = 320;\nconst PANEL_MAX_HEIGHT = 360;\n\nexport interface NodeSearchProps {\n readonly controller: NodeSearchController;\n}\n\nexport function NodeSearch({ controller }: NodeSearchProps): ReactElement | null {\n const { state } = controller;\n const [query, setQuery] = useState('');\n const [active, setActive] = useState(0);\n const inputRef = useRef<HTMLInputElement>(null);\n\n // Reset the query and focus the input each time the palette opens.\n const isOpen = state !== undefined;\n useEffect(() => {\n if (isOpen) {\n setQuery('');\n setActive(0);\n inputRef.current?.focus();\n }\n }, [isOpen]);\n\n const results = useMemo(\n () => (state !== undefined ? controller.results(query) : []),\n [controller, state, query],\n );\n\n // Keep the active index within bounds as results shrink/grow.\n const clampedActive = results.length === 0 ? 0 : Math.min(active, results.length - 1);\n\n const choose = useCallback(\n (view: NodeSearchResultView | undefined): void => {\n if (view !== undefined) {\n controller.commit(view);\n }\n },\n [controller],\n );\n\n const onKeyDown = useCallback(\n (event: KeyboardEvent<HTMLInputElement>): void => {\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n setActive(i => (results.length === 0 ? 0 : (i + 1) % results.length));\n break;\n case 'ArrowUp':\n event.preventDefault();\n setActive(i => (results.length === 0 ? 0 : (i - 1 + results.length) % results.length));\n break;\n case 'Enter':\n event.preventDefault();\n choose(results[clampedActive]);\n break;\n case 'Escape':\n event.preventDefault();\n controller.close();\n break;\n default:\n break;\n }\n },\n [results, clampedActive, choose, controller],\n );\n\n if (state === undefined) {\n return null;\n }\n\n const style = clampToViewport(state.screen.x, state.screen.y);\n const connectMode = state.pending !== undefined;\n\n return (\n <>\n <div\n className=\"hl-node-search-scrim\"\n onPointerDown={() => {\n controller.close();\n }}\n />\n <div className=\"hl-node-search\" style={style} role=\"dialog\" aria-label=\"Create node\">\n <div className=\"hl-node-search-field\">\n <span className=\"hl-node-search-glyph\" aria-hidden>\n {connectMode ? '⤳' : '+'}\n </span>\n <input\n ref={inputRef}\n className=\"hl-node-search-input\"\n value={query}\n placeholder={connectMode ? 'connect to…' : 'search nodes…'}\n onChange={e => {\n setQuery(e.target.value);\n setActive(0);\n }}\n onKeyDown={onKeyDown}\n aria-label=\"Search nodes\"\n autoComplete=\"off\"\n spellCheck={false}\n />\n </div>\n <ul className=\"hl-node-search-list\" role=\"listbox\">\n {results.length === 0 && (\n <li className=\"hl-node-search-empty hl-mono\">no matching nodes</li>\n )}\n {results.map((view, index) => {\n const descriptor = view.result.value;\n const kind = descriptor.kind;\n return (\n <li\n key={descriptor.code}\n role=\"option\"\n aria-selected={index === clampedActive}\n className={\n 'hl-node-search-item' + (index === clampedActive ? ' is-active' : '')\n }\n onPointerEnter={() => setActive(index)}\n onPointerDown={e => {\n e.preventDefault();\n choose(view);\n }}\n >\n <span\n className={`hl-node-search-kind hl-mono hl-kind-${kind.toLowerCase()}`}\n >\n {kind}\n </span>\n <span className=\"hl-node-search-label\">\n {highlight(descriptor.displayName, view.result.match)}\n </span>\n {view.connectPortId !== undefined && (\n <span className=\"hl-node-search-port hl-mono\">{view.connectPortId}</span>\n )}\n </li>\n );\n })}\n </ul>\n </div>\n </>\n );\n}\n\n/** Render a label with the fuzzy-matched characters emphasized. */\nfunction highlight(text: string, match: FuzzyMatch): readonly ReactElement[] {\n const hit = new Set(match.positions);\n const chars = Array.from(text);\n return chars.map((ch, i) =>\n hit.has(i) ? (\n <mark key={i} className=\"hl-node-search-hit\">\n {ch}\n </mark>\n ) : (\n <span key={i}>{ch}</span>\n ),\n );\n}\n\n/** Keep the panel within the viewport when opened near an edge. */\nfunction clampToViewport(x: number, y: number): { left: number; top: number } {\n const maxLeft = Math.max(8, window.innerWidth - PANEL_WIDTH - 8);\n const maxTop = Math.max(8, window.innerHeight - PANEL_MAX_HEIGHT - 8);\n return {\n left: Math.min(Math.max(8, x), maxLeft),\n top: Math.min(Math.max(8, y), maxTop),\n };\n}\n","/**\n * `useNodeSearch` — palette state + commit logic for creating nodes by search.\n *\n * The palette can open in two modes:\n * - blank: create a free-standing node at a point (canvas double-click, `/`).\n * - from a released connection: create a node AND wire the dangling link to a\n * compatible port on it, as ONE undoable step.\n *\n * All mutation goes through the core command service; connection legality and\n * edge ids come from the core (validator + id generator). This hook holds no\n * graph rules of its own.\n */\n\nimport { useCallback, useMemo, useState } from 'react';\nimport type { EditorCore, NodeDescriptor, Point } from '@hlang-tech/editor-core';\nimport { AddNodeCommand, ConnectCommand } from '@hlang-tech/editor-core';\nimport {\n searchNodes,\n connectableCandidates,\n} from './node-search-model';\nimport type {\n PendingConnection,\n NodeSearchResult,\n} from './node-search-model';\n\n/** Where and how the palette is currently open. */\nexport interface NodeSearchState {\n /** Screen-space anchor for rendering the floating panel. */\n readonly screen: Point;\n /** Flow-space position where the created node will be placed. */\n readonly flow: Point;\n /** Set when opened by releasing a dangling connection. */\n readonly pending?: PendingConnection;\n}\n\n/** The palette controller returned by the hook. */\nexport interface NodeSearchController {\n /** Current open state, or `undefined` when closed. */\n readonly state: NodeSearchState | undefined;\n /** Open the palette to create a free-standing node. */\n openBlank(screen: Point, flow: Point): void;\n /** Open the palette to complete a released connection. */\n openFromConnection(screen: Point, flow: Point, pending: PendingConnection): void;\n /** Close the palette without creating anything. */\n close(): void;\n /**\n * Rank registry descriptors for the current query and open mode. In blank\n * mode every node is offered; in connection mode only nodes that can legally\n * complete the pending link are offered.\n */\n results(query: string): readonly NodeSearchResultView[];\n /** Create the chosen node (and wire the pending link, if any), then close. */\n commit(result: NodeSearchResultView): void;\n}\n\n/**\n * A ranked result as the palette renders it: the fuzzy match plus, in\n * connection mode, the port on the new node that completes the link.\n */\nexport interface NodeSearchResultView {\n readonly result: NodeSearchResult;\n /** Present only in connection mode. */\n readonly connectPortId?: string;\n}\n\nexport function useNodeSearch(core: EditorCore): NodeSearchController {\n const [state, setState] = useState<NodeSearchState | undefined>(undefined);\n\n const openBlank = useCallback((screen: Point, flow: Point): void => {\n setState({ screen, flow });\n }, []);\n\n const openFromConnection = useCallback(\n (screen: Point, flow: Point, pending: PendingConnection): void => {\n setState({ screen, flow, pending });\n },\n [],\n );\n\n const close = useCallback((): void => {\n setState(undefined);\n }, []);\n\n const descriptors = core.registry.list();\n\n const results = useCallback(\n (query: string): readonly NodeSearchResultView[] => {\n if (state?.pending !== undefined) {\n return connectableCandidates(\n query,\n descriptors,\n state.pending,\n core.validator,\n ).map(entry => ({ result: entry.candidate, connectPortId: entry.connectPortId }));\n }\n return searchNodes(query, descriptors).map(result => ({ result }));\n },\n [state, descriptors, core],\n );\n\n const commit = useCallback(\n (view: NodeSearchResultView): void => {\n if (state === undefined) {\n return;\n }\n const descriptor: NodeDescriptor = view.result.value;\n const node = core.registry.createNode(descriptor.code, state.flow);\n\n if (state.pending !== undefined && view.connectPortId !== undefined) {\n const pending = state.pending;\n const connectPortId = view.connectPortId;\n // Create the node and wire the released link as one undoable step.\n core.history.transact('Create & Connect Node', () => {\n core.commands.execute(new AddNodeCommand(node));\n const edgeId = core.idGenerator.nextEdgeId();\n const newEndpoint = { nodeId: node.id, portId: connectPortId };\n const [source, target] =\n pending.direction === 'from-source'\n ? [pending.fromEndpoint, newEndpoint]\n : [newEndpoint, pending.fromEndpoint];\n core.commands.execute(new ConnectCommand(edgeId, source, target));\n });\n } else {\n core.commands.execute(new AddNodeCommand(node));\n }\n setState(undefined);\n },\n [state, core],\n );\n\n return useMemo(\n () => ({ state, openBlank, openFromConnection, close, results, commit }),\n [state, openBlank, openFromConnection, close, results, commit],\n );\n}\n","/**\n * Small, dependency-free fuzzy matcher for the node search palette. Pure\n * functions — the only logic in editor-ui that carries its own unit tests\n * (behavior, not pixels). Ranks candidates by subsequence match quality:\n * contiguous and word-boundary matches score higher, earlier matches score\n * higher, shorter targets break ties.\n */\n\n/** A scored match with the matched character positions (for highlighting). */\nexport interface FuzzyMatch {\n readonly score: number;\n readonly positions: readonly number[];\n}\n\n/**\n * Score `query` against `target` as a case-insensitive subsequence match.\n * Returns `null` when `target` does not contain `query` as a subsequence.\n * An empty query matches everything with score 0 (stable, no reordering).\n */\nexport function fuzzyScore(query: string, target: string): FuzzyMatch | null {\n if (query.length === 0) {\n return { score: 0, positions: [] };\n }\n const q = query.toLowerCase();\n const t = target.toLowerCase();\n\n const positions: number[] = [];\n let score = 0;\n let qi = 0;\n let prevMatch = -2;\n\n for (let ti = 0; ti < t.length && qi < q.length; ti += 1) {\n if (t[ti] !== q[qi]) {\n continue;\n }\n positions.push(ti);\n\n // Base point for a matched character.\n let point = 1;\n // Contiguous with the previous matched char.\n if (ti === prevMatch + 1) {\n point += 3;\n }\n // At a word boundary (start, or after a separator / camelCase hump).\n if (ti === 0 || isBoundary(target, ti)) {\n point += 2;\n }\n // Earlier matches are slightly preferred.\n point += Math.max(0, 2 - ti * 0.05);\n\n score += point;\n prevMatch = ti;\n qi += 1;\n }\n\n if (qi < q.length) {\n return null; // not a full subsequence\n }\n\n // Prefer shorter targets when scores are otherwise close.\n score -= target.length * 0.01;\n return { score, positions };\n}\n\nfunction isBoundary(target: string, index: number): boolean {\n const prev = target[index - 1];\n const cur = target[index];\n if (prev === undefined || cur === undefined) {\n return false;\n }\n const isSep = /[\\s\\-_./]/.test(prev);\n const isCamel = prev === prev.toLowerCase() && cur === cur.toUpperCase();\n return isSep || isCamel;\n}\n\n/** A candidate to rank, carrying an opaque payload of type `T`. */\nexport interface FuzzyCandidate<T> {\n readonly text: string;\n readonly value: T;\n}\n\n/** A ranked result: the candidate plus its match. */\nexport interface FuzzyResult<T> {\n readonly value: T;\n readonly text: string;\n readonly match: FuzzyMatch;\n}\n\n/**\n * Rank candidates against a query, best first. Non-matching candidates are\n * dropped. With an empty query, candidates are returned in their original order.\n */\nexport function fuzzyRank<T>(\n query: string,\n candidates: readonly FuzzyCandidate<T>[],\n): readonly FuzzyResult<T>[] {\n const results: FuzzyResult<T>[] = [];\n for (const candidate of candidates) {\n const match = fuzzyScore(query, candidate.text);\n if (match !== null) {\n results.push({ value: candidate.value, text: candidate.text, match });\n }\n }\n if (query.length === 0) {\n return results;\n }\n return results.sort((a, b) => b.match.score - a.match.score);\n}\n","/**\n * Pure model behind the node-search palette. No React, no DOM.\n *\n * Two responsibilities:\n * 1. Turn the design-time registry into fuzzy-searchable candidates and rank\n * them against a query (`descriptorCandidates` + `searchNodes`).\n * 2. When the palette is opened by releasing a dangling connection into empty\n * space, offer ONLY nodes that can legally complete that connection, and\n * remember which port on each closes it (`connectableCandidates`). The\n * legality decision is delegated to the core `IConnectionValidator` — this\n * module never re-encodes hlang's connection rules.\n */\n\nimport type {\n NodeDescriptor,\n PortDescriptor,\n Endpoint,\n IConnectionValidator,\n} from '@hlang-tech/editor-core';\nimport { fuzzyRank } from './fuzzy';\nimport type { FuzzyCandidate, FuzzyResult } from './fuzzy';\n\n/** A registry descriptor made searchable, keyed by its display name. */\nexport type NodeCandidate = FuzzyCandidate<NodeDescriptor>;\n\n/** A ranked search result carrying the matched descriptor. */\nexport type NodeSearchResult = FuzzyResult<NodeDescriptor>;\n\n/** Build fuzzy candidates from registry descriptors (display-name keyed). */\nexport function descriptorCandidates(\n descriptors: readonly NodeDescriptor[],\n): readonly NodeCandidate[] {\n return descriptors.map(descriptor => ({ text: descriptor.displayName, value: descriptor }));\n}\n\n/** Rank descriptors against `query`, best first (empty query keeps order). */\nexport function searchNodes(\n query: string,\n descriptors: readonly NodeDescriptor[],\n): readonly NodeSearchResult[] {\n return fuzzyRank(query, descriptorCandidates(descriptors));\n}\n\n/**\n * A connection left dangling in empty space. `fromEndpoint` is the port the\n * user dragged from and `fromPort` its resolved descriptor; `direction` says\n * whether that endpoint is the connection's source (an output, needing a\n * target) or its target (an input, needing a source). The palette will create a\n * node and wire the missing side.\n */\nexport interface PendingConnection {\n readonly fromEndpoint: Endpoint;\n /** Descriptor of the port the drag started from (resolved from the model). */\n readonly fromPort: PortDescriptor;\n readonly direction: 'from-source' | 'from-target';\n}\n\n/**\n * A search result augmented with the specific port on the candidate node that\n * would complete a pending connection.\n */\nexport interface ConnectableResult {\n readonly candidate: NodeSearchResult;\n /** The port id on the (future) new node that closes the connection. */\n readonly connectPortId: string;\n}\n\n/**\n * Filter and rank descriptors to those that can legally complete `pending`,\n * annotating each with the completing port. Legality is decided by the core\n * validator's model-free `canLink` (direction + DTO): for a dangling source we\n * ask canLink(danglingSource, candidatePort); for a dangling target we ask\n * canLink(candidatePort, danglingTarget). No graph model is consulted, because\n * the candidate node does not exist yet — legality here is purely a property of\n * the two ports.\n */\nexport function connectableCandidates(\n query: string,\n descriptors: readonly NodeDescriptor[],\n pending: PendingConnection,\n validator: Pick<IConnectionValidator, 'canLink'>,\n): readonly ConnectableResult[] {\n const ranked = searchNodes(query, descriptors);\n const out: ConnectableResult[] = [];\n\n for (const result of ranked) {\n const port = firstCompletingPort(result.value.ports, pending, validator);\n if (port !== undefined) {\n out.push({ candidate: result, connectPortId: port });\n }\n }\n return out;\n}\n\n/**\n * Find the first port on `ports` that legally completes `pending`, or\n * `undefined` if none do. For a dangling source (output) we look for an input\n * on the candidate; for a dangling target (input), an output.\n */\nfunction firstCompletingPort(\n ports: readonly PortDescriptor[],\n pending: PendingConnection,\n validator: Pick<IConnectionValidator, 'canLink'>,\n): string | undefined {\n for (const port of ports) {\n const ok =\n pending.direction === 'from-source'\n ? validator.canLink(pending.fromPort, port).ok\n : validator.canLink(port, pending.fromPort).ok;\n if (ok) {\n return port.id;\n }\n }\n return undefined;\n}\n","/**\n * `useNodeSearchTriggers` — bridge React Flow gestures to the node-search\n * palette. Returns handlers to spread onto `<ReactFlow>`:\n *\n * - `onConnectStart` / `onConnectEnd`: when a link is dragged from a port and\n * released into empty space (not onto a handle), open the palette pre-filtered\n * to nodes that can complete that connection.\n * - `onPaneClick`: two clicks on the empty pane within `doubleClickMs` open a\n * blank palette. We use React Flow's first-class `onPaneClick` (which fires\n * only for the pane, never for nodes/edges/handles) rather than a raw DOM\n * double-click, so this never reaches into React Flow's internal markup.\n *\n * Screen→flow coordinate conversion uses the React Flow instance, so created\n * nodes land under the pointer regardless of pan/zoom. This hook must be used\n * within a `ReactFlowProvider` (React Flow's own requirement for `useReactFlow`).\n */\n\nimport { useCallback, useRef } from 'react';\nimport { useReactFlow } from '@xyflow/react';\nimport type { OnConnectStartParams } from '@xyflow/react';\nimport type { EditorCore, PortDescriptor } from '@hlang-tech/editor-core';\nimport type { NodeSearchController } from './useNodeSearch';\nimport type { PendingConnection } from './node-search-model';\n\n/** Max gap between two pane clicks to count as a double-click. */\nconst DEFAULT_DOUBLE_CLICK_MS = 350;\n\n/** Options for the trigger hook (injectable clock keeps it deterministic). */\nexport interface NodeSearchTriggerOptions {\n /** Double-click detection window in ms. Defaults to 350. */\n readonly doubleClickMs?: number;\n /** Monotonic clock in ms. Defaults to `performance.now`. */\n readonly now?: () => number;\n}\n\n/** Where a pointer is, as mouse events (DOM and React) report it. */\nexport interface PointerPosition {\n readonly clientX: number;\n readonly clientY: number;\n}\n\n/** Where touches ended, as touch events report it. */\nexport interface TouchPositions {\n readonly changedTouches: ArrayLike<PointerPosition>;\n}\n\n/** How a connection drag ended: on a node, or (`toNode: null`) in empty space. */\nexport interface ConnectionEnd {\n readonly toNode: object | null;\n}\n\n/**\n * Handlers to spread onto the `<ReactFlow>` element. Each declares only what it\n * reads, so React Flow's full events and states fit them.\n */\nexport interface NodeSearchTriggers {\n readonly onConnectStart: (event: unknown, params: OnConnectStartParams) => void;\n readonly onConnectEnd: (event: PointerPosition | TouchPositions, connectionState: ConnectionEnd) => void;\n /** Attach to `<ReactFlow onPaneClick>`; a rapid second click opens the palette. */\n readonly onPaneClick: (event: PointerPosition) => void;\n}\n\nexport function useNodeSearchTriggers(\n core: EditorCore,\n search: NodeSearchController,\n options: NodeSearchTriggerOptions = {},\n): NodeSearchTriggers {\n const flow = useReactFlow();\n const doubleClickMs = options.doubleClickMs ?? DEFAULT_DOUBLE_CLICK_MS;\n const now = options.now ?? defaultNow;\n\n // Remember the endpoint a connection drag started from, so connect-end can\n // build the pending connection when it lands in empty space.\n const startRef = useRef<OnConnectStartParams | null>(null);\n // Timestamp of the last pane click, for double-click detection.\n const lastPaneClickRef = useRef<number>(Number.NEGATIVE_INFINITY);\n\n const onConnectStart = useCallback((_event: unknown, params: OnConnectStartParams): void => {\n startRef.current = params;\n }, []);\n\n const onConnectEnd = useCallback(\n (event: PointerPosition | TouchPositions, connectionState: ConnectionEnd): void => {\n const start = startRef.current;\n startRef.current = null;\n // Only act when the drag ended in empty space (no destination node/handle).\n if (connectionState.toNode !== null || start === null) {\n return;\n }\n if (start.nodeId === null || start.handleId === null || start.handleType === null) {\n return;\n }\n const point = pointerOf(event);\n if (point === null) {\n return;\n }\n // Resolve the descriptor of the port the drag started from; the palette\n // needs it to decide which node types can complete the connection.\n const fromPort = resolvePort(core, start.nodeId, start.handleId);\n if (fromPort === undefined) {\n return;\n }\n const pending: PendingConnection = {\n fromEndpoint: { nodeId: start.nodeId, portId: start.handleId },\n fromPort,\n // A drag from a 'source' (output) handle needs a target node; a drag\n // from a 'target' (input) handle needs a source node.\n direction: start.handleType === 'source' ? 'from-source' : 'from-target',\n };\n search.openFromConnection(\n point,\n flow.screenToFlowPosition(point),\n pending,\n );\n },\n [core, flow, search],\n );\n\n const onPaneClick = useCallback(\n (event: PointerPosition): void => {\n const t = now();\n const isDouble = t - lastPaneClickRef.current <= doubleClickMs;\n lastPaneClickRef.current = t;\n if (!isDouble) {\n return;\n }\n lastPaneClickRef.current = Number.NEGATIVE_INFINITY; // consume the pair\n const screen = { x: event.clientX, y: event.clientY };\n search.openBlank(screen, flow.screenToFlowPosition(screen));\n },\n [flow, search, doubleClickMs, now],\n );\n\n return { onConnectStart, onConnectEnd, onPaneClick };\n}\n\nfunction defaultNow(): number {\n return performance.now();\n}\n\n/** Resolve a port descriptor by node id + port id from the graph model. */\nfunction resolvePort(\n core: EditorCore,\n nodeId: string,\n portId: string,\n): PortDescriptor | undefined {\n const node = core.model.getNode(nodeId);\n return node?.ports.find(port => port.id === portId);\n}\n\n/** Extract client pointer coords from a mouse or touch connect-end event. */\nfunction pointerOf(event: PointerPosition | TouchPositions): { x: number; y: number } | null {\n if ('clientX' in event) {\n return { x: event.clientX, y: event.clientY };\n }\n const touch = event.changedTouches[0];\n return touch ? { x: touch.clientX, y: touch.clientY } : null;\n}\n","/**\n * `useEditorHotkeys` — global keyboard shortcuts for the editor canvas:\n *\n * ⌘/Ctrl+Z undo ⌘/Ctrl+Shift+Z, ⌘/Ctrl+Y redo\n * ⌘/Ctrl+C copy ⌘/Ctrl+V paste ⌘/Ctrl+X cut ⌘/Ctrl+D duplicate\n * Delete / Backspace delete\n *\n * Clipboard actions run through `useClipboard`; undo/redo drive the history\n * service. Every action is a proper command, so it is itself undoable. The\n * listener is on `window` but SUPPRESSED while a text input / textarea /\n * contenteditable is focused, so typing never triggers a canvas action.\n *\n * When the editor is one part of a larger page, pass `scope`: shortcuts then\n * fire only for keystrokes whose target is inside that element, and every other\n * keystroke (copying page text, Backspace in a page control) is left untouched.\n */\n\nimport { useEffect } from 'react';\nimport type { RefObject } from 'react';\nimport type { EditorCore } from '@hlang-tech/editor-core';\nimport { useClipboard } from '@hlang-tech/editor-react';\n\n/** True when focus is in an editable field, where shortcuts must NOT fire. */\nexport function isEditableTarget(target: EventTarget | null): boolean {\n if (!(target instanceof HTMLElement)) {\n return false;\n }\n const tag = target.tagName;\n return tag === 'INPUT' || tag === 'TEXTAREA' || target.isContentEditable;\n}\n\nexport interface EditorHotkeysOptions {\n /**\n * The element that owns the shortcuts. When given, only keystrokes whose\n * target is inside it are handled; while it is not mounted, none are.\n * Omit it when the editor fills the page.\n */\n readonly scope?: RefObject<HTMLElement | null>;\n}\n\n/** True when `scope` is unset, or when the event's target is inside it. */\nfunction withinScope(target: EventTarget | null, scope: EditorHotkeysOptions['scope']): boolean {\n if (scope === undefined) {\n return true;\n }\n const root = scope.current;\n return root !== null && target instanceof Node && root.contains(target);\n}\n\nexport function useEditorHotkeys(core: EditorCore, options: EditorHotkeysOptions = {}): void {\n const clipboard = useClipboard(core);\n const { scope } = options;\n\n useEffect(() => {\n const onKeyDown = (event: KeyboardEvent): void => {\n if (!withinScope(event.target, scope) || isEditableTarget(event.target)) {\n return;\n }\n const mod = event.metaKey || event.ctrlKey;\n\n // Undo / redo. Redo accepts ⌘⇧Z (Mac) and ⌘Y (Windows) conventions.\n if (mod && !event.altKey) {\n const key = event.key.toLowerCase();\n if (key === 'z' && !event.shiftKey) {\n event.preventDefault();\n core.history.undo();\n return;\n }\n if ((key === 'z' && event.shiftKey) || key === 'y') {\n event.preventDefault();\n core.history.redo();\n return;\n }\n }\n\n if (mod && !event.shiftKey && !event.altKey) {\n const key = event.key.toLowerCase();\n if (key === 'c') {\n event.preventDefault();\n clipboard.copy();\n return;\n }\n if (key === 'x') {\n event.preventDefault();\n clipboard.cut();\n return;\n }\n if (key === 'v') {\n event.preventDefault();\n clipboard.paste();\n return;\n }\n if (key === 'd') {\n event.preventDefault();\n clipboard.duplicate();\n return;\n }\n if (key === 'a') {\n // Select all nodes. Going through core.selection reflects onto the\n // canvas via the derived `selected` flag + selectionChanged reconcile.\n event.preventDefault();\n core.selection.selectNodes(\n core.model.getNodes().map(n => n.id),\n 'replace',\n );\n return;\n }\n }\n\n if (event.key === 'Delete' || event.key === 'Backspace') {\n event.preventDefault();\n clipboard.remove();\n }\n };\n\n window.addEventListener('keydown', onKeyDown);\n return (): void => {\n window.removeEventListener('keydown', onKeyDown);\n };\n }, [core, clipboard, scope]);\n}\n","/**\n * `NodeContextMenu` — the right-click menu for a node. A black/silver glass\n * panel matching the command palette's material and dismissal, listing actions\n * the consumer supplies (duplicate/copy/cut/paste/delete/hide/lock). Presentation\n * only: each item carries its own `onSelect`; this component owns positioning,\n * keyboard navigation, and dismissal.\n */\n\nimport { useCallback, useEffect, useMemo, useRef, useState } from 'react';\nimport type { ReactElement, ReactNode, KeyboardEvent } from 'react';\nimport type { NodeContextMenuController } from './useNodeContextMenu';\nimport './NodeContextMenu.css';\n\nconst PANEL_WIDTH = 208;\nconst ITEM_HEIGHT = 34;\n/** Keep the menu this many px inside each viewport edge. */\nconst VIEWPORT_MARGIN = 8;\n/** Extra vertical padding added to the estimated menu height. */\nconst MENU_VPAD = 12;\n\n/** One menu row. A separator is a bare `{ separator: true }`. */\nexport interface ContextMenuItem {\n readonly id: string;\n readonly label: string;\n /** Optional keyboard-shortcut hint shown right-aligned (e.g. \"⌘D\"). */\n readonly shortcut?: string;\n /** Optional leading glyph. */\n readonly icon?: ReactNode;\n /** Destructive styling (e.g. Delete). */\n readonly danger?: boolean;\n /** Disabled rows are shown dim and are not selectable. */\n readonly disabled?: boolean;\n readonly onSelect: () => void;\n}\n\nexport interface NodeContextMenuProps {\n readonly controller: NodeContextMenuController;\n /** Build the items for the targeted node id (recomputed on open). */\n readonly items: (nodeId: string) => readonly ContextMenuItem[];\n}\n\nexport function NodeContextMenu({ controller, items }: NodeContextMenuProps): ReactElement | null {\n const { state } = controller;\n const [active, setActive] = useState(0);\n const menuRef = useRef<HTMLDivElement>(null);\n\n const isOpen = state !== undefined;\n useEffect(() => {\n if (isOpen) {\n setActive(0);\n menuRef.current?.focus();\n }\n }, [isOpen]);\n\n const rows = useMemo(\n () => (state !== undefined ? items(state.nodeId) : []),\n [items, state],\n );\n\n // Indices that can actually be selected (skip disabled rows).\n const enabledIndices = useMemo(\n () => rows.map((r, i) => (r.disabled ? -1 : i)).filter(i => i >= 0),\n [rows],\n );\n\n const move = useCallback(\n (delta: number): void => {\n if (enabledIndices.length === 0) {\n return;\n }\n setActive(current => {\n const pos = enabledIndices.indexOf(current);\n const nextPos =\n pos === -1\n ? 0\n : (pos + delta + enabledIndices.length) % enabledIndices.length;\n return enabledIndices[nextPos] ?? current;\n });\n },\n [enabledIndices],\n );\n\n const choose = useCallback(\n (item: ContextMenuItem | undefined): void => {\n if (item === undefined || item.disabled) {\n return;\n }\n item.onSelect();\n controller.close();\n },\n [controller],\n );\n\n const onKeyDown = useCallback(\n (event: KeyboardEvent<HTMLDivElement>): void => {\n switch (event.key) {\n case 'ArrowDown':\n event.preventDefault();\n move(1);\n break;\n case 'ArrowUp':\n event.preventDefault();\n move(-1);\n break;\n case 'Enter':\n event.preventDefault();\n choose(rows[active]);\n break;\n case 'Escape':\n event.preventDefault();\n controller.close();\n break;\n default:\n break;\n }\n },\n [move, choose, rows, active, controller],\n );\n\n if (state === undefined) {\n return null;\n }\n\n const style = clampToViewport(state.screen.x, state.screen.y, rows.length);\n\n return (\n <>\n <div\n className=\"hl-ctx-scrim\"\n onPointerDown={() => {\n controller.close();\n }}\n onContextMenu={e => {\n // A right-click on the scrim dismisses rather than opening the OS menu.\n e.preventDefault();\n controller.close();\n }}\n />\n <div\n ref={menuRef}\n className=\"hl-ctx-menu\"\n style={style}\n role=\"menu\"\n aria-label=\"Node actions\"\n tabIndex={-1}\n onKeyDown={onKeyDown}\n >\n {rows.map((item, index) => (\n <button\n key={item.id}\n type=\"button\"\n role=\"menuitem\"\n disabled={item.disabled}\n className={\n 'hl-ctx-item' +\n (item.danger === true ? ' is-danger' : '') +\n (index === active ? ' is-active' : '')\n }\n onPointerEnter={() => !item.disabled && setActive(index)}\n onPointerDown={e => {\n e.preventDefault();\n choose(item);\n }}\n >\n <span className=\"hl-ctx-item-icon\" aria-hidden>\n {item.icon}\n </span>\n <span className=\"hl-ctx-item-label\">{item.label}</span>\n {item.shortcut !== undefined && (\n <span className=\"hl-ctx-item-key hl-mono\">{item.shortcut}</span>\n )}\n </button>\n ))}\n </div>\n </>\n );\n}\n\n/** Keep the menu within the viewport near an edge. */\nfunction clampToViewport(x: number, y: number, rowCount: number): { left: number; top: number } {\n const height = Math.max(ITEM_HEIGHT, rowCount * ITEM_HEIGHT + MENU_VPAD);\n const maxLeft = Math.max(VIEWPORT_MARGIN, window.innerWidth - PANEL_WIDTH - VIEWPORT_MARGIN);\n const maxTop = Math.max(VIEWPORT_MARGIN, window.innerHeight - height - VIEWPORT_MARGIN);\n return {\n left: Math.min(Math.max(VIEWPORT_MARGIN, x), maxLeft),\n top: Math.min(Math.max(VIEWPORT_MARGIN, y), maxTop),\n };\n}\n","/**\n * `useNodeContextMenu` — controller for the right-click node menu. Holds only\n * where the menu is open and which node it targets; the menu ITEMS (labels,\n * shortcuts, actions) are assembled by the consumer from clipboard/view-state\n * actions, so this hook carries no graph rules.\n */\n\nimport { useCallback, useMemo, useState } from 'react';\nimport type { NodeId, Point } from '@hlang-tech/editor-core';\n\n/** Where the menu is open and which node it targets. */\nexport interface NodeContextMenuState {\n /** Screen-space anchor (the click point). */\n readonly screen: Point;\n /** The node the menu acts on. */\n readonly nodeId: NodeId;\n}\n\nexport interface NodeContextMenuController {\n readonly state: NodeContextMenuState | undefined;\n /** Open the menu for a node at a screen point. */\n openForNode(screen: Point, nodeId: NodeId): void;\n close(): void;\n}\n\nexport function useNodeContextMenu(): NodeContextMenuController {\n const [state, setState] = useState<NodeContextMenuState | undefined>(undefined);\n\n const openForNode = useCallback((screen: Point, nodeId: NodeId): void => {\n setState({ screen, nodeId });\n }, []);\n\n const close = useCallback((): void => {\n setState(undefined);\n }, []);\n\n return useMemo(() => ({ state, openForNode, close }), [state, openForNode, close]);\n}\n","/**\n * `Cheatsheet` — a keyboard-shortcut reference in the black/silver glass\n * language. Toggled by the host (typically the `?` key). Presentation only: it\n * takes an `open` flag and an `onClose`, and renders a grouped list of the\n * editor's shortcuts so they are discoverable, not memorized.\n */\n\nimport { useEffect, useRef } from 'react';\nimport type { ReactElement } from 'react';\nimport './Cheatsheet.css';\n\nexport interface ShortcutRow {\n readonly keys: string;\n readonly label: string;\n}\nexport interface ShortcutGroup {\n readonly title: string;\n readonly rows: readonly ShortcutRow[];\n}\n\nexport interface CheatsheetProps {\n readonly open: boolean;\n readonly onClose: () => void;\n /** Groups to display; a sensible default set is used when omitted. */\n readonly groups?: readonly ShortcutGroup[];\n}\n\nconst DEFAULT_GROUPS: readonly ShortcutGroup[] = [\n {\n title: 'Edit',\n rows: [\n { keys: '⌘Z', label: 'Undo' },\n { keys: '⌘⇧Z / ⌘Y', label: 'Redo' },\n { keys: '⌘C', label: 'Copy' },\n { keys: '⌘X', label: 'Cut' },\n { keys: '⌘V', label: 'Paste (at cursor)' },\n { keys: '⌘D', label: 'Duplicate' },\n { keys: '⌫', label: 'Delete' },\n ],\n },\n {\n title: 'Select & navigate',\n rows: [\n { keys: '⌘A', label: 'Select all' },\n { keys: 'Drag', label: 'Box-select (left drag)' },\n { keys: 'Middle / Right drag', label: 'Pan' },\n { keys: 'Space + drag', label: 'Pan' },\n { keys: 'Double-click name', label: 'Rename node' },\n ],\n },\n {\n title: 'Build',\n rows: [\n { keys: 'Double-click canvas', label: 'Search & create node' },\n { keys: 'Drag port to empty', label: 'Create & connect' },\n { keys: 'Drop node on wire', label: 'Insert inline (if compatible)' },\n { keys: 'Drag edge end', label: 'Reconnect' },\n { keys: '?', label: 'This cheatsheet' },\n ],\n },\n];\n\nexport function Cheatsheet({ open, onClose, groups = DEFAULT_GROUPS }: CheatsheetProps): ReactElement | null {\n const dialogRef = useRef<HTMLDivElement>(null);\n useEffect(() => {\n if (!open) {\n return;\n }\n // Move focus into the dialog on open (a11y — keyboard/SR users get an anchor,\n // matching the NodeContextMenu pattern).\n dialogRef.current?.focus();\n const onKey = (e: KeyboardEvent): void => {\n if (e.key === 'Escape') {\n onClose();\n }\n };\n window.addEventListener('keydown', onKey);\n return (): void => window.removeEventListener('keydown', onKey);\n }, [open, onClose]);\n\n if (!open) {\n return null;\n }\n\n return (\n <>\n <div className=\"hl-cheat-scrim\" onPointerDown={onClose} />\n <div\n ref={dialogRef}\n className=\"hl-cheat\"\n role=\"dialog\"\n aria-modal=\"true\"\n aria-label=\"Keyboard shortcuts\"\n tabIndex={-1}\n >\n <div className=\"hl-cheat-head\">\n <span className=\"hl-cheat-title\">Shortcuts</span>\n <button className=\"hl-cheat-close\" onClick={onClose} aria-label=\"Close\">\n ✕\n </button>\n </div>\n <div className=\"hl-cheat-grid\">\n {groups.map(group => (\n <section key={group.title} className=\"hl-cheat-group\">\n <h3 className=\"hl-cheat-group-title hl-mono\">{group.title}</h3>\n <ul className=\"hl-cheat-rows\">\n {group.rows.map(row => (\n // A row is a binding: one action can have several (two ways to pan),\n // so neither the label nor the keys alone identify it.\n <li key={`${row.keys}\\u0000${row.label}`} className=\"hl-cheat-row\">\n <span className=\"hl-cheat-label\">{row.label}</span>\n <kbd className=\"hl-cheat-keys hl-mono\">{row.keys}</kbd>\n </li>\n ))}\n </ul>\n </section>\n ))}\n </div>\n </div>\n </>\n );\n}\n","/**\n * `ToastProvider` / `useToast` — lightweight transient notifications in the\n * black/silver glass language. A host wraps the app once; any component calls\n * `useToast().show('Copied 3 nodes')` for a brief confirmation. Presentation\n * only: it holds a small queue that auto-dismisses.\n */\n\nimport { createContext, useCallback, useContext, useMemo, useRef, useState } from 'react';\nimport type { ReactElement, ReactNode } from 'react';\nimport './Toast.css';\n\ninterface ToastItem {\n readonly id: number;\n readonly message: string;\n}\n\nexport interface ToastApi {\n show(message: string): void;\n}\n\nconst ToastCtx = createContext<ToastApi>({ show: () => undefined });\n\nexport interface ToastProviderProps {\n readonly children: ReactNode;\n /** Auto-dismiss delay in ms (default 2200). */\n readonly duration?: number;\n}\n\nexport function ToastProvider({ children, duration = 2200 }: ToastProviderProps): ReactElement {\n const [items, setItems] = useState<readonly ToastItem[]>([]);\n const seq = useRef(0);\n\n const show = useCallback(\n (message: string): void => {\n seq.current += 1;\n const id = seq.current;\n setItems(prev => [...prev, { id, message }]);\n // Timers are a UI concern; Date/setTimeout are fine in the browser layer.\n setTimeout(() => {\n setItems(prev => prev.filter(t => t.id !== id));\n }, duration);\n },\n [duration],\n );\n\n const api = useMemo<ToastApi>(() => ({ show }), [show]);\n\n return (\n <ToastCtx.Provider value={api}>\n {children}\n <div className=\"hl-toast-stack\" aria-live=\"polite\">\n {items.map(t => (\n <div key={t.id} className=\"hl-toast\">\n {t.message}\n </div>\n ))}\n </div>\n </ToastCtx.Provider>\n );\n}\n\nexport function useToast(): ToastApi {\n return useContext(ToastCtx);\n}\n","/**\n * `useLiveSignals` — feed a running flow's activity/error signals into the\n * LiveSignalStore, which node/edge components subscribe to by id. No global DOM\n * access and no dependency on React Flow's private structure: the store is the\n * single source of truth and components read their own state (see\n * `LiveSignalContext`). Must be used within a `<LiveSignalProvider>`.\n */\n\nimport { useEffect } from 'react';\nimport type { EditorCore } from '@hlang-tech/editor-core';\nimport type { IExecutionHandle } from '@hlang-tech/editor-core';\nimport { useLiveSignalStore } from '../live/LiveSignalContext';\nimport type { EdgeIndexEntry, LiveSignalStore } from '../live/live-signal-store';\n\n/**\n * Drive live visuals from an execution handle. Pass the handle returned by\n * `core.execution.run(...)`; pass `undefined` to clear. Keeps the store's edge\n * index in sync with the model so a source-port pulse lights the right edges.\n *\n * The store is taken from `<LiveSignalProvider>` context; pass `explicitStore`\n * when the feeding component sits at or above the provider (so it and the\n * subscribing components share one store).\n */\nexport function useLiveSignals(\n core: EditorCore,\n handle: IExecutionHandle | undefined,\n explicitStore?: LiveSignalStore,\n): void {\n const contextStore = useLiveSignalStore();\n const store = explicitStore ?? contextStore;\n\n // Keep the edge index current whenever the graph changes.\n useEffect(() => {\n if (store === null) {\n return;\n }\n const syncEdges = (): void => {\n const entries: EdgeIndexEntry[] = core.model.getEdges().map(edge => ({\n id: edge.id,\n sourceNodeId: edge.source.nodeId,\n sourcePortId: edge.source.portId,\n targetNodeId: edge.target.nodeId,\n targetPortId: edge.target.portId,\n isError: edge.source.portId === '@node/error',\n }));\n store.setEdgeIndex(entries);\n };\n syncEdges();\n const added = core.events.on('edgeAdded', syncEdges);\n const removed = core.events.on('edgeRemoved', syncEdges);\n return (): void => {\n added.dispose();\n removed.dispose();\n };\n }, [core, store]);\n\n // Subscribe to the running handle's signals and feed the store.\n useEffect(() => {\n if (store === null) {\n return;\n }\n if (handle === undefined) {\n store.reset();\n return;\n }\n // A traced run reports each delivery, so each node and edge lights exactly\n // when it ran or carried a message. A runner that cannot trace falls back\n // to activity signals.\n const signalSub =\n handle.onDelivery?.(event => {\n store.markDelivery(event);\n }) ?? handle.onActivity(e => store.markActivity(e.nodeId, e.portId));\n const errorSub = handle.onError(e => store.markError(e.nodeId));\n const finishedSub = handle.onFinished?.(e => {\n store.markFinished(e.nodeId);\n });\n return (): void => {\n signalSub.dispose();\n errorSub.dispose();\n finishedSub?.dispose();\n store.reset();\n };\n }, [store, handle]);\n}\n","/**\n * `RunTrace` — what a running graph did: a bounded log of every delivery and\n * error, and per-node statistics (messages in and out, errors, time spent,\n * the latest values). It is fed from an execution handle's `onDelivery` and\n * `onError` (see `useRunTrace`) and read by the run log and the inspector.\n *\n * Like `LiveSignalStore`, it records synchronously and notifies at most once\n * per frame, so a flow delivering thousands of messages a second costs one\n * render per frame. The log is a ring buffer: memory stays bounded however\n * long the run, while the statistics keep counting everything.\n */\n\nimport type {\n INodeDeliveryEvent,\n INodeDroppedEvent,\n INodeEndedEvent,\n INodeErrorEvent,\n INodeFinishedEvent,\n} from '@hlang-tech/editor-core';\nimport { defaultLiveDeps } from './live-signal-store';\nimport type { LiveSignalStoreDeps } from './live-signal-store';\n\n/** How many log entries a trace keeps unless told otherwise. */\nexport const RUN_LOG_CAPACITY = 500;\n\n/** A message delivered on a connection. `at` is milliseconds since the run started. */\nexport interface RunDeliveryEntry {\n readonly kind: 'delivery';\n readonly seq: number;\n readonly at: number;\n readonly sourceNodeId: string;\n readonly sourcePortId: string;\n readonly targetNodeId: string;\n readonly targetPortId: string;\n readonly message: unknown;\n /** How long the receiving node's handlers took, in milliseconds. */\n readonly duration: number;\n}\n\n/** A node error. `at` is milliseconds since the run started. */\nexport interface RunErrorEntry {\n readonly kind: 'error';\n readonly seq: number;\n readonly at: number;\n readonly nodeId: string;\n readonly error: unknown;\n}\n\n/** An input that ended (RFC 0001): every connection into it closed and its messages done. */\nexport interface RunEndedEntry {\n readonly kind: 'ended';\n readonly seq: number;\n readonly at: number;\n readonly nodeId: string;\n readonly portId: string;\n}\n\n/** A node that finished (RFC 0001): its inputs ended and its outputs closed. */\nexport interface RunFinishedEntry {\n readonly kind: 'finished';\n readonly seq: number;\n readonly at: number;\n readonly nodeId: string;\n}\n\n/** A message a full `drop-oldest` connection dropped (RFC 0001). */\nexport interface RunDroppedEntry {\n readonly kind: 'dropped';\n readonly seq: number;\n readonly at: number;\n readonly sourceNodeId: string;\n readonly sourcePortId: string;\n readonly targetNodeId: string;\n readonly targetPortId: string;\n readonly message: unknown;\n}\n\nexport type RunLogEntry = RunDeliveryEntry | RunErrorEntry | RunEndedEntry | RunFinishedEntry | RunDroppedEntry;\n\n/** One node's activity during the run. */\nexport interface NodeRunSummary {\n readonly received: number;\n readonly sent: number;\n readonly errors: number;\n /** Time spent handling what it received, in milliseconds: in total and the longest once. */\n readonly totalMs: number;\n readonly maxMs: number;\n readonly lastReceived: unknown;\n readonly lastSent: unknown;\n /** Messages a full `drop-oldest` connection into this node dropped. */\n readonly dropped: number;\n /** Whether the node has finished: its inputs ended and its outputs closed. */\n readonly finished: boolean;\n}\n\nexport interface RunTraceOptions {\n /** How many log entries to keep. Default `RUN_LOG_CAPACITY`. */\n readonly capacity?: number;\n /** Clock and frame scheduler; injected in tests. */\n readonly deps?: LiveSignalStoreDeps;\n}\n\ninterface MutableStats {\n received: number;\n sent: number;\n errors: number;\n totalMs: number;\n maxMs: number;\n lastReceived: unknown;\n lastSent: unknown;\n dropped: number;\n finished: boolean;\n}\n\ntype Listener = () => void;\n\nexport class RunTrace {\n private readonly capacity: number;\n private readonly deps: LiveSignalStoreDeps;\n /** The log as a ring: `ring[(head + i) % capacity]` is the i-th oldest entry. */\n private readonly ring: RunLogEntry[] = [];\n private head = 0;\n private droppedCount = 0;\n private seq = 0;\n private startedAt = 0;\n private readonly stats = new Map<string, MutableStats>();\n private readonly listeners = new Set<Listener>();\n /** Bumped by every change; the entries cache follows it. */\n private revision = 0;\n /** Bumped once per notified frame; what subscribers compare. */\n private version = 0;\n private frame: number | null = null;\n /** The entries as an array, rebuilt only after a change. */\n private entriesCache: readonly RunLogEntry[] = [];\n private entriesRevision = -1;\n\n constructor(options: RunTraceOptions = {}) {\n const capacity = options.capacity ?? RUN_LOG_CAPACITY;\n if (!Number.isInteger(capacity) || capacity < 1) {\n throw new RangeError('RunTrace capacity must be a positive integer.');\n }\n this.capacity = capacity;\n this.deps = options.deps ?? defaultLiveDeps;\n }\n\n /** Begins a run: clears everything and times entries from now. */\n start(): void {\n this.clear();\n this.startedAt = this.deps.now();\n }\n\n /** Forgets the log and the statistics. */\n clear(): void {\n this.ring.length = 0;\n this.head = 0;\n this.droppedCount = 0;\n this.stats.clear();\n this.changed();\n }\n\n recordDelivery(event: INodeDeliveryEvent): void {\n this.append({\n kind: 'delivery',\n seq: this.nextSeq(),\n at: this.elapsed(),\n sourceNodeId: event.sourceNodeId,\n sourcePortId: event.sourcePortId,\n targetNodeId: event.targetNodeId,\n targetPortId: event.targetPortId,\n message: event.message,\n duration: event.duration,\n });\n const source = this.statsFor(event.sourceNodeId);\n source.sent += 1;\n source.lastSent = event.message;\n const target = this.statsFor(event.targetNodeId);\n target.received += 1;\n target.totalMs += event.duration;\n target.maxMs = Math.max(target.maxMs, event.duration);\n target.lastReceived = event.message;\n this.changed();\n }\n\n recordError(event: INodeErrorEvent): void {\n this.append({ kind: 'error', seq: this.nextSeq(), at: this.elapsed(), nodeId: event.nodeId, error: event.error });\n this.statsFor(event.nodeId).errors += 1;\n this.changed();\n }\n\n recordEnded(event: INodeEndedEvent): void {\n this.append({ kind: 'ended', seq: this.nextSeq(), at: this.elapsed(), nodeId: event.nodeId, portId: event.portId });\n this.statsFor(event.nodeId);\n this.changed();\n }\n\n recordFinished(event: INodeFinishedEvent): void {\n this.append({ kind: 'finished', seq: this.nextSeq(), at: this.elapsed(), nodeId: event.nodeId });\n this.statsFor(event.nodeId).finished = true;\n this.changed();\n }\n\n recordDropped(event: INodeDroppedEvent): void {\n this.append({\n kind: 'dropped',\n seq: this.nextSeq(),\n at: this.elapsed(),\n sourceNodeId: event.sourceNodeId,\n sourcePortId: event.sourcePortId,\n targetNodeId: event.targetNodeId,\n targetPortId: event.targetPortId,\n message: event.message,\n });\n this.statsFor(event.sourceNodeId);\n this.statsFor(event.targetNodeId).dropped += 1;\n this.changed();\n }\n\n /** The log, oldest first. The same array is returned until something changes. */\n entries(): readonly RunLogEntry[] {\n if (this.entriesRevision !== this.revision) {\n const count = this.ring.length;\n const ordered: RunLogEntry[] = [];\n for (let i = 0; i < count; i += 1) {\n const entry = this.ring[(this.head + i) % count];\n if (entry !== undefined) {\n ordered.push(entry);\n }\n }\n this.entriesCache = ordered;\n this.entriesRevision = this.revision;\n }\n return this.entriesCache;\n }\n\n /** A node's statistics, or `undefined` when it has done nothing this run. */\n statsOf(nodeId: string): NodeRunSummary | undefined {\n const stats = this.stats.get(nodeId);\n return stats === undefined ? undefined : { ...stats };\n }\n\n /** How many entries the log has let go of to stay within its capacity. */\n get dropped(): number {\n return this.droppedCount;\n }\n\n /** Changes once per notified frame; a snapshot for `useSyncExternalStore`. */\n getVersion(): number {\n return this.version;\n }\n\n subscribe(listener: Listener): () => void {\n this.listeners.add(listener);\n return () => {\n this.listeners.delete(listener);\n };\n }\n\n private append(entry: RunLogEntry): void {\n if (this.ring.length < this.capacity) {\n this.ring.push(entry);\n return;\n }\n this.ring[this.head] = entry;\n this.head = (this.head + 1) % this.capacity;\n this.droppedCount += 1;\n }\n\n private nextSeq(): number {\n this.seq += 1;\n return this.seq;\n }\n\n private elapsed(): number {\n return this.deps.now() - this.startedAt;\n }\n\n private statsFor(nodeId: string): MutableStats {\n let stats = this.stats.get(nodeId);\n if (stats === undefined) {\n stats = {\n received: 0,\n sent: 0,\n errors: 0,\n totalMs: 0,\n maxMs: 0,\n lastReceived: undefined,\n lastSent: undefined,\n dropped: 0,\n finished: false,\n };\n this.stats.set(nodeId, stats);\n }\n return stats;\n }\n\n /** Schedules one notification for the next frame, however many changes come before it. */\n private changed(): void {\n this.revision += 1;\n if (this.frame !== null) {\n return;\n }\n this.frame = this.deps.schedule(() => {\n this.frame = null;\n this.version += 1;\n for (const listener of [...this.listeners]) {\n listener();\n }\n });\n }\n}\n\n/** Whether `entry` concerns `nodeId`: either end of a delivery, or the node of an error. */\nexport function involves(entry: RunLogEntry, nodeId: string): boolean {\n switch (entry.kind) {\n case 'delivery':\n case 'dropped':\n return entry.sourceNodeId === nodeId || entry.targetNodeId === nodeId;\n case 'error':\n case 'ended':\n case 'finished':\n return entry.nodeId === nodeId;\n }\n}\n","/**\n * `useRunTrace` — feeds a run's deliveries and errors into a `RunTrace`. Each\n * new handle starts a new run in the trace; when the handle goes away (the\n * run stopped) the trace keeps what it recorded, so the log can still be read.\n * A handle that cannot trace (no `onDelivery`) still feeds its errors.\n */\n\nimport { useEffect } from 'react';\nimport type { IExecutionHandle } from '@hlang-tech/editor-core';\nimport type { RunTrace } from '../live/run-trace';\n\nexport function useRunTrace(trace: RunTrace, handle: IExecutionHandle | undefined): void {\n useEffect(() => {\n if (handle === undefined) {\n return;\n }\n trace.start();\n const deliveries = handle.onDelivery?.(event => {\n trace.recordDelivery(event);\n });\n const errors = handle.onError(event => {\n trace.recordError(event);\n });\n // End of stream and drops (RFC 0001), from a runner that traces them.\n const ended = handle.onEnded?.(event => {\n trace.recordEnded(event);\n });\n const finished = handle.onFinished?.(event => {\n trace.recordFinished(event);\n });\n const dropped = handle.onDropped?.(event => {\n trace.recordDropped(event);\n });\n return (): void => {\n deliveries?.dispose();\n errors.dispose();\n ended?.dispose();\n finished?.dispose();\n dropped?.dispose();\n };\n }, [trace, handle]);\n}\n","/**\n * `useFollowScroll` — a scrolling list that stays on its newest entry, as a\n * terminal does. While following, every render scrolls it to the bottom. When\n * the reader scrolls back to read, following stops so the view holds still;\n * scrolling back to the bottom (or `setFollow(true)`) resumes it.\n */\n\nimport { useCallback, useLayoutEffect, useRef, useState } from 'react';\nimport type { RefObject, UIEvent } from 'react';\n\n/** Within this many pixels of the bottom, the list counts as at the bottom. */\nexport const FOLLOW_SLACK_PX = 24;\n\nexport interface FollowScroll<T extends HTMLElement> {\n /** Attach to the scrolling element. */\n readonly ref: RefObject<T | null>;\n /** Attach as the scrolling element's `onScroll`. */\n readonly onScroll: (event: UIEvent<T>) => void;\n readonly follow: boolean;\n readonly setFollow: (follow: boolean) => void;\n}\n\nexport function useFollowScroll<T extends HTMLElement>(): FollowScroll<T> {\n const ref = useRef<T>(null);\n const [follow, setFollow] = useState(true);\n\n // After every render: new entries may have arrived.\n useLayoutEffect(() => {\n const element = ref.current;\n if (follow && element !== null) {\n element.scrollTop = element.scrollHeight;\n }\n });\n\n const onScroll = useCallback((event: UIEvent<T>): void => {\n const element = event.currentTarget;\n setFollow(element.scrollHeight - element.scrollTop - element.clientHeight <= FOLLOW_SLACK_PX);\n }, []);\n\n return { ref, onScroll, follow, setFollow };\n}\n","/**\n * `RunLog` — the editor's live console. Every message the running graph\n * delivers, and every node error, as it happens: when (since the run\n * started), from which node and port to which, a preview of the value, and\n * how long the receiving node took. Choosing a row selects its node, and the\n * log can follow the selection. It reads the `RunTrace` from\n * `<RunTraceProvider>` and renders nothing without one.\n */\n\nimport { useState } from 'react';\nimport type { ReactElement, ReactNode } from 'react';\nimport type { EditorCore } from '@hlang-tech/editor-core';\nimport { useSelection } from '@hlang-tech/editor-react';\nimport { useFollowScroll } from '../hooks/useFollowScroll';\nimport { formatDuration, formatElapsed } from '../live/format';\nimport { previewValue } from '../live/preview';\nimport { involves } from '../live/run-trace';\nimport type { RunLogEntry } from '../live/run-trace';\nimport { useRunTraceStore, useRunTraceVersion } from '../live/RunTraceContext';\nimport './RunLog.css';\n\nexport interface RunLogProps {\n readonly core: EditorCore;\n /** Also called when a row is chosen, after its node is selected (e.g. to bring it into view). */\n readonly onSelectNode?: (nodeId: string) => void;\n /** The log's name, shown at the start of its header and used as its accessible name. */\n readonly title?: string;\n /** Shown at the start of the header in place of the title, e.g. the host's tabs. */\n readonly leading?: ReactNode;\n}\n\nexport function RunLog({ core, onSelectNode, title = 'Run log', leading }: RunLogProps): ReactElement | null {\n const trace = useRunTraceStore();\n useRunTraceVersion(trace);\n const selection = useSelection(core);\n const [onlySelected, setOnlySelected] = useState(false);\n const { ref: bodyRef, onScroll, follow, setFollow } = useFollowScroll<HTMLOListElement>();\n\n const all = trace === null ? [] : trace.entries();\n const selectedId = selection.selectedNodes.length === 1 ? selection.selectedNodes[0] : undefined;\n const filterId = onlySelected ? selectedId : undefined;\n const entries = filterId === undefined ? all : all.filter(entry => involves(entry, filterId));\n\n if (trace === null) {\n return null;\n }\n\n const label = (nodeId: string): string => core.model.getNode(nodeId)?.name ?? nodeId;\n const choose = (nodeId: string): void => {\n core.selection.selectNodes([nodeId], 'replace');\n onSelectNode?.(nodeId);\n };\n\n return (\n <section className=\"hl-runlog\" aria-label={title}>\n <header className=\"hl-runlog-head\">\n {leading ?? <span className=\"hl-runlog-title\">{title}</span>}\n <span className=\"hl-runlog-count hl-mono\">\n {entries.length === all.length\n ? `${String(all.length)} events`\n : `${String(entries.length)} of ${String(all.length)} events`}\n {trace.dropped > 0 ? ` · ${String(trace.dropped)} earlier not kept` : ''}\n </span>\n <span className=\"hl-runlog-actions\">\n <button\n type=\"button\"\n className={`hl-runlog-toggle${onlySelected ? ' is-on' : ''}`}\n aria-pressed={onlySelected}\n disabled={selectedId === undefined && !onlySelected}\n title={selectedId === undefined ? 'Select a node to filter by it' : `Only ${label(selectedId)}`}\n onClick={() => {\n setOnlySelected(value => !value);\n }}\n >\n {onlySelected && selectedId !== undefined ? `Only ${label(selectedId)}` : 'Selected node'}\n </button>\n <button\n type=\"button\"\n className={`hl-runlog-toggle${follow ? ' is-on' : ''}`}\n aria-pressed={follow}\n onClick={() => {\n setFollow(!follow);\n }}\n >\n Follow\n </button>\n <button\n type=\"button\"\n className=\"hl-runlog-toggle\"\n disabled={all.length === 0}\n onClick={() => {\n trace.clear();\n }}\n >\n Clear\n </button>\n </span>\n </header>\n {entries.length === 0 ? (\n <p className=\"hl-runlog-empty\">\n {all.length === 0\n ? 'Run the graph to see every message as it moves through it.'\n : 'Nothing involving the selected node yet.'}\n </p>\n ) : (\n <ol className=\"hl-runlog-body hl-mono\" ref={bodyRef} onScroll={onScroll}>\n {entries.map(entry => (\n <Row key={entry.seq} entry={entry} label={label} onChoose={choose} />\n ))}\n </ol>\n )}\n </section>\n );\n}\n\nfunction Row({\n entry,\n label,\n onChoose,\n}: {\n readonly entry: RunLogEntry;\n readonly label: (nodeId: string) => string;\n readonly onChoose: (nodeId: string) => void;\n}): ReactElement {\n switch (entry.kind) {\n case 'error':\n return (\n <Event className=\"is-error\" at={entry.at} onChoose={() => onChoose(entry.nodeId)} ms=\"\">\n <NodePort node={label(entry.nodeId)} port=\"error\" />\n <span className=\"hl-runlog-value\">{previewValue(entry.error)}</span>\n </Event>\n );\n case 'ended':\n return (\n <Event className=\"is-end\" at={entry.at} onChoose={() => onChoose(entry.nodeId)} ms=\"\">\n <NodePort node={label(entry.nodeId)} port={entry.portId} />\n <span className=\"hl-runlog-value\">ended</span>\n </Event>\n );\n case 'finished':\n return (\n <Event className=\"is-end\" at={entry.at} onChoose={() => onChoose(entry.nodeId)} ms=\"\">\n <NodePort node={label(entry.nodeId)} port=\"\" />\n <span className=\"hl-runlog-value\">finished</span>\n </Event>\n );\n case 'dropped':\n return (\n <Event className=\"is-dropped\" at={entry.at} onChoose={() => onChoose(entry.targetNodeId)} ms=\"\">\n <Route entry={entry} label={label} />\n <span className=\"hl-runlog-value\">dropped {previewValue(entry.message)}</span>\n </Event>\n );\n case 'delivery':\n return (\n <Event className=\"\" at={entry.at} onChoose={() => onChoose(entry.targetNodeId)} ms={formatDuration(entry.duration)}>\n <Route entry={entry} label={label} />\n <span className=\"hl-runlog-value\">{previewValue(entry.message)}</span>\n </Event>\n );\n }\n}\n\n/** One row: when, what (the children: a route or a node, and a value), and how long. */\nfunction Event({\n className,\n at,\n ms,\n onChoose,\n children,\n}: {\n readonly className: string;\n readonly at: number;\n readonly ms: string;\n readonly onChoose: () => void;\n readonly children: ReactNode;\n}): ReactElement {\n return (\n <li className={`hl-runlog-row ${className}`.trim()}>\n <button type=\"button\" className=\"hl-runlog-hit\" onClick={onChoose}>\n <span className=\"hl-runlog-at\">{formatElapsed(at)}</span>\n {children}\n <span className=\"hl-runlog-ms\">{ms}</span>\n </button>\n </li>\n );\n}\n\nfunction NodePort({ node, port }: { readonly node: string; readonly port: string }): ReactElement {\n return (\n <span className=\"hl-runlog-route\">\n <span className=\"hl-runlog-node\">{node}</span>\n {port === '' ? null : <span className=\"hl-runlog-port\">{port}</span>}\n </span>\n );\n}\n\nfunction Route({\n entry,\n label,\n}: {\n readonly entry: { readonly sourceNodeId: string; readonly sourcePortId: string; readonly targetNodeId: string; readonly targetPortId: string };\n readonly label: (nodeId: string) => string;\n}): ReactElement {\n return (\n <span className=\"hl-runlog-route\">\n <span className=\"hl-runlog-node\">{label(entry.sourceNodeId)}</span>\n <span className=\"hl-runlog-port\">{entry.sourcePortId}</span>\n <span className=\"hl-runlog-arrow\" aria-label=\"to\">→</span>\n <span className=\"hl-runlog-node\">{label(entry.targetNodeId)}</span>\n <span className=\"hl-runlog-port\">{entry.targetPortId}</span>\n </span>\n );\n}\n"],"mappings":"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","names":["className","jsx","jsx","jsx","jsx","jsx","jsx","jsxs","className","jsx","jsx","createContext","useContext","jsx","jsx","jsxs","className","jsx","jsxs","className","jsx","jsxs","className","useEffect","useRef","jsx","useCallback","useMemo","useRef","useState","useState","useRef","useMemo","useCallback","jsx","jsxs","useRef","className","useEffect","_a","Fragment","jsx","jsxs","jsx","jsxs","Fragment","jsx","jsx","jsxs","jsx","jsxs","useCallback","useMemo","useRef","useSyncExternalStore","useCallback","useSyncExternalStore","useState","jsx","jsxs","useState","jsx","jsxs","createContext","useContext","useSyncExternalStore","jsx","jsx","jsxs","jsx","jsxs","selectedNodes","useCallback","useEffect","useMemo","useState","useSelection","jsx","jsxs","useState","useCallback","useEffect","useMemo","useSelection","jsx","jsxs","jsx","jsx","useCallback","useEffect","useSelection","jsx","jsxs","useSelection","useEffect","useCallback","useCallback","useEffect","useMemo","useRef","useState","Fragment","jsx","jsxs","useState","useRef","useEffect","useMemo","useCallback","useCallback","useMemo","useState","useState","useCallback","useMemo","useCallback","useRef","useEffect","useCallback","useEffect","useMemo","useRef","useState","Fragment","jsx","jsxs","PANEL_WIDTH","useState","useRef","useEffect","useMemo","useCallback","clampToViewport","useCallback","useMemo","useState","useEffect","useRef","Fragment","jsx","jsxs","useRef","useEffect","createContext","useCallback","useContext","useMemo","useRef","useState","jsx","jsxs","createContext","useState","useRef","useCallback","useMemo","useContext","useEffect","useEffect","useEffect","useCallback","useRef","useState","useState","useSelection","jsx","jsxs","useSelection","useState","className"]}