@signalsafe/tree-spec-editor-react 0.1.2 → 0.2.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 (51) hide show
  1. package/README.md +126 -42
  2. package/dist/TreeSpecGraphEditor.d.ts +2 -2
  3. package/dist/TreeSpecGraphEditor.d.ts.map +1 -1
  4. package/dist/TreeSpecGraphEditor.js +18 -17
  5. package/dist/canvas/constants.d.ts +8 -7
  6. package/dist/canvas/constants.d.ts.map +1 -1
  7. package/dist/canvas/constants.js +10 -7
  8. package/dist/canvas/edgeBuilders.js +2 -2
  9. package/dist/canvas/edgeStyle.js +1 -1
  10. package/dist/canvas/typeGuards.js +1 -1
  11. package/dist/contextMenu/GraphCanvasContextMenu.d.ts +1 -1
  12. package/dist/contextMenu/GraphCanvasContextMenu.d.ts.map +1 -1
  13. package/dist/contextMenu/GraphCanvasContextMenu.js +3 -3
  14. package/dist/hooks/useCanvasContextMenu.d.ts +1 -1
  15. package/dist/hooks/useCanvasContextMenu.d.ts.map +1 -1
  16. package/dist/hooks/useCanvasGraphState.js +2 -2
  17. package/dist/hooks/useEditorAdapter.d.ts +1 -1
  18. package/dist/hooks/useEditorAdapter.d.ts.map +1 -1
  19. package/dist/hooks/useEditorAutosave.d.ts +1 -1
  20. package/dist/hooks/useEditorAutosave.d.ts.map +1 -1
  21. package/dist/hooks/useEditorSelection.d.ts.map +1 -1
  22. package/dist/hooks/useEditorSelection.js +1 -2
  23. package/dist/hooks/useGraphConnect.js +1 -1
  24. package/dist/hooks/useTreeSpecEditor.d.ts +1 -1
  25. package/dist/hooks/useTreeSpecEditor.d.ts.map +1 -1
  26. package/dist/hooks/useTreeSpecEditor.js +5 -5
  27. package/dist/index.d.ts +4 -4
  28. package/dist/index.d.ts.map +1 -1
  29. package/dist/index.js +2 -2
  30. package/dist/nodes/ChoiceCanvasRow.d.ts.map +1 -1
  31. package/dist/nodes/ChoiceCanvasRow.js +6 -6
  32. package/dist/nodes/EndNode.d.ts.map +1 -1
  33. package/dist/nodes/EndNode.js +3 -3
  34. package/dist/nodes/PromptNode.d.ts +1 -1
  35. package/dist/nodes/PromptNode.d.ts.map +1 -1
  36. package/dist/nodes/PromptNode.js +8 -8
  37. package/dist/nodes/PromptNodeChoicesList.d.ts +1 -1
  38. package/dist/nodes/PromptNodeChoicesList.d.ts.map +1 -1
  39. package/dist/nodes/PromptNodeChoicesList.js +4 -4
  40. package/dist/nodes/PromptNodeHeader.d.ts +1 -1
  41. package/dist/nodes/PromptNodeHeader.d.ts.map +1 -1
  42. package/dist/nodes/PromptNodeHeader.js +4 -3
  43. package/dist/nodes/PromptNodeIssueBadges.d.ts.map +1 -1
  44. package/dist/nodes/PromptNodeIssueBadges.js +2 -1
  45. package/dist/nodes/PromptNodeToolbar.d.ts.map +1 -1
  46. package/dist/nodes/PromptNodeToolbar.js +2 -1
  47. package/dist/ui/editorClasses.d.ts +53 -0
  48. package/dist/ui/editorClasses.d.ts.map +1 -0
  49. package/dist/ui/editorClasses.js +69 -0
  50. package/docs/UI_KIT_AGNOSTIC_CANVAS.md +65 -0
  51. package/package.json +17 -9
package/README.md CHANGED
@@ -1,64 +1,148 @@
1
1
  # @signalsafe/tree-spec-editor-react
2
2
 
3
- Headless React layer for the SignalSafe TreeSpec graph editor. Renders the
4
- React Flow canvas, owns React state plumbing, and exposes the editor as a
5
- single React component — without depending on any specific UI library.
3
+ Headless **React + React Flow** layer for the SignalSafe TreeSpec graph editor: canvas component, orchestration hook, and wiring to `@signalsafe/tree-spec-editor-core`.
6
4
 
7
- This is the React-specific sibling to **[`@signalsafe/tree-spec-editor-core`](../tree-spec-editor-core/README.md)**. The core package owns model + helpers (zero UI deps); this package owns React rendering. UI shells (e.g. `@signalsafe/tree-spec-editor` for React + Bootstrap, planned `@signalsafe/tree-spec-editor-react-mui` for React + Material) layer on top.
5
+ | | |
6
+ |---|---|
7
+ | **npm** | `@signalsafe/tree-spec-editor-react` |
8
+ | **GitHub** | [SignalSafeSoftware/tree-spec-editor-react](https://github.com/SignalSafeSoftware/tree-spec-editor-react) |
9
+ | **Peer deps** | `react`, `react-dom`, `reactflow` (^18 / ^11) — **no UI library required** |
8
10
 
9
- ## What this package owns
11
+ ## UI-kit agnostic canvas
10
12
 
11
- - **`TreeSpecGraphEditor`** — the React Flow canvas (Background, Controls, MiniMap, custom node renderer, transition edges, selection wiring, choice focus highlighting, focus/fit-view).
12
- - **`useTreeSpecEditor`** — stateful orchestration hook (load, autosave, validate, publish, selection, undo/redo, choice/edge helpers). Exposes `inspectorNode` (selected node or edge source node), `focusChoiceId`, and `selectedEdge` for sidebar panels.
13
- - **`TreeSpecGraphEditorProps`** — props type.
13
+ The React Flow canvas uses **semantic HTML** and **`graph-editor-*` class hooks** only. It does **not** require Bootstrap CSS, Bootstrap Icons, or any component library.
14
14
 
15
- ## Canvas selection behavior
15
+ **Host applications own styling.** Map `graph-editor-*` in your theme, or pass `className` on `TreeSpecGraphEditor` for layout/sizing. See [docs/UI_KIT_AGNOSTIC_CANVAS.md](./docs/UI_KIT_AGNOSTIC_CANVAS.md).
16
+
17
+ ## What this package does
16
18
 
17
- | Selection | Inspector context | Contextual zoom (`contextualZoom`, default `true`) |
18
- |-----------|-------------------|-----------------------------------------------------|
19
- | **Node** | `selectedNode` | Fits viewport to the node |
20
- | **Edge** | `inspectorNode` = source node; `focusChoiceId` = source choice | **No pan/zoom** (viewport stays put) |
21
- | **Choice** (canvas or inspector focus) | `focusChoiceId` set; nodes list highlights via `focusNodeId` | Fits when the parent node is selected |
19
+ - Renders **`TreeSpecGraphEditor`** (React Flow canvas, custom nodes/edges, selection).
20
+ - Exposes **`useTreeSpecEditor`** for load/validate/autosave/publish orchestration (host injects adapter callbacks).
21
+ - Re-exports core editor types used by the hook.
22
22
 
23
- Pass `onChoiceSelect` + `focusChoiceId` to keep canvas choice rows, inspector choice cards, and the nodes list in sync. Pass `contextualZoom={false}` to disable automatic viewport fitting on node selection.
23
+ ## What this package does not do
24
24
 
25
- ## What lives elsewhere
25
+ - Sidebar panels, modals, toolbars, or UI-kit chrome — use `@signalsafe/tree-spec-editor` or your own UI shell.
26
+ - Routing, HTTP, authentication, or persistence — host app provides adapter implementations.
27
+ - Wire compile/publish to a backend without your adapter code.
26
28
 
27
- | Concern | Package |
28
- |--------|---------|
29
- | Editor model, tree operations, layout, autosave/keyboard helpers, choice edge hints | `@signalsafe/tree-spec-editor-core` |
30
- | Sidebar panels, inspector, modals, toolbar (Bootstrap-styled) | `@signalsafe/tree-spec-editor` |
31
- | Material-styled React shell (planned) | `@signalsafe/tree-spec-editor-react-mui` |
32
- | Angular shell + canvas (planned) | `@signalsafe/tree-spec-editor-angular` |
33
- | Vue shell + canvas (planned) | `@signalsafe/tree-spec-editor-vue` |
29
+ ## Install
34
30
 
35
- ## Maintainer notes
31
+ ```bash
32
+ npm install @signalsafe/tree-spec-editor-react @signalsafe/tree-spec-editor-core @signalsafe/tree-spec react react-dom reactflow
33
+ ```
36
34
 
37
- - **This package stays React + reactflow only.** Angular/Vue hosts will use `-core` with their own canvas packages, not `-react`.
38
- - **Material (React)** hosts should add `-react-mui` (planned), reusing this canvas unchanged.
39
- - Layer boundaries and refactor plan: [docs/ai/packages-editor-architecture.md](../../docs/ai/packages-editor-architecture.md).
35
+ ### React Flow CSS (required)
40
36
 
41
- ## Install
37
+ This package imports `reactflow/dist/style.css` from source. Bundlers treat it as a side effect (`sideEffects: ["**/*.css"]` in `package.json`).
38
+
39
+ Ensure your app loads React Flow styles, for example:
40
+
41
+ ```ts
42
+ import "reactflow/dist/style.css";
43
+ ```
44
+
45
+ If you use `@signalsafe/tree-spec-editor` as the authoring shell, map `graph-editor-*` canvas hooks in host CSS — Bootstrap is optional and host-owned.
46
+
47
+ ## Quick start
48
+
49
+ ```tsx
50
+ import { useState } from "react";
51
+ import TreeSpecGraphEditor from "@signalsafe/tree-spec-editor-react";
52
+ import {
53
+ END_NODE_ID,
54
+ type EditorTree,
55
+ } from "@signalsafe/tree-spec-editor-core";
56
+
57
+ const initialTree: EditorTree = {
58
+ start_node: "start",
59
+ nodes: {
60
+ start: {
61
+ id: "start",
62
+ type: "prompt",
63
+ prompt: "Example prompt",
64
+ choices: [{ id: "done", label: "Finish" }],
65
+ position: { x: 40, y: 120 },
66
+ },
67
+ },
68
+ transitions: [
69
+ {
70
+ id: "t1",
71
+ fromNodeId: "start",
72
+ fromChoiceId: "done",
73
+ toNodeId: END_NODE_ID,
74
+ outcome: "safe",
75
+ },
76
+ ],
77
+ };
78
+
79
+ export function ExampleCanvas() {
80
+ const [tree, setTree] = useState(initialTree);
81
+ return (
82
+ <TreeSpecGraphEditor
83
+ tree={tree}
84
+ onChange={setTree}
85
+ className="graph-editor-canvas-root my-canvas-host"
86
+ />
87
+ );
88
+ }
89
+ ```
90
+
91
+ For full authoring flows (load/save/validate), compose **`useTreeSpecEditor`** with your adapter — see tests and `@signalsafe/tree-spec-editor` for a reference shell.
92
+
93
+ ## Public exports
94
+
95
+ | Export | Purpose |
96
+ |---|---|
97
+ | `default` / `TreeSpecGraphEditor` | React Flow canvas |
98
+ | `TreeSpecGraphEditorProps` | Canvas props |
99
+ | `useTreeSpecEditor` | Stateful editor orchestration |
100
+ | `TreeSpecEditorAdapter`, `UseTreeSpecEditorResult`, … | Adapter and hook types |
101
+
102
+ Import from `@signalsafe/tree-spec-editor-react` only (no subpath exports).
103
+
104
+ ## Package boundaries
105
+
106
+ | Layer | Package |
107
+ |---|---|
108
+ | Wire | `@signalsafe/tree-spec` |
109
+ | Editor model | `@signalsafe/tree-spec-editor-core` |
110
+ | **React canvas (this package)** | `@signalsafe/tree-spec-editor-react` |
111
+ | Authoring shell | `@signalsafe/tree-spec-editor` |
112
+
113
+ ## Canvas selection behavior
114
+
115
+ | Selection | Inspector context | Contextual zoom (default on) |
116
+ |---|---|---|
117
+ | Node | selected node | fits node in viewport |
118
+ | Edge | source node + focused choice | viewport unchanged |
119
+ | Choice | `focusChoiceId` set | fits parent node when selected |
120
+
121
+ Pass `contextualZoom={false}` to disable automatic viewport fitting.
122
+
123
+ ## Development
124
+
125
+ Requires Node.js **>=22.12.0** (`engines.node`). CI runs checks, tests, and smoke on Node **22** and **24**; publish uses Node **24**.
126
+
127
+ `yarn build` uses `tsconfig.build.json` and resolves `@signalsafe/*` from `node_modules`. Ecosystem sibling `paths` in `tsconfig.json` apply to local typecheck/tests only.
42
128
 
43
129
  ```bash
44
- npm install @signalsafe/tree-spec-editor-react react react-dom reactflow
130
+ yarn install
131
+ yarn build
132
+ yarn test
133
+ yarn typecheck
45
134
  ```
46
135
 
47
- `reactflow` is a peer dependency; you must install it (and ship its CSS,
48
- e.g. `import 'reactflow/dist/style.css';`) in the consuming app. The
49
- package itself imports the CSS file from its source, so bundlers that
50
- resolve module references will pick it up automatically.
136
+ ## Security
51
137
 
52
- ## Why a separate package?
138
+ See [SECURITY.md](./SECURITY.md). Host applications must authenticate users, authorize edits, and validate TreeSpec JSON server-side before publish.
53
139
 
54
- This layer is React-specific but **UI-library-agnostic**. Hosts that want
55
- to ship a Material-styled editor only need to publish their own UI shell
56
- (panels, modals, toolbar) — they reuse the canvas and the editor model
57
- unchanged. This also keeps `@signalsafe/tree-spec-editor` (the
58
- Bootstrap variant) from being the sole React entry point.
140
+ ## Changelog and releases
59
141
 
60
- ## Repository
142
+ - [CHANGELOG.md](./CHANGELOG.md)
143
+ - [RELEASING.md](./RELEASING.md)
61
144
 
62
- Standalone source and releases: [SignalSafeSoftware/tree-spec-editor-react](https://github.com/SignalSafeSoftware/tree-spec-editor-react).
145
+ ## Related packages
63
146
 
64
- Published as [`@signalsafe/tree-spec-editor-react`](https://www.npmjs.com/package/@signalsafe/tree-spec-editor-react) on npm.
147
+ - [`@signalsafe/tree-spec-editor-core`](https://github.com/SignalSafeSoftware/tree-spec-editor-core) framework-agnostic editor helpers.
148
+ - [`@signalsafe/tree-spec-editor`](https://github.com/SignalSafeSoftware/tree-spec-editor) — UI-kit agnostic authoring shell (panels, modals, toolbar).
@@ -15,7 +15,7 @@ export type TreeSpecGraphEditorProps = {
15
15
  /** Focused choice on the currently selected node (canvas + inspector sync). */
16
16
  focusChoiceId?: string | null;
17
17
  fitViewNonce?: number;
18
- /** Optional class for the outer container (default includes h-70vh border rounded). */
18
+ /** Optional class for the outer container (default: `graph-editor-canvas-root`). */
19
19
  className?: string;
20
20
  /** When true, disables canvas editing affordances (toolbar, resize, context menu). */
21
21
  readOnly?: boolean;
@@ -30,7 +30,7 @@ export type TreeSpecGraphEditorProps = {
30
30
  * Skipped when `focusNodeId` already targets the same node.
31
31
  */
32
32
  contextualZoom?: boolean;
33
- /** Canvas chrome mode — host should pass Bootstrap `colorScheme` (`light` / `dark`). */
33
+ /** Canvas chrome mode — host theme hint (`light` / `dark`). */
34
34
  colorMode?: 'light' | 'dark';
35
35
  };
36
36
  export default function TreeSpecGraphEditor(props: Readonly<TreeSpecGraphEditorProps>): import("react").JSX.Element;
@@ -1 +1 @@
1
- {"version":3,"file":"TreeSpecGraphEditor.d.ts","sourceRoot":"","sources":["../src/TreeSpecGraphEditor.tsx"],"names":[],"mappings":"AAYA,OAAO,0BAA0B,CAAC;AAElC,OAAO,EAKH,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACxB,MAAM,mCAAmC,CAAC;AAsB3C,MAAM,MAAM,wBAAwB,GAAG;IACnC,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,CAAC;IACrC,MAAM,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC5B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,IAAI,CAAC;IACzC,gGAAgG;IAChG,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5D,oFAAoF;IACpF,kBAAkB,CAAC,EAAE,CACjB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,KACd,IAAI,CAAC;IACV,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,+EAA+E;IAC/E,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,uFAAuF;IACvF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sFAAsF;IACtF,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,uEAAuE;IACvE,eAAe,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,oEAAoE;IACpE,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,kDAAkD;IAClD,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,wFAAwF;IACxF,SAAS,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;CAChC,CAAC;AA4PF,MAAM,CAAC,OAAO,UAAU,mBAAmB,CAAC,KAAK,EAAE,QAAQ,CAAC,wBAAwB,CAAC,+BAMpF"}
1
+ {"version":3,"file":"TreeSpecGraphEditor.d.ts","sourceRoot":"","sources":["../src/TreeSpecGraphEditor.tsx"],"names":[],"mappings":"AAYA,OAAO,0BAA0B,CAAC;AAElC,OAAO,EAKH,KAAK,UAAU,EACf,KAAK,cAAc,EACnB,KAAK,gBAAgB,EACxB,MAAM,mCAAmC,CAAC;AAuB3C,MAAM,MAAM,wBAAwB,GAAG;IACnC,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE,CAAC,IAAI,EAAE,UAAU,KAAK,IAAI,CAAC;IACrC,MAAM,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAC5B,WAAW,CAAC,EAAE,OAAO,CAAC;IACtB,QAAQ,CAAC,EAAE,cAAc,CAAC;IAC1B,QAAQ,CAAC,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,IAAI,CAAC;IACzC,gGAAgG;IAChG,cAAc,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IAC5D,oFAAoF;IACpF,kBAAkB,CAAC,EAAE,CACjB,UAAU,EAAE,MAAM,EAClB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,KACd,IAAI,CAAC;IACV,WAAW,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC5B,+EAA+E;IAC/E,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAC;IAC9B,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oFAAoF;IACpF,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,sFAAsF;IACtF,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,uEAAuE;IACvE,eAAe,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,oEAAoE;IACpE,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,kDAAkD;IAClD,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;IAC1B;;;OAGG;IACH,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,+DAA+D;IAC/D,SAAS,CAAC,EAAE,OAAO,GAAG,MAAM,CAAC;CAChC,CAAC;AA4PF,MAAM,CAAC,OAAO,UAAU,mBAAmB,CAAC,KAAK,EAAE,QAAQ,CAAC,wBAAwB,CAAC,+BAMpF"}
@@ -3,23 +3,24 @@ import { useCallback, useMemo, useRef, useState } from 'react';
3
3
  import ReactFlow, { Background, ConnectionMode, Controls, MiniMap, ReactFlowProvider, useReactFlow, } from 'reactflow';
4
4
  import 'reactflow/dist/style.css';
5
5
  import { GRAPH_SELECTION_KIND, choiceIdFromHandle, resolveGraphViewport, LAYOUT_SNAP_GRID, } from '@signalsafe/tree-spec-editor-core';
6
- import { GraphEditorCanvasContext, } from './GraphEditorCanvasContext';
7
- import { buildEdgeMarker, getIssueEdgeStyle, resolveSelectedEdgeStroke } from './canvas/edgeStyle';
8
- import { CANVAS_CLASS } from './canvas/constants';
9
- import { resolveCanvasFocusChoiceId } from './canvas/focusChoice';
10
- import { isChoiceRowClickTarget } from './canvas/typeGuards';
11
- import { GraphCanvasContextMenu } from './contextMenu/GraphCanvasContextMenu';
12
- import { EndNode } from './nodes/EndNode';
13
- import { PromptNode } from './nodes/PromptNode';
14
- import { joinClasses } from './utils/joinClasses';
15
- import { useCanvasContextMenu } from './hooks/useCanvasContextMenu';
16
- import { useCanvasGraphState } from './hooks/useCanvasGraphState';
17
- import { useCanvasIssueIndex } from './hooks/useCanvasIssueIndex';
18
- import { useCanvasNodeResize } from './hooks/useCanvasNodeResize';
19
- import { useCanvasViewport } from './hooks/useCanvasViewport';
20
- import { useChoiceDragDrop } from './hooks/useChoiceDragDrop';
21
- import { useGraphConnect } from './hooks/useGraphConnect';
22
- function TreeSpecGraphInner({ tree, onChange, issues = [], selected, onSelect, onChoiceSelect, onRepositionChoice, focusNodeId, focusChoiceId = null, showMiniMap = true, fitViewNonce, className = 'h-70vh border rounded', readOnly = false, onDuplicateNode, onDeleteNode, onAutoLayout, contextualZoom = true, colorMode = 'light', }) {
6
+ import { GraphEditorCanvasContext, } from './GraphEditorCanvasContext.js';
7
+ import { buildEdgeMarker, getIssueEdgeStyle, resolveSelectedEdgeStroke } from './canvas/edgeStyle.js';
8
+ import { CANVAS_CLASS } from './canvas/constants.js';
9
+ import { EDITOR_CANVAS_ROOT } from './ui/editorClasses.js';
10
+ import { resolveCanvasFocusChoiceId } from './canvas/focusChoice.js';
11
+ import { isChoiceRowClickTarget } from './canvas/typeGuards.js';
12
+ import { GraphCanvasContextMenu } from './contextMenu/GraphCanvasContextMenu.js';
13
+ import { EndNode } from './nodes/EndNode.js';
14
+ import { PromptNode } from './nodes/PromptNode.js';
15
+ import { joinClasses } from './utils/joinClasses.js';
16
+ import { useCanvasContextMenu } from './hooks/useCanvasContextMenu.js';
17
+ import { useCanvasGraphState } from './hooks/useCanvasGraphState.js';
18
+ import { useCanvasIssueIndex } from './hooks/useCanvasIssueIndex.js';
19
+ import { useCanvasNodeResize } from './hooks/useCanvasNodeResize.js';
20
+ import { useCanvasViewport } from './hooks/useCanvasViewport.js';
21
+ import { useChoiceDragDrop } from './hooks/useChoiceDragDrop.js';
22
+ import { useGraphConnect } from './hooks/useGraphConnect.js';
23
+ function TreeSpecGraphInner({ tree, onChange, issues = [], selected, onSelect, onChoiceSelect, onRepositionChoice, focusNodeId, focusChoiceId = null, showMiniMap = true, fitViewNonce, className = EDITOR_CANVAS_ROOT, readOnly = false, onDuplicateNode, onDeleteNode, onAutoLayout, contextualZoom = true, colorMode = 'light', }) {
23
24
  const rf = useReactFlow();
24
25
  const treeRef = useRef(tree);
25
26
  treeRef.current = tree;
@@ -1,6 +1,6 @@
1
1
  import { MarkerType } from 'reactflow';
2
2
  /** Background highlight when the node matches editor selection (sidebar / issues / canvas). */
3
- export declare const CANVAS_NODE_SELECTED_CLASS = "bg-primary-subtle";
3
+ export declare const CANVAS_NODE_SELECTED_CLASS = "graph-editor-canvas__selected";
4
4
  /** Dark readable text on selected canvas node cards. */
5
5
  export declare const CANVAS_NODE_SELECTED_TEXT_CLASS = "graph-editor-canvas-selected";
6
6
  export declare const CANVAS_CLASS = "graph-editor-canvas";
@@ -18,13 +18,14 @@ export declare const CHOICE_ROW_SELECTABLE_CLASS = "graph-editor-choice-row-sele
18
18
  export declare const CHOICE_HANDLE_CLASS = "graph-editor-handle graph-editor-choice-handle";
19
19
  export declare const NODE_DRAG_HANDLE_CLASS = "graph-editor-drag-handle";
20
20
  export declare const NODE_DRAG_HANDLE_SELECTOR = ".graph-editor-drag-handle";
21
- export declare const TARGET_HANDLE_CLASS_DEFAULT = "handle-bg-default graph-editor-target-handle";
22
- export declare const TARGET_HANDLE_CLASS_DANGER = "handle-bg-danger graph-editor-target-handle";
23
- export declare const CONTEXT_MENU_CLASS = "graph-editor-context-menu dropdown-menu show position-fixed shadow-sm";
21
+ export declare const TARGET_HANDLE_CLASS_DEFAULT = "graph-editor-target-handle graph-editor-target-handle--default";
22
+ export declare const TARGET_HANDLE_CLASS_DANGER = "graph-editor-target-handle graph-editor-target-handle--danger";
23
+ export declare const CONTEXT_MENU_CLASS: string;
24
24
  export declare const REACT_FLOW_PANE_CLASS = "react-flow__pane";
25
- export declare const BORDER_DANGER_CLASS = "border-danger";
26
- export declare const BORDER_WARNING_CLASS = "border-warning";
27
- export declare const END_NODE_WIDTH_CLASS = "w-180";
25
+ export declare const BORDER_DANGER_CLASS = "graph-editor-canvas-node--border-danger";
26
+ export declare const BORDER_WARNING_CLASS = "graph-editor-canvas-node--border-warning";
27
+ export declare const END_NODE_WIDTH_CLASS = "graph-editor-canvas-node--end-width";
28
+ export declare const CANVAS_NODE_CARD_CLASS: string;
28
29
  export declare const MIN_NODE_WIDTH = 180;
29
30
  export declare const MAX_NODE_WIDTH = 560;
30
31
  export declare const MIN_NODE_HEIGHT = 80;
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/canvas/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAEvC,+FAA+F;AAC/F,eAAO,MAAM,0BAA0B,sBAAsB,CAAC;AAE9D,wDAAwD;AACxD,eAAO,MAAM,+BAA+B,iCAAiC,CAAC;AAE9E,eAAO,MAAM,YAAY,wBAAwB,CAAC;AAClD,eAAO,MAAM,iBAAiB,6BAA6B,CAAC;AAC5D,eAAO,MAAM,sBAAsB,kCAAkC,CAAC;AACtE,eAAO,MAAM,4BAA4B,wCAAwC,CAAC;AAElF,eAAO,MAAM,gBAAgB,4BAA4B,CAAC;AAC1D,eAAO,MAAM,mBAAmB,6BAAyB,CAAC;AAC1D,eAAO,MAAM,wBAAwB,oCAAoC,CAAC;AAC1E,eAAO,MAAM,2BAA2B,qCAAiC,CAAC;AAC1E,eAAO,MAAM,wBAAwB,oCAAoC,CAAC;AAC1E,eAAO,MAAM,wBAAwB,oCAAoC,CAAC;AAC1E,eAAO,MAAM,uBAAuB,mCAAmC,CAAC;AACxE,eAAO,MAAM,2BAA2B,uCAAuC,CAAC;AAChF,eAAO,MAAM,mBAAmB,mDAAmD,CAAC;AAEpF,eAAO,MAAM,sBAAsB,6BAA6B,CAAC;AACjE,eAAO,MAAM,yBAAyB,8BAA+B,CAAC;AAEtE,eAAO,MAAM,2BAA2B,iDAAiD,CAAC;AAC1F,eAAO,MAAM,0BAA0B,gDAAgD,CAAC;AAExF,eAAO,MAAM,kBAAkB,0EAA0E,CAAC;AAE1G,eAAO,MAAM,qBAAqB,qBAAqB,CAAC;AAExD,eAAO,MAAM,mBAAmB,kBAAkB,CAAC;AACnD,eAAO,MAAM,oBAAoB,mBAAmB,CAAC;AAErD,eAAO,MAAM,oBAAoB,UAAU,CAAC;AAE5C,eAAO,MAAM,cAAc,MAAM,CAAC;AAClC,eAAO,MAAM,cAAc,MAAM,CAAC;AAClC,eAAO,MAAM,eAAe,KAAK,CAAC;AAClC,eAAO,MAAM,eAAe,MAAM,CAAC;AAEnC,qGAAqG;AACrG,eAAO,MAAM,oBAAoB,SAAS,CAAC;AAE3C,eAAO,MAAM,iBAAiB;;;;CAI7B,CAAC;AAEF,eAAO,MAAM,gBAAgB,OAAO,CAAC;AACrC,eAAO,MAAM,oBAAoB,YAAY,CAAC"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/canvas/constants.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAC;AAKvC,+FAA+F;AAC/F,eAAO,MAAM,0BAA0B,kCAAkC,CAAC;AAE1E,wDAAwD;AACxD,eAAO,MAAM,+BAA+B,iCAAiC,CAAC;AAE9E,eAAO,MAAM,YAAY,wBAAwB,CAAC;AAClD,eAAO,MAAM,iBAAiB,6BAA6B,CAAC;AAC5D,eAAO,MAAM,sBAAsB,kCAAkC,CAAC;AACtE,eAAO,MAAM,4BAA4B,wCAAwC,CAAC;AAElF,eAAO,MAAM,gBAAgB,4BAA4B,CAAC;AAC1D,eAAO,MAAM,mBAAmB,6BAAyB,CAAC;AAC1D,eAAO,MAAM,wBAAwB,oCAAoC,CAAC;AAC1E,eAAO,MAAM,2BAA2B,qCAAiC,CAAC;AAC1E,eAAO,MAAM,wBAAwB,oCAAoC,CAAC;AAC1E,eAAO,MAAM,wBAAwB,oCAAoC,CAAC;AAC1E,eAAO,MAAM,uBAAuB,mCAAmC,CAAC;AACxE,eAAO,MAAM,2BAA2B,uCAAuC,CAAC;AAChF,eAAO,MAAM,mBAAmB,mDAAmD,CAAC;AAEpF,eAAO,MAAM,sBAAsB,6BAA6B,CAAC;AACjE,eAAO,MAAM,yBAAyB,8BAA+B,CAAC;AAEtE,eAAO,MAAM,2BAA2B,mEAAmE,CAAC;AAC5G,eAAO,MAAM,0BAA0B,kEAAkE,CAAC;AAE1G,eAAO,MAAM,kBAAkB,QAM9B,CAAC;AAEF,eAAO,MAAM,qBAAqB,qBAAqB,CAAC;AAExD,eAAO,MAAM,mBAAmB,4CAA4C,CAAC;AAC7E,eAAO,MAAM,oBAAoB,6CAA6C,CAAC;AAE/E,eAAO,MAAM,oBAAoB,wCAAwC,CAAC;AAE1E,eAAO,MAAM,sBAAsB,QAA8D,CAAC;AAElG,eAAO,MAAM,cAAc,MAAM,CAAC;AAClC,eAAO,MAAM,cAAc,MAAM,CAAC;AAClC,eAAO,MAAM,eAAe,KAAK,CAAC;AAClC,eAAO,MAAM,eAAe,MAAM,CAAC;AAEnC,qGAAqG;AACrG,eAAO,MAAM,oBAAoB,SAAS,CAAC;AAE3C,eAAO,MAAM,iBAAiB;;;;CAI7B,CAAC;AAEF,eAAO,MAAM,gBAAgB,OAAO,CAAC;AACrC,eAAO,MAAM,oBAAoB,YAAY,CAAC"}
@@ -1,6 +1,8 @@
1
1
  import { MarkerType } from 'reactflow';
2
+ import { joinClasses } from '../utils/joinClasses.js';
3
+ import { EDITOR_CARD, EDITOR_DROPDOWN_MENU, EDITOR_ROUNDED } from '../ui/editorClasses.js';
2
4
  /** Background highlight when the node matches editor selection (sidebar / issues / canvas). */
3
- export const CANVAS_NODE_SELECTED_CLASS = 'bg-primary-subtle';
5
+ export const CANVAS_NODE_SELECTED_CLASS = 'graph-editor-canvas__selected';
4
6
  /** Dark readable text on selected canvas node cards. */
5
7
  export const CANVAS_NODE_SELECTED_TEXT_CLASS = 'graph-editor-canvas-selected';
6
8
  export const CANVAS_CLASS = 'graph-editor-canvas';
@@ -18,13 +20,14 @@ export const CHOICE_ROW_SELECTABLE_CLASS = 'graph-editor-choice-row-selectable';
18
20
  export const CHOICE_HANDLE_CLASS = 'graph-editor-handle graph-editor-choice-handle';
19
21
  export const NODE_DRAG_HANDLE_CLASS = 'graph-editor-drag-handle';
20
22
  export const NODE_DRAG_HANDLE_SELECTOR = `.${NODE_DRAG_HANDLE_CLASS}`;
21
- export const TARGET_HANDLE_CLASS_DEFAULT = 'handle-bg-default graph-editor-target-handle';
22
- export const TARGET_HANDLE_CLASS_DANGER = 'handle-bg-danger graph-editor-target-handle';
23
- export const CONTEXT_MENU_CLASS = 'graph-editor-context-menu dropdown-menu show position-fixed shadow-sm';
23
+ export const TARGET_HANDLE_CLASS_DEFAULT = 'graph-editor-target-handle graph-editor-target-handle--default';
24
+ export const TARGET_HANDLE_CLASS_DANGER = 'graph-editor-target-handle graph-editor-target-handle--danger';
25
+ export const CONTEXT_MENU_CLASS = joinClasses('graph-editor-context-menu', EDITOR_DROPDOWN_MENU, 'graph-editor-dropdown__menu--open', 'graph-editor-context-menu--fixed', 'graph-editor-shadow--sm');
24
26
  export const REACT_FLOW_PANE_CLASS = 'react-flow__pane';
25
- export const BORDER_DANGER_CLASS = 'border-danger';
26
- export const BORDER_WARNING_CLASS = 'border-warning';
27
- export const END_NODE_WIDTH_CLASS = 'w-180';
27
+ export const BORDER_DANGER_CLASS = 'graph-editor-canvas-node--border-danger';
28
+ export const BORDER_WARNING_CLASS = 'graph-editor-canvas-node--border-warning';
29
+ export const END_NODE_WIDTH_CLASS = 'graph-editor-canvas-node--end-width';
30
+ export const CANVAS_NODE_CARD_CLASS = joinClasses(EDITOR_CARD, EDITOR_ROUNDED, CANVAS_NODE_CLASS);
28
31
  export const MIN_NODE_WIDTH = 180;
29
32
  export const MAX_NODE_WIDTH = 560;
30
33
  export const MIN_NODE_HEIGHT = 80;
@@ -1,7 +1,7 @@
1
1
  import { TERMINAL_OUTCOME } from '@signalsafe/tree-spec';
2
2
  import { END_NODE_ID, choiceIdFromHandle, resolveDefaultEdgeType, resolveEffectiveEdgeType, resolveEdgeStrokeColor, shouldShowEdgeLabel, } from '@signalsafe/tree-spec-editor-core';
3
- import { CHOICE_HANDLE_PREFIX, TARGET_HANDLE_ID, } from './constants';
4
- import { buildEdgeMarker, buildEdgeStyle, resolveEdgePathStroke } from './edgeStyle';
3
+ import { CHOICE_HANDLE_PREFIX, TARGET_HANDLE_ID, } from './constants.js';
4
+ import { buildEdgeMarker, buildEdgeStyle, resolveEdgePathStroke } from './edgeStyle.js';
5
5
  export function edgeLabelForTransition(tree, t) {
6
6
  const node = tree.nodes[t.fromNodeId];
7
7
  const choice = node?.choices?.find((c) => c.id === t.fromChoiceId);
@@ -1,5 +1,5 @@
1
1
  import { DEFAULT_CANVAS_EDGE_STROKE } from '@signalsafe/tree-spec-editor-core';
2
- import { BORDER_DANGER_CLASS, BORDER_WARNING_CLASS, EDGE_ARROW_MARKER, SELECTED_EDGE_STROKE } from './constants';
2
+ import { BORDER_DANGER_CLASS, BORDER_WARNING_CLASS, EDGE_ARROW_MARKER, SELECTED_EDGE_STROKE } from './constants.js';
3
3
  export function getPromptNodeBorderClass(hasErrors, warningCount) {
4
4
  if (hasErrors) {
5
5
  return BORDER_DANGER_CLASS;
@@ -1,4 +1,4 @@
1
- import { CHOICE_ROW_SELECTOR, REACT_FLOW_PANE_CLASS } from './constants';
1
+ import { CHOICE_ROW_SELECTOR, REACT_FLOW_PANE_CLASS } from './constants.js';
2
2
  export function isChoiceRowClickTarget(target) {
3
3
  if (target == null || typeof target !== 'object')
4
4
  return false;
@@ -1,4 +1,4 @@
1
- import type { CanvasContextMenuState } from './types';
1
+ import type { CanvasContextMenuState } from './types.js';
2
2
  export declare function GraphCanvasContextMenu({ menu, readOnly, onClose, onDuplicateNode, onDeleteNode, onAutoLayout, }: Readonly<{
3
3
  menu: CanvasContextMenuState | null;
4
4
  readOnly: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"GraphCanvasContextMenu.d.ts","sourceRoot":"","sources":["../../src/contextMenu/GraphCanvasContextMenu.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,SAAS,CAAC;AAEtD,wBAAgB,sBAAsB,CAAC,EACnC,IAAI,EACJ,QAAQ,EACR,OAAO,EACP,eAAe,EACf,YAAY,EACZ,YAAY,GACf,EAAE,QAAQ,CAAC;IACR,IAAI,EAAE,sBAAsB,GAAG,IAAI,CAAC;IACpC,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,eAAe,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;CAC7B,CAAC,sCAwDD"}
1
+ {"version":3,"file":"GraphCanvasContextMenu.d.ts","sourceRoot":"","sources":["../../src/contextMenu/GraphCanvasContextMenu.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,YAAY,CAAC;AAEzD,wBAAgB,sBAAsB,CAAC,EACnC,IAAI,EACJ,QAAQ,EACR,OAAO,EACP,eAAe,EACf,YAAY,EACZ,YAAY,GACf,EAAE,QAAQ,CAAC;IACR,IAAI,EAAE,sBAAsB,GAAG,IAAI,CAAC;IACpC,QAAQ,EAAE,OAAO,CAAC;IAClB,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,eAAe,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3C,YAAY,CAAC,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,IAAI,CAAC;IACxC,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;CAC7B,CAAC,sCAwDD"}
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { END_NODE_ID } from '@signalsafe/tree-spec-editor-core';
3
- import { CONTEXT_MENU_CLASS } from '../canvas/constants';
4
- import { joinClasses } from '../utils/joinClasses';
3
+ import { CONTEXT_MENU_CLASS } from '../canvas/constants.js';
4
+ import { editorDropdownItemClass } from '../ui/editorClasses.js';
5
5
  export function GraphCanvasContextMenu({ menu, readOnly, onClose, onDuplicateNode, onDeleteNode, onAutoLayout, }) {
6
6
  if (!menu || readOnly)
7
7
  return null;
@@ -32,7 +32,7 @@ export function GraphCanvasContextMenu({ menu, readOnly, onClose, onDuplicateNod
32
32
  }
33
33
  if (items.length === 0)
34
34
  return null;
35
- return (_jsx("div", { className: CONTEXT_MENU_CLASS, style: { left: menu.x, top: menu.y, zIndex: 1050 }, role: "menu", tabIndex: -1, onContextMenu: (event) => event.preventDefault(), onPointerDown: (event) => event.stopPropagation(), children: items.map((item) => (_jsx("button", { type: "button", className: joinClasses('dropdown-item', item.danger && 'text-danger'), role: "menuitem", onClick: () => {
35
+ return (_jsx("div", { className: CONTEXT_MENU_CLASS, style: { left: menu.x, top: menu.y, zIndex: 1050 }, role: "menu", tabIndex: -1, onContextMenu: (event) => event.preventDefault(), onPointerDown: (event) => event.stopPropagation(), children: items.map((item) => (_jsx("button", { type: "button", className: editorDropdownItemClass(item.danger), role: "menuitem", onClick: () => {
36
36
  item.onClick();
37
37
  onClose();
38
38
  }, children: item.label }, item.key))) }));
@@ -1,6 +1,6 @@
1
1
  import { type MouseEvent } from 'react';
2
2
  import type { Node } from 'reactflow';
3
- import type { CanvasContextMenuState } from '../contextMenu/types';
3
+ import type { CanvasContextMenuState } from '../contextMenu/types.js';
4
4
  export type UseCanvasContextMenuOptions = {
5
5
  readOnly: boolean;
6
6
  onAutoLayout?: () => void;
@@ -1 +1 @@
1
- {"version":3,"file":"useCanvasContextMenu.d.ts","sourceRoot":"","sources":["../../src/hooks/useCanvasContextMenu.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoC,KAAK,UAAU,EAAE,MAAM,OAAO,CAAC;AAC1E,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,sBAAsB,CAAC;AAEnE,MAAM,MAAM,2BAA2B,GAAG;IACtC,QAAQ,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACrC,WAAW,EAAE,sBAAsB,GAAG,IAAI,CAAC;IAC3C,gBAAgB,EAAE,MAAM,IAAI,CAAC;IAC7B,iBAAiB,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAC3D,iBAAiB,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;CAClD,CAAC;AAEF,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,2BAA2B,GAAG,0BAA0B,CAsDrG"}
1
+ {"version":3,"file":"useCanvasContextMenu.d.ts","sourceRoot":"","sources":["../../src/hooks/useCanvasContextMenu.ts"],"names":[],"mappings":"AAAA,OAAO,EAAoC,KAAK,UAAU,EAAE,MAAM,OAAO,CAAC;AAC1E,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEtC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,yBAAyB,CAAC;AAEtE,MAAM,MAAM,2BAA2B,GAAG;IACtC,QAAQ,EAAE,OAAO,CAAC;IAClB,YAAY,CAAC,EAAE,MAAM,IAAI,CAAC;CAC7B,CAAC;AAEF,MAAM,MAAM,0BAA0B,GAAG;IACrC,WAAW,EAAE,sBAAsB,GAAG,IAAI,CAAC;IAC3C,gBAAgB,EAAE,MAAM,IAAI,CAAC;IAC7B,iBAAiB,EAAE,CAAC,KAAK,EAAE,UAAU,EAAE,IAAI,EAAE,IAAI,KAAK,IAAI,CAAC;IAC3D,iBAAiB,EAAE,CAAC,KAAK,EAAE,UAAU,KAAK,IAAI,CAAC;CAClD,CAAC;AAEF,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,2BAA2B,GAAG,0BAA0B,CAsDrG"}
@@ -1,8 +1,8 @@
1
1
  import { useCallback, useEffect, useMemo, useRef } from 'react';
2
2
  import { useEdgesState, useNodesState, } from 'reactflow';
3
3
  import { END_NODE_ID, getEditorHints, isNodeLocked, patchGraphEditorMeta, resolveCanvasNodeWidth, resolveEndNodePosition, snapPosition, } from '@signalsafe/tree-spec-editor-core';
4
- import { buildEdgesFromTransitions, buildTransitionsFromEdges } from '../canvas/edgeBuilders';
5
- import { NODE_DRAG_HANDLE_SELECTOR } from '../canvas/constants';
4
+ import { buildEdgesFromTransitions, buildTransitionsFromEdges } from '../canvas/edgeBuilders.js';
5
+ import { NODE_DRAG_HANDLE_SELECTOR } from '../canvas/constants.js';
6
6
  export function useCanvasGraphState(options) {
7
7
  const { tree, onChange, issues, issuesByNode, readOnly, resizeHeightByNodeId, isResizingRef, suppressViewportSaveRef, } = options;
8
8
  const isDraggingRef = useRef(false);
@@ -1,7 +1,7 @@
1
1
  import { type MutableRefObject, type RefObject } from 'react';
2
2
  import { type TreeSpecIssue, type TreeSpecWire } from '@signalsafe/tree-spec';
3
3
  import { type AutosaveStatus, type EditorTree, type TreeSpecAuditEventItem, type TreeSpecSnapshotItem } from '@signalsafe/tree-spec-editor-core';
4
- import type { GraphEditorVersionInfo, UseTreeSpecEditorActions, UseTreeSpecEditorOptions } from './types';
4
+ import type { GraphEditorVersionInfo, UseTreeSpecEditorActions, UseTreeSpecEditorOptions } from './types.js';
5
5
  export type UseEditorAdapterOptions = {
6
6
  options: UseTreeSpecEditorOptions;
7
7
  tree: EditorTree | null;
@@ -1 +1 @@
1
- {"version":3,"file":"useEditorAdapter.d.ts","sourceRoot":"","sources":["../../src/hooks/useEditorAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqD,KAAK,gBAAgB,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAEjH,OAAO,EAKH,KAAK,aAAa,EAClB,KAAK,YAAY,EACpB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAQH,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EAC5B,MAAM,mCAAmC,CAAC;AAE3C,OAAO,KAAK,EAER,sBAAsB,EACtB,wBAAwB,EACxB,wBAAwB,EAC3B,MAAM,SAAS,CAAC;AAEjB,MAAM,MAAM,uBAAuB,GAAG;IAClC,OAAO,EAAE,wBAAwB,CAAC;IAClC,IAAI,EAAE,UAAU,GAAG,IAAI,CAAC;IACxB,WAAW,EAAE,OAAO,CAAC;IACrB,cAAc,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACxC,yBAAyB,EAAE,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,KAAK,IAAI,CAAC;IAC7D,eAAe,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAC1C,iBAAiB,EAAE,CAAC,MAAM,EAAE,cAAc,KAAK,IAAI,CAAC;CACvD,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,EAAE,OAAO,CAAC;IACpB,aAAa,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,WAAW,EAAE,YAAY,GAAG,IAAI,CAAC;IACjC,WAAW,EAAE,sBAAsB,GAAG,IAAI,CAAC;IAC3C,WAAW,EAAE,aAAa,EAAE,CAAC;IAC7B,YAAY,EAAE,aAAa,EAAE,CAAC;IAC9B,SAAS,EAAE,oBAAoB,EAAE,CAAC;IAClC,WAAW,EAAE,sBAAsB,EAAE,CAAC;IACtC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,YAAY,EAAE,OAAO,CAAC;IACtB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,mBAAmB,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAC7C,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACtC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,mBAAmB,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAC7C,QAAQ,EAAE,wBAAwB,CAAC,UAAU,CAAC,CAAC;IAC/C,SAAS,EAAE,wBAAwB,CAAC,WAAW,CAAC,CAAC;IACjD,cAAc,EAAE,wBAAwB,CAAC,gBAAgB,CAAC,CAAC;IAC3D,eAAe,EAAE,wBAAwB,CAAC,iBAAiB,CAAC,CAAC;IAC7D,YAAY,EAAE,wBAAwB,CAAC,cAAc,CAAC,CAAC;IACvD,WAAW,EAAE,SAAS,CAAC,wBAAwB,CAAC,UAAU,CAAC,CAAC,CAAC;IAC7D,YAAY,EAAE,SAAS,CAAC,wBAAwB,CAAC,WAAW,CAAC,CAAC,CAAC;CAClE,CAAC;AAEF,wBAAgB,gBAAgB,CAAC,cAAc,EAAE,uBAAuB,GAAG,sBAAsB,CAsShG"}
1
+ {"version":3,"file":"useEditorAdapter.d.ts","sourceRoot":"","sources":["../../src/hooks/useEditorAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqD,KAAK,gBAAgB,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAEjH,OAAO,EAKH,KAAK,aAAa,EAClB,KAAK,YAAY,EACpB,MAAM,uBAAuB,CAAC;AAE/B,OAAO,EAQH,KAAK,cAAc,EACnB,KAAK,UAAU,EACf,KAAK,sBAAsB,EAC3B,KAAK,oBAAoB,EAC5B,MAAM,mCAAmC,CAAC;AAE3C,OAAO,KAAK,EAER,sBAAsB,EACtB,wBAAwB,EACxB,wBAAwB,EAC3B,MAAM,YAAY,CAAC;AAEpB,MAAM,MAAM,uBAAuB,GAAG;IAClC,OAAO,EAAE,wBAAwB,CAAC;IAClC,IAAI,EAAE,UAAU,GAAG,IAAI,CAAC;IACxB,WAAW,EAAE,OAAO,CAAC;IACrB,cAAc,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACxC,yBAAyB,EAAE,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,KAAK,IAAI,CAAC;IAC7D,eAAe,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAC1C,iBAAiB,EAAE,CAAC,MAAM,EAAE,cAAc,KAAK,IAAI,CAAC;CACvD,CAAC;AAEF,MAAM,MAAM,sBAAsB,GAAG;IACjC,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,EAAE,OAAO,CAAC;IACpB,aAAa,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACvC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,OAAO,EAAE,OAAO,CAAC;IACjB,mBAAmB,EAAE,MAAM,GAAG,IAAI,CAAC;IACnC,eAAe,EAAE,MAAM,GAAG,IAAI,CAAC;IAC/B,WAAW,EAAE,YAAY,GAAG,IAAI,CAAC;IACjC,WAAW,EAAE,sBAAsB,GAAG,IAAI,CAAC;IAC3C,WAAW,EAAE,aAAa,EAAE,CAAC;IAC7B,YAAY,EAAE,aAAa,EAAE,CAAC;IAC9B,SAAS,EAAE,oBAAoB,EAAE,CAAC;IAClC,WAAW,EAAE,sBAAsB,EAAE,CAAC;IACtC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,YAAY,EAAE,OAAO,CAAC;IACtB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,mBAAmB,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAC7C,SAAS,EAAE,OAAO,CAAC;IACnB,YAAY,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IACtC,gBAAgB,EAAE,OAAO,CAAC;IAC1B,mBAAmB,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,IAAI,CAAC;IAC7C,QAAQ,EAAE,wBAAwB,CAAC,UAAU,CAAC,CAAC;IAC/C,SAAS,EAAE,wBAAwB,CAAC,WAAW,CAAC,CAAC;IACjD,cAAc,EAAE,wBAAwB,CAAC,gBAAgB,CAAC,CAAC;IAC3D,eAAe,EAAE,wBAAwB,CAAC,iBAAiB,CAAC,CAAC;IAC7D,YAAY,EAAE,wBAAwB,CAAC,cAAc,CAAC,CAAC;IACvD,WAAW,EAAE,SAAS,CAAC,wBAAwB,CAAC,UAAU,CAAC,CAAC,CAAC;IAC7D,YAAY,EAAE,SAAS,CAAC,wBAAwB,CAAC,WAAW,CAAC,CAAC,CAAC;CAClE,CAAC;AAEF,wBAAgB,gBAAgB,CAAC,cAAc,EAAE,uBAAuB,GAAG,sBAAsB,CAsShG"}
@@ -1,6 +1,6 @@
1
1
  import { type MutableRefObject, type RefObject } from 'react';
2
2
  import { type AutosaveStatus, type EditorTree } from '@signalsafe/tree-spec-editor-core';
3
- import type { UseTreeSpecEditorActions } from './types';
3
+ import type { UseTreeSpecEditorActions } from './types.js';
4
4
  export type UseEditorAutosaveOptions = {
5
5
  enableAutosave: boolean;
6
6
  autosaveDebounceMs: number;
@@ -1 +1 @@
1
- {"version":3,"file":"useEditorAutosave.d.ts","sourceRoot":"","sources":["../../src/hooks/useEditorAutosave.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,gBAAgB,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAIjF,OAAO,EAAmB,KAAK,cAAc,EAAE,KAAK,UAAU,EAAE,MAAM,mCAAmC,CAAC;AAE1G,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,SAAS,CAAC;AAExD,MAAM,MAAM,wBAAwB,GAAG;IACnC,cAAc,EAAE,OAAO,CAAC;IACxB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,IAAI,EAAE,UAAU,GAAG,IAAI,CAAC;IACxB,WAAW,EAAE,OAAO,CAAC;IACrB,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,EAAE,OAAO,CAAC;IACpB,cAAc,EAAE,cAAc,CAAC;IAC/B,iBAAiB,EAAE,CAAC,MAAM,EAAE,cAAc,KAAK,IAAI,CAAC;IACpD,eAAe,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAC1C,YAAY,EAAE,SAAS,CAAC,wBAAwB,CAAC,WAAW,CAAC,CAAC,CAAC;CAClE,CAAC;AAEF,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,IAAI,CA2CzE"}
1
+ {"version":3,"file":"useEditorAutosave.d.ts","sourceRoot":"","sources":["../../src/hooks/useEditorAutosave.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,gBAAgB,EAAE,KAAK,SAAS,EAAE,MAAM,OAAO,CAAC;AAIjF,OAAO,EAAmB,KAAK,cAAc,EAAE,KAAK,UAAU,EAAE,MAAM,mCAAmC,CAAC;AAE1G,OAAO,KAAK,EAAE,wBAAwB,EAAE,MAAM,YAAY,CAAC;AAE3D,MAAM,MAAM,wBAAwB,GAAG;IACnC,cAAc,EAAE,OAAO,CAAC;IACxB,kBAAkB,EAAE,MAAM,CAAC;IAC3B,QAAQ,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,IAAI,EAAE,UAAU,GAAG,IAAI,CAAC;IACxB,WAAW,EAAE,OAAO,CAAC;IACrB,MAAM,EAAE,OAAO,CAAC;IAChB,UAAU,EAAE,OAAO,CAAC;IACpB,cAAc,EAAE,cAAc,CAAC;IAC/B,iBAAiB,EAAE,CAAC,MAAM,EAAE,cAAc,KAAK,IAAI,CAAC;IACpD,eAAe,EAAE,gBAAgB,CAAC,MAAM,CAAC,CAAC;IAC1C,YAAY,EAAE,SAAS,CAAC,wBAAwB,CAAC,WAAW,CAAC,CAAC,CAAC;CAClE,CAAC;AAEF,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,IAAI,CA2CzE"}
@@ -1 +1 @@
1
- {"version":3,"file":"useEditorSelection.d.ts","sourceRoot":"","sources":["../../src/hooks/useEditorSelection.ts"],"names":[],"mappings":"AAEA,OAAO,EAIH,KAAK,UAAU,EACf,KAAK,gBAAgB,EACrB,KAAK,UAAU,EACf,KAAK,cAAc,EACtB,MAAM,mCAAmC,CAAC;AAE3C,MAAM,MAAM,wBAAwB,GAAG;IACnC,SAAS,EAAE,cAAc,CAAC;IAC1B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,UAAU,GAAG,IAAI,CAAC;IAChC,YAAY,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACtC,aAAa,EAAE,UAAU,GAAG,IAAI,CAAC;IACjC,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACzD,cAAc,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,IAAI,CAAC;IAC/C,cAAc,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAC5C,gBAAgB,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAC9C,gBAAgB,EAAE,MAAM,IAAI,CAAC;IAC7B,WAAW,EAAE,CAAC,KAAK,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IACvE,YAAY,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,IAAI,CAAC;CAChD,CAAC;AAEF,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,GAAG,wBAAwB,CA6EpF"}
1
+ {"version":3,"file":"useEditorSelection.d.ts","sourceRoot":"","sources":["../../src/hooks/useEditorSelection.ts"],"names":[],"mappings":"AAEA,OAAO,EAIH,KAAK,UAAU,EACf,KAAK,gBAAgB,EACrB,KAAK,UAAU,EACf,KAAK,cAAc,EACtB,MAAM,mCAAmC,CAAC;AAE3C,MAAM,MAAM,wBAAwB,GAAG;IACnC,SAAS,EAAE,cAAc,CAAC;IAC1B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,YAAY,EAAE,MAAM,CAAC;IACrB,YAAY,EAAE,UAAU,GAAG,IAAI,CAAC;IAChC,YAAY,EAAE,gBAAgB,GAAG,IAAI,CAAC;IACtC,aAAa,EAAE,UAAU,GAAG,IAAI,CAAC;IACjC,YAAY,EAAE,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,KAAK,IAAI,CAAC;IACzD,cAAc,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,IAAI,CAAC;IAC/C,cAAc,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAC5C,gBAAgB,EAAE,CAAC,EAAE,EAAE,MAAM,GAAG,IAAI,KAAK,IAAI,CAAC;IAC9C,gBAAgB,EAAE,MAAM,IAAI,CAAC;IAC7B,WAAW,EAAE,CAAC,KAAK,EAAE;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,SAAS,CAAC,EAAE,MAAM,CAAA;KAAE,KAAK,IAAI,CAAC;IACvE,YAAY,EAAE,CAAC,IAAI,EAAE,cAAc,KAAK,IAAI,CAAC;CAChD,CAAC;AAEF,wBAAgB,kBAAkB,CAAC,IAAI,EAAE,UAAU,GAAG,IAAI,GAAG,wBAAwB,CA4EpF"}
@@ -13,8 +13,7 @@ export function useEditorSelection(tree) {
13
13
  const applySelection = useCallback((next) => {
14
14
  setSelection(next);
15
15
  if (next.kind === GRAPH_SELECTION_KIND.EDGE && next.id && tree) {
16
- const edge = tree.transitions.find((t) => t.id === next.id);
17
- if (!edge)
16
+ if (!tree.transitions.some((t) => t.id === next.id))
18
17
  return;
19
18
  }
20
19
  const { focusNodeId: nextFocusNodeId, focusChoiceId: nextFocusChoiceId } = resolveGraphSelectionFocus(next, tree);
@@ -1,7 +1,7 @@
1
1
  import { useCallback, useRef } from 'react';
2
2
  import { useReactFlow } from 'reactflow';
3
3
  import { GRAPH_SELECTION_KIND, applyEditorConnect, applyEditorConnectOnDrop, applyEditorReconnect, isValidEditorConnection, } from '@signalsafe/tree-spec-editor-core';
4
- import { isReactFlowPaneTarget } from '../canvas/typeGuards';
4
+ import { isReactFlowPaneTarget } from '../canvas/typeGuards.js';
5
5
  export function useGraphConnect(options) {
6
6
  const { treeRef, onChange, onSelect, readOnly } = options;
7
7
  const rf = useReactFlow();
@@ -1,4 +1,4 @@
1
- import type { UseTreeSpecEditorOptions, UseTreeSpecEditorResult } from './types';
1
+ import type { UseTreeSpecEditorOptions, UseTreeSpecEditorResult } from './types.js';
2
2
  /**
3
3
  * Headless React hook that owns the full stateful behavior of the SignalSafe
4
4
  * TreeSpec graph editor — loading, autosave, validation, publish, snapshots,
@@ -1 +1 @@
1
- {"version":3,"file":"useTreeSpecEditor.d.ts","sourceRoot":"","sources":["../../src/hooks/useTreeSpecEditor.ts"],"names":[],"mappings":"AAwCA,OAAO,KAAK,EAER,wBAAwB,EACxB,uBAAuB,EAE1B,MAAM,SAAS,CAAC;AAcjB;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,uBAAuB,CA6f5F"}
1
+ {"version":3,"file":"useTreeSpecEditor.d.ts","sourceRoot":"","sources":["../../src/hooks/useTreeSpecEditor.ts"],"names":[],"mappings":"AAwCA,OAAO,KAAK,EAER,wBAAwB,EACxB,uBAAuB,EAE1B,MAAM,YAAY,CAAC;AAcpB;;;;;;GAMG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,wBAAwB,GAAG,uBAAuB,CA6f5F"}
@@ -1,11 +1,11 @@
1
1
  import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
2
2
  import { compileTreeSpec, decompileTreeSpec, TERMINAL_OUTCOME, TREE_SPEC_ISSUE_SEVERITY, } from '@signalsafe/tree-spec';
3
3
  import { applyTreeTemplate, autoLayoutTree, AUTOSAVE_STATUS, deleteNode, deleteTransitionsForChoice, END_NODE_ID, getNextSpawnPosition, getTransition, GRAPH_SELECTION_KIND, moveChoiceInTree, moveNodeChoice, patchChoiceEdgeHints, patchGraphEditorMeta, renameNodeChoiceId, safeUUID, upsertTransition, } from '@signalsafe/tree-spec-editor-core';
4
- import { useEditorAdapter } from './useEditorAdapter';
5
- import { useEditorAutosave } from './useEditorAutosave';
6
- import { useEditorHistory } from './useEditorHistory';
7
- import { useEditorSelection } from './useEditorSelection';
8
- import { dispatchEditorKeyboardShortcut, resolveEditorKeyboardShortcutAction } from './keyboardShortcutDispatch';
4
+ import { useEditorAdapter } from './useEditorAdapter.js';
5
+ import { useEditorAutosave } from './useEditorAutosave.js';
6
+ import { useEditorHistory } from './useEditorHistory.js';
7
+ import { useEditorSelection } from './useEditorSelection.js';
8
+ import { dispatchEditorKeyboardShortcut, resolveEditorKeyboardShortcutAction } from './keyboardShortcutDispatch.js';
9
9
  const DEFAULT_AUTOSAVE_DEBOUNCE_MS = 2500;
10
10
  function isTextFieldTarget(target) {
11
11
  const tag = target instanceof HTMLElement ? target.tagName.toLowerCase() : '';
package/dist/index.d.ts CHANGED
@@ -10,8 +10,8 @@
10
10
  * UI shells layer on top of this package; routing is host-injected via hook
11
11
  * callbacks.
12
12
  */
13
- export { default } from './TreeSpecGraphEditor';
14
- export type { TreeSpecGraphEditorProps } from './TreeSpecGraphEditor';
15
- export { useTreeSpecEditor } from './hooks/useTreeSpecEditor';
16
- export type { AdapterValidationIssue, GraphEditorVersionInfo, TreeSpecEditorAdapter, UseTreeSpecEditorActions, UseTreeSpecEditorOptions, UseTreeSpecEditorResult, UseTreeSpecEditorState, } from './hooks/types';
13
+ export { default } from './TreeSpecGraphEditor.js';
14
+ export type { TreeSpecGraphEditorProps } from './TreeSpecGraphEditor.js';
15
+ export { useTreeSpecEditor } from './hooks/useTreeSpecEditor.js';
16
+ export type { AdapterValidationIssue, GraphEditorVersionInfo, TreeSpecEditorAdapter, UseTreeSpecEditorActions, UseTreeSpecEditorOptions, UseTreeSpecEditorResult, UseTreeSpecEditorState, } from './hooks/types.js';
17
17
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,uBAAuB,CAAC;AAChD,YAAY,EAAE,wBAAwB,EAAE,MAAM,uBAAuB,CAAC;AAEtE,OAAO,EAAE,iBAAiB,EAAE,MAAM,2BAA2B,CAAC;AAC9D,YAAY,EACR,sBAAsB,EACtB,sBAAsB,EACtB,qBAAqB,EACrB,wBAAwB,EACxB,wBAAwB,EACxB,uBAAuB,EACvB,sBAAsB,GACzB,MAAM,eAAe,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,0BAA0B,CAAC;AACnD,YAAY,EAAE,wBAAwB,EAAE,MAAM,0BAA0B,CAAC;AAEzE,OAAO,EAAE,iBAAiB,EAAE,MAAM,8BAA8B,CAAC;AACjE,YAAY,EACR,sBAAsB,EACtB,sBAAsB,EACtB,qBAAqB,EACrB,wBAAwB,EACxB,wBAAwB,EACxB,uBAAuB,EACvB,sBAAsB,GACzB,MAAM,kBAAkB,CAAC"}
package/dist/index.js CHANGED
@@ -10,5 +10,5 @@
10
10
  * UI shells layer on top of this package; routing is host-injected via hook
11
11
  * callbacks.
12
12
  */
13
- export { default } from './TreeSpecGraphEditor';
14
- export { useTreeSpecEditor } from './hooks/useTreeSpecEditor';
13
+ export { default } from './TreeSpecGraphEditor.js';
14
+ export { useTreeSpecEditor } from './hooks/useTreeSpecEditor.js';
@@ -1 +1 @@
1
- {"version":3,"file":"ChoiceCanvasRow.d.ts","sourceRoot":"","sources":["../../src/nodes/ChoiceCanvasRow.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,mCAAmC,CAAC;AAkBtE,wBAAgB,eAAe,CAAC,EAC5B,MAAM,EACN,MAAM,EACN,WAAW,EACX,aAAa,EACb,eAAe,EACf,QAAQ,GACX,EAAE,QAAQ,CAAC;IACR,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,YAAY,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,OAAO,CAAC;CACrB,CAAC,+BAqHD"}
1
+ {"version":3,"file":"ChoiceCanvasRow.d.ts","sourceRoot":"","sources":["../../src/nodes/ChoiceCanvasRow.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,mCAAmC,CAAC;AAkCtE,wBAAgB,eAAe,CAAC,EAC5B,MAAM,EACN,MAAM,EACN,WAAW,EACX,aAAa,EACb,eAAe,EACf,QAAQ,GACX,EAAE,QAAQ,CAAC;IACR,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,YAAY,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,OAAO,CAAC;CACrB,CAAC,+BAoID"}
@@ -1,8 +1,8 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Handle, Position } from 'reactflow';
3
- import { CANVAS_NODE_SELECTED_CLASS, CANVAS_NODE_SELECTED_TEXT_CLASS, CANVAS_CHOICE_SELECTED_CLASS, CHOICE_DRAG_HANDLE_CLASS, CHOICE_DRAG_HANDLE_SELECTOR, CHOICE_DROP_TARGET_CLASS, CHOICE_HANDLE_CLASS, CHOICE_ROW_CLASS, CHOICE_ROW_SELECT_CLASS, CHOICE_ROW_SELECTABLE_CLASS, CHOICE_HANDLE_PREFIX, } from '../canvas/constants';
4
- import { useGraphEditorCanvas } from '../GraphEditorCanvasContext';
5
- import { joinClasses } from '../utils/joinClasses';
3
+ import { CANVAS_NODE_SELECTED_CLASS, CANVAS_NODE_SELECTED_TEXT_CLASS, CANVAS_CHOICE_SELECTED_CLASS, CHOICE_DRAG_HANDLE_CLASS, CHOICE_DRAG_HANDLE_SELECTOR, CHOICE_DROP_TARGET_CLASS, CHOICE_HANDLE_CLASS, CHOICE_ROW_CLASS, CHOICE_ROW_SELECT_CLASS, CHOICE_ROW_SELECTABLE_CLASS, CHOICE_HANDLE_PREFIX, } from '../canvas/constants.js';
4
+ import { useGraphEditorCanvas } from '../GraphEditorCanvasContext.js';
5
+ import { EDITOR_FLEX_ALIGN_CENTER, EDITOR_FLEX_GROW_1, EDITOR_FLEX_ROW, EDITOR_FLEX_SHRINK_0, EDITOR_ICON, EDITOR_LIST_ITEM, EDITOR_MIN_W_0, EDITOR_SPACING_GAP_1, EDITOR_SPACING_P_0, EDITOR_SPACING_PX_2, EDITOR_SPACING_PY_2, EDITOR_TEXT_START, EDITOR_W_FULL, editorBadgeToneClass, joinClasses, } from '../ui/editorClasses.js';
6
6
  export function ChoiceCanvasRow({ nodeId, choice, choiceIndex, focusChoiceId, choiceTextClass, readOnly, }) {
7
7
  const { choiceDrag, choiceDropTarget, onSelectChoice, onChoiceDragStart, onChoiceDragEnd, onChoiceDragOver, onChoiceDrop, } = useGraphEditorCanvas();
8
8
  const isFocused = focusChoiceId === choice.id;
@@ -38,12 +38,12 @@ export function ChoiceCanvasRow({ nodeId, choice, choiceIndex, focusChoiceId, ch
38
38
  event.stopPropagation();
39
39
  onSelectChoice(nodeId, choice.id);
40
40
  };
41
- return (_jsx("li", { className: joinClasses('list-group-item p-0 border-0', isDropTarget && CHOICE_DROP_TARGET_CLASS), onDragOver: handleDragOver, onDrop: handleDrop, children: _jsxs("div", { className: joinClasses('d-flex align-items-center gap-1 min-w-0 py-2 px-2 w-100', CHOICE_ROW_CLASS, isFocused && CANVAS_CHOICE_SELECTED_CLASS, isFocused && CANVAS_NODE_SELECTED_CLASS, isFocused && CANVAS_NODE_SELECTED_TEXT_CLASS), children: [readOnly ? null : (_jsx("button", { type: "button", className: `${CHOICE_DRAG_HANDLE_CLASS} flex-shrink-0`, draggable: true, onDragStart: (event) => {
41
+ return (_jsx("li", { className: joinClasses(EDITOR_LIST_ITEM, EDITOR_SPACING_P_0, 'graph-editor-list__item--plain', isDropTarget && CHOICE_DROP_TARGET_CLASS), onDragOver: handleDragOver, onDrop: handleDrop, children: _jsxs("div", { className: joinClasses(EDITOR_FLEX_ROW, EDITOR_FLEX_ALIGN_CENTER, EDITOR_SPACING_GAP_1, EDITOR_MIN_W_0, EDITOR_SPACING_PY_2, EDITOR_SPACING_PX_2, EDITOR_W_FULL, CHOICE_ROW_CLASS, isFocused && CANVAS_CHOICE_SELECTED_CLASS, isFocused && CANVAS_NODE_SELECTED_CLASS, isFocused && CANVAS_NODE_SELECTED_TEXT_CLASS), children: [readOnly ? null : (_jsx("button", { type: "button", className: joinClasses(CHOICE_DRAG_HANDLE_CLASS, EDITOR_FLEX_SHRINK_0), draggable: true, onDragStart: (event) => {
42
42
  event.stopPropagation();
43
43
  onChoiceDragStart(nodeId, choice.id);
44
44
  event.dataTransfer.effectAllowed = 'move';
45
45
  event.dataTransfer.setData('text/plain', `${nodeId}::${choice.id}`);
46
- }, onDragEnd: () => onChoiceDragEnd(), onClick: (event) => event.stopPropagation(), title: "Drag to reorder or move to another node", "aria-label": "Drag choice", children: _jsx("i", { className: "bi bi-grip-vertical", "aria-hidden": true }) })), _jsxs("button", { type: "button", className: joinClasses(CHOICE_ROW_SELECT_CLASS, 'text-start flex-grow-1 min-w-0 d-flex align-items-center gap-1', readOnly ? '' : CHOICE_ROW_SELECTABLE_CLASS), disabled: readOnly, onClick: handleChoiceSelect, onKeyDown: (event) => {
46
+ }, onDragEnd: () => onChoiceDragEnd(), onClick: (event) => event.stopPropagation(), title: "Drag to reorder or move to another node", "aria-label": "Drag choice", children: _jsx("span", { className: joinClasses(EDITOR_ICON, 'graph-editor-icon--grip'), "aria-hidden": true, children: "\u22EE\u22EE" }) })), _jsxs("button", { type: "button", className: joinClasses(CHOICE_ROW_SELECT_CLASS, EDITOR_TEXT_START, EDITOR_FLEX_GROW_1, EDITOR_MIN_W_0, EDITOR_FLEX_ROW, EDITOR_FLEX_ALIGN_CENTER, EDITOR_SPACING_GAP_1, readOnly ? '' : CHOICE_ROW_SELECTABLE_CLASS), disabled: readOnly, onClick: handleChoiceSelect, onKeyDown: (event) => {
47
47
  if (readOnly)
48
48
  return;
49
49
  if (event.key === 'Enter' || event.key === ' ') {
@@ -51,5 +51,5 @@ export function ChoiceCanvasRow({ nodeId, choice, choiceIndex, focusChoiceId, ch
51
51
  event.stopPropagation();
52
52
  onSelectChoice(nodeId, choice.id);
53
53
  }
54
- }, children: [_jsx("span", { className: joinClasses(choiceTextClass, 'flex-grow-1 min-w-0'), title: choice.label, children: choice.label }), _jsx("span", { className: "badge bg-light text-dark flex-shrink-0", children: choice.id })] }), _jsx(Handle, { type: "source", position: Position.Right, id: `${CHOICE_HANDLE_PREFIX}${choice.id}`, className: CHOICE_HANDLE_CLASS })] }) }));
54
+ }, children: [_jsx("span", { className: joinClasses(choiceTextClass, EDITOR_FLEX_GROW_1, EDITOR_MIN_W_0), title: choice.label, children: choice.label }), _jsx("span", { className: joinClasses(editorBadgeToneClass('neutral'), EDITOR_FLEX_SHRINK_0), children: choice.id })] }), _jsx(Handle, { type: "source", position: Position.Right, id: `${CHOICE_HANDLE_PREFIX}${choice.id}`, className: CHOICE_HANDLE_CLASS })] }) }));
55
55
  }
@@ -1 +1 @@
1
- {"version":3,"file":"EndNode.d.ts","sourceRoot":"","sources":["../../src/nodes/EndNode.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,SAAS,EAAE,MAAM,WAAW,CAAC;AAa7D,wBAAgB,OAAO,CAAC,EAAE,QAAQ,EAAE,EAAE,SAAS,+BAoB9C"}
1
+ {"version":3,"file":"EndNode.d.ts","sourceRoot":"","sources":["../../src/nodes/EndNode.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAoB,KAAK,SAAS,EAAE,MAAM,WAAW,CAAC;AAsB7D,wBAAgB,OAAO,CAAC,EAAE,QAAQ,EAAE,EAAE,SAAS,+BAkB9C"}
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Handle, Position } from 'reactflow';
3
- import { BORDER_DANGER_CLASS, CANVAS_NODE_CLASS, CANVAS_NODE_SELECTED_CLASS, CANVAS_NODE_SELECTED_TEXT_CLASS, END_NODE_WIDTH_CLASS, TARGET_HANDLE_CLASS_DANGER, TARGET_HANDLE_ID, } from '../canvas/constants';
4
- import { joinClasses } from '../utils/joinClasses';
3
+ import { BORDER_DANGER_CLASS, CANVAS_NODE_CARD_CLASS, CANVAS_NODE_SELECTED_CLASS, CANVAS_NODE_SELECTED_TEXT_CLASS, END_NODE_WIDTH_CLASS, TARGET_HANDLE_CLASS_DANGER, TARGET_HANDLE_ID, } from '../canvas/constants.js';
4
+ import { EDITOR_CARD_BODY, EDITOR_MUTED, EDITOR_SPACING_P_2, EDITOR_TEXT_BOLD, EDITOR_TEXT_CENTER, EDITOR_TEXT_DANGER, EDITOR_TEXT_SM, joinClasses, } from '../ui/editorClasses.js';
5
5
  export function EndNode({ selected }) {
6
- return (_jsxs("div", { className: joinClasses('card', 'rounded', CANVAS_NODE_CLASS, BORDER_DANGER_CLASS, END_NODE_WIDTH_CLASS, selected && CANVAS_NODE_SELECTED_CLASS, selected && CANVAS_NODE_SELECTED_TEXT_CLASS), children: [_jsx(Handle, { type: "target", position: Position.Left, id: TARGET_HANDLE_ID, className: TARGET_HANDLE_CLASS_DANGER }), _jsxs("div", { className: "card-body p-2 text-center", children: [_jsx("div", { className: "fw-bold text-danger", children: "END" }), _jsx("div", { className: "text-muted font-size-12", children: "Outcome required" })] })] }));
6
+ return (_jsxs("div", { className: joinClasses(CANVAS_NODE_CARD_CLASS, BORDER_DANGER_CLASS, END_NODE_WIDTH_CLASS, selected && CANVAS_NODE_SELECTED_CLASS, selected && CANVAS_NODE_SELECTED_TEXT_CLASS), children: [_jsx(Handle, { type: "target", position: Position.Left, id: TARGET_HANDLE_ID, className: TARGET_HANDLE_CLASS_DANGER }), _jsxs("div", { className: joinClasses(EDITOR_CARD_BODY, EDITOR_SPACING_P_2, EDITOR_TEXT_CENTER), children: [_jsx("div", { className: joinClasses(EDITOR_TEXT_BOLD, EDITOR_TEXT_DANGER), children: "END" }), _jsx("div", { className: joinClasses(EDITOR_MUTED, EDITOR_TEXT_SM), children: "Outcome required" })] })] }));
7
7
  }
@@ -1,5 +1,5 @@
1
1
  import { type NodeProps } from 'reactflow';
2
- import type { PromptNodeData } from './types';
2
+ import type { PromptNodeData } from './types.js';
3
3
  type PromptNodeProps = Readonly<NodeProps<PromptNodeData>>;
4
4
  export declare function PromptNode({ data, selected, id }: PromptNodeProps): import("react").JSX.Element;
5
5
  export {};
@@ -1 +1 @@
1
- {"version":3,"file":"PromptNode.d.ts","sourceRoot":"","sources":["../../src/nodes/PromptNode.tsx"],"names":[],"mappings":"AACA,OAAO,EAAyD,KAAK,SAAS,EAAE,MAAM,WAAW,CAAC;AA2BlG,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C,KAAK,eAAe,GAAG,QAAQ,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC,CAAC;AAE3D,wBAAgB,UAAU,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,EAAE,eAAe,+BA+GjE"}
1
+ {"version":3,"file":"PromptNode.d.ts","sourceRoot":"","sources":["../../src/nodes/PromptNode.tsx"],"names":[],"mappings":"AACA,OAAO,EAAyD,KAAK,SAAS,EAAE,MAAM,WAAW,CAAC;AAoClG,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,KAAK,eAAe,GAAG,QAAQ,CAAC,SAAS,CAAC,cAAc,CAAC,CAAC,CAAC;AAE3D,wBAAgB,UAAU,CAAC,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,EAAE,EAAE,eAAe,+BA6GjE"}
@@ -2,13 +2,13 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
2
2
  import { useCallback, useEffect } from 'react';
3
3
  import { Handle, NodeResizer, Position, useUpdateNodeInternals } from 'reactflow';
4
4
  import { editorHintsToStyle, getEditorHints, nodeTextWrapClassName, resolveNodeTextWrap, } from '@signalsafe/tree-spec-editor-core';
5
- import { CANVAS_NODE_BODY_CLASS, CANVAS_NODE_CLASS, CANVAS_NODE_SELECTED_CLASS, CANVAS_NODE_SELECTED_TEXT_CLASS, MIN_NODE_HEIGHT, MAX_NODE_HEIGHT, MIN_NODE_WIDTH, MAX_NODE_WIDTH, TARGET_HANDLE_CLASS_DEFAULT, TARGET_HANDLE_ID, } from '../canvas/constants';
6
- import { getPromptNodeBorderClass } from '../canvas/edgeStyle';
7
- import { useGraphEditorCanvas } from '../GraphEditorCanvasContext';
8
- import { joinClasses } from '../utils/joinClasses';
9
- import { PromptNodeChoicesList } from './PromptNodeChoicesList';
10
- import { PromptNodeHeader } from './PromptNodeHeader';
11
- import { PromptNodeToolbar } from './PromptNodeToolbar';
5
+ import { CANVAS_NODE_BODY_CLASS, CANVAS_NODE_CARD_CLASS, CANVAS_NODE_SELECTED_CLASS, CANVAS_NODE_SELECTED_TEXT_CLASS, MIN_NODE_HEIGHT, MAX_NODE_HEIGHT, MIN_NODE_WIDTH, MAX_NODE_WIDTH, TARGET_HANDLE_CLASS_DEFAULT, TARGET_HANDLE_ID, } from '../canvas/constants.js';
6
+ import { getPromptNodeBorderClass } from '../canvas/edgeStyle.js';
7
+ import { useGraphEditorCanvas } from '../GraphEditorCanvasContext.js';
8
+ import { EDITOR_CARD_BODY, EDITOR_MIN_W_0, EDITOR_MUTED, EDITOR_SPACING_MB_0, EDITOR_SPACING_PX_2, EDITOR_SPACING_PY_2, EDITOR_TEXT_SM, joinClasses, } from '../ui/editorClasses.js';
9
+ import { PromptNodeChoicesList } from './PromptNodeChoicesList.js';
10
+ import { PromptNodeHeader } from './PromptNodeHeader.js';
11
+ import { PromptNodeToolbar } from './PromptNodeToolbar.js';
12
12
  export function PromptNode({ data, selected, id }) {
13
13
  const n = data.node;
14
14
  const choices = n.choices ?? [];
@@ -47,5 +47,5 @@ export function PromptNode({ data, selected, id }) {
47
47
  onResizeNodeStart(id, params.width, params.height);
48
48
  }, onResize: handleResize, onResizeEnd: (_event, params) => {
49
49
  onResizeNode(id, params.width, params.height);
50
- } })) : null, _jsxs("div", { className: joinClasses('card', 'rounded', CANVAS_NODE_CLASS, borderClass, showNodeHighlight && CANVAS_NODE_SELECTED_CLASS, showNodeHighlight && CANVAS_NODE_SELECTED_TEXT_CLASS), style: cardStyle, children: [_jsx(Handle, { type: "target", position: Position.Left, id: TARGET_HANDLE_ID, className: TARGET_HANDLE_CLASS_DEFAULT }), _jsx(PromptNodeHeader, { node: n, data: data, editor: editor, locked: locked, readOnly: readOnly }), _jsxs("div", { className: `${CANVAS_NODE_BODY_CLASS} min-w-0`, style: scrollBodyStyle, children: [_jsx("div", { className: "card-body py-2 px-2 min-w-0 nodrag", children: _jsx("div", { className: joinClasses('font-size-12 mb-0', promptTextClass), title: n.prompt || undefined, children: n.prompt || _jsx("em", { className: "text-muted", children: "(empty prompt)" }) }) }), _jsx(PromptNodeChoicesList, { nodeId: id, choices: choices, focusChoiceId: focusChoiceId, choiceTextClass: choiceTextClass, readOnly: readOnly, choiceDrag: choiceDrag, choiceDropTarget: choiceDropTarget, onChoiceDragOver: onChoiceDragOver, onChoiceDrop: onChoiceDrop })] })] })] }));
50
+ } })) : null, _jsxs("div", { className: joinClasses(CANVAS_NODE_CARD_CLASS, borderClass, showNodeHighlight && CANVAS_NODE_SELECTED_CLASS, showNodeHighlight && CANVAS_NODE_SELECTED_TEXT_CLASS), style: cardStyle, children: [_jsx(Handle, { type: "target", position: Position.Left, id: TARGET_HANDLE_ID, className: TARGET_HANDLE_CLASS_DEFAULT }), _jsx(PromptNodeHeader, { node: n, data: data, editor: editor, locked: locked, readOnly: readOnly }), _jsxs("div", { className: joinClasses(CANVAS_NODE_BODY_CLASS, EDITOR_MIN_W_0), style: scrollBodyStyle, children: [_jsx("div", { className: joinClasses(EDITOR_CARD_BODY, EDITOR_SPACING_PY_2, EDITOR_SPACING_PX_2, EDITOR_MIN_W_0, 'nodrag'), children: _jsx("div", { className: joinClasses(EDITOR_TEXT_SM, EDITOR_SPACING_MB_0, promptTextClass), title: n.prompt || undefined, children: n.prompt || _jsx("em", { className: EDITOR_MUTED, children: "(empty prompt)" }) }) }), _jsx(PromptNodeChoicesList, { nodeId: id, choices: choices, focusChoiceId: focusChoiceId, choiceTextClass: choiceTextClass, readOnly: readOnly, choiceDrag: choiceDrag, choiceDropTarget: choiceDropTarget, onChoiceDragOver: onChoiceDragOver, onChoiceDrop: onChoiceDrop })] })] })] }));
51
51
  }
@@ -1,5 +1,5 @@
1
1
  import { type EditorChoice } from '@signalsafe/tree-spec-editor-core';
2
- import { type GraphEditorCanvasContextValue } from '../GraphEditorCanvasContext';
2
+ import { type GraphEditorCanvasContextValue } from '../GraphEditorCanvasContext.js';
3
3
  export declare function PromptNodeChoicesList({ nodeId, choices, focusChoiceId, choiceTextClass, readOnly, choiceDrag, choiceDropTarget, onChoiceDragOver, onChoiceDrop, }: Readonly<{
4
4
  nodeId: string;
5
5
  choices: EditorChoice[];
@@ -1 +1 @@
1
- {"version":3,"file":"PromptNodeChoicesList.d.ts","sourceRoot":"","sources":["../../src/nodes/PromptNodeChoicesList.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,mCAAmC,CAAC;AAMtE,OAAO,EAAE,KAAK,6BAA6B,EAAE,MAAM,6BAA6B,CAAC;AAIjF,wBAAgB,qBAAqB,CAAC,EAClC,MAAM,EACN,OAAO,EACP,aAAa,EACb,eAAe,EACf,QAAQ,EACR,UAAU,EACV,gBAAgB,EAChB,gBAAgB,EAChB,YAAY,GACf,EAAE,QAAQ,CAAC;IACR,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,6BAA6B,CAAC,YAAY,CAAC,CAAC;IACxD,gBAAgB,EAAE,6BAA6B,CAAC,kBAAkB,CAAC,CAAC;IACpE,gBAAgB,EAAE,6BAA6B,CAAC,kBAAkB,CAAC,CAAC;IACpE,YAAY,EAAE,6BAA6B,CAAC,cAAc,CAAC,CAAC;CAC/D,CAAC,+BA2DD"}
1
+ {"version":3,"file":"PromptNodeChoicesList.d.ts","sourceRoot":"","sources":["../../src/nodes/PromptNodeChoicesList.tsx"],"names":[],"mappings":"AAEA,OAAO,EAAE,KAAK,YAAY,EAAE,MAAM,mCAAmC,CAAC;AAMtE,OAAO,EAAE,KAAK,6BAA6B,EAAE,MAAM,gCAAgC,CAAC;AAapF,wBAAgB,qBAAqB,CAAC,EAClC,MAAM,EACN,OAAO,EACP,aAAa,EACb,eAAe,EACf,QAAQ,EACR,UAAU,EACV,gBAAgB,EAChB,gBAAgB,EAChB,YAAY,GACf,EAAE,QAAQ,CAAC;IACR,MAAM,EAAE,MAAM,CAAC;IACf,OAAO,EAAE,YAAY,EAAE,CAAC;IACxB,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,eAAe,EAAE,MAAM,CAAC;IACxB,QAAQ,EAAE,OAAO,CAAC;IAClB,UAAU,EAAE,6BAA6B,CAAC,YAAY,CAAC,CAAC;IACxD,gBAAgB,EAAE,6BAA6B,CAAC,kBAAkB,CAAC,CAAC;IACpE,gBAAgB,EAAE,6BAA6B,CAAC,kBAAkB,CAAC,CAAC;IACpE,YAAY,EAAE,6BAA6B,CAAC,cAAc,CAAC,CAAC;CAC/D,CAAC,+BA8DD"}
@@ -1,7 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { CHOICE_DROP_APPEND_CLASS, CHOICE_DROP_TARGET_CLASS, } from '../canvas/constants';
3
- import { joinClasses } from '../utils/joinClasses';
4
- import { ChoiceCanvasRow } from './ChoiceCanvasRow';
2
+ import { CHOICE_DROP_APPEND_CLASS, CHOICE_DROP_TARGET_CLASS, } from '../canvas/constants.js';
3
+ import { EDITOR_LIST_FLUSH, EDITOR_LIST_ITEM_EMPTY, EDITOR_MIN_W_0, EDITOR_MUTED, EDITOR_SPACING_PX_2, EDITOR_SPACING_PY_2, EDITOR_TEXT_SM, joinClasses, } from '../ui/editorClasses.js';
4
+ import { ChoiceCanvasRow } from './ChoiceCanvasRow.js';
5
5
  export function PromptNodeChoicesList({ nodeId, choices, focusChoiceId, choiceTextClass, readOnly, choiceDrag, choiceDropTarget, onChoiceDragOver, onChoiceDrop, }) {
6
6
  const handleListDragOver = (event) => {
7
7
  if (readOnly || !choiceDrag)
@@ -18,7 +18,7 @@ export function PromptNodeChoicesList({ nodeId, choices, focusChoiceId, choiceTe
18
18
  event.stopPropagation();
19
19
  onChoiceDrop(nodeId, choices.length);
20
20
  };
21
- return (_jsxs("ul", { className: "list-group list-group-flush font-size-12 min-w-0 nodrag", "aria-label": "Node choices", onDragOver: handleListDragOver, onDrop: handleListDrop, children: [choices.length === 0 ? (_jsx("li", { className: joinClasses('list-group-item py-2 px-2 text-muted', choiceDrag && CHOICE_DROP_TARGET_CLASS), children: _jsx("em", { children: "No choices" }) })) : (choices.map((c, choiceIndex) => (_jsx(ChoiceCanvasRow, { nodeId: nodeId, choice: c, choiceIndex: choiceIndex, focusChoiceId: focusChoiceId, choiceTextClass: choiceTextClass, readOnly: readOnly }, c.id)))), choiceDrag && readOnly === false && choices.length > 0 ? (_jsx("li", { className: joinClasses(CHOICE_DROP_APPEND_CLASS, 'list-unstyled', choiceDropTarget?.nodeId === nodeId &&
21
+ return (_jsxs("ul", { className: joinClasses(EDITOR_LIST_FLUSH, EDITOR_TEXT_SM, EDITOR_MIN_W_0, 'nodrag'), "aria-label": "Node choices", onDragOver: handleListDragOver, onDrop: handleListDrop, children: [choices.length === 0 ? (_jsx("li", { className: joinClasses(EDITOR_LIST_ITEM_EMPTY, EDITOR_SPACING_PY_2, EDITOR_SPACING_PX_2, EDITOR_MUTED, choiceDrag && CHOICE_DROP_TARGET_CLASS), children: _jsx("em", { children: "No choices" }) })) : (choices.map((c, choiceIndex) => (_jsx(ChoiceCanvasRow, { nodeId: nodeId, choice: c, choiceIndex: choiceIndex, focusChoiceId: focusChoiceId, choiceTextClass: choiceTextClass, readOnly: readOnly }, c.id)))), choiceDrag && readOnly === false && choices.length > 0 ? (_jsx("li", { className: joinClasses(CHOICE_DROP_APPEND_CLASS, 'graph-editor-list__append-target', choiceDropTarget?.nodeId === nodeId &&
22
22
  choiceDropTarget.index === choices.length &&
23
23
  CHOICE_DROP_TARGET_CLASS), "aria-hidden": true })) : null] }));
24
24
  }
@@ -1,5 +1,5 @@
1
1
  import { getEditorHints, type EditorNode } from '@signalsafe/tree-spec-editor-core';
2
- import type { PromptNodeData } from './types';
2
+ import type { PromptNodeData } from './types.js';
3
3
  export declare function PromptNodeHeader({ node, data, editor, locked, readOnly, }: Readonly<{
4
4
  node: EditorNode;
5
5
  data: PromptNodeData;
@@ -1 +1 @@
1
- {"version":3,"file":"PromptNodeHeader.d.ts","sourceRoot":"","sources":["../../src/nodes/PromptNodeHeader.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,KAAK,UAAU,EAAE,MAAM,mCAAmC,CAAC;AAIpF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAE9C,wBAAgB,gBAAgB,CAAC,EAC7B,IAAI,EACJ,IAAI,EACJ,MAAM,EACN,MAAM,EACN,QAAQ,GACX,EAAE,QAAQ,CAAC;IACR,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,cAAc,CAAC;IACrB,MAAM,EAAE,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;IAC1C,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;CACrB,CAAC,+BAkCD"}
1
+ {"version":3,"file":"PromptNodeHeader.d.ts","sourceRoot":"","sources":["../../src/nodes/PromptNodeHeader.tsx"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,KAAK,UAAU,EAAE,MAAM,mCAAmC,CAAC;AAyBpF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,wBAAgB,gBAAgB,CAAC,EAC7B,IAAI,EACJ,IAAI,EACJ,MAAM,EACN,MAAM,EACN,QAAQ,GACX,EAAE,QAAQ,CAAC;IACR,IAAI,EAAE,UAAU,CAAC;IACjB,IAAI,EAAE,cAAc,CAAC;IACrB,MAAM,EAAE,UAAU,CAAC,OAAO,cAAc,CAAC,CAAC;IAC1C,MAAM,EAAE,OAAO,CAAC;IAChB,QAAQ,EAAE,OAAO,CAAC;CACrB,CAAC,+BA2DD"}
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { NODE_DRAG_HANDLE_CLASS } from '../canvas/constants';
3
- import { PromptNodeIssueBadges } from './PromptNodeIssueBadges';
2
+ import { NODE_DRAG_HANDLE_CLASS } from '../canvas/constants.js';
3
+ import { EDITOR_CARD_HEADER_MUTED, EDITOR_FLEX_ALIGN_START, EDITOR_FLEX_BETWEEN, EDITOR_FLEX_GROW_1, EDITOR_FLEX_ROW, EDITOR_FLEX_SHRINK_0, EDITOR_ICON, EDITOR_MIN_W_0, EDITOR_MUTED, EDITOR_OVERFLOW_HIDDEN, EDITOR_SPACING_GAP_1, EDITOR_SPACING_GAP_2, EDITOR_SPACING_MS_1, EDITOR_SPACING_PX_2, EDITOR_SPACING_PY_2, EDITOR_TEXT_BOLD, EDITOR_TEXT_MD, EDITOR_TEXT_XS, joinClasses, } from '../ui/editorClasses.js';
4
+ import { PromptNodeIssueBadges } from './PromptNodeIssueBadges.js';
4
5
  export function PromptNodeHeader({ node, data, editor, locked, readOnly, }) {
5
- return (_jsx("div", { className: "card-header bg-body-secondary py-2 px-2 min-w-0 flex-shrink-0", children: _jsxs("div", { className: "d-flex justify-content-between align-items-start gap-2 min-w-0", children: [_jsxs("div", { className: "d-flex align-items-start gap-1 min-w-0 flex-grow-1 overflow-hidden", children: [locked || readOnly ? null : (_jsx("span", { className: `${NODE_DRAG_HANDLE_CLASS} flex-shrink-0`, title: "Drag node", "aria-label": "Drag node", children: _jsx("i", { className: "bi bi-grip-vertical", "aria-hidden": true }) })), _jsx("div", { className: "min-w-0 flex-grow-1 overflow-hidden", children: _jsxs("div", { className: "fw-bold font-size-13", children: [data.isStart ? '▶ ' : '', node.type, editor.locked ? (_jsx("i", { className: "bi bi-lock-fill ms-1 text-secondary", title: "Locked", "aria-hidden": true })) : null, _jsx(PromptNodeIssueBadges, { issuesTotal: data.issuesTotal, issuesErrors: data.issuesErrors, issuesWarnings: data.issuesWarnings, issuesInfo: data.issuesInfo })] }) })] }), _jsx("div", { className: "text-muted font-size-11 flex-shrink-0", children: node.id.slice(0, 8) })] }) }));
6
+ return (_jsx("div", { className: joinClasses(EDITOR_CARD_HEADER_MUTED, EDITOR_SPACING_PY_2, EDITOR_SPACING_PX_2, EDITOR_MIN_W_0, EDITOR_FLEX_SHRINK_0), children: _jsxs("div", { className: joinClasses(EDITOR_FLEX_BETWEEN, EDITOR_FLEX_ALIGN_START, EDITOR_SPACING_GAP_2, EDITOR_MIN_W_0), children: [_jsxs("div", { className: joinClasses(EDITOR_FLEX_ROW, EDITOR_FLEX_ALIGN_START, EDITOR_SPACING_GAP_1, EDITOR_MIN_W_0, EDITOR_FLEX_GROW_1, EDITOR_OVERFLOW_HIDDEN), children: [locked || readOnly ? null : (_jsx("span", { className: joinClasses(NODE_DRAG_HANDLE_CLASS, EDITOR_FLEX_SHRINK_0), title: "Drag node", "aria-label": "Drag node", children: _jsx("span", { className: joinClasses(EDITOR_ICON, 'graph-editor-icon--grip'), "aria-hidden": true, children: "\u22EE\u22EE" }) })), _jsx("div", { className: joinClasses(EDITOR_MIN_W_0, EDITOR_FLEX_GROW_1, EDITOR_OVERFLOW_HIDDEN), children: _jsxs("div", { className: joinClasses(EDITOR_TEXT_BOLD, EDITOR_TEXT_MD), children: [data.isStart ? '▶ ' : '', node.type, editor.locked ? (_jsx("span", { className: joinClasses(EDITOR_ICON, 'graph-editor-icon--lock', EDITOR_SPACING_MS_1), title: "Locked", "aria-hidden": true, children: "\uD83D\uDD12" })) : null, _jsx(PromptNodeIssueBadges, { issuesTotal: data.issuesTotal, issuesErrors: data.issuesErrors, issuesWarnings: data.issuesWarnings, issuesInfo: data.issuesInfo })] }) })] }), _jsx("div", { className: joinClasses(EDITOR_MUTED, EDITOR_TEXT_XS, EDITOR_FLEX_SHRINK_0), children: node.id.slice(0, 8) })] }) }));
6
7
  }
@@ -1 +1 @@
1
- {"version":3,"file":"PromptNodeIssueBadges.d.ts","sourceRoot":"","sources":["../../src/nodes/PromptNodeIssueBadges.tsx"],"names":[],"mappings":"AAAA,wBAAgB,qBAAqB,CAAC,EAClC,WAAW,EACX,YAAY,EACZ,cAAc,EACd,UAAU,GACb,EAAE,QAAQ,CAAC;IACR,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;CACtB,CAAC,sCAcD"}
1
+ {"version":3,"file":"PromptNodeIssueBadges.d.ts","sourceRoot":"","sources":["../../src/nodes/PromptNodeIssueBadges.tsx"],"names":[],"mappings":"AAEA,wBAAgB,qBAAqB,CAAC,EAClC,WAAW,EACX,YAAY,EACZ,cAAc,EACd,UAAU,GACb,EAAE,QAAQ,CAAC;IACR,WAAW,EAAE,MAAM,CAAC;IACpB,YAAY,EAAE,MAAM,CAAC;IACrB,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;CACtB,CAAC,sCAgBD"}
@@ -1,6 +1,7 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import { EDITOR_SPACING_ME_1, EDITOR_SPACING_MS_2, editorBadgeToneClass } from '../ui/editorClasses.js';
2
3
  export function PromptNodeIssueBadges({ issuesTotal, issuesErrors, issuesWarnings, issuesInfo, }) {
3
4
  if (issuesTotal <= 0)
4
5
  return null;
5
- return (_jsxs("span", { className: "ms-2", title: `${issuesErrors} errors, ${issuesWarnings} warnings, ${issuesInfo} info`, children: [issuesErrors > 0 ? _jsx("span", { className: "badge bg-danger me-1", children: issuesErrors }) : null, issuesWarnings > 0 ? (_jsx("span", { className: "badge bg-warning text-dark me-1", children: issuesWarnings })) : null, issuesInfo > 0 ? _jsx("span", { className: "badge bg-info text-dark", children: issuesInfo }) : null] }));
6
+ return (_jsxs("span", { className: EDITOR_SPACING_MS_2, title: `${issuesErrors} errors, ${issuesWarnings} warnings, ${issuesInfo} info`, children: [issuesErrors > 0 ? (_jsx("span", { className: `${editorBadgeToneClass('danger')} ${EDITOR_SPACING_ME_1}`, children: issuesErrors })) : null, issuesWarnings > 0 ? (_jsx("span", { className: `${editorBadgeToneClass('warning')} ${EDITOR_SPACING_ME_1}`, children: issuesWarnings })) : null, issuesInfo > 0 ? _jsx("span", { className: editorBadgeToneClass('info'), children: issuesInfo }) : null] }));
6
7
  }
@@ -1 +1 @@
1
- {"version":3,"file":"PromptNodeToolbar.d.ts","sourceRoot":"","sources":["../../src/nodes/PromptNodeToolbar.tsx"],"names":[],"mappings":"AAEA,wBAAgB,iBAAiB,CAAC,EAC9B,MAAM,EACN,eAAe,EACf,YAAY,GACf,EAAE,QAAQ,CAAC;IACR,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,YAAY,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CACtC,CAAC,+BA0BD"}
1
+ {"version":3,"file":"PromptNodeToolbar.d.ts","sourceRoot":"","sources":["../../src/nodes/PromptNodeToolbar.tsx"],"names":[],"mappings":"AASA,wBAAgB,iBAAiB,CAAC,EAC9B,MAAM,EACN,eAAe,EACf,YAAY,GACf,EAAE,QAAQ,CAAC;IACR,MAAM,EAAE,MAAM,CAAC;IACf,eAAe,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;IACtC,YAAY,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;CACtC,CAAC,+BA8BD"}
@@ -1,5 +1,6 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Position, NodeToolbar } from 'reactflow';
3
+ import { EDITOR_BTN_GROUP, EDITOR_ICON, EDITOR_SR_ONLY, editorBtnToneClass, } from '../ui/editorClasses.js';
3
4
  export function PromptNodeToolbar({ nodeId, onDuplicateNode, onDeleteNode, }) {
4
- return (_jsx(NodeToolbar, { isVisible: true, position: Position.Bottom, offset: 8, align: "start", children: _jsxs("fieldset", { className: "btn-group btn-group-sm shadow-sm border-0 p-0 m-0", children: [_jsx("legend", { className: "visually-hidden", children: "Node actions" }), _jsx("button", { type: "button", className: "btn btn-light border", title: "Duplicate node", "aria-label": "Duplicate node", onClick: () => onDuplicateNode(nodeId), children: _jsx("i", { className: "bi bi-files", "aria-hidden": true }) }), _jsx("button", { type: "button", className: "btn btn-light border text-danger", title: "Delete node", "aria-label": "Delete node", onClick: () => onDeleteNode(nodeId), children: _jsx("i", { className: "bi bi-trash", "aria-hidden": true }) })] }) }));
5
+ return (_jsx(NodeToolbar, { isVisible: true, position: Position.Bottom, offset: 8, align: "start", children: _jsxs("fieldset", { className: EDITOR_BTN_GROUP, children: [_jsx("legend", { className: EDITOR_SR_ONLY, children: "Node actions" }), _jsx("button", { type: "button", className: editorBtnToneClass('light'), title: "Duplicate node", "aria-label": "Duplicate node", onClick: () => onDuplicateNode(nodeId), children: _jsx("span", { className: EDITOR_ICON, "aria-hidden": true, children: "\u29C9" }) }), _jsx("button", { type: "button", className: editorBtnToneClass('danger'), title: "Delete node", "aria-label": "Delete node", onClick: () => onDeleteNode(nodeId), children: _jsx("span", { className: EDITOR_ICON, "aria-hidden": true, children: "\u2715" }) })] }) }));
5
6
  }
@@ -0,0 +1,53 @@
1
+ /** UI-kit agnostic canvas class hooks (aligned with @signalsafe/tree-spec-editor). */
2
+ import { joinClasses } from '../utils/joinClasses.js';
3
+ export { joinClasses };
4
+ export declare const EDITOR_CARD = "graph-editor-card";
5
+ export declare const EDITOR_CARD_HEADER = "graph-editor-card__header";
6
+ export declare const EDITOR_CARD_BODY = "graph-editor-card__body";
7
+ export declare const EDITOR_CARD_HEADER_MUTED = "graph-editor-card__header graph-editor-surface--muted";
8
+ export declare const EDITOR_LIST = "graph-editor-list";
9
+ export declare const EDITOR_LIST_FLUSH = "graph-editor-list graph-editor-list--flush";
10
+ export declare const EDITOR_LIST_ITEM = "graph-editor-list__item";
11
+ export declare const EDITOR_LIST_ITEM_EMPTY = "graph-editor-list__item graph-editor-list__item--empty";
12
+ export declare const EDITOR_BTN = "graph-editor-btn";
13
+ export declare const EDITOR_BTN_GROUP = "graph-editor-btn-group graph-editor-btn-group--sm";
14
+ export declare const EDITOR_BADGE = "graph-editor-badge";
15
+ export declare const EDITOR_DROPDOWN_MENU = "graph-editor-dropdown__menu";
16
+ export declare const EDITOR_DROPDOWN_ITEM = "graph-editor-dropdown__item";
17
+ export declare const EDITOR_FLEX = "graph-editor-flex";
18
+ export declare const EDITOR_FLEX_BETWEEN = "graph-editor-flex graph-editor-flex--between";
19
+ export declare const EDITOR_FLEX_ROW = "graph-editor-flex graph-editor-flex--row";
20
+ export declare const EDITOR_FLEX_ALIGN_START = "graph-editor-flex graph-editor-flex--align-start";
21
+ export declare const EDITOR_FLEX_ALIGN_CENTER = "graph-editor-flex graph-editor-flex--align-center";
22
+ export declare const EDITOR_MIN_W_0 = "graph-editor-min-w-0";
23
+ export declare const EDITOR_FLEX_SHRINK_0 = "graph-editor-flex-shrink-0";
24
+ export declare const EDITOR_FLEX_GROW_1 = "graph-editor-flex-grow-1";
25
+ export declare const EDITOR_OVERFLOW_HIDDEN = "graph-editor-overflow-hidden";
26
+ export declare const EDITOR_W_FULL = "graph-editor-w-full";
27
+ export declare const EDITOR_MUTED = "graph-editor-muted";
28
+ export declare const EDITOR_TEXT_DANGER = "graph-editor-text--danger";
29
+ export declare const EDITOR_TEXT_CENTER = "graph-editor-text--center";
30
+ export declare const EDITOR_TEXT_START = "graph-editor-text--start";
31
+ export declare const EDITOR_TEXT_BOLD = "graph-editor-text--bold";
32
+ export declare const EDITOR_TEXT_XS = "graph-editor-text--xs";
33
+ export declare const EDITOR_TEXT_SM = "graph-editor-text--sm";
34
+ export declare const EDITOR_TEXT_MD = "graph-editor-text--md";
35
+ export declare const EDITOR_SPACING_PY_2 = "graph-editor-spacing--py-2";
36
+ export declare const EDITOR_SPACING_PX_2 = "graph-editor-spacing--px-2";
37
+ export declare const EDITOR_SPACING_P_2 = "graph-editor-spacing--p-2";
38
+ export declare const EDITOR_SPACING_GAP_1 = "graph-editor-spacing--gap-1";
39
+ export declare const EDITOR_SPACING_GAP_2 = "graph-editor-spacing--gap-2";
40
+ export declare const EDITOR_SPACING_MB_0 = "graph-editor-spacing--mb-0";
41
+ export declare const EDITOR_SPACING_MS_1 = "graph-editor-spacing--ms-1";
42
+ export declare const EDITOR_SPACING_MS_2 = "graph-editor-spacing--ms-2";
43
+ export declare const EDITOR_SPACING_ME_1 = "graph-editor-spacing--me-1";
44
+ export declare const EDITOR_SPACING_P_0 = "graph-editor-spacing--p-0";
45
+ export declare const EDITOR_SPACING_M_0 = "graph-editor-spacing--m-0";
46
+ export declare const EDITOR_ROUNDED = "graph-editor-rounded";
47
+ export declare const EDITOR_SR_ONLY = "graph-editor-sr-only";
48
+ export declare const EDITOR_ICON = "graph-editor-icon";
49
+ export declare const EDITOR_CANVAS_ROOT = "graph-editor-canvas-root";
50
+ export declare function editorBtnToneClass(variant?: string): string;
51
+ export declare function editorBadgeToneClass(variant: 'danger' | 'warning' | 'info' | 'neutral'): string;
52
+ export declare function editorDropdownItemClass(danger?: boolean): string;
53
+ //# sourceMappingURL=editorClasses.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"editorClasses.d.ts","sourceRoot":"","sources":["../../src/ui/editorClasses.ts"],"names":[],"mappings":"AAAA,sFAAsF;AAEtF,OAAO,EAAE,WAAW,EAAE,MAAM,yBAAyB,CAAC;AAEtD,OAAO,EAAE,WAAW,EAAE,CAAC;AAEvB,eAAO,MAAM,WAAW,sBAAsB,CAAC;AAC/C,eAAO,MAAM,kBAAkB,8BAA8B,CAAC;AAC9D,eAAO,MAAM,gBAAgB,4BAA4B,CAAC;AAC1D,eAAO,MAAM,wBAAwB,0DAA0D,CAAC;AAEhG,eAAO,MAAM,WAAW,sBAAsB,CAAC;AAC/C,eAAO,MAAM,iBAAiB,+CAA+C,CAAC;AAC9E,eAAO,MAAM,gBAAgB,4BAA4B,CAAC;AAC1D,eAAO,MAAM,sBAAsB,2DAA2D,CAAC;AAE/F,eAAO,MAAM,UAAU,qBAAqB,CAAC;AAC7C,eAAO,MAAM,gBAAgB,sDAAsD,CAAC;AACpF,eAAO,MAAM,YAAY,uBAAuB,CAAC;AAEjD,eAAO,MAAM,oBAAoB,gCAAgC,CAAC;AAClE,eAAO,MAAM,oBAAoB,gCAAgC,CAAC;AAElE,eAAO,MAAM,WAAW,sBAAsB,CAAC;AAC/C,eAAO,MAAM,mBAAmB,iDAAiD,CAAC;AAClF,eAAO,MAAM,eAAe,6CAA6C,CAAC;AAC1E,eAAO,MAAM,uBAAuB,qDAAqD,CAAC;AAC1F,eAAO,MAAM,wBAAwB,sDAAsD,CAAC;AAC5F,eAAO,MAAM,cAAc,yBAAyB,CAAC;AACrD,eAAO,MAAM,oBAAoB,+BAA+B,CAAC;AACjE,eAAO,MAAM,kBAAkB,6BAA6B,CAAC;AAC7D,eAAO,MAAM,sBAAsB,iCAAiC,CAAC;AACrE,eAAO,MAAM,aAAa,wBAAwB,CAAC;AAEnD,eAAO,MAAM,YAAY,uBAAuB,CAAC;AACjD,eAAO,MAAM,kBAAkB,8BAA8B,CAAC;AAC9D,eAAO,MAAM,kBAAkB,8BAA8B,CAAC;AAC9D,eAAO,MAAM,iBAAiB,6BAA6B,CAAC;AAC5D,eAAO,MAAM,gBAAgB,4BAA4B,CAAC;AAC1D,eAAO,MAAM,cAAc,0BAA0B,CAAC;AACtD,eAAO,MAAM,cAAc,0BAA0B,CAAC;AACtD,eAAO,MAAM,cAAc,0BAA0B,CAAC;AAEtD,eAAO,MAAM,mBAAmB,+BAA+B,CAAC;AAChE,eAAO,MAAM,mBAAmB,+BAA+B,CAAC;AAChE,eAAO,MAAM,kBAAkB,8BAA8B,CAAC;AAC9D,eAAO,MAAM,oBAAoB,gCAAgC,CAAC;AAClE,eAAO,MAAM,oBAAoB,gCAAgC,CAAC;AAClE,eAAO,MAAM,mBAAmB,+BAA+B,CAAC;AAChE,eAAO,MAAM,mBAAmB,+BAA+B,CAAC;AAChE,eAAO,MAAM,mBAAmB,+BAA+B,CAAC;AAChE,eAAO,MAAM,mBAAmB,+BAA+B,CAAC;AAChE,eAAO,MAAM,kBAAkB,8BAA8B,CAAC;AAC9D,eAAO,MAAM,kBAAkB,8BAA8B,CAAC;AAE9D,eAAO,MAAM,cAAc,yBAAyB,CAAC;AACrD,eAAO,MAAM,cAAc,yBAAyB,CAAC;AACrD,eAAO,MAAM,WAAW,sBAAsB,CAAC;AAE/C,eAAO,MAAM,kBAAkB,6BAA6B,CAAC;AAE7D,wBAAgB,kBAAkB,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,MAAM,CAG3D;AAED,wBAAgB,oBAAoB,CAAC,OAAO,EAAE,QAAQ,GAAG,SAAS,GAAG,MAAM,GAAG,SAAS,GAAG,MAAM,CAE/F;AAED,wBAAgB,uBAAuB,CAAC,MAAM,CAAC,EAAE,OAAO,GAAG,MAAM,CAEhE"}
@@ -0,0 +1,69 @@
1
+ /** UI-kit agnostic canvas class hooks (aligned with @signalsafe/tree-spec-editor). */
2
+ import { joinClasses } from '../utils/joinClasses.js';
3
+ export { joinClasses };
4
+ export const EDITOR_CARD = 'graph-editor-card';
5
+ export const EDITOR_CARD_HEADER = 'graph-editor-card__header';
6
+ export const EDITOR_CARD_BODY = 'graph-editor-card__body';
7
+ export const EDITOR_CARD_HEADER_MUTED = 'graph-editor-card__header graph-editor-surface--muted';
8
+ export const EDITOR_LIST = 'graph-editor-list';
9
+ export const EDITOR_LIST_FLUSH = 'graph-editor-list graph-editor-list--flush';
10
+ export const EDITOR_LIST_ITEM = 'graph-editor-list__item';
11
+ export const EDITOR_LIST_ITEM_EMPTY = 'graph-editor-list__item graph-editor-list__item--empty';
12
+ export const EDITOR_BTN = 'graph-editor-btn';
13
+ export const EDITOR_BTN_GROUP = 'graph-editor-btn-group graph-editor-btn-group--sm';
14
+ export const EDITOR_BADGE = 'graph-editor-badge';
15
+ export const EDITOR_DROPDOWN_MENU = 'graph-editor-dropdown__menu';
16
+ export const EDITOR_DROPDOWN_ITEM = 'graph-editor-dropdown__item';
17
+ export const EDITOR_FLEX = 'graph-editor-flex';
18
+ export const EDITOR_FLEX_BETWEEN = 'graph-editor-flex graph-editor-flex--between';
19
+ export const EDITOR_FLEX_ROW = 'graph-editor-flex graph-editor-flex--row';
20
+ export const EDITOR_FLEX_ALIGN_START = 'graph-editor-flex graph-editor-flex--align-start';
21
+ export const EDITOR_FLEX_ALIGN_CENTER = 'graph-editor-flex graph-editor-flex--align-center';
22
+ export const EDITOR_MIN_W_0 = 'graph-editor-min-w-0';
23
+ export const EDITOR_FLEX_SHRINK_0 = 'graph-editor-flex-shrink-0';
24
+ export const EDITOR_FLEX_GROW_1 = 'graph-editor-flex-grow-1';
25
+ export const EDITOR_OVERFLOW_HIDDEN = 'graph-editor-overflow-hidden';
26
+ export const EDITOR_W_FULL = 'graph-editor-w-full';
27
+ export const EDITOR_MUTED = 'graph-editor-muted';
28
+ export const EDITOR_TEXT_DANGER = 'graph-editor-text--danger';
29
+ export const EDITOR_TEXT_CENTER = 'graph-editor-text--center';
30
+ export const EDITOR_TEXT_START = 'graph-editor-text--start';
31
+ export const EDITOR_TEXT_BOLD = 'graph-editor-text--bold';
32
+ export const EDITOR_TEXT_XS = 'graph-editor-text--xs';
33
+ export const EDITOR_TEXT_SM = 'graph-editor-text--sm';
34
+ export const EDITOR_TEXT_MD = 'graph-editor-text--md';
35
+ export const EDITOR_SPACING_PY_2 = 'graph-editor-spacing--py-2';
36
+ export const EDITOR_SPACING_PX_2 = 'graph-editor-spacing--px-2';
37
+ export const EDITOR_SPACING_P_2 = 'graph-editor-spacing--p-2';
38
+ export const EDITOR_SPACING_GAP_1 = 'graph-editor-spacing--gap-1';
39
+ export const EDITOR_SPACING_GAP_2 = 'graph-editor-spacing--gap-2';
40
+ export const EDITOR_SPACING_MB_0 = 'graph-editor-spacing--mb-0';
41
+ export const EDITOR_SPACING_MS_1 = 'graph-editor-spacing--ms-1';
42
+ export const EDITOR_SPACING_MS_2 = 'graph-editor-spacing--ms-2';
43
+ export const EDITOR_SPACING_ME_1 = 'graph-editor-spacing--me-1';
44
+ export const EDITOR_SPACING_P_0 = 'graph-editor-spacing--p-0';
45
+ export const EDITOR_SPACING_M_0 = 'graph-editor-spacing--m-0';
46
+ export const EDITOR_ROUNDED = 'graph-editor-rounded';
47
+ export const EDITOR_SR_ONLY = 'graph-editor-sr-only';
48
+ export const EDITOR_ICON = 'graph-editor-icon';
49
+ export const EDITOR_CANVAS_ROOT = 'graph-editor-canvas-root';
50
+ export function editorBtnToneClass(variant) {
51
+ const tone = normalizeBtnTone(variant);
52
+ return `${EDITOR_BTN} graph-editor-btn--${tone}`;
53
+ }
54
+ export function editorBadgeToneClass(variant) {
55
+ return `${EDITOR_BADGE} graph-editor-badge--${variant}`;
56
+ }
57
+ export function editorDropdownItemClass(danger) {
58
+ return joinClasses(EDITOR_DROPDOWN_ITEM, danger && 'graph-editor-dropdown__item--danger');
59
+ }
60
+ function normalizeBtnTone(variant) {
61
+ if (!variant)
62
+ return 'neutral';
63
+ const map = {
64
+ light: 'light',
65
+ danger: 'danger',
66
+ neutral: 'neutral',
67
+ };
68
+ return map[variant] ?? variant.replace(/^outline-/, '');
69
+ }
@@ -0,0 +1,65 @@
1
+ # Canvas UI-kit agnostic styling
2
+
3
+ **Package:** `@signalsafe/tree-spec-editor-react`
4
+ **Status:** Implemented (0.2.0+)
5
+
6
+ ---
7
+
8
+ ## Summary
9
+
10
+ The React Flow canvas emits **semantic HTML** with stable **`graph-editor-*` class hooks**. It does **not** require Bootstrap CSS or Bootstrap Icons.
11
+
12
+ **Host applications own styling.** Map `graph-editor-*` classes in your theme (DeliveryPlus, Tailwind, MUI, etc.) or override via the `className` prop on `TreeSpecGraphEditor`.
13
+
14
+ Peer dependencies: `react`, `react-dom`, `reactflow` only.
15
+
16
+ ---
17
+
18
+ ## Class hooks
19
+
20
+ Canvas nodes, choices, toolbars, and context menus use tokens from `src/ui/editorClasses.ts` and `src/canvas/constants.ts`:
21
+
22
+ | Area | Example classes |
23
+ |------|-----------------|
24
+ | Canvas root | `graph-editor-canvas-root`, `graph-editor-canvas` |
25
+ | Node card | `graph-editor-card`, `graph-editor-canvas-node`, `graph-editor-card__header`, `graph-editor-card__body` |
26
+ | Selection | `graph-editor-canvas__selected`, `graph-editor-canvas-selected`, `graph-editor-canvas-choice-selected` |
27
+ | Issue borders | `graph-editor-canvas-node--border-danger`, `graph-editor-canvas-node--border-warning` |
28
+ | Lists / choices | `graph-editor-list`, `graph-editor-list__item`, `graph-editor-choice-row` |
29
+ | Badges | `graph-editor-badge`, `graph-editor-badge--danger` / `--warning` / `--info` |
30
+ | Toolbar | `graph-editor-btn-group`, `graph-editor-btn`, `graph-editor-btn--light` |
31
+ | Context menu | `graph-editor-context-menu`, `graph-editor-dropdown__menu`, `graph-editor-dropdown__item` |
32
+ | Handles | `graph-editor-target-handle`, `graph-editor-choice-handle` |
33
+
34
+ Text wrap helpers from `@signalsafe/tree-spec-editor-core` already use `graph-editor-node-text-*` classes.
35
+
36
+ ---
37
+
38
+ ## Host override strategy
39
+
40
+ 1. **CSS bridge** — add host styles targeting `graph-editor-*` (recommended for DeliveryPlus migration).
41
+ 2. **`className` prop** — pass layout/sizing classes on `TreeSpecGraphEditor` (default is `graph-editor-canvas-root`).
42
+ 3. **Shell package** — `@signalsafe/tree-spec-editor` can map the same hooks to Bootstrap utilities in host SCSS.
43
+
44
+ This package ships **no CSS file**; `sideEffects: ["**/*.css"]` applies only to the React Flow stylesheet import.
45
+
46
+ ---
47
+
48
+ ## Migration from 0.1.x
49
+
50
+ | Before (0.1.x) | After (0.2.0) |
51
+ |----------------|---------------|
52
+ | `bg-primary-subtle` selection highlight | `graph-editor-canvas__selected` |
53
+ | `border-warning` / `border-danger` | `graph-editor-canvas-node--border-warning` / `--border-danger` |
54
+ | Bootstrap `card`, `list-group`, `btn`, `badge` | `graph-editor-card`, `graph-editor-list`, `graph-editor-btn`, `graph-editor-badge` |
55
+ | Default `className="h-70vh border rounded"` | Default `className="graph-editor-canvas-root"` |
56
+ | Bootstrap Icons (`bi bi-*`) | Unicode / `graph-editor-icon` spans |
57
+
58
+ **Semver:** minor (0.2.0) — DOM class contract change; component props unchanged.
59
+
60
+ ---
61
+
62
+ ## Related packages
63
+
64
+ - `@signalsafe/tree-spec-editor` — full authoring shell (UI-kit agnostic panels; host-owned Bootstrap optional)
65
+ - `@signalsafe/tree-spec-editor-core` — headless model and layout helpers
package/package.json CHANGED
@@ -1,8 +1,8 @@
1
1
  {
2
2
  "name": "@signalsafe/tree-spec-editor-react",
3
- "version": "0.1.2",
3
+ "version": "0.2.0",
4
4
  "type": "module",
5
- "description": "Headless React canvas for the SignalSafe TreeSpec graph editor (React Flow shell, no UI library).",
5
+ "description": "UI-kit agnostic React Flow canvas for the SignalSafe TreeSpec graph editor (no UI library).",
6
6
  "license": "MIT",
7
7
  "repository": {
8
8
  "type": "git",
@@ -23,7 +23,9 @@
23
23
  "typescript",
24
24
  "signalsafe"
25
25
  ],
26
- "sideEffects": false,
26
+ "sideEffects": [
27
+ "**/*.css"
28
+ ],
27
29
  "main": "./dist/index.js",
28
30
  "types": "./dist/index.d.ts",
29
31
  "exports": {
@@ -34,28 +36,33 @@
34
36
  }
35
37
  },
36
38
  "files": [
37
- "dist",
38
- "README.md",
39
- "LICENSE"
39
+ "dist",
40
+ "README.md",
41
+ "LICENSE",
42
+ "docs"
40
43
  ],
41
44
  "engines": {
42
- "node": ">=18"
45
+ "node": ">=22.12.0"
43
46
  },
47
+ "packageManager": "yarn@1.22.22",
44
48
  "publishConfig": {
45
49
  "access": "public"
46
50
  },
47
51
  "scripts": {
48
52
  "build": "tsc -p tsconfig.build.json",
53
+ "lint": "yarn typecheck",
49
54
  "typecheck": "tsc --noEmit",
50
55
  "pack:local": "npm pack --pack-destination ../../dist/reusable-npm",
56
+ "smoke:package": "node scripts/smoke-package.mjs",
51
57
  "prepublishOnly": "npm run build",
52
58
  "prepare": "npm run build",
53
59
  "test": "vitest run",
60
+ "test:coverage": "yarn test --coverage",
54
61
  "test:monorepo": "cd ../../frontend && yarn vitest run --config vitest.tree-spec-editor-react.config.ts"
55
62
  },
56
63
  "dependencies": {
57
- "@signalsafe/tree-spec": "^0.3.1",
58
- "@signalsafe/tree-spec-editor-core": "^0.1.2"
64
+ "@signalsafe/tree-spec": "^0.3.3",
65
+ "@signalsafe/tree-spec-editor-core": "^0.1.4"
59
66
  },
60
67
  "peerDependencies": {
61
68
  "react": "^18.0.0",
@@ -71,6 +78,7 @@
71
78
  "react-test-renderer": "^18.3.1",
72
79
  "reactflow": "^11.11.4",
73
80
  "typescript": "^5.4.2",
81
+ "@vitest/coverage-v8": "^3.2.4",
74
82
  "vitest": "^3.2.4"
75
83
  }
76
84
  }