@principal-ai/principal-view-react 0.6.10 → 0.6.12

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 (66) hide show
  1. package/README.md +2 -5
  2. package/dist/components/ConfigurationSelector.js +4 -2
  3. package/dist/components/ConfigurationSelector.js.map +1 -1
  4. package/dist/components/EdgeInfoPanel.d.ts.map +1 -1
  5. package/dist/components/EdgeInfoPanel.js +43 -13
  6. package/dist/components/EdgeInfoPanel.js.map +1 -1
  7. package/dist/components/GraphRenderer.d.ts.map +1 -1
  8. package/dist/components/GraphRenderer.js +133 -83
  9. package/dist/components/GraphRenderer.js.map +1 -1
  10. package/dist/components/NodeInfoPanel.d.ts.map +1 -1
  11. package/dist/components/NodeInfoPanel.js +143 -45
  12. package/dist/components/NodeInfoPanel.js.map +1 -1
  13. package/dist/edges/CustomEdge.d.ts +1 -0
  14. package/dist/edges/CustomEdge.d.ts.map +1 -1
  15. package/dist/edges/CustomEdge.js +18 -4
  16. package/dist/edges/CustomEdge.js.map +1 -1
  17. package/dist/edges/GenericEdge.d.ts.map +1 -1
  18. package/dist/edges/GenericEdge.js +2 -2
  19. package/dist/edges/GenericEdge.js.map +1 -1
  20. package/dist/hooks/usePathBasedEvents.d.ts +1 -1
  21. package/dist/hooks/usePathBasedEvents.d.ts.map +1 -1
  22. package/dist/hooks/usePathBasedEvents.js +9 -9
  23. package/dist/hooks/usePathBasedEvents.js.map +1 -1
  24. package/dist/index.d.ts +2 -2
  25. package/dist/index.d.ts.map +1 -1
  26. package/dist/index.js.map +1 -1
  27. package/dist/nodes/CustomNode.d.ts.map +1 -1
  28. package/dist/nodes/CustomNode.js +62 -45
  29. package/dist/nodes/CustomNode.js.map +1 -1
  30. package/dist/nodes/GenericNode.d.ts.map +1 -1
  31. package/dist/nodes/GenericNode.js.map +1 -1
  32. package/dist/utils/animationMapping.d.ts.map +1 -1
  33. package/dist/utils/animationMapping.js +12 -12
  34. package/dist/utils/animationMapping.js.map +1 -1
  35. package/dist/utils/graphConverter.d.ts.map +1 -1
  36. package/dist/utils/graphConverter.js +47 -19
  37. package/dist/utils/graphConverter.js.map +1 -1
  38. package/dist/utils/iconResolver.d.ts.map +1 -1
  39. package/dist/utils/iconResolver.js +1 -1
  40. package/dist/utils/iconResolver.js.map +1 -1
  41. package/package.json +2 -1
  42. package/src/components/ConfigurationSelector.tsx +5 -5
  43. package/src/components/EdgeInfoPanel.tsx +79 -37
  44. package/src/components/GraphRenderer.tsx +526 -365
  45. package/src/components/NodeInfoPanel.tsx +209 -86
  46. package/src/edges/CustomEdge.tsx +40 -7
  47. package/src/edges/GenericEdge.tsx +2 -6
  48. package/src/hooks/usePathBasedEvents.ts +54 -45
  49. package/src/index.ts +11 -2
  50. package/src/nodes/CustomNode.tsx +137 -109
  51. package/src/nodes/GenericNode.tsx +4 -3
  52. package/src/stories/AnimationWorkshop.stories.tsx +131 -12
  53. package/src/stories/CanvasEdgeTypes.stories.tsx +980 -0
  54. package/src/stories/CanvasNodeTypes.stories.tsx +898 -0
  55. package/src/stories/ColorPriority.stories.tsx +20 -10
  56. package/src/stories/EventDrivenAnimations.stories.tsx +8 -0
  57. package/src/stories/EventLog.stories.tsx +1 -1
  58. package/src/stories/GraphRenderer.stories.tsx +23 -10
  59. package/src/stories/IndustryThemes.stories.tsx +481 -0
  60. package/src/stories/MultiConfig.stories.tsx +8 -0
  61. package/src/stories/MultiDirectionalConnections.stories.tsx +8 -0
  62. package/src/stories/NodeFieldsAudit.stories.tsx +124 -37
  63. package/src/stories/NodeShapes.stories.tsx +73 -59
  64. package/src/utils/animationMapping.ts +19 -23
  65. package/src/utils/graphConverter.ts +61 -21
  66. package/src/utils/iconResolver.tsx +5 -1
@@ -6,6 +6,7 @@ const react_1 = require("react");
6
6
  const react_2 = require("@xyflow/react");
7
7
  require("@xyflow/react/dist/style.css");
8
8
  const principal_view_core_1 = require("@principal-ai/principal-view-core");
9
+ const industry_theme_1 = require("@principal-ade/industry-theme");
9
10
  const CustomNode_1 = require("../nodes/CustomNode");
10
11
  const CustomEdge_1 = require("../edges/CustomEdge");
11
12
  const graphConverter_1 = require("../utils/graphConverter");
@@ -31,6 +32,7 @@ const createEmptyEditState = () => ({
31
32
  */
32
33
  const GraphRendererInner = ({ configuration, nodes: propNodes, edges: propEdges, violations = [], configName: _configName, showMinimap = true, showControls = true, showBackground = true, events = [], onEventProcessed, editable = false, onPendingChangesChange, onEditStateChange, editStateRef, }) => {
33
34
  const { fitView } = (0, react_2.useReactFlow)();
35
+ const { theme } = (0, industry_theme_1.useTheme)();
34
36
  // Track active animations
35
37
  const [animationState, setAnimationState] = (0, react_1.useState)({
36
38
  nodeAnimations: {},
@@ -49,13 +51,25 @@ const GraphRendererInner = ({ configuration, nodes: propNodes, edges: propEdges,
49
51
  const [localNodes, setLocalNodes] = (0, react_1.useState)(propNodes);
50
52
  const [localEdges, setLocalEdges] = (0, react_1.useState)(propEdges);
51
53
  // Track the prop values to detect external changes
52
- const propNodesKeyRef = (0, react_1.useRef)(propNodes.map(n => n.id).sort().join(','));
53
- const propEdgesKeyRef = (0, react_1.useRef)(propEdges.map(e => e.id).sort().join(','));
54
+ const propNodesKeyRef = (0, react_1.useRef)(propNodes
55
+ .map((n) => n.id)
56
+ .sort()
57
+ .join(','));
58
+ const propEdgesKeyRef = (0, react_1.useRef)(propEdges
59
+ .map((e) => e.id)
60
+ .sort()
61
+ .join(','));
54
62
  // Sync local state with props when props change (e.g., config reload)
55
63
  // This only happens when the structure changes, not during editing
56
64
  (0, react_1.useEffect)(() => {
57
- const newNodesKey = propNodes.map(n => n.id).sort().join(',');
58
- const newEdgesKey = propEdges.map(e => e.id).sort().join(',');
65
+ const newNodesKey = propNodes
66
+ .map((n) => n.id)
67
+ .sort()
68
+ .join(',');
69
+ const newEdgesKey = propEdges
70
+ .map((e) => e.id)
71
+ .sort()
72
+ .join(',');
59
73
  if (newNodesKey !== propNodesKeyRef.current || newEdgesKey !== propEdgesKeyRef.current) {
60
74
  propNodesKeyRef.current = newNodesKey;
61
75
  propEdgesKeyRef.current = newEdgesKey;
@@ -73,11 +87,11 @@ const GraphRendererInner = ({ configuration, nodes: propNodes, edges: propEdges,
73
87
  const edges = editable ? localEdges : propEdges;
74
88
  // Helper to check if there are pending changes
75
89
  const checkHasChanges = (0, react_1.useCallback)((state) => {
76
- return state.positionChanges.size > 0 ||
90
+ return (state.positionChanges.size > 0 ||
77
91
  state.nodeUpdates.size > 0 ||
78
92
  state.deletedNodeIds.size > 0 ||
79
93
  state.createdEdges.length > 0 ||
80
- state.deletedEdges.length > 0;
94
+ state.deletedEdges.length > 0);
81
95
  }, []);
82
96
  // Helper to update edit state and notify parent
83
97
  const updateEditState = (0, react_1.useCallback)((updater) => {
@@ -112,7 +126,7 @@ const GraphRendererInner = ({ configuration, nodes: propNodes, edges: propEdges,
112
126
  if (!editable)
113
127
  return;
114
128
  // Update local nodes
115
- setLocalNodes(prev => prev.map(node => {
129
+ setLocalNodes((prev) => prev.map((node) => {
116
130
  if (node.id === nodeId) {
117
131
  return {
118
132
  ...node,
@@ -123,7 +137,7 @@ const GraphRendererInner = ({ configuration, nodes: propNodes, edges: propEdges,
123
137
  return node;
124
138
  }));
125
139
  // Track the change
126
- updateEditState(prev => {
140
+ updateEditState((prev) => {
127
141
  const newUpdates = new Map(prev.nodeUpdates);
128
142
  const existing = newUpdates.get(nodeId) || {};
129
143
  newUpdates.set(nodeId, {
@@ -138,10 +152,10 @@ const GraphRendererInner = ({ configuration, nodes: propNodes, edges: propEdges,
138
152
  if (!editable)
139
153
  return;
140
154
  // Remove from local state
141
- setLocalNodes(prev => prev.filter(n => n.id !== nodeId));
142
- setLocalEdges(prev => prev.filter(e => e.from !== nodeId && e.to !== nodeId));
155
+ setLocalNodes((prev) => prev.filter((n) => n.id !== nodeId));
156
+ setLocalEdges((prev) => prev.filter((e) => e.from !== nodeId && e.to !== nodeId));
143
157
  // Track the change
144
- updateEditState(prev => {
158
+ updateEditState((prev) => {
145
159
  const newDeletedNodes = new Set(prev.deletedNodeIds);
146
160
  newDeletedNodes.add(nodeId);
147
161
  // Remove any pending updates for this node
@@ -151,7 +165,7 @@ const GraphRendererInner = ({ configuration, nodes: propNodes, edges: propEdges,
151
165
  const newPositions = new Map(prev.positionChanges);
152
166
  newPositions.delete(nodeId);
153
167
  // Remove created edges that involve this node
154
- const newCreatedEdges = prev.createdEdges.filter(e => e.from !== nodeId && e.to !== nodeId);
168
+ const newCreatedEdges = prev.createdEdges.filter((e) => e.from !== nodeId && e.to !== nodeId);
155
169
  return {
156
170
  ...prev,
157
171
  deletedNodeIds: newDeletedNodes,
@@ -167,13 +181,13 @@ const GraphRendererInner = ({ configuration, nodes: propNodes, edges: propEdges,
167
181
  if (!editable)
168
182
  return;
169
183
  // Find the edge before removing it so we can track its full info
170
- const edgeToDelete = localEdges.find(e => e.id === edgeId);
184
+ const edgeToDelete = localEdges.find((e) => e.id === edgeId);
171
185
  // Remove from local state
172
- setLocalEdges(prev => prev.filter(e => e.id !== edgeId));
186
+ setLocalEdges((prev) => prev.filter((e) => e.id !== edgeId));
173
187
  // Track the change
174
- updateEditState(prev => {
188
+ updateEditState((prev) => {
175
189
  // Check if this was a newly created edge
176
- const createdEdgeIndex = prev.createdEdges.findIndex(e => e.id === edgeId);
190
+ const createdEdgeIndex = prev.createdEdges.findIndex((e) => e.id === edgeId);
177
191
  if (createdEdgeIndex >= 0) {
178
192
  // Just remove it from created edges
179
193
  const newCreatedEdges = [...prev.createdEdges];
@@ -182,12 +196,15 @@ const GraphRendererInner = ({ configuration, nodes: propNodes, edges: propEdges,
182
196
  }
183
197
  // Otherwise mark as deleted with full edge info
184
198
  if (edgeToDelete) {
185
- const newDeletedEdges = [...prev.deletedEdges, {
199
+ const newDeletedEdges = [
200
+ ...prev.deletedEdges,
201
+ {
186
202
  id: edgeId,
187
203
  from: edgeToDelete.from,
188
204
  to: edgeToDelete.to,
189
- type: edgeToDelete.type
190
- }];
205
+ type: edgeToDelete.type,
206
+ },
207
+ ];
191
208
  return { ...prev, deletedEdges: newDeletedEdges };
192
209
  }
193
210
  return prev;
@@ -199,14 +216,14 @@ const GraphRendererInner = ({ configuration, nodes: propNodes, edges: propEdges,
199
216
  if (!editable || !connection.source || !connection.target)
200
217
  return;
201
218
  // Find source and target node types
202
- const sourceNode = nodes.find(n => n.id === connection.source);
203
- const targetNode = nodes.find(n => n.id === connection.target);
219
+ const sourceNode = nodes.find((n) => n.id === connection.source);
220
+ const targetNode = nodes.find((n) => n.id === connection.target);
204
221
  if (!sourceNode || !targetNode)
205
222
  return;
206
223
  // Find valid edge types for this connection
207
224
  const validTypes = configuration.allowedConnections
208
- .filter(ac => ac.from === sourceNode.type && ac.to === targetNode.type)
209
- .map(ac => ac.via);
225
+ .filter((ac) => ac.from === sourceNode.type && ac.to === targetNode.type)
226
+ .map((ac) => ac.via);
210
227
  const uniqueTypes = [...new Set(validTypes)];
211
228
  if (uniqueTypes.length === 0) {
212
229
  console.warn(`No valid edge types for connection from ${sourceNode.type} to ${targetNode.type}`);
@@ -242,11 +259,14 @@ const GraphRendererInner = ({ configuration, nodes: propNodes, edges: propEdges,
242
259
  sourceHandle,
243
260
  targetHandle,
244
261
  };
245
- setLocalEdges(prev => [...prev, newEdge]);
262
+ setLocalEdges((prev) => [...prev, newEdge]);
246
263
  // Track the change
247
- updateEditState(prev => ({
264
+ updateEditState((prev) => ({
248
265
  ...prev,
249
- createdEdges: [...prev.createdEdges, { id: edgeId, from, to, type, sourceHandle, targetHandle }],
266
+ createdEdges: [
267
+ ...prev.createdEdges,
268
+ { id: edgeId, from, to, type, sourceHandle, targetHandle },
269
+ ],
250
270
  }));
251
271
  }, [updateEditState]);
252
272
  // Handle edge type selection from picker
@@ -271,16 +291,16 @@ const GraphRendererInner = ({ configuration, nodes: propNodes, edges: propEdges,
271
291
  if (!editable || !newConnection.source || !newConnection.target)
272
292
  return;
273
293
  // Find the original edge in our local state
274
- const originalEdge = localEdges.find(e => e.id === oldEdge.id);
294
+ const originalEdge = localEdges.find((e) => e.id === oldEdge.id);
275
295
  if (!originalEdge)
276
296
  return;
277
297
  // Find source and target node types for validation
278
- const sourceNode = nodes.find(n => n.id === newConnection.source);
279
- const targetNode = nodes.find(n => n.id === newConnection.target);
298
+ const sourceNode = nodes.find((n) => n.id === newConnection.source);
299
+ const targetNode = nodes.find((n) => n.id === newConnection.target);
280
300
  if (!sourceNode || !targetNode)
281
301
  return;
282
302
  // Check if the new connection is valid for this edge type
283
- const isValidConnection = configuration.allowedConnections.some(ac => ac.from === sourceNode.type && ac.to === targetNode.type && ac.via === originalEdge.type);
303
+ const isValidConnection = configuration.allowedConnections.some((ac) => ac.from === sourceNode.type && ac.to === targetNode.type && ac.via === originalEdge.type);
284
304
  if (!isValidConnection) {
285
305
  console.warn(`Cannot reconnect: ${originalEdge.type} edge not allowed from ${sourceNode.type} to ${targetNode.type}`);
286
306
  return;
@@ -288,7 +308,7 @@ const GraphRendererInner = ({ configuration, nodes: propNodes, edges: propEdges,
288
308
  // Mark as successful before updating
289
309
  edgeReconnectSuccessful.current = true;
290
310
  // Update local edges - manually update the edge to preserve its type and id
291
- setLocalEdges(prev => prev.map(edge => {
311
+ setLocalEdges((prev) => prev.map((edge) => {
292
312
  if (edge.id === oldEdge.id) {
293
313
  return {
294
314
  ...edge,
@@ -302,9 +322,9 @@ const GraphRendererInner = ({ configuration, nodes: propNodes, edges: propEdges,
302
322
  return edge;
303
323
  }));
304
324
  // Track the change - remove old edge and add new one
305
- updateEditState(prev => {
325
+ updateEditState((prev) => {
306
326
  // Check if this was a newly created edge
307
- const createdEdgeIndex = prev.createdEdges.findIndex(e => e.id === oldEdge.id);
327
+ const createdEdgeIndex = prev.createdEdges.findIndex((e) => e.id === oldEdge.id);
308
328
  if (createdEdgeIndex >= 0) {
309
329
  // Update the created edge entry
310
330
  const newCreatedEdges = [...prev.createdEdges];
@@ -318,20 +338,26 @@ const GraphRendererInner = ({ configuration, nodes: propNodes, edges: propEdges,
318
338
  return { ...prev, createdEdges: newCreatedEdges };
319
339
  }
320
340
  // For existing edges, track as delete + create
321
- const newDeletedEdges = [...prev.deletedEdges, {
341
+ const newDeletedEdges = [
342
+ ...prev.deletedEdges,
343
+ {
322
344
  id: oldEdge.id,
323
345
  from: originalEdge.from,
324
346
  to: originalEdge.to,
325
347
  type: originalEdge.type,
326
- }];
327
- const newCreatedEdges = [...prev.createdEdges, {
348
+ },
349
+ ];
350
+ const newCreatedEdges = [
351
+ ...prev.createdEdges,
352
+ {
328
353
  id: oldEdge.id,
329
354
  from: newConnection.source,
330
355
  to: newConnection.target,
331
356
  type: originalEdge.type,
332
357
  sourceHandle: newConnection.sourceHandle ?? undefined,
333
358
  targetHandle: newConnection.targetHandle ?? undefined,
334
- }];
359
+ },
360
+ ];
335
361
  return { ...prev, deletedEdges: newDeletedEdges, createdEdges: newCreatedEdges };
336
362
  });
337
363
  }, [editable, localEdges, nodes, configuration.allowedConnections, updateEditState]);
@@ -348,7 +374,7 @@ const GraphRendererInner = ({ configuration, nodes: propNodes, edges: propEdges,
348
374
  const selectedEdge = (0, react_1.useMemo)(() => {
349
375
  if (!selectedEdgeId)
350
376
  return null;
351
- return edges.find(e => e.id === selectedEdgeId);
377
+ return edges.find((e) => e.id === selectedEdgeId);
352
378
  }, [selectedEdgeId, edges]);
353
379
  const selectedEdgeTypeDefinition = (0, react_1.useMemo)(() => {
354
380
  if (!selectedEdge)
@@ -358,7 +384,7 @@ const GraphRendererInner = ({ configuration, nodes: propNodes, edges: propEdges,
358
384
  const selectedNode = (0, react_1.useMemo)(() => {
359
385
  if (!selectedNodeId)
360
386
  return null;
361
- return nodes.find(n => n.id === selectedNodeId);
387
+ return nodes.find((n) => n.id === selectedNodeId);
362
388
  }, [selectedNodeId, nodes]);
363
389
  const selectedNodeTypeDefinition = (0, react_1.useMemo)(() => {
364
390
  if (!selectedNode)
@@ -377,7 +403,7 @@ const GraphRendererInner = ({ configuration, nodes: propNodes, edges: propEdges,
377
403
  const edgeId = edgeEvent.edgeId;
378
404
  const animation = edgeEvent.animation;
379
405
  if (animation && edgeId) {
380
- setAnimationState(prev => ({
406
+ setAnimationState((prev) => ({
381
407
  ...prev,
382
408
  edgeAnimations: {
383
409
  ...prev.edgeAnimations,
@@ -391,7 +417,7 @@ const GraphRendererInner = ({ configuration, nodes: propNodes, edges: propEdges,
391
417
  }));
392
418
  const duration = animation.duration || 1000;
393
419
  setTimeout(() => {
394
- setAnimationState(prev => {
420
+ setAnimationState((prev) => {
395
421
  const newEdgeAnimations = { ...prev.edgeAnimations };
396
422
  delete newEdgeAnimations[edgeId];
397
423
  return { ...prev, edgeAnimations: newEdgeAnimations };
@@ -406,7 +432,7 @@ const GraphRendererInner = ({ configuration, nodes: propNodes, edges: propEdges,
406
432
  const newState = stateEvent.newState;
407
433
  if (nodeId && newState) {
408
434
  // Update the node's state
409
- setLocalNodes(prev => prev.map(node => node.id === nodeId ? { ...node, state: newState } : node));
435
+ setLocalNodes((prev) => prev.map((node) => (node.id === nodeId ? { ...node, state: newState } : node)));
410
436
  // Trigger animation based on state
411
437
  const stateToAnimation = {
412
438
  processing: 'pulse',
@@ -416,7 +442,7 @@ const GraphRendererInner = ({ configuration, nodes: propNodes, edges: propEdges,
416
442
  const animationType = stateToAnimation[newState];
417
443
  if (animationType) {
418
444
  const duration = animationType === 'pulse' ? 1500 : animationType === 'flash' ? 1000 : 500;
419
- setAnimationState(prev => ({
445
+ setAnimationState((prev) => ({
420
446
  ...prev,
421
447
  nodeAnimations: {
422
448
  ...prev.nodeAnimations,
@@ -425,7 +451,7 @@ const GraphRendererInner = ({ configuration, nodes: propNodes, edges: propEdges,
425
451
  }));
426
452
  if (animationType !== 'pulse') {
427
453
  setTimeout(() => {
428
- setAnimationState(prev => {
454
+ setAnimationState((prev) => {
429
455
  const newNodeAnimations = { ...prev.nodeAnimations };
430
456
  delete newNodeAnimations[nodeId];
431
457
  return { ...prev, nodeAnimations: newNodeAnimations };
@@ -440,7 +466,7 @@ const GraphRendererInner = ({ configuration, nodes: propNodes, edges: propEdges,
440
466
  const nodeEvent = latestEvent.payload;
441
467
  const nodeId = nodeEvent.nodeId;
442
468
  if (nodeId) {
443
- setAnimationState(prev => ({
469
+ setAnimationState((prev) => ({
444
470
  ...prev,
445
471
  nodeAnimations: {
446
472
  ...prev.nodeAnimations,
@@ -448,7 +474,7 @@ const GraphRendererInner = ({ configuration, nodes: propNodes, edges: propEdges,
448
474
  },
449
475
  }));
450
476
  setTimeout(() => {
451
- setAnimationState(prev => {
477
+ setAnimationState((prev) => {
452
478
  const newNodeAnimations = { ...prev.nodeAnimations };
453
479
  delete newNodeAnimations[nodeId];
454
480
  return { ...prev, nodeAnimations: newNodeAnimations };
@@ -465,7 +491,7 @@ const GraphRendererInner = ({ configuration, nodes: propNodes, edges: propEdges,
465
491
  const converted = (0, graphConverter_1.convertToXYFlowNodes)(nodes, configuration, violations);
466
492
  const layoutType = configuration.display?.layout || 'hierarchical';
467
493
  const positioned = (0, graphConverter_1.autoLayoutNodes)(converted, [], layoutType);
468
- return positioned.map(node => {
494
+ return positioned.map((node) => {
469
495
  const animation = animationState.nodeAnimations[node.id];
470
496
  // Apply any pending position changes
471
497
  const pendingPosition = editStateRef.current.positionChanges.get(node.id);
@@ -475,16 +501,21 @@ const GraphRendererInner = ({ configuration, nodes: propNodes, edges: propEdges,
475
501
  data: {
476
502
  ...node.data,
477
503
  editable,
478
- ...(animation ? {
479
- animationType: animation.type,
480
- animationDuration: animation.duration,
481
- } : {}),
504
+ ...(animation
505
+ ? {
506
+ animationType: animation.type,
507
+ animationDuration: animation.duration,
508
+ }
509
+ : {}),
482
510
  },
483
511
  };
484
512
  });
485
513
  }, [nodes, configuration, violations, animationState.nodeAnimations, editable, editStateRef]);
486
514
  const baseNodesKey = (0, react_1.useMemo)(() => {
487
- return nodes.map(n => n.id).sort().join(',');
515
+ return nodes
516
+ .map((n) => n.id)
517
+ .sort()
518
+ .join(',');
488
519
  }, [nodes]);
489
520
  // Local xyflow nodes state for dragging
490
521
  const [xyflowLocalNodes, setXyflowLocalNodes] = (0, react_1.useState)(xyflowNodesBase);
@@ -510,16 +541,15 @@ const GraphRendererInner = ({ configuration, nodes: propNodes, edges: propEdges,
510
541
  const handleNodesChange = (0, react_1.useCallback)((changes) => {
511
542
  if (!editable)
512
543
  return;
513
- setXyflowLocalNodes(nds => (0, react_2.applyNodeChanges)(changes, nds));
544
+ setXyflowLocalNodes((nds) => (0, react_2.applyNodeChanges)(changes, nds));
514
545
  // Track position changes on drag end
515
- const positionChanges = changes
516
- .filter((change) => change.type === 'position' &&
546
+ const positionChanges = changes.filter((change) => change.type === 'position' &&
517
547
  'position' in change &&
518
548
  change.position !== undefined &&
519
549
  'dragging' in change &&
520
550
  change.dragging === false);
521
551
  if (positionChanges.length > 0) {
522
- updateEditState(prev => {
552
+ updateEditState((prev) => {
523
553
  const newPositions = new Map(prev.positionChanges);
524
554
  for (const change of positionChanges) {
525
555
  newPositions.set(change.id, {
@@ -533,7 +563,7 @@ const GraphRendererInner = ({ configuration, nodes: propNodes, edges: propEdges,
533
563
  }, [editable, updateEditState]);
534
564
  const xyflowEdges = (0, react_1.useMemo)(() => {
535
565
  const converted = (0, graphConverter_1.convertToXYFlowEdges)(edges, configuration, violations);
536
- return converted.map(edge => {
566
+ return converted.map((edge) => {
537
567
  const animation = animationState.edgeAnimations[edge.id];
538
568
  if (animation) {
539
569
  return {
@@ -565,26 +595,28 @@ const GraphRendererInner = ({ configuration, nodes: propNodes, edges: propEdges,
565
595
  // ============================================
566
596
  // RENDER
567
597
  // ============================================
568
- return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)(react_2.ReactFlow, { nodes: xyflowNodes, edges: xyflowEdges, nodeTypes: nodeTypes, edgeTypes: edgeTypes, minZoom: 0.1, maxZoom: 4, defaultEdgeOptions: { type: 'custom' }, onEdgeClick: onEdgeClick, onNodeClick: onNodeClick, proOptions: { hideAttribution: true }, nodesDraggable: editable, elementsSelectable: editable, nodesConnectable: editable, edgesReconnectable: editable, onNodesChange: handleNodesChange, onConnect: handleConnect, onReconnectStart: handleReconnectStart, onReconnect: handleReconnect, onReconnectEnd: handleReconnectEnd, panOnDrag: true, selectionOnDrag: false, children: [showBackground && (0, jsx_runtime_1.jsx)(react_2.Background, { color: "#e5e5e5", gap: 16, size: 1 }), showControls && (0, jsx_runtime_1.jsx)(react_2.Controls, { showZoom: true, showFitView: true, showInteractive: true }), showMinimap && ((0, jsx_runtime_1.jsx)(react_2.MiniMap, { nodeColor: (node) => {
598
+ return ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsxs)(react_2.ReactFlow, { nodes: xyflowNodes, edges: xyflowEdges, nodeTypes: nodeTypes, edgeTypes: edgeTypes, minZoom: 0.1, maxZoom: 4, defaultEdgeOptions: { type: 'custom' }, onEdgeClick: onEdgeClick, onNodeClick: onNodeClick, proOptions: { hideAttribution: true }, nodesDraggable: editable, elementsSelectable: editable, nodesConnectable: editable, edgesReconnectable: editable, onNodesChange: handleNodesChange, onConnect: handleConnect, onReconnectStart: handleReconnectStart, onReconnect: handleReconnect, onReconnectEnd: handleReconnectEnd, panOnDrag: true, selectionOnDrag: false, children: [showBackground && (0, jsx_runtime_1.jsx)(react_2.Background, { color: theme.colors.border, gap: 16, size: 1 }), showControls && (0, jsx_runtime_1.jsx)(react_2.Controls, { showZoom: true, showFitView: true, showInteractive: true }), showMinimap && ((0, jsx_runtime_1.jsx)(react_2.MiniMap, { nodeColor: (node) => {
569
599
  const nodeData = node.data;
570
- return nodeData?.typeDefinition?.color || '#888';
600
+ return nodeData?.typeDefinition?.color || theme.colors.secondary;
571
601
  }, nodeBorderRadius: 2, pannable: true, zoomable: true }))] }, baseNodesKey), selectedEdge && selectedEdgeTypeDefinition && ((0, jsx_runtime_1.jsx)(EdgeInfoPanel_1.EdgeInfoPanel, { edge: selectedEdge, typeDefinition: selectedEdgeTypeDefinition, sourceNodeId: selectedEdge.from, targetNodeId: selectedEdge.to, onClose: onCloseEdgeInfoPanel, onDelete: editable ? handleEdgeDelete : undefined })), selectedNode && selectedNodeTypeDefinition && ((0, jsx_runtime_1.jsx)(NodeInfoPanel_1.NodeInfoPanel, { node: selectedNode, typeDefinition: selectedNodeTypeDefinition, availableNodeTypes: configuration.nodeTypes, onClose: onCloseNodeInfoPanel, onDelete: editable ? handleNodeDelete : undefined, onUpdate: editable ? handleNodeUpdate : undefined })), pendingConnection && ((0, jsx_runtime_1.jsxs)("div", { style: {
572
602
  position: 'absolute',
573
603
  top: '50%',
574
604
  left: '50%',
575
605
  transform: 'translate(-50%, -50%)',
576
- backgroundColor: 'white',
606
+ backgroundColor: theme.colors.background,
607
+ color: theme.colors.text,
577
608
  borderRadius: '8px',
578
609
  boxShadow: '0 4px 12px rgba(0,0,0,0.15)',
579
610
  padding: '16px',
580
611
  minWidth: '200px',
581
612
  zIndex: 1000,
582
- }, children: [(0, jsx_runtime_1.jsx)("div", { style: { fontWeight: 'bold', marginBottom: '12px', fontSize: '14px' }, children: "Select Edge Type" }), (0, jsx_runtime_1.jsxs)("div", { style: { fontSize: '12px', color: '#666', marginBottom: '12px' }, children: [pendingConnection.from, " \u2192 ", pendingConnection.to] }), (0, jsx_runtime_1.jsx)("div", { style: { display: 'flex', flexDirection: 'column', gap: '8px' }, children: pendingConnection.validTypes.map(type => {
613
+ border: `1px solid ${theme.colors.border}`,
614
+ }, children: [(0, jsx_runtime_1.jsx)("div", { style: { fontWeight: 'bold', marginBottom: '12px', fontSize: '14px' }, children: "Select Edge Type" }), (0, jsx_runtime_1.jsxs)("div", { style: { fontSize: '12px', color: theme.colors.textSecondary, marginBottom: '12px' }, children: [pendingConnection.from, " \u2192 ", pendingConnection.to] }), (0, jsx_runtime_1.jsx)("div", { style: { display: 'flex', flexDirection: 'column', gap: '8px' }, children: pendingConnection.validTypes.map((type) => {
583
615
  const typeDefinition = configuration.edgeTypes[type];
584
616
  return ((0, jsx_runtime_1.jsx)("button", { onClick: () => handleEdgeTypeSelect(type), style: {
585
617
  padding: '8px 12px',
586
- backgroundColor: typeDefinition?.color || '#888',
587
- color: 'white',
618
+ backgroundColor: typeDefinition?.color || theme.colors.secondary,
619
+ color: theme.colors.background,
588
620
  border: 'none',
589
621
  borderRadius: '4px',
590
622
  cursor: 'pointer',
@@ -596,9 +628,9 @@ const GraphRendererInner = ({ configuration, nodes: propNodes, edges: propEdges,
596
628
  marginTop: '12px',
597
629
  width: '100%',
598
630
  padding: '8px 12px',
599
- backgroundColor: '#f0f0f0',
600
- color: '#666',
601
- border: 'none',
631
+ backgroundColor: theme.colors.surface,
632
+ color: theme.colors.textSecondary,
633
+ border: `1px solid ${theme.colors.border}`,
602
634
  borderRadius: '4px',
603
635
  cursor: 'pointer',
604
636
  fontSize: '12px',
@@ -660,11 +692,20 @@ function useCanvasToLegacy(canvas, library) {
660
692
  const nodeType = vv?.nodeType || node.type;
661
693
  if (!nodeTypes[nodeType]) {
662
694
  // Color priority: vv.fill > node.color > vv.states.idle.color
663
- const fillColor = vv?.fill
664
- || (typeof node.color === 'string' ? node.color : undefined)
665
- || vv?.states?.idle?.color;
695
+ const fillColor = vv?.fill ||
696
+ (typeof node.color === 'string' ? node.color : undefined) ||
697
+ vv?.states?.idle?.color;
698
+ // Derive description from text content (everything after line 1) for text nodes
699
+ let nodeDescription = `${nodeType} node`;
700
+ if (node.type === 'text' && 'text' in node) {
701
+ const lines = node.text.split('\n');
702
+ const descFromText = lines.slice(1).join('\n').trim();
703
+ if (descFromText) {
704
+ nodeDescription = descFromText;
705
+ }
706
+ }
666
707
  nodeTypes[nodeType] = {
667
- description: vv?.description || `${nodeType} node`,
708
+ description: nodeDescription,
668
709
  shape: vv?.shape || 'rectangle',
669
710
  icon: vv?.icon,
670
711
  color: fillColor,
@@ -703,8 +744,8 @@ function useCanvasToLegacy(canvas, library) {
703
744
  };
704
745
  }
705
746
  // Find node types for from/to
706
- const fromNode = canvas.nodes?.find(n => n.id === edge.fromNode);
707
- const toNode = canvas.nodes?.find(n => n.id === edge.toNode);
747
+ const fromNode = canvas.nodes?.find((n) => n.id === edge.fromNode);
748
+ const toNode = canvas.nodes?.find((n) => n.id === edge.toNode);
708
749
  const fromType = fromNode?.pv?.nodeType || edge.fromNode;
709
750
  const toType = toNode?.pv?.nodeType || edge.toNode;
710
751
  allowedConnections.push({
@@ -758,16 +799,12 @@ function useCanvasToLegacy(canvas, library) {
758
799
  */
759
800
  exports.GraphRenderer = (0, react_1.forwardRef)((props, ref) => {
760
801
  const { canvas, library, className, width = '100%', height = '100%' } = props;
802
+ const { theme } = (0, industry_theme_1.useTheme)();
761
803
  // Convert canvas to internal format (merging library types if provided)
762
804
  const canvasData = useCanvasToLegacy(canvas, library);
763
- // Validate we have required data
764
- if (!canvasData) {
765
- return ((0, jsx_runtime_1.jsx)("div", { className: className, style: { width, height, display: 'flex', alignItems: 'center', justifyContent: 'center' }, children: (0, jsx_runtime_1.jsx)("p", { style: { color: '#666' }, children: "No canvas data provided." }) }));
766
- }
767
- const { configuration, nodes, edges } = canvasData;
768
- // Internal edit state ref
805
+ // Internal edit state ref - must be before any conditional returns
769
806
  const editStateRef = (0, react_1.useRef)(createEmptyEditState());
770
- // Expose imperative handle
807
+ // Expose imperative handle - must be before any conditional returns
771
808
  (0, react_1.useImperativeHandle)(ref, () => ({
772
809
  getPendingChanges: () => {
773
810
  const state = editStateRef.current;
@@ -781,14 +818,14 @@ exports.GraphRenderer = (0, react_1.forwardRef)((props, ref) => {
781
818
  updates,
782
819
  })),
783
820
  deletedNodeIds: Array.from(state.deletedNodeIds),
784
- createdEdges: state.createdEdges.map(e => ({
821
+ createdEdges: state.createdEdges.map((e) => ({
785
822
  from: e.from,
786
823
  to: e.to,
787
824
  type: e.type,
788
825
  sourceHandle: e.sourceHandle,
789
826
  targetHandle: e.targetHandle,
790
827
  })),
791
- deletedEdges: state.deletedEdges.map(e => ({ from: e.from, to: e.to, type: e.type })),
828
+ deletedEdges: state.deletedEdges.map((e) => ({ from: e.from, to: e.to, type: e.type })),
792
829
  hasChanges: state.positionChanges.size > 0 ||
793
830
  state.nodeUpdates.size > 0 ||
794
831
  state.deletedNodeIds.size > 0 ||
@@ -801,13 +838,26 @@ exports.GraphRenderer = (0, react_1.forwardRef)((props, ref) => {
801
838
  },
802
839
  hasUnsavedChanges: () => {
803
840
  const state = editStateRef.current;
804
- return state.positionChanges.size > 0 ||
841
+ return (state.positionChanges.size > 0 ||
805
842
  state.nodeUpdates.size > 0 ||
806
843
  state.deletedNodeIds.size > 0 ||
807
844
  state.createdEdges.length > 0 ||
808
- state.deletedEdges.length > 0;
845
+ state.deletedEdges.length > 0);
809
846
  },
810
847
  }), []);
848
+ // Validate we have required data
849
+ if (!canvasData) {
850
+ return ((0, jsx_runtime_1.jsx)("div", { className: className, style: {
851
+ width,
852
+ height,
853
+ display: 'flex',
854
+ alignItems: 'center',
855
+ justifyContent: 'center',
856
+ backgroundColor: theme.colors.background,
857
+ color: theme.colors.textSecondary,
858
+ }, children: (0, jsx_runtime_1.jsx)("p", { children: "No canvas data provided." }) }));
859
+ }
860
+ const { configuration, nodes, edges } = canvasData;
811
861
  // Extract only the props that inner component needs
812
862
  const { violations, configName, showMinimap, showControls, showBackground, events, onEventProcessed, editable, onPendingChangesChange, } = props;
813
863
  return ((0, jsx_runtime_1.jsx)("div", { className: className, style: { width, height, position: 'relative' }, children: (0, jsx_runtime_1.jsx)(react_2.ReactFlowProvider, { children: (0, jsx_runtime_1.jsx)(GraphRendererInner, { configuration: configuration, nodes: nodes, edges: edges, violations: violations, configName: configName, showMinimap: showMinimap, showControls: showControls, showBackground: showBackground, events: events, onEventProcessed: onEventProcessed, editable: editable, onPendingChangesChange: onPendingChangesChange, editStateRef: editStateRef }) }) }));