@modernrelay/orbit-react 0.13.5 → 0.14.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.
Files changed (56) hide show
  1. package/dist/{chunk-DGFLU2SN.js → chunk-DTXFQLNP.js} +2 -2
  2. package/dist/chunk-DTXFQLNP.js.map +1 -0
  3. package/dist/{chunk-7XB47YST.js → chunk-NPOV5GA3.js} +2 -2
  4. package/dist/chunk-NPOV5GA3.js.map +1 -0
  5. package/dist/{chunk-QJ7JXQVK.js → chunk-ODOPSUI7.js} +4 -4
  6. package/dist/chunk-ODOPSUI7.js.map +1 -0
  7. package/dist/{chunk-JN7QCMFW.js → chunk-S36LHSNX.js} +2 -2
  8. package/dist/chunk-S36LHSNX.js.map +1 -0
  9. package/dist/components/ContextMenu.d.ts +4 -4
  10. package/dist/components/ContextMenu.js +2 -2
  11. package/dist/components/ContextMenu.js.map +1 -1
  12. package/dist/components/Histogram.d.ts +1 -1
  13. package/dist/components/Histogram.js +3 -3
  14. package/dist/components/Histogram.js.map +1 -1
  15. package/dist/components/Inspector.d.ts +20 -20
  16. package/dist/components/Inspector.js +1 -1
  17. package/dist/components/Inspector.js.map +1 -1
  18. package/dist/components/Legend.d.ts +9 -10
  19. package/dist/components/Legend.js +3 -3
  20. package/dist/components/Legend.js.map +1 -1
  21. package/dist/components/Minimap.d.ts +29 -29
  22. package/dist/components/Minimap.js +1 -1
  23. package/dist/components/Minimap.js.map +1 -1
  24. package/dist/components/Navigator.d.ts +24 -24
  25. package/dist/components/Navigator.js +3 -3
  26. package/dist/components/Navigator.js.map +1 -1
  27. package/dist/components/Search.d.ts +28 -28
  28. package/dist/components/Search.js +3 -3
  29. package/dist/components/Search.js.map +1 -1
  30. package/dist/components/SelectionActions.d.ts +3 -3
  31. package/dist/components/SelectionActions.js +1 -1
  32. package/dist/components/SelectionActions.js.map +1 -1
  33. package/dist/components/SimControls.d.ts +15 -16
  34. package/dist/components/SimControls.js +2 -2
  35. package/dist/components/SimControls.js.map +1 -1
  36. package/dist/components/Table.d.ts +4 -4
  37. package/dist/components/Table.js +2 -2
  38. package/dist/components/Table.js.map +1 -1
  39. package/dist/components/Timeline.d.ts +2 -2
  40. package/dist/components/Timeline.js +3 -3
  41. package/dist/components/Timeline.js.map +1 -1
  42. package/dist/components/Toolbar.d.ts +2 -2
  43. package/dist/components/Toolbar.js +1 -1
  44. package/dist/components/Toolbar.js.map +1 -1
  45. package/dist/components/Tooltip.d.ts +16 -16
  46. package/dist/components/Tooltip.js +1 -1
  47. package/dist/components/Tooltip.js.map +1 -1
  48. package/dist/index.d.ts +105 -106
  49. package/dist/index.js +8 -8
  50. package/dist/index.js.map +1 -1
  51. package/dist/{shared-Bj3Gk219.d.ts → shared-n98tkXJe.d.ts} +3 -3
  52. package/package.json +2 -2
  53. package/dist/chunk-7XB47YST.js.map +0 -1
  54. package/dist/chunk-DGFLU2SN.js.map +0 -1
  55. package/dist/chunk-JN7QCMFW.js.map +0 -1
  56. package/dist/chunk-QJ7JXQVK.js.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/SimControls/index.tsx"],"names":[],"mappings":"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","file":"SimControls.js","sourcesContent":["/**\n * `@modernrelay/orbit-react/components/SimControls` — `<GraphSimControls>`,\n * the §16.11 simulation control panel (S12-T12).\n *\n * Live sliders over the effective `SimulationConfig` fields (gravity,\n * repulsion, friction, linkDistance, linkSpring, collision, decay, center —\n * repulsionTheta is omitted: inert on cosmos >= 3.4), a speed\n * preset toggle, and a reheat button. Every control write is ONE atomic\n * host update — `applyHostUpdate({ simulation: merged })`, the same lane the\n * `<Graph>` `simulation` prop uses — which sinks as a single config-only\n * `engine.commit`: no structure, no buffers, no restart, positions untouched\n * (R-16.11-02, E1).\n *\n * ## Current-value resolution (v0.10, investigated)\n * The store publishes NO simulation/layout lane and the instance exposes no\n * config getter — `layout`/`simulation` are instance-local in\n * `createGraphInstance`; `GraphStoreState` carries only `simulationRunning`.\n * The panel therefore mirrors the caller's `simulation` prop (the same\n * object handed to `<Graph>`) and merges control writes over that mirror; a\n * prop identity change re-seeds the mirror (the external writer wins). Like\n * `subgraph` (§9.2), the lane is last-writer-wins: the panel and the\n * `<Graph>` prop write the same state. `onSimulationChange` fires with the\n * full merged config after every write so controlled callers can loop it\n * back through their `simulation` prop (the spec's `onLayoutChange` seam\n * traffics in the LayoutSpec object form and is post-v0.10).\n *\n * ## Applicability (R-16.11-04)\n * Rendered ONLY under layout `'force'` — the `layout` prop mirrors the\n * caller's `<Graph>` prop for the same no-observable-lane reason, defaulting\n * to `'force'` (the instance construction default). Under `'fixed'` the\n * panel renders nothing. The spec's third case — `static` while its\n * convergence run is active — is N/A in v0.10: `LayoutKind` is\n * `'force' | 'fixed'` (core types.ts) and the store exposes no\n * convergence-run state; wire it when the `static` variant lands.\n *\n * ## Reheat\n * The spec names `reheat(alpha)`; the shipped instance surface is\n * `resumeSimulation()` (§16.1 simulation controls — sinks to\n * `engine.start()` and publishes `simulationRunning`). The button calls\n * that; the alpha parameter follows when core grows the reheat API.\n *\n * ## Speed toggle\n * A preset over the `decay` lane — the §10 cool-down tunable (cosmos\n * `simulationDecay`), which core exposes as of v0.10.2. ON writes a smaller\n * coefficient so the run cools SLOWER and stays lively; OFF restores the\n * pre-toggle value, or the engine default when the field was unset. The\n * toggle and the Cool-down slider are two views over one lane, so moving\n * either is reflected by the other. Same config-only commit discipline as\n * every slider. (Before v0.10.2 this proxied through `friction` because\n * `decay` had no core lane — that workaround is now retired.)\n *\n * ## Keyboard & ARIA (§15.1)\n * Native `<input type=\"range\">`/checkbox controls with `<label htmlFor>`\n * wiring. Arrow/Home/End/Page keys are handled in `onKeyDown` with\n * `preventDefault()` so stepping is deterministic both in browsers (never\n * double-steps against the native range keyboard model) and under jsdom\n * (which has no native range keyboard model at all).\n */\n\nimport { Fragment, useCallback, useId, useRef, useState, useSyncExternalStore } from 'react';\nimport type { CSSProperties, ReactElement, ReactNode } from 'react';\nimport type { LayoutKind, SimulationConfig } from '@modernrelay/orbit-core';\nimport type { AnyGraphInstance } from '../../GraphProvider';\nimport { cornerStyle, mergeStyle, useResolvedInstance } from '../shared';\nimport type { GraphCorner } from '../shared';\n\nexport type SimFieldKey = keyof SimulationConfig;\n\nexport interface SimFieldDescriptor {\n key: SimFieldKey;\n /** Visible label text (rendered as a text node). */\n label: string;\n min: number;\n max: number;\n step: number;\n /** Displayed when the field is unset — the engine default the simulation\n * is actually running with (cosmos 3.3.0 `defaultConfigValues`). Never\n * WRITTEN unless the user moves the control. */\n fallback: number;\n}\n\n/** §16.11 slider roster = the full v0.10 `SimulationConfig` field list. */\nexport const SIM_FIELDS: readonly SimFieldDescriptor[] = [\n { key: 'gravity', label: 'Gravity', min: 0, max: 1, step: 0.01, fallback: 0.25 },\n { key: 'repulsion', label: 'Repulsion', min: 0, max: 2, step: 0.01, fallback: 1 },\n { key: 'friction', label: 'Friction', min: 0, max: 1, step: 0.01, fallback: 0.85 },\n { key: 'linkDistance', label: 'Link distance', min: 1, max: 100, step: 1, fallback: 10 },\n { key: 'linkSpring', label: 'Link spring', min: 0, max: 2, step: 0.01, fallback: 1 },\n // v0.10.2: the rest of the §10 tunable set. `collision` and `center` ship\n // OFF at the engine default, so their sliders start at 0 — moving one is\n // what turns the force on.\n { key: 'collision', label: 'Collision', min: 0, max: 2, step: 0.01, fallback: 0 },\n { key: 'decay', label: 'Cool-down', min: 100, max: 20000, step: 100, fallback: 5000 },\n // repulsionTheta is deliberately absent: cosmos >= 3.4 ignores it\n // (grid-based repulsion) — a slider that visibly does nothing is worse\n // than no slider. The SimulationConfig field survives for other engines.\n { key: 'center', label: 'Centering', min: 0, max: 1, step: 0.01, fallback: 0 },\n];\n\n/** Speed-preset friction values (module JSDoc: the toggle's documented\n * simulation field is `friction` until core ships `decay`). */\nexport const SPEED_NORMAL_DECAY = 5000;\n/** A smaller decay coefficient cools SLOWER, so the run keeps moving —\n * \"fast\" here means \"stays lively\", matching the §10 semantics. */\nexport const SPEED_FAST_DECAY = 1000;\n\nexport interface GraphSimControlsProps {\n /** Explicit instance (multi-instance pages); ambient context otherwise. */\n instance?: AnyGraphInstance;\n /** Active layout kind — mirror of the caller's <Graph> `layout` prop\n * (no observable lane exists; module JSDoc). Default 'force'. */\n layout?: LayoutKind;\n /** Current simulation config seed — the same object passed to <Graph>.\n * An identity change re-seeds the panel's mirror. */\n simulation?: SimulationConfig;\n /** Fires with the FULL merged SimulationConfig after every write. */\n onSimulationChange?: (next: SimulationConfig) => void;\n /** Render-prop REPLACEMENT for a field row; the default renders\n * label + native range input + value readout. `set` clamps/quantizes to\n * the descriptor's bounds and step before writing. */\n renderField?: (ctx: {\n field: SimFieldDescriptor;\n value: number;\n /** Stable id for `htmlFor` wiring in custom rows. */\n inputId: string;\n set: (value: number) => void;\n }) => ReactNode;\n /** Accessible name of the panel. Default 'Simulation controls'. */\n label?: string;\n /** Corner this panel anchors to. Default 'bottom-left'. */\n position?: GraphCorner;\n /** Distance from the two anchored edges in CSS px. Default 12. */\n offset?: number;\n /** Class hook for the root; providing it drops the default styles\n * INCLUDING placement — position it yourself in CSS. */\n className?: string;\n /** Style overrides merged over the defaults; an inset you set here\n * wins over the one `position` implies (resolved per axis). */\n style?: CSSProperties;\n}\n\n/** Decimal places of `step` — the quantization grid for keyboard stepping. */\nfunction stepDecimals(step: number): number {\n const s = String(step);\n const dot = s.indexOf('.');\n return dot === -1 ? 0 : s.length - dot - 1;\n}\n\n/** Clamp to [min, max] and quantize to the step's decimal grid so repeated\n * keyboard steps never accumulate float noise (0.25 + 0.01 stays 0.26). */\nfunction quantize(field: SimFieldDescriptor, raw: number): number {\n const clamped = Math.min(field.max, Math.max(field.min, raw));\n return Number(clamped.toFixed(stepDecimals(field.step)));\n}\n\n/** §15.1 keyboard model for a slider; null = key not handled (let it pass). */\nfunction keyboardTarget(field: SimFieldDescriptor, value: number, key: string): number | null {\n switch (key) {\n case 'ArrowRight':\n case 'ArrowUp':\n return quantize(field, value + field.step);\n case 'ArrowLeft':\n case 'ArrowDown':\n return quantize(field, value - field.step);\n case 'PageUp':\n return quantize(field, value + field.step * 10);\n case 'PageDown':\n return quantize(field, value - field.step * 10);\n case 'Home':\n return field.min;\n case 'End':\n return field.max;\n default:\n return null;\n }\n}\n\n// --- styling defaults (headless-styleable: className/style override) ---\nconst PANEL_STYLE: CSSProperties = {\n width: 250,\n pointerEvents: 'auto',\n display: 'flex',\n flexDirection: 'column',\n gap: 6,\n padding: 10,\n borderRadius: 8,\n background: 'rgba(23, 25, 32, 0.96)',\n border: '1px solid rgba(255, 255, 255, 0.14)',\n color: '#e8eaf0',\n font: '12px/1.4 system-ui, sans-serif',\n};\nconst TITLE_STYLE: CSSProperties = { fontWeight: 600, fontSize: 13 };\nconst ROW_STYLE: CSSProperties = { display: 'flex', alignItems: 'center', gap: 6 };\nconst LABEL_STYLE: CSSProperties = { flex: 'none', width: 86, opacity: 0.8 };\nconst SLIDER_STYLE: CSSProperties = { flex: 1, minWidth: 0 };\nconst VALUE_STYLE: CSSProperties = {\n flex: 'none',\n width: 38,\n textAlign: 'right',\n fontVariantNumeric: 'tabular-nums',\n};\nconst BUTTON_STYLE: CSSProperties = {\n appearance: 'none',\n background: 'transparent',\n border: '1px solid rgba(255, 255, 255, 0.2)',\n borderRadius: 6,\n color: 'inherit',\n cursor: 'pointer',\n font: 'inherit',\n padding: '4px 10px',\n};\nconst STATUS_STYLE: CSSProperties = { opacity: 0.65 };\n\nexport function GraphSimControls(props: GraphSimControlsProps): ReactElement | null {\n const instance = useResolvedInstance(props.instance, '<GraphSimControls>');\n const baseId = useId();\n\n // Mirror of the last-known SimulationConfig (module JSDoc: no store lane\n // exists to subscribe to). Prop identity change re-seeds — external\n // writer wins (the React-documented derive-during-render pattern).\n const [mirror, setMirror] = useState<SimulationConfig>(() => props.simulation ?? {});\n const [seededFrom, setSeededFrom] = useState(props.simulation);\n if (seededFrom !== props.simulation) {\n setSeededFrom(props.simulation);\n setMirror(props.simulation ?? {});\n }\n\n /** Decay the speed preset restores on release; undefined = the field was\n * unset pre-toggle (restore the engine-default constant). */\n const preSpeedDecayRef = useRef<number | undefined>(undefined);\n\n // The one simulation lane the store DOES publish (§16.1).\n const subscribe = useCallback(\n (onStoreChange: () => void) => instance.store.subscribe(onStoreChange),\n [instance],\n );\n const getRunning = useCallback(\n () => instance.store.getState().simulationRunning,\n [instance],\n );\n const simulationRunning = useSyncExternalStore(subscribe, getRunning, getRunning);\n\n // R-16.11-04 applicability gate — after hooks, per the rules of hooks.\n if ((props.layout ?? 'force') !== 'force') return null;\n\n /** ONE atomic config-only host update per control write (R-16.11-02). */\n const write = (next: SimulationConfig): void => {\n setMirror(next);\n instance.applyHostUpdate({ simulation: next });\n props.onSimulationChange?.(next);\n };\n\n const setField = (key: SimFieldKey, value: number): void => {\n const next: SimulationConfig = { ...mirror };\n next[key] = value;\n write(next);\n };\n\n // The preset holds exactly while decay sits at the fast value — the toggle\n // and the cool-down slider are two views over the same lane.\n const speedOn = mirror.decay === SPEED_FAST_DECAY;\n const toggleSpeed = (): void => {\n if (speedOn) {\n const restored = preSpeedDecayRef.current ?? SPEED_NORMAL_DECAY;\n preSpeedDecayRef.current = undefined;\n setField('decay', restored);\n } else {\n preSpeedDecayRef.current = mirror.decay;\n setField('decay', SPEED_FAST_DECAY);\n }\n };\n\n const panelLabel = props.label ?? 'Simulation controls';\n const speedId = `${baseId}-speed`;\n\n return (\n <div\n data-orbit-simcontrols=\"\"\n role=\"group\"\n aria-label={panelLabel}\n className={props.className}\n style={\n props.className !== undefined\n ? props.style\n : mergeStyle(\n { ...cornerStyle(props.position ?? 'bottom-left', props.offset), ...PANEL_STYLE },\n props.style,\n )\n }\n >\n <div data-orbit-simcontrols-title=\"\" style={TITLE_STYLE}>\n {panelLabel}\n </div>\n\n {SIM_FIELDS.map((field) => {\n const value = mirror[field.key] ?? field.fallback;\n const inputId = `${baseId}-${field.key}`;\n const set = (v: number): void => {\n setField(field.key, quantize(field, v));\n };\n if (props.renderField !== undefined) {\n return (\n <Fragment key={field.key}>\n {props.renderField({ field, value, inputId, set })}\n </Fragment>\n );\n }\n return (\n <div key={field.key} data-orbit-simcontrols-field={field.key} style={ROW_STYLE}>\n <label htmlFor={inputId} style={LABEL_STYLE}>\n {field.label}\n </label>\n <input\n id={inputId}\n type=\"range\"\n data-orbit-simcontrols-input={field.key}\n min={field.min}\n max={field.max}\n step={field.step}\n value={value}\n onChange={(e) => {\n const v = Number(e.target.value);\n if (Number.isFinite(v)) set(v);\n }}\n onKeyDown={(e) => {\n const target = keyboardTarget(field, value, e.key);\n if (target === null) return;\n // Suppress the browser's native range step so the write goes\n // through this handler exactly once (module JSDoc).\n e.preventDefault();\n if (target !== value) setField(field.key, target);\n }}\n style={SLIDER_STYLE}\n />\n <output\n htmlFor={inputId}\n data-orbit-simcontrols-value={field.key}\n style={VALUE_STYLE}\n >\n {String(value)}\n </output>\n </div>\n );\n })}\n\n <div data-orbit-simcontrols-speed-row=\"\" style={ROW_STYLE}>\n <input\n id={speedId}\n type=\"checkbox\"\n data-orbit-simcontrols-speed=\"\"\n checked={speedOn}\n onChange={toggleSpeed}\n />\n <label htmlFor={speedId}>Speed boost</label>\n </div>\n\n <div style={ROW_STYLE}>\n <button\n type=\"button\"\n data-orbit-simcontrols-reheat=\"\"\n style={BUTTON_STYLE}\n onClick={() => {\n instance.resumeSimulation();\n }}\n >\n Reheat\n </button>\n <span data-orbit-simcontrols-status=\"\" style={STATUS_STYLE}>\n {simulationRunning ? 'simulation running' : 'settled'}\n </span>\n </div>\n </div>\n );\n}\n\n/** S0-T02 tree-shake probe — must never reach a root-only consumer bundle. */\nexport const __ORBIT_SIMCONTROLS_SENTINEL__ = 'orbit-react/components/SimControls';\n"]}
1
+ {"version":3,"sources":["../../src/components/SimControls/index.tsx"],"names":[],"mappings":"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","file":"SimControls.js","sourcesContent":["/**\n * `@modernrelay/orbit-react/components/SimControls` — `<GraphSimControls>`,\n * the simulation control panel.\n *\n * Live sliders over the effective `SimulationConfig` fields (gravity,\n * repulsion, friction, linkDistance, linkSpring, collision, decay, center\n * repulsionTheta is omitted: inert on cosmos >= 3.4), a speed\n * preset toggle, and a reheat button. Every control write is ONE atomic\n * host update — `applyHostUpdate({ simulation: merged })`, the same lane the\n * `<Graph>` `simulation` prop uses — which sinks as a single config-only\n * `engine.commit`: no structure, no buffers, no restart, positions untouched.\n *\n * ## Current-value resolution (v0.10, investigated)\n * The store publishes NO simulation/layout lane and the instance exposes no\n * config getter — `layout`/`simulation` are instance-local in\n * `createGraphInstance`; `GraphStoreState` carries only `simulationRunning`.\n * The panel therefore mirrors the caller's `simulation` prop (the same\n * object handed to `<Graph>`) and merges control writes over that mirror; a\n * prop identity change re-seeds the mirror (the external writer wins). Like\n * `subgraph`, the lane is last-writer-wins: the panel and the\n * `<Graph>` prop write the same state. `onSimulationChange` fires with the\n * full merged config after every write so controlled callers can loop it\n * back through their `simulation` prop (the spec's `onLayoutChange` seam\n * traffics in the LayoutSpec object form and is post-v0.10).\n *\n * ## Applicability\n * Rendered ONLY under layout `'force'` — the `layout` prop mirrors the\n * caller's `<Graph>` prop for the same no-observable-lane reason, defaulting\n * to `'force'` (the instance construction default). Under `'fixed'` the\n * panel renders nothing. The spec's third case — `static` while its\n * convergence run is active — is N/A in v0.10: `LayoutKind` is\n * `'force' | 'fixed'` (core types.ts) and the store exposes no\n * convergence-run state; wire it when the `static` variant lands.\n *\n * ## Reheat\n * The spec names `reheat(alpha)`; the shipped instance surface is\n * `resumeSimulation` (simulation controls — sinks to\n * `engine.start` and publishes `simulationRunning`). The button calls\n * that; the alpha parameter follows when core grows the reheat API.\n *\n * ## Speed toggle\n * A preset over the `decay` lane — the cool-down tunable (cosmos\n * `simulationDecay`), which core exposes as of v0.10.2. ON writes a smaller\n * coefficient so the run cools SLOWER and stays lively; OFF restores the\n * pre-toggle value, or the engine default when the field was unset. The\n * toggle and the Cool-down slider are two views over one lane, so moving\n * either is reflected by the other. Same config-only commit discipline as\n * every slider. (Before v0.10.2 this proxied through `friction` because\n * `decay` had no core lane — that workaround is now retired.)\n *\n * ## Keyboard & ARIA\n * Native `<input type=\"range\">`/checkbox controls with `<label htmlFor>`\n * wiring. Arrow/Home/End/Page keys are handled in `onKeyDown` with\n * `preventDefault` so stepping is deterministic both in browsers (never\n * double-steps against the native range keyboard model) and under jsdom\n * (which has no native range keyboard model at all).\n */\n\nimport { Fragment, useCallback, useId, useRef, useState, useSyncExternalStore } from 'react';\nimport type { CSSProperties, ReactElement, ReactNode } from 'react';\nimport type { LayoutKind, SimulationConfig } from '@modernrelay/orbit-core';\nimport type { AnyGraphInstance } from '../../GraphProvider';\nimport { cornerStyle, mergeStyle, useResolvedInstance } from '../shared';\nimport type { GraphCorner } from '../shared';\n\nexport type SimFieldKey = keyof SimulationConfig;\n\nexport interface SimFieldDescriptor {\n key: SimFieldKey;\n /** Visible label text (rendered as a text node). */\n label: string;\n min: number;\n max: number;\n step: number;\n /** Displayed when the field is unset — the engine default the simulation\n * is actually running with (cosmos 3.3.0 `defaultConfigValues`). Never\n * WRITTEN unless the user moves the control. */\n fallback: number;\n}\n\n/** slider roster = the full v0.10 `SimulationConfig` field list. */\nexport const SIM_FIELDS: readonly SimFieldDescriptor[] = [\n { key: 'gravity', label: 'Gravity', min: 0, max: 1, step: 0.01, fallback: 0.25 },\n { key: 'repulsion', label: 'Repulsion', min: 0, max: 2, step: 0.01, fallback: 1 },\n { key: 'friction', label: 'Friction', min: 0, max: 1, step: 0.01, fallback: 0.85 },\n { key: 'linkDistance', label: 'Link distance', min: 1, max: 100, step: 1, fallback: 10 },\n { key: 'linkSpring', label: 'Link spring', min: 0, max: 2, step: 0.01, fallback: 1 },\n // v0.10.2: the rest of the tunable set. `collision` and `center` ship\n // OFF at the engine default, so their sliders start at 0 — moving one is\n // what turns the force on.\n { key: 'collision', label: 'Collision', min: 0, max: 2, step: 0.01, fallback: 0 },\n { key: 'decay', label: 'Cool-down', min: 100, max: 20000, step: 100, fallback: 5000 },\n // repulsionTheta is deliberately absent: cosmos >= 3.4 ignores it\n // (grid-based repulsion) — a slider that visibly does nothing is worse\n // than no slider. The SimulationConfig field survives for other engines.\n { key: 'center', label: 'Centering', min: 0, max: 1, step: 0.01, fallback: 0 },\n];\n\n/** Speed-preset friction values (module JSDoc: the toggle's documented\n * simulation field is `friction` until core ships `decay`). */\nexport const SPEED_NORMAL_DECAY = 5000;\n/** A smaller decay coefficient cools SLOWER, so the run keeps moving\n * \"fast\" here means \"stays lively\", matching the semantics. */\nexport const SPEED_FAST_DECAY = 1000;\n\nexport interface GraphSimControlsProps {\n /** Explicit instance (multi-instance pages); ambient context otherwise. */\n instance?: AnyGraphInstance;\n /** Active layout kind — mirror of the caller's <Graph> `layout` prop\n * (no observable lane exists; module JSDoc). Default 'force'. */\n layout?: LayoutKind;\n /** Current simulation config seed — the same object passed to <Graph>.\n * An identity change re-seeds the panel's mirror. */\n simulation?: SimulationConfig;\n /** Fires with the FULL merged SimulationConfig after every write. */\n onSimulationChange?: (next: SimulationConfig) => void;\n /** Render-prop REPLACEMENT for a field row; the default renders\n * label + native range input + value readout. `set` clamps/quantizes to\n * the descriptor's bounds and step before writing. */\n renderField?: (ctx: {\n field: SimFieldDescriptor;\n value: number;\n /** Stable id for `htmlFor` wiring in custom rows. */\n inputId: string;\n set: (value: number) => void;\n }) => ReactNode;\n /** Accessible name of the panel. Default 'Simulation controls'. */\n label?: string;\n /** Corner this panel anchors to. Default 'bottom-left'. */\n position?: GraphCorner;\n /** Distance from the two anchored edges in CSS px. Default 12. */\n offset?: number;\n /** Class hook for the root; providing it drops the default styles\n * INCLUDING placement — position it yourself in CSS. */\n className?: string;\n /** Style overrides merged over the defaults; an inset you set here\n * wins over the one `position` implies (resolved per axis). */\n style?: CSSProperties;\n}\n\n/** Decimal places of `step` — the quantization grid for keyboard stepping. */\nfunction stepDecimals(step: number): number {\n const s = String(step);\n const dot = s.indexOf('.');\n return dot === -1 ? 0 : s.length - dot - 1;\n}\n\n/** Clamp to [min, max] and quantize to the step's decimal grid so repeated\n * keyboard steps never accumulate float noise (0.25 + 0.01 stays 0.26). */\nfunction quantize(field: SimFieldDescriptor, raw: number): number {\n const clamped = Math.min(field.max, Math.max(field.min, raw));\n return Number(clamped.toFixed(stepDecimals(field.step)));\n}\n\n/** keyboard model for a slider; null = key not handled (let it pass). */\nfunction keyboardTarget(field: SimFieldDescriptor, value: number, key: string): number | null {\n switch (key) {\n case 'ArrowRight':\n case 'ArrowUp':\n return quantize(field, value + field.step);\n case 'ArrowLeft':\n case 'ArrowDown':\n return quantize(field, value - field.step);\n case 'PageUp':\n return quantize(field, value + field.step * 10);\n case 'PageDown':\n return quantize(field, value - field.step * 10);\n case 'Home':\n return field.min;\n case 'End':\n return field.max;\n default:\n return null;\n }\n}\n\n// --- styling defaults (headless-styleable: className/style override) ---\nconst PANEL_STYLE: CSSProperties = {\n width: 250,\n pointerEvents: 'auto',\n display: 'flex',\n flexDirection: 'column',\n gap: 6,\n padding: 10,\n borderRadius: 8,\n background: 'rgba(23, 25, 32, 0.96)',\n border: '1px solid rgba(255, 255, 255, 0.14)',\n color: '#e8eaf0',\n font: '12px/1.4 system-ui, sans-serif',\n};\nconst TITLE_STYLE: CSSProperties = { fontWeight: 600, fontSize: 13 };\nconst ROW_STYLE: CSSProperties = { display: 'flex', alignItems: 'center', gap: 6 };\nconst LABEL_STYLE: CSSProperties = { flex: 'none', width: 86, opacity: 0.8 };\nconst SLIDER_STYLE: CSSProperties = { flex: 1, minWidth: 0 };\nconst VALUE_STYLE: CSSProperties = {\n flex: 'none',\n width: 38,\n textAlign: 'right',\n fontVariantNumeric: 'tabular-nums',\n};\nconst BUTTON_STYLE: CSSProperties = {\n appearance: 'none',\n background: 'transparent',\n border: '1px solid rgba(255, 255, 255, 0.2)',\n borderRadius: 6,\n color: 'inherit',\n cursor: 'pointer',\n font: 'inherit',\n padding: '4px 10px',\n};\nconst STATUS_STYLE: CSSProperties = { opacity: 0.65 };\n\nexport function GraphSimControls(props: GraphSimControlsProps): ReactElement | null {\n const instance = useResolvedInstance(props.instance, '<GraphSimControls>');\n const baseId = useId();\n\n // Mirror of the last-known SimulationConfig (module JSDoc: no store lane\n // exists to subscribe to). Prop identity change re-seeds — external\n // writer wins (the React-documented derive-during-render pattern).\n const [mirror, setMirror] = useState<SimulationConfig>(() => props.simulation ?? {});\n const [seededFrom, setSeededFrom] = useState(props.simulation);\n if (seededFrom !== props.simulation) {\n setSeededFrom(props.simulation);\n setMirror(props.simulation ?? {});\n }\n\n /** Decay the speed preset restores on release; undefined = the field was\n * unset pre-toggle (restore the engine-default constant). */\n const preSpeedDecayRef = useRef<number | undefined>(undefined);\n\n // The one simulation lane the store DOES publish.\n const subscribe = useCallback(\n (onStoreChange: () => void) => instance.store.subscribe(onStoreChange),\n [instance],\n );\n const getRunning = useCallback(\n () => instance.store.getState().simulationRunning,\n [instance],\n );\n const simulationRunning = useSyncExternalStore(subscribe, getRunning, getRunning);\n\n // applicability gate — after hooks, per the rules of hooks.\n if ((props.layout ?? 'force') !== 'force') return null;\n\n /** ONE atomic config-only host update per control write. */\n const write = (next: SimulationConfig): void => {\n setMirror(next);\n instance.applyHostUpdate({ simulation: next });\n props.onSimulationChange?.(next);\n };\n\n const setField = (key: SimFieldKey, value: number): void => {\n const next: SimulationConfig = { ...mirror };\n next[key] = value;\n write(next);\n };\n\n // The preset holds exactly while decay sits at the fast value — the toggle\n // and the cool-down slider are two views over the same lane.\n const speedOn = mirror.decay === SPEED_FAST_DECAY;\n const toggleSpeed = (): void => {\n if (speedOn) {\n const restored = preSpeedDecayRef.current ?? SPEED_NORMAL_DECAY;\n preSpeedDecayRef.current = undefined;\n setField('decay', restored);\n } else {\n preSpeedDecayRef.current = mirror.decay;\n setField('decay', SPEED_FAST_DECAY);\n }\n };\n\n const panelLabel = props.label ?? 'Simulation controls';\n const speedId = `${baseId}-speed`;\n\n return (\n <div\n data-orbit-simcontrols=\"\"\n role=\"group\"\n aria-label={panelLabel}\n className={props.className}\n style={\n props.className !== undefined\n ? props.style\n : mergeStyle(\n { ...cornerStyle(props.position ?? 'bottom-left', props.offset), ...PANEL_STYLE },\n props.style,\n )\n }\n >\n <div data-orbit-simcontrols-title=\"\" style={TITLE_STYLE}>\n {panelLabel}\n </div>\n\n {SIM_FIELDS.map((field) => {\n const value = mirror[field.key] ?? field.fallback;\n const inputId = `${baseId}-${field.key}`;\n const set = (v: number): void => {\n setField(field.key, quantize(field, v));\n };\n if (props.renderField !== undefined) {\n return (\n <Fragment key={field.key}>\n {props.renderField({ field, value, inputId, set })}\n </Fragment>\n );\n }\n return (\n <div key={field.key} data-orbit-simcontrols-field={field.key} style={ROW_STYLE}>\n <label htmlFor={inputId} style={LABEL_STYLE}>\n {field.label}\n </label>\n <input\n id={inputId}\n type=\"range\"\n data-orbit-simcontrols-input={field.key}\n min={field.min}\n max={field.max}\n step={field.step}\n value={value}\n onChange={(e) => {\n const v = Number(e.target.value);\n if (Number.isFinite(v)) set(v);\n }}\n onKeyDown={(e) => {\n const target = keyboardTarget(field, value, e.key);\n if (target === null) return;\n // Suppress the browser's native range step so the write goes\n // through this handler exactly once (module JSDoc).\n e.preventDefault();\n if (target !== value) setField(field.key, target);\n }}\n style={SLIDER_STYLE}\n />\n <output\n htmlFor={inputId}\n data-orbit-simcontrols-value={field.key}\n style={VALUE_STYLE}\n >\n {String(value)}\n </output>\n </div>\n );\n })}\n\n <div data-orbit-simcontrols-speed-row=\"\" style={ROW_STYLE}>\n <input\n id={speedId}\n type=\"checkbox\"\n data-orbit-simcontrols-speed=\"\"\n checked={speedOn}\n onChange={toggleSpeed}\n />\n <label htmlFor={speedId}>Speed boost</label>\n </div>\n\n <div style={ROW_STYLE}>\n <button\n type=\"button\"\n data-orbit-simcontrols-reheat=\"\"\n style={BUTTON_STYLE}\n onClick={() => {\n instance.resumeSimulation();\n }}\n >\n Reheat\n </button>\n <span data-orbit-simcontrols-status=\"\" style={STATUS_STYLE}>\n {simulationRunning ? 'simulation running' : 'settled'}\n </span>\n </div>\n </div>\n );\n}\n\n/** tree-shake probe — must never reach a root-only consumer bundle. */\nexport const __ORBIT_SIMCONTROLS_SENTINEL__ = 'orbit-react/components/SimControls';\n"]}
@@ -4,8 +4,8 @@ import { GraphEdge, GraphNode } from '@modernrelay/orbit-core';
4
4
  import { A as AnyGraphInstance } from '../GraphProvider-B8ITDXS0.js';
5
5
 
6
6
  /**
7
- * Pure row/column/sort/filter helpers for `<GraphTable>` (§16.10).
8
- * Framework-free so the §8 sort-coercion contract and the bounded column
7
+ * Pure row/column/sort/filter helpers for `<GraphTable>`.
8
+ * Framework-free so the sort-coercion contract and the bounded column
9
9
  * derivation stay unit-testable without a DOM.
10
10
  */
11
11
 
@@ -13,7 +13,7 @@ type GraphTableMode = 'nodes' | 'edges';
13
13
  interface GraphTableColumn {
14
14
  /** Column key: 'id', 'source'/'target' (edge mode), or an attr key. */
15
15
  key: string;
16
- /** Header text; defaults to the key. Rendered as a TEXT NODE (§14). */
16
+ /** Header text; defaults to the key. Rendered as a TEXT NODE. */
17
17
  label?: string;
18
18
  }
19
19
  interface GraphTableSort {
@@ -34,7 +34,7 @@ interface GraphTableRowRef {
34
34
  edge?: GraphEdge<any>;
35
35
  }
36
36
 
37
- /** S0-T02 tree-shake probe: importing `<Graph>` alone must not pull this. */
37
+ /** tree-shake probe: importing `<Graph>` alone must not pull this. */
38
38
  declare const __ORBIT_TABLE_SENTINEL__ = "orbit-react/components/Table";
39
39
  /** Default crossfilter dimension key the table filter registers on. */
40
40
  declare const TABLE_FILTER_DIMENSION_DEFAULT = "table";
@@ -1,4 +1,4 @@
1
- import { useResolvedInstance } from '../chunk-7XB47YST.js';
1
+ import { useResolvedInstance } from '../chunk-NPOV5GA3.js';
2
2
  import { forwardRef, useState, useMemo, useCallback, useRef, useEffect, useImperativeHandle, useSyncExternalStore } from 'react';
3
3
  import { coerceNumeric } from '@modernrelay/orbit-core';
4
4
  import { jsxs, jsx } from 'react/jsx-runtime';
@@ -296,7 +296,7 @@ function GraphTableInner(props, ref) {
296
296
  const session = wrote.instance.getCrossfilterSession();
297
297
  if (session !== null) void session.setBrush(wrote.key, null).catch(() => void 0);
298
298
  },
299
- []
299
+ [instance, mode, dimensionKey]
300
300
  );
301
301
  const selectedNodes = useMemo(() => new Set(selection.nodeIds), [selection]);
302
302
  const selectedEdges = useMemo(() => new Set(selection.edgeIds), [selection]);
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/Table/model.ts","../../src/components/Table/csv.ts","../../src/components/Table/index.tsx"],"names":[],"mappings":"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","file":"Table.js","sourcesContent":["/**\n * Pure row/column/sort/filter helpers for `<GraphTable>` (§16.10).\n * Framework-free so the §8 sort-coercion contract and the bounded column\n * derivation stay unit-testable without a DOM.\n */\n\nimport { coerceNumeric } from '@modernrelay/orbit-core';\nimport type { GraphEdge, GraphNode } from '@modernrelay/orbit-core';\n\nexport type GraphTableMode = 'nodes' | 'edges';\n\nexport interface GraphTableColumn {\n /** Column key: 'id', 'source'/'target' (edge mode), or an attr key. */\n key: string;\n /** Header text; defaults to the key. Rendered as a TEXT NODE (§14). */\n label?: string;\n}\n\nexport interface GraphTableSort {\n key: string;\n direction: 'asc' | 'desc';\n}\n\n/**\n * One table row. Node rows: `key === id === NodeId`. Edge rows carry the\n * caller edge; `id` is null when the caller supplied no edge id (such rows\n * render and export but cannot write edge selection — the core-synthesized\n * id is not observable through the public surface).\n */\nexport interface GraphTableRowRef {\n /** Stable render identity (node id, edge id, or a positional edge key). */\n key: string;\n /** Public id usable for selection writes; null = unaddressable edge row. */\n id: string | null;\n edge?: GraphEdge<any>;\n}\n\n/** Attr value → display TEXT (never markup): strings verbatim, numbers via\n * String, null/undefined empty, structured values JSON (cycles degrade to\n * the String form) — the Inspector's §14 convention. */\nexport function cellText(value: unknown): string {\n if (value === null || value === undefined) return '';\n if (typeof value === 'string') return value;\n if (typeof value === 'object') {\n try {\n return JSON.stringify(value) ?? String(value);\n } catch {\n return String(value);\n }\n }\n return String(value);\n}\n\nexport function nodeCellValue(\n node: GraphNode<any> | undefined,\n id: string,\n key: string,\n): unknown {\n if (key === 'id') return id;\n const attrs = node?.attrs as Record<string, unknown> | undefined;\n return attrs?.[key];\n}\n\nexport function edgeCellValue(edge: GraphEdge<any>, key: string): unknown {\n if (key === 'id') return edge.id ?? '';\n if (key === 'source') return edge.source;\n if (key === 'target') return edge.target;\n const attrs = edge.attrs as Record<string, unknown> | undefined;\n return attrs?.[key];\n}\n\nexport function normalizeColumns(\n pick: readonly (string | GraphTableColumn)[],\n): readonly GraphTableColumn[] {\n return pick.map((c) => (typeof c === 'string' ? { key: c } : c));\n}\n\n/**\n * Derived columns: the identity keys for the mode ('id', plus\n * 'source'/'target' for edges) followed by the union of attr keys over the\n * SAMPLED PREFIX the caller passes (bounded — attrs seen only past the\n * sample do not create columns; use the `columns` prop to pin them).\n * First-seen key order.\n */\nexport function deriveColumns(\n mode: GraphTableMode,\n attrsSample: readonly (Record<string, unknown> | undefined)[],\n): readonly GraphTableColumn[] {\n const keys: string[] = mode === 'edges' ? ['id', 'source', 'target'] : ['id'];\n const seen = new Set(keys);\n for (const attrs of attrsSample) {\n if (attrs === undefined) continue;\n for (const key of Object.keys(attrs)) {\n if (!seen.has(key)) {\n seen.add(key);\n keys.push(key);\n }\n }\n }\n return keys.map((key) => ({ key }));\n}\n\n// ---------------------------------------------------------------------------\n// §8 sort coercion. Three tiers:\n// 0 numeric — values `coerceNumeric` admits (numbers, numeric strings);\n// 1 string — everything else with content (plain strings, booleans,\n// structured values by display text);\n// 2 null — null/undefined, non-finite numbers, empty strings, and the\n// §8 sentinel strings 'NaN'/'Infinity'/'±Infinity'.\n// Tier order is fixed (numeric block, then string block); `direction` flips\n// ordering WITHIN each tier; the null tier is ALWAYS LAST regardless of\n// direction. Ties preserve base row order (stable sort).\n// ---------------------------------------------------------------------------\n\nexport interface SortKey {\n tier: 0 | 1 | 2;\n num: number;\n str: string;\n}\n\nconst NULL_KEY: SortKey = { tier: 2, num: 0, str: '' };\n\n/** Case-insensitive §8 hygiene sentinels (mirrors `coerceNumeric`'s list). */\nfunction isSentinelString(value: string): boolean {\n const lower = value.trim().toLowerCase();\n return (\n lower === '' ||\n lower === 'nan' ||\n lower === 'infinity' ||\n lower === '-infinity' ||\n lower === '+infinity'\n );\n}\n\nexport function sortKeyOf(value: unknown): SortKey {\n if (value === null || value === undefined) return NULL_KEY;\n const num = coerceNumeric(value);\n if (num !== null) return { tier: 0, num, str: '' };\n if (typeof value === 'number') return NULL_KEY; // non-finite\n if (typeof value === 'string') {\n return isSentinelString(value) ? NULL_KEY : { tier: 1, num: 0, str: value };\n }\n return { tier: 1, num: 0, str: cellText(value) };\n}\n\nexport function compareSortKeys(a: SortKey, b: SortKey, direction: 1 | -1): number {\n if (a.tier !== b.tier) {\n if (a.tier === 2) return 1; // nulls last regardless of direction\n if (b.tier === 2) return -1;\n return a.tier - b.tier; // numeric block before string block, fixed\n }\n if (a.tier === 2) return 0;\n if (a.tier === 0) return direction * (a.num < b.num ? -1 : a.num > b.num ? 1 : 0);\n return direction * (a.str < b.str ? -1 : a.str > b.str ? 1 : 0);\n}\n\n/** Case-insensitive substring match over a row's rendered cell texts. */\nexport function textMatches(texts: readonly string[], queryLower: string): boolean {\n for (const text of texts) {\n if (text.toLowerCase().includes(queryLower)) return true;\n }\n return false;\n}\n","/**\n * RFC-4180 CSV serialization with formula-injection neutralization\n * (§16.10 R-16.10-04, S12-T11).\n *\n * Contract:\n * - records join with CRLF (no trailing record terminator);\n * - a cell is quoted iff its text contains a double quote, comma, CR, or\n * LF; embedded double quotes double;\n * - NEUTRALIZATION (default on): a NON-NUMERIC cell whose text begins with\n * `=`, `+`, `-`, `@`, TAB, or CR gets a leading apostrophe — attr values\n * are untrusted (§14/§19) and must never export as live spreadsheet\n * formulas. Cells whose RAW value is a finite number are exempt and\n * serialize as plain numbers (`-5` stays `-5`). Neutralization runs\n * BEFORE quoting, so a prefixed cell still quotes correctly.\n * - header cells are strings and follow the same rules (attr KEYS are\n * untrusted too).\n *\n * The documented opt-out (`neutralizeFormulas: false`) is for callers\n * exporting legitimate formulas; the default stays safe.\n */\n\nimport { cellText } from './model';\n\nconst FORMULA_LEADS = '=+-@\\t\\r';\n\nexport function csvCell(value: unknown, neutralize: boolean): string {\n const numericExempt = typeof value === 'number' && Number.isFinite(value);\n let text = cellText(value);\n if (neutralize && !numericExempt && text.length > 0 && FORMULA_LEADS.includes(text[0]!)) {\n text = `'${text}`;\n }\n if (/[\",\\r\\n]/.test(text)) {\n text = `\"${text.replaceAll('\"', '\"\"')}\"`;\n }\n return text;\n}\n\nexport function toCsvString(\n header: readonly string[],\n rows: readonly (readonly unknown[])[],\n neutralize: boolean,\n): string {\n const records: string[] = [header.map((h) => csvCell(h, neutralize)).join(',')];\n for (const row of rows) {\n records.push(row.map((cell) => csvCell(cell, neutralize)).join(','));\n }\n return records.join('\\r\\n');\n}\n","/**\n * `@modernrelay/orbit-react/components/Table` — `<GraphTable>`, the §16.10\n * virtualized crossfiltered tabular view (S12-T10/T11).\n *\n * Rows are nodes (default) or edges; columns derive from the union of attr\n * keys over a BOUNDED sampled prefix (`columnSample`, default 200) plus the\n * identity keys, or are picked explicitly via `columns`. Every cell renders\n * as a TEXT NODE (§14 untrusted content); `renderCell` replaces cell content.\n *\n * ## Virtualization\n * Hand-rolled windowing (no external dependency): a fixed-height scroll\n * viewport over a full-height spacer with an absolutely positioned window of\n * `ceil(height/rowHeight) + 2*overscan` rows — the mounted row count is\n * BOUNDED regardless of row count (100K rows mount ~30 DOM rows). Row\n * geometry is prop-driven (`rowHeight`, `height`), never measured, so the\n * math is deterministic under jsdom; class hooks drop decorative styles but\n * MECHANICAL styles (viewport height, spacer, window offset, row height,\n * cell flex) always apply — geometry changes go through the props.\n *\n * ## Bidirectional sync\n * - graph → table: rows follow `instance.getVisibleNodeIds()` (scope ∧ §9.1\n * mask) via a store subscription; brushes, filters, legend toggles, and\n * hide/show narrow the rows. An edge row lists iff BOTH endpoints are\n * visible (the public surface exposes no per-edge visibility read —\n * documented approximation).\n * - table → graph: the text/predicate filter registers through the §16.6\n * crossfilter session as a brush on `filterDimension` (default 'table') —\n * the host opts in by configuring an ID-KEYED categorical dimension\n * `{ key: filterDimension, kind: 'categorical', get: (n) => n.id }`; the\n * filter then writes `{ excluded: nonMatchingIds }` over the scene roster\n * (null when the filter clears / matches everything), narrowing the graph\n * AND every other crossfilter view through the standard §9.1 mask fast\n * path, with standard brush history coalescing. DEGRADATION is graceful\n * and documented: no session (host never set `crossfilter`), an unknown\n * dimension key, or edge mode filter rows LOCALLY only — the graph is\n * untouched. A dimension keyed by anything other than row ids degrades the\n * same way (unknown excluded keys mask nothing). Unmounting clears any\n * brush this table wrote.\n * - selection: row click (or Enter/Space) writes the §16.2 SelectionState\n * through `selectNodes`/`selectEdges` (replace; meta/ctrl toggles\n * membership), so controlled selection degrades to intent per §6.4;\n * selected rows carry `aria-selected=\"true\"`.\n *\n * ## Sorting (§8 coercion)\n * Header click cycles none → asc → desc → none. Values sort in three tiers —\n * numeric (`coerceNumeric`-admitted), string (everything else with content),\n * null (null/undefined, non-finite, empty, and the 'NaN'/'Infinity' sentinel\n * strings). Tier order is fixed; direction flips order within a tier; the\n * null tier is ALWAYS LAST regardless of direction.\n *\n * ## CSV export (T11)\n * `exportCsv()` on the forwarded ref returns an RFC-4180 string over the\n * CURRENT filtered + sorted rows and visible columns: CRLF records, quote\n * doubling, and formula-injection neutralization (see ./csv.ts). The\n * documented opt-out is `neutralizeFormulas={false}`.\n *\n * Edge-mode row sourcing (documented v0.10 compromise): the public instance\n * surface exposes no edge roster, so `mode=\"edges\"` reads rows from the\n * `edges` prop — the same array the host passed in its snapshot. Edge rows\n * without a caller-supplied id render and export but cannot write selection.\n */\n\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n useSyncExternalStore,\n} from 'react';\nimport type {\n CSSProperties,\n ForwardedRef,\n KeyboardEvent,\n MouseEvent,\n ReactElement,\n ReactNode,\n UIEvent,\n} from 'react';\nimport type {\n BrushState,\n GraphEdge,\n GraphNode,\n GraphStoreState,\n SelectionState,\n} from '@modernrelay/orbit-core';\nimport type { AnyGraphInstance } from '../../GraphProvider';\nimport { useResolvedInstance } from '../shared';\nimport {\n cellText,\n compareSortKeys,\n deriveColumns,\n edgeCellValue,\n nodeCellValue,\n normalizeColumns,\n sortKeyOf,\n textMatches,\n} from './model';\nimport type { GraphTableColumn, GraphTableMode, GraphTableRowRef, GraphTableSort } from './model';\nimport { toCsvString } from './csv';\n\nexport type { GraphTableColumn, GraphTableMode, GraphTableRowRef, GraphTableSort } from './model';\n\n/** S0-T02 tree-shake probe: importing `<Graph>` alone must not pull this. */\nexport const __ORBIT_TABLE_SENTINEL__ = 'orbit-react/components/Table';\n\nconst COLUMN_SAMPLE_DEFAULT = 200;\nconst ROW_HEIGHT_DEFAULT = 28;\nconst HEIGHT_DEFAULT = 320;\nconst OVERSCAN_DEFAULT = 8;\n/** Default crossfilter dimension key the table filter registers on. */\nexport const TABLE_FILTER_DIMENSION_DEFAULT = 'table';\n\nexport interface GraphTableCellContext {\n row: GraphTableRowRef;\n /** Resolved node for node rows (undefined for edge rows / unknown ids). */\n node?: GraphNode<any>;\n column: GraphTableColumn;\n value: unknown;\n /** The default display text (always safe to render as a text node). */\n text: string;\n}\n\nexport interface GraphTableHandle {\n /** RFC-4180 CSV over the current filtered+sorted rows (see module doc). */\n exportCsv(): string;\n}\n\nexport interface GraphTableProps {\n /** Explicit instance (multi-instance pages); ambient context otherwise. */\n instance?: AnyGraphInstance;\n /** Row source. Default 'nodes'. */\n mode?: GraphTableMode;\n /** Edge-mode rows (documented compromise — see module doc). */\n edges?: readonly GraphEdge<any>[];\n /** Explicit column pick; replaces derivation entirely. */\n columns?: readonly (string | GraphTableColumn)[];\n /** Bounded derivation prefix (rows sampled for the attr-key union). Default 200. */\n columnSample?: number;\n /** Controlled filter text; uncontrolled via the built-in input otherwise. */\n filterText?: string;\n onFilterTextChange?: (text: string) => void;\n /** Composed AND with the text filter; receives the underlying item. */\n filterPredicate?: (item: GraphNode<any> | GraphEdge<any>) => boolean;\n /** Crossfilter dimension key the filter registers on. Default 'table'. */\n filterDimension?: string;\n /** CSV formula-injection neutralization opt-out. Default true (safe). */\n neutralizeFormulas?: boolean;\n /** Row height in CSS px (mechanical — drives the window math). Default 28. */\n rowHeight?: number;\n /** Scroll viewport height in CSS px (mechanical). Default 320. */\n height?: number;\n /** Extra rows mounted on each side of the viewport. Default 8. */\n overscan?: number;\n /** Replaces default cell content (rendered inside the cell element). */\n renderCell?: (ctx: GraphTableCellContext) => ReactNode;\n /** Accessible name of the table. Default 'Graph table'. */\n label?: string;\n /** Class hook for the root; providing it drops the decorative styles. */\n className?: string;\n style?: CSSProperties;\n /** Class hook for body rows; providing it drops their decorative styles. */\n rowClassName?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Store subscriptions\n// ---------------------------------------------------------------------------\n\n/**\n * Version string that changes whenever the row model could: revisions,\n * visible counts, accepted counts, status, and session availability. The\n * session listener re-attaches on every store publication (the\n * _shared/crossfilter convention — engine rebuilds swap subscribers).\n */\nfunction useTableVersion(instance: AnyGraphInstance): string {\n const subscribe = useCallback(\n (onChange: () => void) => {\n let sessionUnsub: (() => void) | null = null;\n const attach = (): void => {\n sessionUnsub?.();\n sessionUnsub = null;\n const session = instance.getCrossfilterSession();\n if (session !== null) sessionUnsub = session.subscribe(onChange);\n };\n attach();\n const storeUnsub = instance.store.subscribe(() => {\n attach();\n onChange();\n });\n return () => {\n storeUnsub();\n sessionUnsub?.();\n sessionUnsub = null;\n };\n },\n [instance],\n );\n const getSnapshot = useCallback((): string => {\n const s: GraphStoreState = instance.store.getState();\n const hasSession = instance.getCrossfilterSession() !== null ? 1 : 0;\n return `${s.status}:${s.revisions.model}:${s.revisions.scope}:${s.revisions.render}:${s.visible.nodes}:${s.visible.edges}:${s.nodeCount}:${s.edgeCount}:${hasSession}`;\n }, [instance]);\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\n/** The store keeps `selection` referentially stable across unrelated\n * publishes, so the raw field is a valid useSyncExternalStore snapshot. */\nfunction useSelection(instance: AnyGraphInstance): SelectionState {\n const subscribe = useCallback(\n (onChange: () => void) => instance.store.subscribe(onChange),\n [instance],\n );\n const getSnapshot = useCallback(\n (): SelectionState => instance.store.getState().selection,\n [instance],\n );\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\n// ---------------------------------------------------------------------------\n// Styling defaults (decorative styles drop when the class hooks are given;\n// mechanical geometry always applies — see module doc).\n// ---------------------------------------------------------------------------\n\nconst ROOT_STYLE: CSSProperties = {\n display: 'flex',\n flexDirection: 'column',\n gap: 6,\n padding: 8,\n borderRadius: 8,\n background: 'rgba(23, 25, 32, 0.96)',\n border: '1px solid rgba(255, 255, 255, 0.14)',\n color: '#e8eaf0',\n font: '12px/1.4 system-ui, sans-serif',\n};\nconst TOOLBAR_STYLE: CSSProperties = { display: 'flex', alignItems: 'center', gap: 8 };\nconst FILTER_STYLE: CSSProperties = {\n flex: 1,\n minWidth: 0,\n background: 'rgba(255, 255, 255, 0.06)',\n border: '1px solid rgba(255, 255, 255, 0.14)',\n borderRadius: 6,\n color: 'inherit',\n font: 'inherit',\n padding: '3px 8px',\n};\nconst COUNT_STYLE: CSSProperties = { opacity: 0.65, whiteSpace: 'nowrap' };\nconst HEADER_ROW_STYLE: CSSProperties = { borderBottom: '1px solid rgba(255, 255, 255, 0.2)' };\nconst HEADER_BUTTON_STYLE: CSSProperties = {\n appearance: 'none',\n background: 'transparent',\n border: 'none',\n color: 'inherit',\n cursor: 'pointer',\n font: 'inherit',\n fontWeight: 600,\n padding: '2px 4px',\n textAlign: 'left',\n width: '100%',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n};\nconst ROW_STYLE: CSSProperties = { cursor: 'pointer' };\nconst ROW_SELECTED_STYLE: CSSProperties = {\n ...ROW_STYLE,\n background: 'rgba(122, 162, 255, 0.22)',\n};\nconst CELL_STYLE: CSSProperties = {\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n padding: '0 4px',\n};\nconst EMPTY_STYLE: CSSProperties = { fontStyle: 'italic', opacity: 0.8, padding: 4 };\n\n/** Mechanical (always applied) flex geometry for header/body cells. */\nconst CELL_MECHANICS: CSSProperties = { flex: 1, minWidth: 0 };\n\nfunction GraphTableInner(\n props: GraphTableProps,\n ref: ForwardedRef<GraphTableHandle>,\n): ReactElement {\n const instance = useResolvedInstance(props.instance, '<GraphTable>');\n const version = useTableVersion(instance);\n const selection = useSelection(instance);\n\n const mode: GraphTableMode = props.mode ?? 'nodes';\n const rowHeight = props.rowHeight ?? ROW_HEIGHT_DEFAULT;\n const height = props.height ?? HEIGHT_DEFAULT;\n const overscan = props.overscan ?? OVERSCAN_DEFAULT;\n const dimensionKey = props.filterDimension ?? TABLE_FILTER_DIMENSION_DEFAULT;\n const neutralize = props.neutralizeFormulas ?? true;\n const predicate = props.filterPredicate;\n\n const [internalFilter, setInternalFilter] = useState('');\n const filterText = props.filterText ?? internalFilter;\n const query = filterText.trim().toLowerCase();\n const [sort, setSort] = useState<GraphTableSort | null>(null);\n const [scrollTop, setScrollTop] = useState(0);\n\n // --- row model -------------------------------------------------------------\n\n const edgesProp = props.edges;\n const baseRows = useMemo<readonly GraphTableRowRef[]>(() => {\n void version; // rebuild on every relevant store publication\n if (mode === 'edges') {\n const visible = new Set(instance.getVisibleNodeIds());\n const out: GraphTableRowRef[] = [];\n (edgesProp ?? []).forEach((edge, i) => {\n if (!visible.has(edge.source) || !visible.has(edge.target)) return;\n if (edge.id !== undefined) out.push({ key: edge.id, id: edge.id, edge });\n else out.push({ key: `${i}:${edge.source}→${edge.target}`, id: null, edge });\n });\n return out;\n }\n return instance.getVisibleNodeIds().map((id) => ({ key: id, id }));\n }, [instance, version, mode, edgesProp]);\n\n const columnSample = props.columnSample ?? COLUMN_SAMPLE_DEFAULT;\n const columnsProp = props.columns;\n const columns = useMemo<readonly GraphTableColumn[]>(() => {\n if (columnsProp !== undefined) return normalizeColumns(columnsProp);\n const sample = baseRows.slice(0, columnSample).map((row) => {\n return row.edge !== undefined\n ? (row.edge.attrs as Record<string, unknown> | undefined)\n : ((instance.getNode(row.key) as GraphNode<any> | undefined)?.attrs as\n | Record<string, unknown>\n | undefined);\n });\n return deriveColumns(mode, sample);\n }, [instance, baseRows, mode, columnsProp, columnSample]);\n\n const valueOf = useCallback(\n (row: GraphTableRowRef, key: string): unknown =>\n row.edge !== undefined\n ? edgeCellValue(row.edge, key)\n : nodeCellValue(instance.getNode(row.key) as GraphNode<any> | undefined, row.key, key),\n [instance],\n );\n\n /** Text/predicate match for one row over the visible columns. */\n const matchesRow = useCallback(\n (row: GraphTableRowRef): boolean => {\n if (predicate !== undefined) {\n const item =\n row.edge !== undefined\n ? row.edge\n : (instance.getNode(row.key) as GraphNode<any> | undefined);\n if (item === undefined || !predicate(item)) return false;\n }\n if (query === '') return true;\n return textMatches(\n columns.map((col) => cellText(valueOf(row, col.key))),\n query,\n );\n },\n [instance, predicate, query, columns, valueOf],\n );\n\n const filterActive = query !== '' || predicate !== undefined;\n const filteredRows = useMemo<readonly GraphTableRowRef[]>(\n () => (filterActive ? baseRows.filter(matchesRow) : baseRows),\n [baseRows, filterActive, matchesRow],\n );\n\n const sortedRows = useMemo<readonly GraphTableRowRef[]>(() => {\n if (sort === null || !columns.some((c) => c.key === sort.key)) return filteredRows;\n const direction: 1 | -1 = sort.direction === 'asc' ? 1 : -1;\n const decorated = filteredRows.map((row) => ({\n row,\n key: sortKeyOf(valueOf(row, sort.key)),\n }));\n decorated.sort((a, b) => compareSortKeys(a.key, b.key, direction)); // stable → base-order ties\n return decorated.map((d) => d.row);\n }, [filteredRows, sort, columns, valueOf]);\n\n // --- table → graph: crossfilter registration (see module doc) ---------------\n\n /** Set once this table wrote a non-null brush; unmount clears it. */\n const wroteBrushRef = useRef<{ instance: AnyGraphInstance; key: string } | null>(null);\n\n useEffect(() => {\n if (mode !== 'nodes') return;\n const session = instance.getCrossfilterSession();\n if (session === null) return;\n try {\n session.getBrush(dimensionKey);\n } catch {\n return; // dimension not configured — degrade to local-only filtering\n }\n let brush: BrushState = null;\n if (filterActive) {\n const excluded: string[] = [];\n for (const id of instance.getSceneNodeIds()) {\n if (!matchesRow({ key: id, id })) excluded.push(id);\n }\n if (excluded.length > 0) brush = { excluded };\n }\n if (brush !== null) wroteBrushRef.current = { instance, key: dimensionKey };\n // Deep-equal brushes no-op inside the engine, so re-runs are cheap.\n void session.setBrush(dimensionKey, brush).catch(() => undefined);\n }, [instance, version, mode, dimensionKey, filterActive, matchesRow]);\n\n useEffect(\n () => () => {\n const wrote = wroteBrushRef.current;\n if (wrote === null) return;\n wroteBrushRef.current = null;\n const session = wrote.instance.getCrossfilterSession();\n if (session !== null) void session.setBrush(wrote.key, null).catch(() => undefined);\n },\n [],\n );\n\n // --- selection ---------------------------------------------------------------\n\n const selectedNodes = useMemo(() => new Set(selection.nodeIds), [selection]);\n const selectedEdges = useMemo(() => new Set(selection.edgeIds), [selection]);\n const isSelected = (row: GraphTableRowRef): boolean =>\n row.edge !== undefined\n ? row.id !== null && selectedEdges.has(row.id)\n : selectedNodes.has(row.key);\n\n const activateRow = (row: GraphTableRowRef, additive: boolean): void => {\n if (row.edge !== undefined) {\n if (row.id === null) return; // unaddressable (no caller edge id)\n const id = row.id;\n if (additive) {\n const current = selection.edgeIds;\n instance.selectEdges(\n current.includes(id) ? current.filter((e) => e !== id) : [...current, id],\n );\n } else {\n instance.selectEdges([id]);\n }\n return;\n }\n if (additive) {\n const current = selection.nodeIds;\n instance.selectNodes(\n current.includes(row.key) ? current.filter((n) => n !== row.key) : [...current, row.key],\n );\n } else {\n instance.selectNodes([row.key]);\n }\n };\n\n // --- CSV export (T11) ----------------------------------------------------------\n\n const exportStateRef = useRef({ columns, rows: sortedRows, valueOf, neutralize });\n exportStateRef.current = { columns, rows: sortedRows, valueOf, neutralize };\n useImperativeHandle(\n ref,\n (): GraphTableHandle => ({\n exportCsv: (): string => {\n const s = exportStateRef.current;\n return toCsvString(\n s.columns.map((col) => col.label ?? col.key),\n s.rows.map((row) => s.columns.map((col) => s.valueOf(row, col.key))),\n s.neutralize,\n );\n },\n }),\n [],\n );\n\n // --- windowing -----------------------------------------------------------------\n\n const total = sortedRows.length;\n const first = Math.max(0, Math.floor(scrollTop / rowHeight) - overscan);\n const windowSize = Math.ceil(height / rowHeight) + overscan * 2;\n const windowRows = sortedRows.slice(first, first + windowSize);\n\n const onScroll = (e: UIEvent<HTMLDivElement>): void => {\n setScrollTop(e.currentTarget.scrollTop);\n };\n\n const cycleSort = (key: string): void => {\n setSort((prev) => {\n if (prev === null || prev.key !== key) return { key, direction: 'asc' };\n if (prev.direction === 'asc') return { key, direction: 'desc' };\n return null;\n });\n };\n\n const onFilterChange = (text: string): void => {\n if (props.filterText === undefined) setInternalFilter(text);\n props.onFilterTextChange?.(text);\n };\n\n const styled = props.className === undefined;\n const rowStyled = props.rowClassName === undefined;\n const label = props.label ?? 'Graph table';\n\n const renderRow = (row: GraphTableRowRef, index: number): ReactElement => {\n const selected = isSelected(row);\n const node =\n row.edge === undefined\n ? (instance.getNode(row.key) as GraphNode<any> | undefined)\n : undefined;\n const mechanics: CSSProperties = {\n height: rowHeight,\n display: 'flex',\n alignItems: 'center',\n boxSizing: 'border-box',\n };\n return (\n <div\n key={row.key}\n role=\"row\"\n aria-rowindex={first + index + 2}\n aria-selected={selected}\n data-orbit-table-row={row.key}\n tabIndex={0}\n className={props.rowClassName}\n style={\n rowStyled ? { ...mechanics, ...(selected ? ROW_SELECTED_STYLE : ROW_STYLE) } : mechanics\n }\n onClick={(e: MouseEvent<HTMLDivElement>) => {\n activateRow(row, e.metaKey || e.ctrlKey);\n }}\n onKeyDown={(e: KeyboardEvent<HTMLDivElement>) => {\n if (e.key !== 'Enter' && e.key !== ' ') return;\n e.preventDefault();\n activateRow(row, e.metaKey || e.ctrlKey);\n }}\n >\n {columns.map((col) => {\n const value = valueOf(row, col.key);\n const text = cellText(value);\n const ctx: GraphTableCellContext =\n node !== undefined\n ? { row, node, column: col, value, text }\n : { row, column: col, value, text };\n return (\n <div\n key={col.key}\n role=\"cell\"\n data-orbit-table-cell={col.key}\n style={styled ? { ...CELL_MECHANICS, ...CELL_STYLE } : CELL_MECHANICS}\n >\n {props.renderCell !== undefined ? props.renderCell(ctx) : text}\n </div>\n );\n })}\n </div>\n );\n };\n\n return (\n <div\n data-orbit-table={mode}\n role=\"group\"\n aria-label={label}\n className={props.className}\n style={styled ? { ...ROOT_STYLE, ...props.style } : props.style}\n >\n <div data-orbit-table-toolbar=\"\" style={styled ? TOOLBAR_STYLE : undefined}>\n <input\n type=\"text\"\n data-orbit-table-filter=\"\"\n aria-label=\"Filter rows\"\n value={filterText}\n style={styled ? FILTER_STYLE : undefined}\n onChange={(e) => {\n onFilterChange(e.currentTarget.value);\n }}\n />\n <span data-orbit-table-count=\"\" style={styled ? COUNT_STYLE : undefined}>\n {`${total} of ${baseRows.length} rows`}\n </span>\n </div>\n <div role=\"table\" aria-label={`${label} rows`} aria-rowcount={total + 1}>\n <div role=\"rowgroup\">\n <div\n role=\"row\"\n aria-rowindex={1}\n data-orbit-table-head=\"\"\n style={styled ? { display: 'flex', ...HEADER_ROW_STYLE } : { display: 'flex' }}\n >\n {columns.map((col) => {\n const active = sort !== null && sort.key === col.key;\n const ariaSort = active\n ? sort.direction === 'asc'\n ? 'ascending'\n : 'descending'\n : 'none';\n return (\n <div\n key={col.key}\n role=\"columnheader\"\n aria-sort={ariaSort}\n data-orbit-table-header={col.key}\n style={CELL_MECHANICS}\n >\n <button\n type=\"button\"\n data-orbit-table-sort={col.key}\n style={styled ? HEADER_BUTTON_STYLE : undefined}\n onClick={() => {\n cycleSort(col.key);\n }}\n >\n {col.label ?? col.key}\n </button>\n </div>\n );\n })}\n </div>\n </div>\n <div\n role=\"rowgroup\"\n data-orbit-table-viewport=\"\"\n onScroll={onScroll}\n style={{ height, overflowY: 'auto', position: 'relative' }}\n >\n {total === 0 ? (\n <div data-orbit-table-empty=\"\" style={styled ? EMPTY_STYLE : undefined}>\n No rows\n </div>\n ) : (\n <div\n data-orbit-table-spacer=\"\"\n style={{ height: total * rowHeight, position: 'relative' }}\n >\n <div\n data-orbit-table-window=\"\"\n style={{ position: 'absolute', top: first * rowHeight, left: 0, right: 0 }}\n >\n {windowRows.map((row, i) => renderRow(row, i))}\n </div>\n </div>\n )}\n </div>\n </div>\n </div>\n );\n}\n\nexport const GraphTable = forwardRef<GraphTableHandle, GraphTableProps>(GraphTableInner);\nGraphTable.displayName = 'GraphTable';\n"]}
1
+ {"version":3,"sources":["../../src/components/Table/model.ts","../../src/components/Table/csv.ts","../../src/components/Table/index.tsx"],"names":[],"mappings":"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","file":"Table.js","sourcesContent":["/**\n * Pure row/column/sort/filter helpers for `<GraphTable>`.\n * Framework-free so the sort-coercion contract and the bounded column\n * derivation stay unit-testable without a DOM.\n */\n\nimport { coerceNumeric } from '@modernrelay/orbit-core';\nimport type { GraphEdge, GraphNode } from '@modernrelay/orbit-core';\n\nexport type GraphTableMode = 'nodes' | 'edges';\n\nexport interface GraphTableColumn {\n /** Column key: 'id', 'source'/'target' (edge mode), or an attr key. */\n key: string;\n /** Header text; defaults to the key. Rendered as a TEXT NODE. */\n label?: string;\n}\n\nexport interface GraphTableSort {\n key: string;\n direction: 'asc' | 'desc';\n}\n\n/**\n * One table row. Node rows: `key === id === NodeId`. Edge rows carry the\n * caller edge; `id` is null when the caller supplied no edge id (such rows\n * render and export but cannot write edge selection — the core-synthesized\n * id is not observable through the public surface).\n */\nexport interface GraphTableRowRef {\n /** Stable render identity (node id, edge id, or a positional edge key). */\n key: string;\n /** Public id usable for selection writes; null = unaddressable edge row. */\n id: string | null;\n edge?: GraphEdge<any>;\n}\n\n/** Attr value → display TEXT (never markup): strings verbatim, numbers via\n * String, null/undefined empty, structured values JSON (cycles degrade to\n * the String form) — the Inspector's convention. */\nexport function cellText(value: unknown): string {\n if (value === null || value === undefined) return '';\n if (typeof value === 'string') return value;\n if (typeof value === 'object') {\n try {\n return JSON.stringify(value) ?? String(value);\n } catch {\n return String(value);\n }\n }\n return String(value);\n}\n\nexport function nodeCellValue(\n node: GraphNode<any> | undefined,\n id: string,\n key: string,\n): unknown {\n if (key === 'id') return id;\n const attrs = node?.attrs as Record<string, unknown> | undefined;\n return attrs?.[key];\n}\n\nexport function edgeCellValue(edge: GraphEdge<any>, key: string): unknown {\n if (key === 'id') return edge.id ?? '';\n if (key === 'source') return edge.source;\n if (key === 'target') return edge.target;\n const attrs = edge.attrs as Record<string, unknown> | undefined;\n return attrs?.[key];\n}\n\nexport function normalizeColumns(\n pick: readonly (string | GraphTableColumn)[],\n): readonly GraphTableColumn[] {\n return pick.map((c) => (typeof c === 'string' ? { key: c } : c));\n}\n\n/**\n * Derived columns: the identity keys for the mode ('id', plus\n * 'source'/'target' for edges) followed by the union of attr keys over the\n * SAMPLED PREFIX the caller passes (bounded — attrs seen only past the\n * sample do not create columns; use the `columns` prop to pin them).\n * First-seen key order.\n */\nexport function deriveColumns(\n mode: GraphTableMode,\n attrsSample: readonly (Record<string, unknown> | undefined)[],\n): readonly GraphTableColumn[] {\n const keys: string[] = mode === 'edges' ? ['id', 'source', 'target'] : ['id'];\n const seen = new Set(keys);\n for (const attrs of attrsSample) {\n if (attrs === undefined) continue;\n for (const key of Object.keys(attrs)) {\n if (!seen.has(key)) {\n seen.add(key);\n keys.push(key);\n }\n }\n }\n return keys.map((key) => ({ key }));\n}\n\n// ---------------------------------------------------------------------------\n// sort coercion. Three tiers:\n// 0 numeric — values `coerceNumeric` admits (numbers, numeric strings);\n// 1 string — everything else with content (plain strings, booleans,\n// structured values by display text);\n// 2 null — null/undefined, non-finite numbers, empty strings, and the\n// sentinel strings 'NaN'/'Infinity'/'±Infinity'.\n// Tier order is fixed (numeric block, then string block); `direction` flips\n// ordering WITHIN each tier; the null tier is ALWAYS LAST regardless of\n// direction. Ties preserve base row order (stable sort).\n// ---------------------------------------------------------------------------\n\nexport interface SortKey {\n tier: 0 | 1 | 2;\n num: number;\n str: string;\n}\n\nconst NULL_KEY: SortKey = { tier: 2, num: 0, str: '' };\n\n/** Case-insensitive hygiene sentinels (mirrors `coerceNumeric`'s list). */\nfunction isSentinelString(value: string): boolean {\n const lower = value.trim().toLowerCase();\n return (\n lower === '' ||\n lower === 'nan' ||\n lower === 'infinity' ||\n lower === '-infinity' ||\n lower === '+infinity'\n );\n}\n\nexport function sortKeyOf(value: unknown): SortKey {\n if (value === null || value === undefined) return NULL_KEY;\n const num = coerceNumeric(value);\n if (num !== null) return { tier: 0, num, str: '' };\n if (typeof value === 'number') return NULL_KEY; // non-finite\n if (typeof value === 'string') {\n return isSentinelString(value) ? NULL_KEY : { tier: 1, num: 0, str: value };\n }\n return { tier: 1, num: 0, str: cellText(value) };\n}\n\nexport function compareSortKeys(a: SortKey, b: SortKey, direction: 1 | -1): number {\n if (a.tier !== b.tier) {\n if (a.tier === 2) return 1; // nulls last regardless of direction\n if (b.tier === 2) return -1;\n return a.tier - b.tier; // numeric block before string block, fixed\n }\n if (a.tier === 2) return 0;\n if (a.tier === 0) return direction * (a.num < b.num ? -1 : a.num > b.num ? 1 : 0);\n return direction * (a.str < b.str ? -1 : a.str > b.str ? 1 : 0);\n}\n\n/** Case-insensitive substring match over a row's rendered cell texts. */\nexport function textMatches(texts: readonly string[], queryLower: string): boolean {\n for (const text of texts) {\n if (text.toLowerCase().includes(queryLower)) return true;\n }\n return false;\n}\n","/**\n * RFC-4180 CSV serialization with formula-injection neutralization.\n *\n * Contract:\n * - records join with CRLF (no trailing record terminator);\n * - a cell is quoted iff its text contains a double quote, comma, CR, or\n * LF; embedded double quotes double;\n * - NEUTRALIZATION (default on): a NON-NUMERIC cell whose text begins with\n * `=`, `+`, `-`, `@`, TAB, or CR gets a leading apostrophe — attr values\n * are untrusted and must never export as live spreadsheet\n * formulas. Cells whose RAW value is a finite number are exempt and\n * serialize as plain numbers (`-5` stays `-5`). Neutralization runs\n * BEFORE quoting, so a prefixed cell still quotes correctly.\n * - header cells are strings and follow the same rules (attr KEYS are\n * untrusted too).\n *\n * The documented opt-out (`neutralizeFormulas: false`) is for callers\n * exporting legitimate formulas; the default stays safe.\n */\n\nimport { cellText } from './model';\n\nconst FORMULA_LEADS = '=+-@\\t\\r';\n\nexport function csvCell(value: unknown, neutralize: boolean): string {\n const numericExempt = typeof value === 'number' && Number.isFinite(value);\n let text = cellText(value);\n if (neutralize && !numericExempt && text.length > 0 && FORMULA_LEADS.includes(text[0]!)) {\n text = `'${text}`;\n }\n if (/[\",\\r\\n]/.test(text)) {\n text = `\"${text.replaceAll('\"', '\"\"')}\"`;\n }\n return text;\n}\n\nexport function toCsvString(\n header: readonly string[],\n rows: readonly (readonly unknown[])[],\n neutralize: boolean,\n): string {\n const records: string[] = [header.map((h) => csvCell(h, neutralize)).join(',')];\n for (const row of rows) {\n records.push(row.map((cell) => csvCell(cell, neutralize)).join(','));\n }\n return records.join('\\r\\n');\n}\n","/**\n * `@modernrelay/orbit-react/components/Table` — `<GraphTable>`, the\n * virtualized crossfiltered tabular view.\n *\n * Rows are nodes (default) or edges; columns derive from the union of attr\n * keys over a BOUNDED sampled prefix (`columnSample`, default 200) plus the\n * identity keys, or are picked explicitly via `columns`. Every cell renders\n * as a TEXT NODE; `renderCell` replaces cell content.\n *\n * ## Virtualization\n * Hand-rolled windowing (no external dependency): a fixed-height scroll\n * viewport over a full-height spacer with an absolutely positioned window of\n * `ceil(height/rowHeight) + 2*overscan` rows — the mounted row count is\n * BOUNDED regardless of row count (100K rows mount ~30 DOM rows). Row\n * geometry is prop-driven (`rowHeight`, `height`), never measured, so the\n * math is deterministic under jsdom; class hooks drop decorative styles but\n * MECHANICAL styles (viewport height, spacer, window offset, row height,\n * cell flex) always apply — geometry changes go through the props.\n *\n * ## Bidirectional sync\n * - graph → table: rows follow `instance.getVisibleNodeIds` (scope ∧\n * mask) via a store subscription; brushes, filters, legend toggles, and\n * hide/show narrow the rows. An edge row lists iff BOTH endpoints are\n * visible (the public surface exposes no per-edge visibility read\n * documented approximation).\n * - table → graph: the text/predicate filter registers through the\n * crossfilter session as a brush on `filterDimension` (default 'table')\n * the host opts in by configuring an ID-KEYED categorical dimension\n * `{ key: filterDimension, kind: 'categorical', get: (n) => n.id }`; the\n * filter then writes `{ excluded: nonMatchingIds }` over the scene roster\n * (null when the filter clears / matches everything), narrowing the graph\n * AND every other crossfilter view through the standard mask fast\n * path, with standard brush history coalescing. DEGRADATION is graceful\n * and documented: no session (host never set `crossfilter`), an unknown\n * dimension key, or edge mode filter rows LOCALLY only — the graph is\n * untouched. A dimension keyed by anything other than row ids degrades the\n * same way (unknown excluded keys mask nothing). Unmounting clears any\n * brush this table wrote.\n * - selection: row click (or Enter/Space) writes the SelectionState\n * through `selectNodes`/`selectEdges` (replace; meta/ctrl toggles\n * membership), so controlled selection emits intent without mutating state;\n * selected rows carry `aria-selected=\"true\"`.\n *\n * ## Sorting\n * Header click cycles none → asc → desc → none. Values sort in three tiers\n * numeric (`coerceNumeric`-admitted), string (everything else with content),\n * null (null/undefined, non-finite, empty, and the 'NaN'/'Infinity' sentinel\n * strings). Tier order is fixed; direction flips order within a tier; the\n * null tier is ALWAYS LAST regardless of direction.\n *\n * ## CSV export\n * `exportCsv` on the forwarded ref returns an RFC-4180 string over the\n * CURRENT filtered + sorted rows and visible columns: CRLF records, quote\n * doubling, and formula-injection neutralization (see ./csv.ts). The\n * documented opt-out is `neutralizeFormulas={false}`.\n *\n * Edge-mode row sourcing (documented v0.10 compromise): the public instance\n * surface exposes no edge roster, so `mode=\"edges\"` reads rows from the\n * `edges` prop — the same array the host passed in its snapshot. Edge rows\n * without a caller-supplied id render and export but cannot write selection.\n */\n\nimport {\n forwardRef,\n useCallback,\n useEffect,\n useImperativeHandle,\n useMemo,\n useRef,\n useState,\n useSyncExternalStore,\n} from 'react';\nimport type {\n CSSProperties,\n ForwardedRef,\n KeyboardEvent,\n MouseEvent,\n ReactElement,\n ReactNode,\n UIEvent,\n} from 'react';\nimport type {\n BrushState,\n GraphEdge,\n GraphNode,\n GraphStoreState,\n SelectionState,\n} from '@modernrelay/orbit-core';\nimport type { AnyGraphInstance } from '../../GraphProvider';\nimport { useResolvedInstance } from '../shared';\nimport {\n cellText,\n compareSortKeys,\n deriveColumns,\n edgeCellValue,\n nodeCellValue,\n normalizeColumns,\n sortKeyOf,\n textMatches,\n} from './model';\nimport type { GraphTableColumn, GraphTableMode, GraphTableRowRef, GraphTableSort } from './model';\nimport { toCsvString } from './csv';\n\nexport type { GraphTableColumn, GraphTableMode, GraphTableRowRef, GraphTableSort } from './model';\n\n/** tree-shake probe: importing `<Graph>` alone must not pull this. */\nexport const __ORBIT_TABLE_SENTINEL__ = 'orbit-react/components/Table';\n\nconst COLUMN_SAMPLE_DEFAULT = 200;\nconst ROW_HEIGHT_DEFAULT = 28;\nconst HEIGHT_DEFAULT = 320;\nconst OVERSCAN_DEFAULT = 8;\n/** Default crossfilter dimension key the table filter registers on. */\nexport const TABLE_FILTER_DIMENSION_DEFAULT = 'table';\n\nexport interface GraphTableCellContext {\n row: GraphTableRowRef;\n /** Resolved node for node rows (undefined for edge rows / unknown ids). */\n node?: GraphNode<any>;\n column: GraphTableColumn;\n value: unknown;\n /** The default display text (always safe to render as a text node). */\n text: string;\n}\n\nexport interface GraphTableHandle {\n /** RFC-4180 CSV over the current filtered+sorted rows (see module doc). */\n exportCsv(): string;\n}\n\nexport interface GraphTableProps {\n /** Explicit instance (multi-instance pages); ambient context otherwise. */\n instance?: AnyGraphInstance;\n /** Row source. Default 'nodes'. */\n mode?: GraphTableMode;\n /** Edge-mode rows (documented compromise — see module doc). */\n edges?: readonly GraphEdge<any>[];\n /** Explicit column pick; replaces derivation entirely. */\n columns?: readonly (string | GraphTableColumn)[];\n /** Bounded derivation prefix (rows sampled for the attr-key union). Default 200. */\n columnSample?: number;\n /** Controlled filter text; uncontrolled via the built-in input otherwise. */\n filterText?: string;\n onFilterTextChange?: (text: string) => void;\n /** Composed AND with the text filter; receives the underlying item. */\n filterPredicate?: (item: GraphNode<any> | GraphEdge<any>) => boolean;\n /** Crossfilter dimension key the filter registers on. Default 'table'. */\n filterDimension?: string;\n /** CSV formula-injection neutralization opt-out. Default true (safe). */\n neutralizeFormulas?: boolean;\n /** Row height in CSS px (mechanical — drives the window math). Default 28. */\n rowHeight?: number;\n /** Scroll viewport height in CSS px (mechanical). Default 320. */\n height?: number;\n /** Extra rows mounted on each side of the viewport. Default 8. */\n overscan?: number;\n /** Replaces default cell content (rendered inside the cell element). */\n renderCell?: (ctx: GraphTableCellContext) => ReactNode;\n /** Accessible name of the table. Default 'Graph table'. */\n label?: string;\n /** Class hook for the root; providing it drops the decorative styles. */\n className?: string;\n style?: CSSProperties;\n /** Class hook for body rows; providing it drops their decorative styles. */\n rowClassName?: string;\n}\n\n// ---------------------------------------------------------------------------\n// Store subscriptions\n// ---------------------------------------------------------------------------\n\n/**\n * Version string that changes whenever the row model could: revisions,\n * visible counts, accepted counts, status, and session availability. The\n * session listener re-attaches on every store publication (the\n * _shared/crossfilter convention — engine rebuilds swap subscribers).\n */\nfunction useTableVersion(instance: AnyGraphInstance): string {\n const subscribe = useCallback(\n (onChange: () => void) => {\n let sessionUnsub: (() => void) | null = null;\n const attach = (): void => {\n sessionUnsub?.();\n sessionUnsub = null;\n const session = instance.getCrossfilterSession();\n if (session !== null) sessionUnsub = session.subscribe(onChange);\n };\n attach();\n const storeUnsub = instance.store.subscribe(() => {\n attach();\n onChange();\n });\n return () => {\n storeUnsub();\n sessionUnsub?.();\n sessionUnsub = null;\n };\n },\n [instance],\n );\n const getSnapshot = useCallback((): string => {\n const s: GraphStoreState = instance.store.getState();\n const hasSession = instance.getCrossfilterSession() !== null ? 1 : 0;\n return `${s.status}:${s.revisions.model}:${s.revisions.scope}:${s.revisions.render}:${s.visible.nodes}:${s.visible.edges}:${s.nodeCount}:${s.edgeCount}:${hasSession}`;\n }, [instance]);\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\n/** The store keeps `selection` referentially stable across unrelated\n * publishes, so the raw field is a valid useSyncExternalStore snapshot. */\nfunction useSelection(instance: AnyGraphInstance): SelectionState {\n const subscribe = useCallback(\n (onChange: () => void) => instance.store.subscribe(onChange),\n [instance],\n );\n const getSnapshot = useCallback(\n (): SelectionState => instance.store.getState().selection,\n [instance],\n );\n return useSyncExternalStore(subscribe, getSnapshot, getSnapshot);\n}\n\n// ---------------------------------------------------------------------------\n// Styling defaults (decorative styles drop when the class hooks are given;\n// mechanical geometry always applies — see module doc).\n// ---------------------------------------------------------------------------\n\nconst ROOT_STYLE: CSSProperties = {\n display: 'flex',\n flexDirection: 'column',\n gap: 6,\n padding: 8,\n borderRadius: 8,\n background: 'rgba(23, 25, 32, 0.96)',\n border: '1px solid rgba(255, 255, 255, 0.14)',\n color: '#e8eaf0',\n font: '12px/1.4 system-ui, sans-serif',\n};\nconst TOOLBAR_STYLE: CSSProperties = { display: 'flex', alignItems: 'center', gap: 8 };\nconst FILTER_STYLE: CSSProperties = {\n flex: 1,\n minWidth: 0,\n background: 'rgba(255, 255, 255, 0.06)',\n border: '1px solid rgba(255, 255, 255, 0.14)',\n borderRadius: 6,\n color: 'inherit',\n font: 'inherit',\n padding: '3px 8px',\n};\nconst COUNT_STYLE: CSSProperties = { opacity: 0.65, whiteSpace: 'nowrap' };\nconst HEADER_ROW_STYLE: CSSProperties = { borderBottom: '1px solid rgba(255, 255, 255, 0.2)' };\nconst HEADER_BUTTON_STYLE: CSSProperties = {\n appearance: 'none',\n background: 'transparent',\n border: 'none',\n color: 'inherit',\n cursor: 'pointer',\n font: 'inherit',\n fontWeight: 600,\n padding: '2px 4px',\n textAlign: 'left',\n width: '100%',\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n};\nconst ROW_STYLE: CSSProperties = { cursor: 'pointer' };\nconst ROW_SELECTED_STYLE: CSSProperties = {\n ...ROW_STYLE,\n background: 'rgba(122, 162, 255, 0.22)',\n};\nconst CELL_STYLE: CSSProperties = {\n overflow: 'hidden',\n textOverflow: 'ellipsis',\n whiteSpace: 'nowrap',\n padding: '0 4px',\n};\nconst EMPTY_STYLE: CSSProperties = { fontStyle: 'italic', opacity: 0.8, padding: 4 };\n\n/** Mechanical (always applied) flex geometry for header/body cells. */\nconst CELL_MECHANICS: CSSProperties = { flex: 1, minWidth: 0 };\n\nfunction GraphTableInner(\n props: GraphTableProps,\n ref: ForwardedRef<GraphTableHandle>,\n): ReactElement {\n const instance = useResolvedInstance(props.instance, '<GraphTable>');\n const version = useTableVersion(instance);\n const selection = useSelection(instance);\n\n const mode: GraphTableMode = props.mode ?? 'nodes';\n const rowHeight = props.rowHeight ?? ROW_HEIGHT_DEFAULT;\n const height = props.height ?? HEIGHT_DEFAULT;\n const overscan = props.overscan ?? OVERSCAN_DEFAULT;\n const dimensionKey = props.filterDimension ?? TABLE_FILTER_DIMENSION_DEFAULT;\n const neutralize = props.neutralizeFormulas ?? true;\n const predicate = props.filterPredicate;\n\n const [internalFilter, setInternalFilter] = useState('');\n const filterText = props.filterText ?? internalFilter;\n const query = filterText.trim().toLowerCase();\n const [sort, setSort] = useState<GraphTableSort | null>(null);\n const [scrollTop, setScrollTop] = useState(0);\n\n // --- row model -------------------------------------------------------------\n\n const edgesProp = props.edges;\n const baseRows = useMemo<readonly GraphTableRowRef[]>(() => {\n void version; // rebuild on every relevant store publication\n if (mode === 'edges') {\n const visible = new Set(instance.getVisibleNodeIds());\n const out: GraphTableRowRef[] = [];\n (edgesProp ?? []).forEach((edge, i) => {\n if (!visible.has(edge.source) || !visible.has(edge.target)) return;\n if (edge.id !== undefined) out.push({ key: edge.id, id: edge.id, edge });\n else out.push({ key: `${i}:${edge.source}→${edge.target}`, id: null, edge });\n });\n return out;\n }\n return instance.getVisibleNodeIds().map((id) => ({ key: id, id }));\n }, [instance, version, mode, edgesProp]);\n\n const columnSample = props.columnSample ?? COLUMN_SAMPLE_DEFAULT;\n const columnsProp = props.columns;\n const columns = useMemo<readonly GraphTableColumn[]>(() => {\n if (columnsProp !== undefined) return normalizeColumns(columnsProp);\n const sample = baseRows.slice(0, columnSample).map((row) => {\n return row.edge !== undefined\n ? (row.edge.attrs as Record<string, unknown> | undefined)\n : ((instance.getNode(row.key) as GraphNode<any> | undefined)?.attrs as\n | Record<string, unknown>\n | undefined);\n });\n return deriveColumns(mode, sample);\n }, [instance, baseRows, mode, columnsProp, columnSample]);\n\n const valueOf = useCallback(\n (row: GraphTableRowRef, key: string): unknown =>\n row.edge !== undefined\n ? edgeCellValue(row.edge, key)\n : nodeCellValue(instance.getNode(row.key) as GraphNode<any> | undefined, row.key, key),\n [instance],\n );\n\n /** Text/predicate match for one row over the visible columns. */\n const matchesRow = useCallback(\n (row: GraphTableRowRef): boolean => {\n if (predicate !== undefined) {\n const item =\n row.edge !== undefined\n ? row.edge\n : (instance.getNode(row.key) as GraphNode<any> | undefined);\n if (item === undefined || !predicate(item)) return false;\n }\n if (query === '') return true;\n return textMatches(\n columns.map((col) => cellText(valueOf(row, col.key))),\n query,\n );\n },\n [instance, predicate, query, columns, valueOf],\n );\n\n const filterActive = query !== '' || predicate !== undefined;\n const filteredRows = useMemo<readonly GraphTableRowRef[]>(\n () => (filterActive ? baseRows.filter(matchesRow) : baseRows),\n [baseRows, filterActive, matchesRow],\n );\n\n const sortedRows = useMemo<readonly GraphTableRowRef[]>(() => {\n if (sort === null || !columns.some((c) => c.key === sort.key)) return filteredRows;\n const direction: 1 | -1 = sort.direction === 'asc' ? 1 : -1;\n const decorated = filteredRows.map((row) => ({\n row,\n key: sortKeyOf(valueOf(row, sort.key)),\n }));\n decorated.sort((a, b) => compareSortKeys(a.key, b.key, direction)); // stable → base-order ties\n return decorated.map((d) => d.row);\n }, [filteredRows, sort, columns, valueOf]);\n\n // --- table → graph: crossfilter registration (see module doc) ---------------\n\n /** Set once this table wrote a non-null brush; unmount clears it. */\n const wroteBrushRef = useRef<{ instance: AnyGraphInstance; key: string } | null>(null);\n\n useEffect(() => {\n if (mode !== 'nodes') return;\n const session = instance.getCrossfilterSession();\n if (session === null) return;\n try {\n session.getBrush(dimensionKey);\n } catch {\n return; // dimension not configured — degrade to local-only filtering\n }\n let brush: BrushState = null;\n if (filterActive) {\n const excluded: string[] = [];\n for (const id of instance.getSceneNodeIds()) {\n if (!matchesRow({ key: id, id })) excluded.push(id);\n }\n if (excluded.length > 0) brush = { excluded };\n }\n if (brush !== null) wroteBrushRef.current = { instance, key: dimensionKey };\n // Deep-equal brushes no-op inside the engine, so re-runs are cheap.\n void session.setBrush(dimensionKey, brush).catch(() => undefined);\n }, [instance, version, mode, dimensionKey, filterActive, matchesRow]);\n\n // Clearing only on final unmount left the previous dimension's\n // brush active across `dimensionKey`/`mode`/`instance` transitions,\n // silently intersecting later filters. The cleanup now runs on every\n // identity change (and still on unmount); the write effect above re-arms\n // the new identity immediately after.\n useEffect(\n () => () => {\n const wrote = wroteBrushRef.current;\n if (wrote === null) return;\n wroteBrushRef.current = null;\n const session = wrote.instance.getCrossfilterSession();\n if (session !== null) void session.setBrush(wrote.key, null).catch(() => undefined);\n },\n [instance, mode, dimensionKey],\n );\n\n // --- selection ---------------------------------------------------------------\n\n const selectedNodes = useMemo(() => new Set(selection.nodeIds), [selection]);\n const selectedEdges = useMemo(() => new Set(selection.edgeIds), [selection]);\n const isSelected = (row: GraphTableRowRef): boolean =>\n row.edge !== undefined\n ? row.id !== null && selectedEdges.has(row.id)\n : selectedNodes.has(row.key);\n\n const activateRow = (row: GraphTableRowRef, additive: boolean): void => {\n if (row.edge !== undefined) {\n if (row.id === null) return; // unaddressable (no caller edge id)\n const id = row.id;\n if (additive) {\n const current = selection.edgeIds;\n instance.selectEdges(\n current.includes(id) ? current.filter((e) => e !== id) : [...current, id],\n );\n } else {\n instance.selectEdges([id]);\n }\n return;\n }\n if (additive) {\n const current = selection.nodeIds;\n instance.selectNodes(\n current.includes(row.key) ? current.filter((n) => n !== row.key) : [...current, row.key],\n );\n } else {\n instance.selectNodes([row.key]);\n }\n };\n\n // --- CSV export ---------------------------------------------------------------\n\n const exportStateRef = useRef({ columns, rows: sortedRows, valueOf, neutralize });\n exportStateRef.current = { columns, rows: sortedRows, valueOf, neutralize };\n useImperativeHandle(\n ref,\n (): GraphTableHandle => ({\n exportCsv: (): string => {\n const s = exportStateRef.current;\n return toCsvString(\n s.columns.map((col) => col.label ?? col.key),\n s.rows.map((row) => s.columns.map((col) => s.valueOf(row, col.key))),\n s.neutralize,\n );\n },\n }),\n [],\n );\n\n // --- windowing -----------------------------------------------------------------\n\n const total = sortedRows.length;\n const first = Math.max(0, Math.floor(scrollTop / rowHeight) - overscan);\n const windowSize = Math.ceil(height / rowHeight) + overscan * 2;\n const windowRows = sortedRows.slice(first, first + windowSize);\n\n const onScroll = (e: UIEvent<HTMLDivElement>): void => {\n setScrollTop(e.currentTarget.scrollTop);\n };\n\n const cycleSort = (key: string): void => {\n setSort((prev) => {\n if (prev === null || prev.key !== key) return { key, direction: 'asc' };\n if (prev.direction === 'asc') return { key, direction: 'desc' };\n return null;\n });\n };\n\n const onFilterChange = (text: string): void => {\n if (props.filterText === undefined) setInternalFilter(text);\n props.onFilterTextChange?.(text);\n };\n\n const styled = props.className === undefined;\n const rowStyled = props.rowClassName === undefined;\n const label = props.label ?? 'Graph table';\n\n const renderRow = (row: GraphTableRowRef, index: number): ReactElement => {\n const selected = isSelected(row);\n const node =\n row.edge === undefined\n ? (instance.getNode(row.key) as GraphNode<any> | undefined)\n : undefined;\n const mechanics: CSSProperties = {\n height: rowHeight,\n display: 'flex',\n alignItems: 'center',\n boxSizing: 'border-box',\n };\n return (\n <div\n key={row.key}\n role=\"row\"\n aria-rowindex={first + index + 2}\n aria-selected={selected}\n data-orbit-table-row={row.key}\n tabIndex={0}\n className={props.rowClassName}\n style={\n rowStyled ? { ...mechanics, ...(selected ? ROW_SELECTED_STYLE : ROW_STYLE) } : mechanics\n }\n onClick={(e: MouseEvent<HTMLDivElement>) => {\n activateRow(row, e.metaKey || e.ctrlKey);\n }}\n onKeyDown={(e: KeyboardEvent<HTMLDivElement>) => {\n if (e.key !== 'Enter' && e.key !== ' ') return;\n e.preventDefault();\n activateRow(row, e.metaKey || e.ctrlKey);\n }}\n >\n {columns.map((col) => {\n const value = valueOf(row, col.key);\n const text = cellText(value);\n const ctx: GraphTableCellContext =\n node !== undefined\n ? { row, node, column: col, value, text }\n : { row, column: col, value, text };\n return (\n <div\n key={col.key}\n role=\"cell\"\n data-orbit-table-cell={col.key}\n style={styled ? { ...CELL_MECHANICS, ...CELL_STYLE } : CELL_MECHANICS}\n >\n {props.renderCell !== undefined ? props.renderCell(ctx) : text}\n </div>\n );\n })}\n </div>\n );\n };\n\n return (\n <div\n data-orbit-table={mode}\n role=\"group\"\n aria-label={label}\n className={props.className}\n style={styled ? { ...ROOT_STYLE, ...props.style } : props.style}\n >\n <div data-orbit-table-toolbar=\"\" style={styled ? TOOLBAR_STYLE : undefined}>\n <input\n type=\"text\"\n data-orbit-table-filter=\"\"\n aria-label=\"Filter rows\"\n value={filterText}\n style={styled ? FILTER_STYLE : undefined}\n onChange={(e) => {\n onFilterChange(e.currentTarget.value);\n }}\n />\n <span data-orbit-table-count=\"\" style={styled ? COUNT_STYLE : undefined}>\n {`${total} of ${baseRows.length} rows`}\n </span>\n </div>\n <div role=\"table\" aria-label={`${label} rows`} aria-rowcount={total + 1}>\n <div role=\"rowgroup\">\n <div\n role=\"row\"\n aria-rowindex={1}\n data-orbit-table-head=\"\"\n style={styled ? { display: 'flex', ...HEADER_ROW_STYLE } : { display: 'flex' }}\n >\n {columns.map((col) => {\n const active = sort !== null && sort.key === col.key;\n const ariaSort = active\n ? sort.direction === 'asc'\n ? 'ascending'\n : 'descending'\n : 'none';\n return (\n <div\n key={col.key}\n role=\"columnheader\"\n aria-sort={ariaSort}\n data-orbit-table-header={col.key}\n style={CELL_MECHANICS}\n >\n <button\n type=\"button\"\n data-orbit-table-sort={col.key}\n style={styled ? HEADER_BUTTON_STYLE : undefined}\n onClick={() => {\n cycleSort(col.key);\n }}\n >\n {col.label ?? col.key}\n </button>\n </div>\n );\n })}\n </div>\n </div>\n <div\n role=\"rowgroup\"\n data-orbit-table-viewport=\"\"\n onScroll={onScroll}\n style={{ height, overflowY: 'auto', position: 'relative' }}\n >\n {total === 0 ? (\n <div data-orbit-table-empty=\"\" style={styled ? EMPTY_STYLE : undefined}>\n No rows\n </div>\n ) : (\n <div\n data-orbit-table-spacer=\"\"\n style={{ height: total * rowHeight, position: 'relative' }}\n >\n <div\n data-orbit-table-window=\"\"\n style={{ position: 'absolute', top: first * rowHeight, left: 0, right: 0 }}\n >\n {windowRows.map((row, i) => renderRow(row, i))}\n </div>\n </div>\n )}\n </div>\n </div>\n </div>\n );\n}\n\nexport const GraphTable = forwardRef<GraphTableHandle, GraphTableProps>(GraphTableInner);\nGraphTable.displayName = 'GraphTable';\n"]}
@@ -3,7 +3,7 @@ import { TimelinePlayback } from '@modernrelay/orbit-core';
3
3
  import { A as AnyGraphInstance } from '../GraphProvider-B8ITDXS0.js';
4
4
 
5
5
  /**
6
- * <GraphTimeline> — §16.6 timeline playback control (S9).
6
+ * <GraphTimeline> — timeline playback control.
7
7
  *
8
8
  * A slim horizontal band over one numeric/temporal crossfilter dimension:
9
9
  * the same pointer-drag brushing as the histogram (shared module), a
@@ -15,7 +15,7 @@ import { A as AnyGraphInstance } from '../GraphProvider-B8ITDXS0.js';
15
15
  */
16
16
 
17
17
  interface GraphTimelineProps {
18
- /** Crossfilter dimension key — numeric/temporal to be playable (§16.6). */
18
+ /** Crossfilter dimension key — numeric/temporal to be playable. */
19
19
  dimension: string;
20
20
  /** Playback options forwarded to instance.playTimeline. */
21
21
  playback?: Partial<TimelinePlayback>;
@@ -1,6 +1,6 @@
1
- import { useRangeBrush, brushRangePct, sliderValueText, sliderValueNow } from '../chunk-DGFLU2SN.js';
2
- import { useCrossfilterDimension, useSessionSetBrush } from '../chunk-JN7QCMFW.js';
3
- import { useResolvedInstance } from '../chunk-7XB47YST.js';
1
+ import { useRangeBrush, brushRangePct, sliderValueText, sliderValueNow } from '../chunk-DTXFQLNP.js';
2
+ import { useCrossfilterDimension, useSessionSetBrush } from '../chunk-S36LHSNX.js';
3
+ import { useResolvedInstance } from '../chunk-NPOV5GA3.js';
4
4
  import { useCallback, useSyncExternalStore } from 'react';
5
5
  import { jsxs, jsx } from 'react/jsx-runtime';
6
6
 
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/components/Timeline/index.tsx"],"names":[],"mappings":"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","file":"Timeline.js","sourcesContent":["/**\n * <GraphTimeline> — §16.6 timeline playback control (S9).\n *\n * A slim horizontal band over one numeric/temporal crossfilter dimension:\n * the same pointer-drag brushing as the histogram (shared module), a\n * play/pause button wired to instance.playTimeline/pauseTimeline (the button\n * mirrors store `timeline.playingKey === dimension`), and a translucent\n * current-window indicator. While PLAYING, a user drag pauses playback (the\n * core folds the pause into the same brush publication). Headless-styleable:\n * providing `className` drops the built-in dark-theme inline styles.\n */\n\nimport { useCallback, useSyncExternalStore } from 'react';\nimport type { CSSProperties, ReactElement } from 'react';\nimport type { TimelinePlayback } from '@modernrelay/orbit-core';\nimport type { AnyGraphInstance } from '../../GraphProvider';\nimport { useResolvedInstance } from '../shared';\nimport { brushRangePct, sliderValueNow, sliderValueText, useRangeBrush } from '../_shared/brush';\nimport { useCrossfilterDimension, useSessionSetBrush } from '../_shared/crossfilter';\n\nexport interface GraphTimelineProps {\n /** Crossfilter dimension key — numeric/temporal to be playable (§16.6). */\n dimension: string;\n /** Playback options forwarded to instance.playTimeline. */\n playback?: Partial<TimelinePlayback>;\n /** Band height in CSS px. Default 24. */\n height?: number;\n /** Explicit instance; defaults to the ambient <Graph>/<GraphProvider> one. */\n instance?: AnyGraphInstance;\n /** Class hook for the root; providing it drops the default styles. */\n className?: string;\n style?: CSSProperties;\n /** Class hook for the play/pause button; providing it drops its defaults. */\n buttonClassName?: string;\n}\n\n// --- default dark-theme styling (dropped when `className` is provided) ---\n\nconst ROOT_STYLE: CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n gap: 8,\n padding: 6,\n borderRadius: 8,\n background: 'rgba(23, 25, 32, 0.92)',\n border: '1px solid rgba(255, 255, 255, 0.14)',\n color: '#e8eaf0',\n font: '12px/1.4 system-ui, sans-serif',\n};\n\nconst BUTTON_STYLE: CSSProperties = {\n appearance: 'none',\n background: 'transparent',\n border: 'none',\n borderRadius: 6,\n color: 'inherit',\n cursor: 'pointer',\n font: 'inherit',\n minWidth: 28,\n minHeight: 28,\n padding: '2px 6px',\n};\n\nconst DISABLED_BUTTON_STYLE: CSSProperties = {\n ...BUTTON_STYLE,\n cursor: 'default',\n opacity: 0.4,\n};\n\nconst PLOT_STYLE: CSSProperties = {\n position: 'relative',\n flex: 1,\n cursor: 'crosshair',\n touchAction: 'none',\n userSelect: 'none',\n};\n\nconst SVG_STYLE: CSSProperties = { display: 'block', width: '100%' };\n\nconst TRACK_FILL = 'rgba(148, 163, 184, 0.18)';\nconst DENSITY_FILL = 'rgba(148, 163, 184, 0.4)';\nconst WINDOW_FILL = 'rgba(122, 162, 255, 0.28)';\nconst WINDOW_STROKE = 'rgba(122, 162, 255, 0.9)';\n\nexport function GraphTimeline(props: GraphTimelineProps): ReactElement {\n const instance = useResolvedInstance(props.instance, '<GraphTimeline>');\n const { summary, brush } = useCrossfilterDimension(instance, props.dimension);\n const setBrush = useSessionSetBrush(instance, props.dimension);\n\n // --- store mirror: timeline.playingKey drives the play/pause toggle ---\n const subscribe = useCallback(\n (onStoreChange: () => void) => instance.store.subscribe(onStoreChange),\n [instance],\n );\n const getPlayingKey = useCallback(\n (): string | null => instance.store.getState().timeline.playingKey,\n [instance],\n );\n const playingKey = useSyncExternalStore(subscribe, getPlayingKey, getPlayingKey);\n const playing = playingKey === props.dimension;\n\n const domain = summary?.domain ?? null;\n const handlers = useRangeBrush({\n domain,\n binCount: summary?.bins.length ?? 0,\n brush,\n setBrush,\n });\n\n const playable = summary !== null && summary.kind !== 'categorical' && domain !== null;\n const toggle = useCallback((): void => {\n if (instance.store.getState().timeline.playingKey === props.dimension) {\n instance.pauseTimeline();\n return;\n }\n try {\n instance.playTimeline(props.dimension, props.playback);\n } catch {\n // Not playable (categorical / unknown / no dimensions yet): inert.\n }\n }, [instance, props.dimension, props.playback]);\n\n const styled = props.className === undefined;\n const height = props.height ?? 24;\n const bins = summary?.bins ?? [];\n const maxTotal = bins.reduce((m, b) => (b.total > m ? b.total : m), 0);\n const barW = bins.length > 0 ? 100 / bins.length : 100;\n const range = brushRangePct(brush, domain);\n const label = playing ? 'Pause timeline' : 'Play timeline';\n\n return (\n <div\n data-orbit-timeline={props.dimension}\n role=\"group\"\n aria-label={`${props.dimension} timeline`}\n className={props.className}\n style={styled ? { ...ROOT_STYLE, ...props.style } : props.style}\n >\n <button\n type=\"button\"\n data-orbit-timeline-toggle=\"\"\n aria-label={label}\n title={label}\n aria-pressed={playing}\n disabled={!playable}\n className={props.buttonClassName}\n style={\n props.buttonClassName !== undefined\n ? undefined\n : playable\n ? BUTTON_STYLE\n : DISABLED_BUTTON_STYLE\n }\n onClick={toggle}\n >\n {playing ? '⏸' : '▶'}\n </button>\n <div\n data-orbit-timeline-plot=\"\"\n tabIndex={0}\n aria-label={`${props.dimension} timeline brush: drag to filter, arrow keys nudge, Escape clears`}\n role=\"slider\"\n aria-orientation=\"horizontal\"\n aria-valuemin={summary?.domain?.min ?? 0}\n aria-valuemax={summary?.domain?.max ?? 0}\n aria-valuenow={sliderValueNow(brush, summary?.domain)}\n aria-valuetext={sliderValueText(brush, summary?.domain)}\n style={styled ? PLOT_STYLE : undefined}\n onPointerDown={handlers.onPointerDown}\n onPointerMove={handlers.onPointerMove}\n onPointerUp={handlers.onPointerUp}\n onPointerCancel={handlers.onPointerCancel}\n onDoubleClick={handlers.onDoubleClick}\n onKeyDown={handlers.onKeyDown}\n >\n <svg\n width=\"100%\"\n height={height}\n viewBox=\"0 0 100 100\"\n preserveAspectRatio=\"none\"\n aria-hidden=\"true\"\n focusable=\"false\"\n style={styled ? SVG_STYLE : undefined}\n >\n <rect x={0} y={0} width={100} height={100} fill={TRACK_FILL} rx={2} />\n {bins.map((bin, i) => {\n const h = maxTotal > 0 ? (bin.total / maxTotal) * 100 : 0;\n return (\n <rect\n key={i}\n data-orbit-timeline-density=\"\"\n x={i * barW + barW * 0.1}\n y={100 - h}\n width={barW * 0.8}\n height={h}\n fill={DENSITY_FILL}\n />\n );\n })}\n {range !== null ? (\n <rect\n data-orbit-timeline-window=\"\"\n x={range.leftPct}\n y={0}\n width={range.widthPct}\n height={100}\n fill={WINDOW_FILL}\n stroke={WINDOW_STROKE}\n strokeWidth={0.75}\n pointerEvents=\"none\"\n />\n ) : null}\n </svg>\n </div>\n </div>\n );\n}\n"]}
1
+ {"version":3,"sources":["../../src/components/Timeline/index.tsx"],"names":[],"mappings":";;;;;;AAsCA,IAAM,UAAA,GAA4B;AAAA,EAChC,OAAA,EAAS,MAAA;AAAA,EACT,UAAA,EAAY,QAAA;AAAA,EACZ,GAAA,EAAK,CAAA;AAAA,EACL,OAAA,EAAS,CAAA;AAAA,EACT,YAAA,EAAc,CAAA;AAAA,EACd,UAAA,EAAY,wBAAA;AAAA,EACZ,MAAA,EAAQ,qCAAA;AAAA,EACR,KAAA,EAAO,SAAA;AAAA,EACP,IAAA,EAAM;AACR,CAAA;AAEA,IAAM,YAAA,GAA8B;AAAA,EAClC,UAAA,EAAY,MAAA;AAAA,EACZ,UAAA,EAAY,aAAA;AAAA,EACZ,MAAA,EAAQ,MAAA;AAAA,EACR,YAAA,EAAc,CAAA;AAAA,EACd,KAAA,EAAO,SAAA;AAAA,EACP,MAAA,EAAQ,SAAA;AAAA,EACR,IAAA,EAAM,SAAA;AAAA,EACN,QAAA,EAAU,EAAA;AAAA,EACV,SAAA,EAAW,EAAA;AAAA,EACX,OAAA,EAAS;AACX,CAAA;AAEA,IAAM,qBAAA,GAAuC;AAAA,EAC3C,GAAG,YAAA;AAAA,EACH,MAAA,EAAQ,SAAA;AAAA,EACR,OAAA,EAAS;AACX,CAAA;AAEA,IAAM,UAAA,GAA4B;AAAA,EAChC,QAAA,EAAU,UAAA;AAAA,EACV,IAAA,EAAM,CAAA;AAAA,EACN,MAAA,EAAQ,WAAA;AAAA,EACR,WAAA,EAAa,MAAA;AAAA,EACb,UAAA,EAAY;AACd,CAAA;AAEA,IAAM,SAAA,GAA2B,EAAE,OAAA,EAAS,OAAA,EAAS,OAAO,MAAA,EAAO;AAEnE,IAAM,UAAA,GAAa,2BAAA;AACnB,IAAM,YAAA,GAAe,0BAAA;AACrB,IAAM,WAAA,GAAc,2BAAA;AACpB,IAAM,aAAA,GAAgB,0BAAA;AAEf,SAAS,cAAc,KAAA,EAAyC;AACrE,EAAA,MAAM,QAAA,GAAW,mBAAA,CAAoB,KAAA,CAAM,QAAA,EAAU,iBAAiB,CAAA;AACtE,EAAA,MAAM,EAAE,OAAA,EAAS,KAAA,KAAU,uBAAA,CAAwB,QAAA,EAAU,MAAM,SAAS,CAAA;AAC5E,EAAA,MAAM,QAAA,GAAW,kBAAA,CAAmB,QAAA,EAAU,KAAA,CAAM,SAAS,CAAA;AAG7D,EAAA,MAAM,SAAA,GAAY,WAAA;AAAA,IAChB,CAAC,aAAA,KAA8B,QAAA,CAAS,KAAA,CAAM,UAAU,aAAa,CAAA;AAAA,IACrE,CAAC,QAAQ;AAAA,GACX;AACA,EAAA,MAAM,aAAA,GAAgB,WAAA;AAAA,IACpB,MAAqB,QAAA,CAAS,KAAA,CAAM,QAAA,GAAW,QAAA,CAAS,UAAA;AAAA,IACxD,CAAC,QAAQ;AAAA,GACX;AACA,EAAA,MAAM,UAAA,GAAa,oBAAA,CAAqB,SAAA,EAAW,aAAA,EAAe,aAAa,CAAA;AAC/E,EAAA,MAAM,OAAA,GAAU,eAAe,KAAA,CAAM,SAAA;AAErC,EAAA,MAAM,MAAA,GAAS,SAAS,MAAA,IAAU,IAAA;AAClC,EAAA,MAAM,WAAW,aAAA,CAAc;AAAA,IAC7B,MAAA;AAAA,IACA,QAAA,EAAU,OAAA,EAAS,IAAA,CAAK,MAAA,IAAU,CAAA;AAAA,IAClC,KAAA;AAAA,IACA;AAAA,GACD,CAAA;AAED,EAAA,MAAM,WAAW,OAAA,KAAY,IAAA,IAAQ,OAAA,CAAQ,IAAA,KAAS,iBAAiB,MAAA,KAAW,IAAA;AAClF,EAAA,MAAM,MAAA,GAAS,YAAY,MAAY;AACrC,IAAA,IAAI,SAAS,KAAA,CAAM,QAAA,GAAW,QAAA,CAAS,UAAA,KAAe,MAAM,SAAA,EAAW;AACrE,MAAA,QAAA,CAAS,aAAA,EAAc;AACvB,MAAA;AAAA,IACF;AACA,IAAA,IAAI;AACF,MAAA,QAAA,CAAS,YAAA,CAAa,KAAA,CAAM,SAAA,EAAW,KAAA,CAAM,QAAQ,CAAA;AAAA,IACvD,CAAA,CAAA,MAAQ;AAAA,IAER;AAAA,EACF,GAAG,CAAC,QAAA,EAAU,MAAM,SAAA,EAAW,KAAA,CAAM,QAAQ,CAAC,CAAA;AAE9C,EAAA,MAAM,MAAA,GAAS,MAAM,SAAA,KAAc,MAAA;AACnC,EAAA,MAAM,MAAA,GAAS,MAAM,MAAA,IAAU,EAAA;AAC/B,EAAA,MAAM,IAAA,GAAO,OAAA,EAAS,IAAA,IAAQ,EAAC;AAC/B,EAAA,MAAM,QAAA,GAAW,IAAA,CAAK,MAAA,CAAO,CAAC,CAAA,EAAG,CAAA,KAAO,CAAA,CAAE,KAAA,GAAQ,CAAA,GAAI,CAAA,CAAE,KAAA,GAAQ,CAAA,EAAI,CAAC,CAAA;AACrE,EAAA,MAAM,OAAO,IAAA,CAAK,MAAA,GAAS,CAAA,GAAI,GAAA,GAAM,KAAK,MAAA,GAAS,GAAA;AACnD,EAAA,MAAM,KAAA,GAAQ,aAAA,CAAc,KAAA,EAAO,MAAM,CAAA;AACzC,EAAA,MAAM,KAAA,GAAQ,UAAU,gBAAA,GAAmB,eAAA;AAE3C,EAAA,uBACE,IAAA;AAAA,IAAC,KAAA;AAAA,IAAA;AAAA,MACC,uBAAqB,KAAA,CAAM,SAAA;AAAA,MAC3B,IAAA,EAAK,OAAA;AAAA,MACL,YAAA,EAAY,CAAA,EAAG,KAAA,CAAM,SAAS,CAAA,SAAA,CAAA;AAAA,MAC9B,WAAW,KAAA,CAAM,SAAA;AAAA,MACjB,KAAA,EAAO,SAAS,EAAE,GAAG,YAAY,GAAG,KAAA,CAAM,KAAA,EAAM,GAAI,KAAA,CAAM,KAAA;AAAA,MAE1D,QAAA,EAAA;AAAA,wBAAA,GAAA;AAAA,UAAC,QAAA;AAAA,UAAA;AAAA,YACC,IAAA,EAAK,QAAA;AAAA,YACL,4BAAA,EAA2B,EAAA;AAAA,YAC3B,YAAA,EAAY,KAAA;AAAA,YACZ,KAAA,EAAO,KAAA;AAAA,YACP,cAAA,EAAc,OAAA;AAAA,YACd,UAAU,CAAC,QAAA;AAAA,YACX,WAAW,KAAA,CAAM,eAAA;AAAA,YACjB,OACE,KAAA,CAAM,eAAA,KAAoB,MAAA,GACtB,MAAA,GACA,WACE,YAAA,GACA,qBAAA;AAAA,YAER,OAAA,EAAS,MAAA;AAAA,YAER,oBAAU,QAAA,GAAM;AAAA;AAAA,SACnB;AAAA,wBACA,GAAA;AAAA,UAAC,KAAA;AAAA,UAAA;AAAA,YACC,0BAAA,EAAyB,EAAA;AAAA,YACzB,QAAA,EAAU,CAAA;AAAA,YACV,YAAA,EAAY,CAAA,EAAG,KAAA,CAAM,SAAS,CAAA,gEAAA,CAAA;AAAA,YAC9B,IAAA,EAAK,QAAA;AAAA,YACL,kBAAA,EAAiB,YAAA;AAAA,YACjB,eAAA,EAAe,OAAA,EAAS,MAAA,EAAQ,GAAA,IAAO,CAAA;AAAA,YACvC,eAAA,EAAe,OAAA,EAAS,MAAA,EAAQ,GAAA,IAAO,CAAA;AAAA,YACvC,eAAA,EAAe,cAAA,CAAe,KAAA,EAAO,OAAA,EAAS,MAAM,CAAA;AAAA,YACpD,gBAAA,EAAgB,eAAA,CAAgB,KAAA,EAAO,OAAA,EAAS,MAAM,CAAA;AAAA,YACtD,KAAA,EAAO,SAAS,UAAA,GAAa,MAAA;AAAA,YAC7B,eAAe,QAAA,CAAS,aAAA;AAAA,YACxB,eAAe,QAAA,CAAS,aAAA;AAAA,YACxB,aAAa,QAAA,CAAS,WAAA;AAAA,YACtB,iBAAiB,QAAA,CAAS,eAAA;AAAA,YAC1B,eAAe,QAAA,CAAS,aAAA;AAAA,YACxB,WAAW,QAAA,CAAS,SAAA;AAAA,YAEpB,QAAA,kBAAA,IAAA;AAAA,cAAC,KAAA;AAAA,cAAA;AAAA,gBACC,KAAA,EAAM,MAAA;AAAA,gBACN,MAAA;AAAA,gBACA,OAAA,EAAQ,aAAA;AAAA,gBACR,mBAAA,EAAoB,MAAA;AAAA,gBACpB,aAAA,EAAY,MAAA;AAAA,gBACZ,SAAA,EAAU,OAAA;AAAA,gBACV,KAAA,EAAO,SAAS,SAAA,GAAY,MAAA;AAAA,gBAE5B,QAAA,EAAA;AAAA,kCAAA,GAAA,CAAC,MAAA,EAAA,EAAK,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,CAAA,EAAG,KAAA,EAAO,GAAA,EAAK,MAAA,EAAQ,GAAA,EAAK,IAAA,EAAM,UAAA,EAAY,EAAA,EAAI,CAAA,EAAG,CAAA;AAAA,kBACnE,IAAA,CAAK,GAAA,CAAI,CAAC,GAAA,EAAK,CAAA,KAAM;AACpB,oBAAA,MAAM,IAAI,QAAA,GAAW,CAAA,GAAK,GAAA,CAAI,KAAA,GAAQ,WAAY,GAAA,GAAM,CAAA;AACxD,oBAAA,uBACE,GAAA;AAAA,sBAAC,MAAA;AAAA,sBAAA;AAAA,wBAEC,6BAAA,EAA4B,EAAA;AAAA,wBAC5B,CAAA,EAAG,CAAA,GAAI,IAAA,GAAO,IAAA,GAAO,GAAA;AAAA,wBACrB,GAAG,GAAA,GAAM,CAAA;AAAA,wBACT,OAAO,IAAA,GAAO,GAAA;AAAA,wBACd,MAAA,EAAQ,CAAA;AAAA,wBACR,IAAA,EAAM;AAAA,uBAAA;AAAA,sBAND;AAAA,qBAOP;AAAA,kBAEJ,CAAC,CAAA;AAAA,kBACA,UAAU,IAAA,mBACT,GAAA;AAAA,oBAAC,MAAA;AAAA,oBAAA;AAAA,sBACC,4BAAA,EAA2B,EAAA;AAAA,sBAC3B,GAAG,KAAA,CAAM,OAAA;AAAA,sBACT,CAAA,EAAG,CAAA;AAAA,sBACH,OAAO,KAAA,CAAM,QAAA;AAAA,sBACb,MAAA,EAAQ,GAAA;AAAA,sBACR,IAAA,EAAM,WAAA;AAAA,sBACN,MAAA,EAAQ,aAAA;AAAA,sBACR,WAAA,EAAa,IAAA;AAAA,sBACb,aAAA,EAAc;AAAA;AAAA,mBAChB,GACE;AAAA;AAAA;AAAA;AACN;AAAA;AACF;AAAA;AAAA,GACF;AAEJ","file":"Timeline.js","sourcesContent":["/**\n * <GraphTimeline> — timeline playback control.\n *\n * A slim horizontal band over one numeric/temporal crossfilter dimension:\n * the same pointer-drag brushing as the histogram (shared module), a\n * play/pause button wired to instance.playTimeline/pauseTimeline (the button\n * mirrors store `timeline.playingKey === dimension`), and a translucent\n * current-window indicator. While PLAYING, a user drag pauses playback (the\n * core folds the pause into the same brush publication). Headless-styleable:\n * providing `className` drops the built-in dark-theme inline styles.\n */\n\nimport { useCallback, useSyncExternalStore } from 'react';\nimport type { CSSProperties, ReactElement } from 'react';\nimport type { TimelinePlayback } from '@modernrelay/orbit-core';\nimport type { AnyGraphInstance } from '../../GraphProvider';\nimport { useResolvedInstance } from '../shared';\nimport { brushRangePct, sliderValueNow, sliderValueText, useRangeBrush } from '../_shared/brush';\nimport { useCrossfilterDimension, useSessionSetBrush } from '../_shared/crossfilter';\n\nexport interface GraphTimelineProps {\n /** Crossfilter dimension key — numeric/temporal to be playable. */\n dimension: string;\n /** Playback options forwarded to instance.playTimeline. */\n playback?: Partial<TimelinePlayback>;\n /** Band height in CSS px. Default 24. */\n height?: number;\n /** Explicit instance; defaults to the ambient <Graph>/<GraphProvider> one. */\n instance?: AnyGraphInstance;\n /** Class hook for the root; providing it drops the default styles. */\n className?: string;\n style?: CSSProperties;\n /** Class hook for the play/pause button; providing it drops its defaults. */\n buttonClassName?: string;\n}\n\n// --- default dark-theme styling (dropped when `className` is provided) ---\n\nconst ROOT_STYLE: CSSProperties = {\n display: 'flex',\n alignItems: 'center',\n gap: 8,\n padding: 6,\n borderRadius: 8,\n background: 'rgba(23, 25, 32, 0.92)',\n border: '1px solid rgba(255, 255, 255, 0.14)',\n color: '#e8eaf0',\n font: '12px/1.4 system-ui, sans-serif',\n};\n\nconst BUTTON_STYLE: CSSProperties = {\n appearance: 'none',\n background: 'transparent',\n border: 'none',\n borderRadius: 6,\n color: 'inherit',\n cursor: 'pointer',\n font: 'inherit',\n minWidth: 28,\n minHeight: 28,\n padding: '2px 6px',\n};\n\nconst DISABLED_BUTTON_STYLE: CSSProperties = {\n ...BUTTON_STYLE,\n cursor: 'default',\n opacity: 0.4,\n};\n\nconst PLOT_STYLE: CSSProperties = {\n position: 'relative',\n flex: 1,\n cursor: 'crosshair',\n touchAction: 'none',\n userSelect: 'none',\n};\n\nconst SVG_STYLE: CSSProperties = { display: 'block', width: '100%' };\n\nconst TRACK_FILL = 'rgba(148, 163, 184, 0.18)';\nconst DENSITY_FILL = 'rgba(148, 163, 184, 0.4)';\nconst WINDOW_FILL = 'rgba(122, 162, 255, 0.28)';\nconst WINDOW_STROKE = 'rgba(122, 162, 255, 0.9)';\n\nexport function GraphTimeline(props: GraphTimelineProps): ReactElement {\n const instance = useResolvedInstance(props.instance, '<GraphTimeline>');\n const { summary, brush } = useCrossfilterDimension(instance, props.dimension);\n const setBrush = useSessionSetBrush(instance, props.dimension);\n\n // --- store mirror: timeline.playingKey drives the play/pause toggle ---\n const subscribe = useCallback(\n (onStoreChange: () => void) => instance.store.subscribe(onStoreChange),\n [instance],\n );\n const getPlayingKey = useCallback(\n (): string | null => instance.store.getState().timeline.playingKey,\n [instance],\n );\n const playingKey = useSyncExternalStore(subscribe, getPlayingKey, getPlayingKey);\n const playing = playingKey === props.dimension;\n\n const domain = summary?.domain ?? null;\n const handlers = useRangeBrush({\n domain,\n binCount: summary?.bins.length ?? 0,\n brush,\n setBrush,\n });\n\n const playable = summary !== null && summary.kind !== 'categorical' && domain !== null;\n const toggle = useCallback((): void => {\n if (instance.store.getState().timeline.playingKey === props.dimension) {\n instance.pauseTimeline();\n return;\n }\n try {\n instance.playTimeline(props.dimension, props.playback);\n } catch {\n // Not playable (categorical / unknown / no dimensions yet): inert.\n }\n }, [instance, props.dimension, props.playback]);\n\n const styled = props.className === undefined;\n const height = props.height ?? 24;\n const bins = summary?.bins ?? [];\n const maxTotal = bins.reduce((m, b) => (b.total > m ? b.total : m), 0);\n const barW = bins.length > 0 ? 100 / bins.length : 100;\n const range = brushRangePct(brush, domain);\n const label = playing ? 'Pause timeline' : 'Play timeline';\n\n return (\n <div\n data-orbit-timeline={props.dimension}\n role=\"group\"\n aria-label={`${props.dimension} timeline`}\n className={props.className}\n style={styled ? { ...ROOT_STYLE, ...props.style } : props.style}\n >\n <button\n type=\"button\"\n data-orbit-timeline-toggle=\"\"\n aria-label={label}\n title={label}\n aria-pressed={playing}\n disabled={!playable}\n className={props.buttonClassName}\n style={\n props.buttonClassName !== undefined\n ? undefined\n : playable\n ? BUTTON_STYLE\n : DISABLED_BUTTON_STYLE\n }\n onClick={toggle}\n >\n {playing ? '⏸' : '▶'}\n </button>\n <div\n data-orbit-timeline-plot=\"\"\n tabIndex={0}\n aria-label={`${props.dimension} timeline brush: drag to filter, arrow keys nudge, Escape clears`}\n role=\"slider\"\n aria-orientation=\"horizontal\"\n aria-valuemin={summary?.domain?.min ?? 0}\n aria-valuemax={summary?.domain?.max ?? 0}\n aria-valuenow={sliderValueNow(brush, summary?.domain)}\n aria-valuetext={sliderValueText(brush, summary?.domain)}\n style={styled ? PLOT_STYLE : undefined}\n onPointerDown={handlers.onPointerDown}\n onPointerMove={handlers.onPointerMove}\n onPointerUp={handlers.onPointerUp}\n onPointerCancel={handlers.onPointerCancel}\n onDoubleClick={handlers.onDoubleClick}\n onKeyDown={handlers.onKeyDown}\n >\n <svg\n width=\"100%\"\n height={height}\n viewBox=\"0 0 100 100\"\n preserveAspectRatio=\"none\"\n aria-hidden=\"true\"\n focusable=\"false\"\n style={styled ? SVG_STYLE : undefined}\n >\n <rect x={0} y={0} width={100} height={100} fill={TRACK_FILL} rx={2} />\n {bins.map((bin, i) => {\n const h = maxTotal > 0 ? (bin.total / maxTotal) * 100 : 0;\n return (\n <rect\n key={i}\n data-orbit-timeline-density=\"\"\n x={i * barW + barW * 0.1}\n y={100 - h}\n width={barW * 0.8}\n height={h}\n fill={DENSITY_FILL}\n />\n );\n })}\n {range !== null ? (\n <rect\n data-orbit-timeline-window=\"\"\n x={range.leftPct}\n y={0}\n width={range.widthPct}\n height={100}\n fill={WINDOW_FILL}\n stroke={WINDOW_STROKE}\n strokeWidth={0.75}\n pointerEvents=\"none\"\n />\n ) : null}\n </svg>\n </div>\n </div>\n );\n}\n"]}
@@ -1,10 +1,10 @@
1
1
  import { CSSProperties, RefObject, ReactNode, ReactElement } from 'react';
2
2
  import { A as AnyGraphInstance } from '../GraphProvider-B8ITDXS0.js';
3
- import { G as GraphCorner } from '../shared-Bj3Gk219.js';
3
+ import { G as GraphCorner } from '../shared-n98tkXJe.js';
4
4
  import '@modernrelay/orbit-core';
5
5
 
6
6
  /**
7
- * <GraphToolbar> — §16.1 camera & simulation controls (S7-T06).
7
+ * <GraphToolbar> — camera & simulation controls.
8
8
  *
9
9
  * Thin view over the GraphInstance ref API: zoom ±, fit view, reset view,
10
10
  * fullscreen toggle, screenshot download, and a simulation play/pause toggle
@@ -1,4 +1,4 @@
1
- import { useResolvedInstance, mergeStyle, cornerStyle } from '../chunk-7XB47YST.js';
1
+ import { useResolvedInstance, mergeStyle, cornerStyle } from '../chunk-NPOV5GA3.js';
2
2
  import { useCallback, useSyncExternalStore, useState, useEffect, Fragment } from 'react';
3
3
  import { jsx } from 'react/jsx-runtime';
4
4