@kiberon-labs/behave-graph-flow 2.0.0 → 3.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (251) hide show
  1. package/.storybook/manager.ts +6 -0
  2. package/.storybook/preview.ts +49 -1
  3. package/.storybook/styles.css +9 -3
  4. package/.turbo/turbo-build.log +1 -1
  5. package/CHANGELOG.md +368 -0
  6. package/dist/AnyControlImpl-Ds-CShIB.js +20 -0
  7. package/dist/AnyControlImpl-Ds-CShIB.js.map +1 -0
  8. package/dist/DocumentationBrowserPanelImpl-deZNzFX8.js +166 -0
  9. package/dist/DocumentationBrowserPanelImpl-deZNzFX8.js.map +1 -0
  10. package/dist/index.css +36 -33
  11. package/dist/index.css.map +1 -1
  12. package/dist/index.d.ts +1865 -550
  13. package/dist/index.d.ts.map +1 -1
  14. package/dist/index.js +14357 -11221
  15. package/dist/index.js.map +1 -1
  16. package/dist/noteImpl-KkrrWgJd.js +242 -0
  17. package/dist/noteImpl-KkrrWgJd.js.map +1 -0
  18. package/dist/styles.module-CvmpDkZj.css +3 -0
  19. package/dist/styles.module-CvmpDkZj.css.map +1 -0
  20. package/dist/styles.module-DZxg8aW9.js +271 -0
  21. package/dist/styles.module-DZxg8aW9.js.map +1 -0
  22. package/dist/useChangeNodeData-ChQGK7AI.js +23 -0
  23. package/dist/useChangeNodeData-ChQGK7AI.js.map +1 -0
  24. package/docs/protocol.md +43 -20
  25. package/package.json +5 -9
  26. package/src/components/FloatingToolbar/index.module.css +5 -13
  27. package/src/components/FloatingToolbar/index.tsx +9 -9
  28. package/src/components/Flow.tsx +34 -23
  29. package/src/components/contextMenus/DynamicContextMenu.tsx +85 -0
  30. package/src/components/contextMenus/NodePicker.module.css +13 -13
  31. package/src/components/contextMenus/edge.tsx +9 -95
  32. package/src/components/contextMenus/node.tsx +9 -149
  33. package/src/components/contextMenus/selection.tsx +5 -71
  34. package/src/components/controls/any/AnyControlImpl.tsx +14 -0
  35. package/src/components/controls/any/index.tsx +13 -2
  36. package/src/components/edges/index.tsx +75 -69
  37. package/src/components/layoutController/index.module.css +3 -0
  38. package/src/components/layoutController/index.tsx +24 -1
  39. package/src/components/layoutController/utils.ts +46 -3
  40. package/src/components/menubar/defaults.tsx +55 -19
  41. package/src/components/menubar/menuItem.module.css +18 -3
  42. package/src/components/menubar/menuItem.tsx +34 -1
  43. package/src/components/nodes/behave/NodeContainer.module.css +26 -25
  44. package/src/components/nodes/group/index.tsx +3 -3
  45. package/src/components/nodes/wrapper/styles.module.css +6 -32
  46. package/src/components/panels/alignment/index.module.css +0 -10
  47. package/src/components/panels/alignment/index.tsx +4 -4
  48. package/src/components/panels/base/styles.module.css +2 -2
  49. package/src/components/panels/common/PanelHeader.module.css +24 -0
  50. package/src/components/panels/common/PanelHeader.tsx +22 -0
  51. package/src/components/panels/common/SectionTitle.module.css +13 -0
  52. package/src/components/panels/common/SectionTitle.tsx +10 -0
  53. package/src/components/panels/events/EditEventPanel.tsx +14 -5
  54. package/src/components/panels/events/ManageEventsPanel.tsx +11 -8
  55. package/src/components/panels/events/styles.module.css +6 -64
  56. package/src/components/panels/graphProperties/index.tsx +125 -0
  57. package/src/components/panels/history/index.tsx +2 -2
  58. package/src/components/panels/history/styles.module.css +0 -9
  59. package/src/components/panels/keymaps/index.module.css +3 -13
  60. package/src/components/panels/keymaps/index.tsx +1 -2
  61. package/src/components/panels/layers/index.tsx +20 -15
  62. package/src/components/panels/layers/styles.module.css +9 -12
  63. package/src/components/panels/legend/index.tsx +1 -1
  64. package/src/components/panels/logs/index.module.css +25 -19
  65. package/src/components/panels/logs/index.tsx +7 -7
  66. package/src/components/panels/nodeInputs/InputsGroup.tsx +1 -0
  67. package/src/components/panels/nodeInputs/NodeSettings.tsx +2 -2
  68. package/src/components/panels/nodeInputs/NodeTitleEditor.tsx +1 -1
  69. package/src/components/panels/nodeInputs/OutputsGroup.tsx +2 -12
  70. package/src/components/panels/nodeInputs/index.module.css +99 -75
  71. package/src/components/panels/nodeInputs/index.tsx +21 -11
  72. package/src/components/panels/nodeInputs/useNodeHandlers.ts +2 -2
  73. package/src/components/panels/nodeInputs/useNodeInputsData.ts +23 -43
  74. package/src/components/panels/nodePicker/index.tsx +8 -8
  75. package/src/components/panels/panel/index.module.css +7 -7
  76. package/src/components/panels/search/index.module.css +0 -50
  77. package/src/components/panels/search/index.tsx +2 -2
  78. package/src/components/panels/systemSettings/ConversionsSettings.tsx +203 -0
  79. package/src/components/panels/systemSettings/index.tsx +221 -176
  80. package/src/components/panels/systemSettings/styles.module.css +135 -8
  81. package/src/components/panels/traces/GridLines.tsx +1 -1
  82. package/src/components/panels/traces/TimeGrid.tsx +3 -3
  83. package/src/components/panels/traces/TraceLane.tsx +1 -1
  84. package/src/components/panels/traces/index.module.css +1 -8
  85. package/src/components/panels/traces/index.tsx +8 -4
  86. package/src/components/panels/traces/useDerivedSpans.ts +241 -146
  87. package/src/components/panels/traces/utils.ts +8 -0
  88. package/src/components/panels/variables/CreateVariableScreen.tsx +3 -3
  89. package/src/components/panels/variables/ManageVariablesScreen.tsx +12 -9
  90. package/src/components/panels/variables/index.tsx +2 -2
  91. package/src/components/panels/variables/styles.module.css +4 -91
  92. package/src/components/primitives/icon.module.css +4 -4
  93. package/src/components/sockets/input/index.tsx +9 -2
  94. package/src/components/sockets/input/styles.module.css +2 -3
  95. package/src/components/sockets/output/index.tsx +10 -3
  96. package/src/components/sockets/output/styles.module.css +1 -6
  97. package/src/css/notes.css +135 -0
  98. package/src/css/prosemirror.css +3 -3
  99. package/src/css/rc-dock.css +143 -43
  100. package/src/css/rc-menu.css +56 -55
  101. package/src/css/themes/kiberon.css +127 -0
  102. package/src/css/vars.css +197 -13
  103. package/src/css/vscode-elements.css +124 -0
  104. package/src/generators/CallSubgraphGenerator.tsx +136 -0
  105. package/src/generators/CustomEventOnTriggeredGenerator.tsx +2 -2
  106. package/src/generators/GraphBoundaryGenerator.module.css +32 -0
  107. package/src/generators/GraphBoundaryGenerator.tsx +193 -0
  108. package/src/generators/SequenceGenerator.tsx +2 -2
  109. package/src/generators/SwitchOnIntegerGenerator.tsx +2 -2
  110. package/src/generators/SwitchOnStringGenerator.tsx +2 -2
  111. package/src/generators/callSubgraphSync.ts +126 -0
  112. package/src/generators/registerDefaultGenerators.ts +21 -0
  113. package/src/generators/registerDefaults.ts +26 -0
  114. package/src/hooks/useBehaveGraphFlow.ts +2 -2
  115. package/src/hooks/useFlowHandlers.ts +47 -9
  116. package/src/hooks/useWasdPan.ts +26 -4
  117. package/src/index.css +4 -16
  118. package/src/index.ts +17 -0
  119. package/src/manifest/contributionRegistry.ts +93 -0
  120. package/src/manifest/index.ts +4 -0
  121. package/src/manifest/loadManifest.ts +82 -0
  122. package/src/manifest/manifestPlugin.ts +29 -0
  123. package/src/manifest/passthroughValueType.ts +40 -0
  124. package/src/plugin/alignment/index.ts +22 -12
  125. package/src/plugin/autosave/controller.ts +366 -0
  126. package/src/plugin/autosave/index.tsx +114 -0
  127. package/src/plugin/autosave/panel/BackupPanel.tsx +141 -0
  128. package/src/plugin/autosave/panel/index.tsx +1 -0
  129. package/src/plugin/autosave/panel/styles.module.css +56 -0
  130. package/src/plugin/autosave/settings.ts +65 -0
  131. package/src/plugin/autosave/storage.ts +147 -0
  132. package/src/plugin/docs/index.tsx +2 -4
  133. package/src/plugin/docs/panel/DocumentationBrowserPanelImpl.tsx +200 -0
  134. package/src/plugin/docs/panel/index.tsx +15 -194
  135. package/src/plugin/docs/panel/styles.module.css +8 -8
  136. package/src/plugin/graphrunner/actions.ts +258 -185
  137. package/src/plugin/graphrunner/buttons.tsx +34 -26
  138. package/src/plugin/graphrunner/client.ts +4 -1
  139. package/src/plugin/graphrunner/index.tsx +29 -100
  140. package/src/plugin/graphrunner/panel.tsx +2 -2
  141. package/src/plugin/graphrunner/runController.ts +283 -0
  142. package/src/plugin/graphrunner/runner.ts +21 -192
  143. package/src/plugin/graphrunner/store.ts +14 -24
  144. package/src/plugin/graphrunner/styles.module.css +17 -57
  145. package/src/plugin/graphrunner/transport.ts +26 -0
  146. package/src/plugin/graphrunner/types.ts +21 -0
  147. package/src/plugin/graphrunner-local/execution-utils.ts +260 -80
  148. package/src/plugin/graphrunner-local/index.tsx +8 -2
  149. package/src/plugin/graphrunner-local/panel.tsx +131 -175
  150. package/src/plugin/graphrunner-local/styles.module.css +57 -76
  151. package/src/plugin/graphrunner-local/transport.ts +151 -184
  152. package/src/plugin/graphrunner-webworker/graph-executor.worker.ts +2 -0
  153. package/src/plugin/graphrunner-webworker/index.tsx +4 -10
  154. package/src/plugin/graphrunner-webworker/store.ts +9 -0
  155. package/src/plugin/kitchen-sink/index.ts +38 -0
  156. package/src/{layout/dagre.tsx → plugin/layout/dagre.ts} +17 -5
  157. package/src/{layout → plugin/layout}/elk.ts +22 -6
  158. package/src/plugin/layout/index.ts +80 -0
  159. package/src/plugin/notes/FormatToolbar.tsx +200 -0
  160. package/src/plugin/notes/index.tsx +191 -0
  161. package/src/plugin/notes/nodeActions.ts +100 -0
  162. package/src/plugin/notes/note.tsx +20 -0
  163. package/src/plugin/notes/noteImpl.tsx +89 -0
  164. package/src/plugin/realtime/realtimeRunner.ts +58 -4
  165. package/src/specifics/CustomEventOnTriggeredSpecific.tsx +2 -2
  166. package/src/specifics/CustomEventTriggerSpecific.tsx +2 -2
  167. package/src/specifics/VariableGetSpecific.tsx +2 -2
  168. package/src/specifics/VariableSetSpecific.tsx +2 -2
  169. package/src/store/actions.tsx +5 -5
  170. package/src/store/commands.ts +278 -0
  171. package/src/store/contextMenu.ts +192 -0
  172. package/src/store/conversions.ts +47 -0
  173. package/src/store/flow.tsx +23 -38
  174. package/src/store/graphMeta.ts +39 -0
  175. package/src/store/hotKeys.tsx +301 -260
  176. package/src/store/layers.ts +3 -3
  177. package/src/store/registry.ts +12 -4
  178. package/src/store/selection.ts +3 -3
  179. package/src/store/settings.ts +82 -82
  180. package/src/store/settingsSchema.ts +210 -0
  181. package/src/store/tabs.ts +5 -1
  182. package/src/store/traces.ts +3 -3
  183. package/src/system/graph.ts +11 -14
  184. package/src/system/graphSession.ts +172 -0
  185. package/src/system/index.ts +3 -0
  186. package/src/system/notifications.ts +13 -0
  187. package/src/system/persistence.ts +82 -0
  188. package/src/system/plugin.ts +28 -0
  189. package/src/system/provider.tsx +64 -0
  190. package/src/system/system.ts +518 -88
  191. package/src/system/tabLoader.tsx +70 -32
  192. package/src/system/undoRedo.ts +1 -1
  193. package/src/transformers/Uigraph.ts +5 -4
  194. package/src/transformers/contract.ts +87 -0
  195. package/src/transformers/flowToBehave.ts +13 -5
  196. package/src/types/nodes.ts +8 -3
  197. package/src/types.ts +2 -0
  198. package/src/util/autoConvert.ts +200 -0
  199. package/src/util/isValidConnection.ts +23 -2
  200. package/stories/defaults/defaultStoryProvider.tsx +17 -14
  201. package/stories/defaults/systemGenerator.ts +6 -1
  202. package/stories/{components/nodes/comment.stories.tsx → plugins/notes.stories.tsx} +24 -30
  203. package/tests/autoConvert.test.ts +329 -0
  204. package/tests/autosavePlugin.test.ts +204 -0
  205. package/tests/callSubgraphSync.test.ts +148 -0
  206. package/tests/commandRegistry.test.ts +137 -0
  207. package/tests/contract.test.ts +51 -0
  208. package/tests/contractSerialize.test.ts +62 -0
  209. package/tests/deriveSpans.test.ts +71 -0
  210. package/tests/flowToBehave.test.ts +2 -1
  211. package/tests/hotkeys.test.ts +79 -0
  212. package/tests/keepAliveLifecycle.test.ts +167 -0
  213. package/tests/loadManifest.test.ts +113 -0
  214. package/tests/noteMarkdown.test.ts +65 -0
  215. package/tests/notesPlugin.test.ts +162 -0
  216. package/tests/persistence.test.ts +51 -0
  217. package/tests/saveLoad.test.ts +7 -6
  218. package/tests/settings.test.ts +178 -0
  219. package/tests/traceStore.test.ts +46 -0
  220. package/tests/visual/README.md +2 -2
  221. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-conversation-chromium-win32.png +0 -0
  222. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-events-chromium-win32.png +0 -0
  223. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-history-chromium-win32.png +0 -0
  224. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-keymaps-chromium-win32.png +0 -0
  225. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-layers-chromium-win32.png +0 -0
  226. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-legend-chromium-win32.png +0 -0
  227. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-localGraphRunner-chromium-win32.png +0 -0
  228. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-logs-chromium-win32.png +0 -0
  229. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-nodeInputs-chromium-win32.png +0 -0
  230. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-nodePicker-chromium-win32.png +0 -0
  231. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-panel-chromium-win32.png +0 -0
  232. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-search-chromium-win32.png +0 -0
  233. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-systemSettings-chromium-win32.png +0 -0
  234. package/tests/visual/__screenshots__/panels.visual.test.tsx/panel-variables-chromium-win32.png +0 -0
  235. package/tests/visual/panels.visual.test.tsx +3 -3
  236. package/tests/wasdPan.test.ts +71 -0
  237. package/vitest.config.ts +1 -1
  238. package/vitest.visual.config.ts +7 -0
  239. package/.storybook/vscode.css +0 -814
  240. package/src/components/nodes/comment/FormatToolbar.tsx +0 -118
  241. package/src/components/nodes/comment/comment.tsx +0 -103
  242. package/src/components/nodes/comment/styles.module.css +0 -150
  243. package/src/components/panels/conversation/index.module.css +0 -151
  244. package/src/components/panels/conversation/index.tsx +0 -162
  245. package/src/components/panels/events/CustomEventsEditor.tsx +0 -384
  246. package/src/css/vscode.css +0 -13
  247. package/src/hooks/useDetachNodes.ts +0 -39
  248. package/src/plugin/graphrunner-webworker/types.ts +0 -17
  249. package/src/specifics/registerDefaultSpecifics.ts +0 -5
  250. package/src/store/chat.ts +0 -73
  251. package/src/store/graphRunnerClient.ts +0 -110
@@ -3,6 +3,19 @@ import type { Renderable, Toast } from 'react-hot-toast';
3
3
 
4
4
  export type NotificationType = 'info' | 'success' | 'error' | 'loading';
5
5
 
6
+ export interface NotificationData {
7
+ type: NotificationType;
8
+ message: string;
9
+ options?: {
10
+ id?: string;
11
+ duration?: number;
12
+ position?: any;
13
+ icon?: Renderable;
14
+ style?: React.CSSProperties;
15
+ className?: string;
16
+ ariaLive?: any;
17
+ };
18
+ }
6
19
  export interface NotificationOptions {
7
20
  /**
8
21
  * Toast ID for programmatic dismissal
@@ -0,0 +1,82 @@
1
+ import type { LayoutBase } from 'rc-dock';
2
+ import type { GraphJSON } from '@kiberon-labs/behave-graph';
3
+ import type { UIGraphJSON } from '@/types/graph';
4
+ import { downloadJson } from '@/util/downloadJson';
5
+ import type { System } from './system';
6
+
7
+ /**
8
+ * Sinks invoked when the editor emits its save events. Each entry maps one
9
+ * editor-level pubsub topic to the side effect that persists it (write the JSON
10
+ * somewhere). Override any subset to redirect where saved data goes; sinks left
11
+ * unspecified keep the built-in file-download behaviour.
12
+ *
13
+ * Loading is not represented here: the menubar's "Load" items already read a
14
+ * file from disk and deserialize it into the focused graph by default, so there
15
+ * is nothing host-specific to wire for the common case.
16
+ */
17
+ export interface PersistenceAdapter {
18
+ /** Persist a full UI graph save (`graph:saved`). */
19
+ saveGraph: (graph: UIGraphJSON) => void;
20
+ /** Persist a raw inner behave-graph save (`graph:inner:saved`). */
21
+ saveInnerGraph: (graph: GraphJSON) => void;
22
+ /** Persist a dock layout save (`layout:saved`). */
23
+ saveLayout: (layout: LayoutBase) => void;
24
+ }
25
+
26
+ /**
27
+ * Whether the file-download default can run. Guards the built-in sinks so that
28
+ * constructing a `System` in a non-DOM context (tests, SSR, the compiler) never
29
+ * throws , the subscriptions are harmless, only the download body is skipped.
30
+ */
31
+ const canDownload = (): boolean =>
32
+ typeof document !== 'undefined' && typeof URL !== 'undefined';
33
+
34
+ /**
35
+ * The built-in persistence: saving triggers a browser download of the
36
+ * corresponding JSON file. This is the default so a freshly constructed editor
37
+ * has working Save actions without any per-host or per-story wiring.
38
+ */
39
+ export const defaultPersistenceAdapter: PersistenceAdapter = {
40
+ saveGraph: (graph) => {
41
+ if (canDownload()) downloadJson('graph.json', graph);
42
+ },
43
+ saveInnerGraph: (graph) => {
44
+ if (canDownload()) downloadJson('graph.behave.json', graph);
45
+ },
46
+ saveLayout: (layout) => {
47
+ if (canDownload()) downloadJson('layout.json', layout);
48
+ }
49
+ };
50
+
51
+ /**
52
+ * Subscribe the given (or default) persistence sinks to the editor's save
53
+ * topics. Any sink not provided falls back to {@link defaultPersistenceAdapter}.
54
+ * Returns a disposer that removes every subscription it added.
55
+ */
56
+ export function installPersistence(
57
+ system: System,
58
+ adapter: Partial<PersistenceAdapter> = {}
59
+ ): () => void {
60
+ const resolved: PersistenceAdapter = {
61
+ ...defaultPersistenceAdapter,
62
+ ...adapter
63
+ };
64
+
65
+ const tokens = [
66
+ system.pubsub.subscribe('graph:saved', (_, graph) =>
67
+ resolved.saveGraph(graph)
68
+ ),
69
+ system.pubsub.subscribe('graph:inner:saved', (_, graph) =>
70
+ resolved.saveInnerGraph(graph)
71
+ ),
72
+ system.pubsub.subscribe('layout:saved', (_, layout) =>
73
+ resolved.saveLayout(layout)
74
+ )
75
+ ];
76
+
77
+ return () => {
78
+ for (const token of tokens) {
79
+ if (typeof token === 'string') system.pubsub.unsubscribe(token);
80
+ }
81
+ };
82
+ }
@@ -1,4 +1,5 @@
1
1
  import type { System } from '.';
2
+ import type { GraphSession } from './graphSession';
2
3
 
3
4
  /**
4
5
  * Plugin initialization function type
@@ -7,6 +8,33 @@ import type { System } from '.';
7
8
  export interface Plugin<TOptions = void> {
8
9
  (system: System, options: TOptions): void | Promise<void>;
9
10
  }
11
+
12
+ /**
13
+ * Cleanup returned by a {@link SessionExtension}. Run when the session it was
14
+ * applied to is disposed (its tab closed).
15
+ */
16
+ export type SessionExtensionCleanup = () => void;
17
+
18
+ /**
19
+ * Extends a single {@link GraphSession}. Registered at the editor level via
20
+ * `system.registerSessionExtension(...)`, it runs against every graph , those
21
+ * already open at registration time and any created afterwards , so an editor
22
+ * plugin can attach per-graph state (extra stores, controllers, pubsub
23
+ * subscriptions) to each new graph instance.
24
+ *
25
+ * Return a cleanup to tear that per-graph state down when the session is
26
+ * disposed.
27
+ *
28
+ * @example
29
+ * system.registerSessionExtension((session) => {
30
+ * const controller = new MyController(session);
31
+ * session.decorate('myController', controller);
32
+ * return () => controller.dispose();
33
+ * });
34
+ */
35
+ export interface SessionExtension {
36
+ (session: GraphSession): void | SessionExtensionCleanup;
37
+ }
10
38
  export type PluginOpts = {
11
39
  name: string;
12
40
  };
@@ -1,5 +1,11 @@
1
1
  import React, { createContext, useContext, type ReactNode } from 'react';
2
+ import { useStore } from 'zustand';
2
3
  import type { System } from './system';
4
+ import type { GraphSession } from './graphSession';
5
+
6
+ // ---------------------------------------------------------------------------
7
+ // Editor system context
8
+ // ---------------------------------------------------------------------------
3
9
 
4
10
  export const SystemContext = createContext<System | undefined>(undefined);
5
11
 
@@ -7,10 +13,20 @@ export type SystemProviderProps = {
7
13
  children: ReactNode;
8
14
  value: System;
9
15
  };
16
+
17
+ /**
18
+ * Provides the editor-level {@link System} to the React tree.
19
+ */
10
20
  export function SystemProvider({ children, value }: SystemProviderProps) {
11
21
  return <SystemContext value={value}>{children}</SystemContext>;
12
22
  }
13
23
 
24
+ /** Alias for {@link SystemProvider} expressing its editor-level role. */
25
+ export const EditorProvider = SystemProvider;
26
+
27
+ /**
28
+ * Access the editor-level {@link System}.
29
+ */
14
30
  export function useSystem(): System {
15
31
  const context = useContext(SystemContext);
16
32
 
@@ -20,3 +36,51 @@ export function useSystem(): System {
20
36
 
21
37
  return context;
22
38
  }
39
+
40
+ /** Alias for {@link useSystem}. */
41
+ export const useEditor = useSystem;
42
+
43
+ // ---------------------------------------------------------------------------
44
+ // Per-graph session context
45
+ // ---------------------------------------------------------------------------
46
+
47
+ const GraphContext = createContext<GraphSession | undefined>(undefined);
48
+
49
+ export type GraphProviderProps = {
50
+ children: ReactNode;
51
+ value: GraphSession;
52
+ };
53
+
54
+ /**
55
+ * Provides a single {@link GraphSession} to the subtree rendered inside a graph
56
+ * tab. Components within use {@link useGraph} to read per-graph state bound to
57
+ * their own tab, regardless of which tab is currently focused.
58
+ */
59
+ export function GraphProvider({ children, value }: GraphProviderProps) {
60
+ return <GraphContext value={value}>{children}</GraphContext>;
61
+ }
62
+
63
+ /**
64
+ * Access the {@link GraphSession} of the surrounding graph tab.
65
+ */
66
+ export function useGraph(): GraphSession {
67
+ const context = useContext(GraphContext);
68
+
69
+ if (context === undefined) {
70
+ throw new Error('useGraph must be used within a GraphProvider');
71
+ }
72
+
73
+ return context;
74
+ }
75
+
76
+ /**
77
+ * Access the currently focused {@link GraphSession}, or undefined when no graph
78
+ * is open. Subscribes to the editor's active-graph store, so panels rendered
79
+ * outside of a graph tab re-render when the focused graph changes.
80
+ */
81
+ export function useActiveGraph(): GraphSession | undefined {
82
+ const editor = useSystem();
83
+ return useStore(editor.activeGraph, (s) =>
84
+ s.activeGraphId ? s.sessions[s.activeGraphId] : undefined
85
+ );
86
+ }