@principal-ai/principal-view-react 0.6.9 → 0.6.11

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 (64) 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 +135 -82
  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.map +1 -1
  14. package/dist/edges/CustomEdge.js +2 -2
  15. package/dist/edges/CustomEdge.js.map +1 -1
  16. package/dist/edges/GenericEdge.d.ts.map +1 -1
  17. package/dist/edges/GenericEdge.js +2 -2
  18. package/dist/edges/GenericEdge.js.map +1 -1
  19. package/dist/hooks/usePathBasedEvents.d.ts +1 -1
  20. package/dist/hooks/usePathBasedEvents.d.ts.map +1 -1
  21. package/dist/hooks/usePathBasedEvents.js +9 -9
  22. package/dist/hooks/usePathBasedEvents.js.map +1 -1
  23. package/dist/index.d.ts +2 -2
  24. package/dist/index.d.ts.map +1 -1
  25. package/dist/index.js.map +1 -1
  26. package/dist/nodes/CustomNode.d.ts.map +1 -1
  27. package/dist/nodes/CustomNode.js +61 -44
  28. package/dist/nodes/CustomNode.js.map +1 -1
  29. package/dist/nodes/GenericNode.d.ts.map +1 -1
  30. package/dist/nodes/GenericNode.js.map +1 -1
  31. package/dist/utils/animationMapping.d.ts.map +1 -1
  32. package/dist/utils/animationMapping.js +12 -12
  33. package/dist/utils/animationMapping.js.map +1 -1
  34. package/dist/utils/graphConverter.d.ts.map +1 -1
  35. package/dist/utils/graphConverter.js +23 -17
  36. package/dist/utils/graphConverter.js.map +1 -1
  37. package/dist/utils/iconResolver.d.ts.map +1 -1
  38. package/dist/utils/iconResolver.js +1 -1
  39. package/dist/utils/iconResolver.js.map +1 -1
  40. package/package.json +2 -1
  41. package/src/components/ConfigurationSelector.tsx +5 -5
  42. package/src/components/EdgeInfoPanel.tsx +79 -37
  43. package/src/components/GraphRenderer.tsx +528 -364
  44. package/src/components/NodeInfoPanel.tsx +209 -86
  45. package/src/edges/CustomEdge.tsx +6 -4
  46. package/src/edges/GenericEdge.tsx +2 -6
  47. package/src/hooks/usePathBasedEvents.ts +54 -45
  48. package/src/index.ts +11 -2
  49. package/src/nodes/CustomNode.tsx +132 -106
  50. package/src/nodes/GenericNode.tsx +4 -3
  51. package/src/stories/AnimationWorkshop.stories.tsx +131 -12
  52. package/src/stories/CanvasNodeTypes.stories.tsx +898 -0
  53. package/src/stories/ColorPriority.stories.tsx +20 -10
  54. package/src/stories/EventDrivenAnimations.stories.tsx +8 -0
  55. package/src/stories/EventLog.stories.tsx +1 -1
  56. package/src/stories/GraphRenderer.stories.tsx +23 -10
  57. package/src/stories/IndustryThemes.stories.tsx +481 -0
  58. package/src/stories/MultiConfig.stories.tsx +8 -0
  59. package/src/stories/MultiDirectionalConnections.stories.tsx +8 -0
  60. package/src/stories/NodeFieldsAudit.stories.tsx +124 -37
  61. package/src/stories/NodeShapes.stories.tsx +73 -59
  62. package/src/utils/animationMapping.ts +19 -23
  63. package/src/utils/graphConverter.ts +35 -19
  64. package/src/utils/iconResolver.tsx +5 -1
@@ -1,17 +1,57 @@
1
1
  import React, { useState } from 'react';
2
2
  import type { NodeState, NodeTypeDefinition } from '@principal-ai/principal-view-core';
3
+ import { useTheme } from '@principal-ade/industry-theme';
3
4
  import { resolveIcon } from '../utils/iconResolver';
4
5
 
5
6
  // Common icons for the icon selector
6
7
  const COMMON_ICONS = [
7
- 'Settings', 'Database', 'Package', 'Server', 'Cloud', 'Globe',
8
- 'File', 'Folder', 'Code', 'Terminal', 'Cpu', 'HardDrive',
9
- 'Network', 'Wifi', 'Lock', 'Unlock', 'Key', 'Shield',
10
- 'User', 'Users', 'Mail', 'MessageSquare', 'Bell', 'Calendar',
11
- 'Clock', 'Timer', 'Zap', 'Activity', 'BarChart', 'PieChart',
12
- 'CheckCircle', 'XCircle', 'AlertCircle', 'Info', 'HelpCircle',
13
- 'Play', 'Pause', 'Square', 'Circle', 'Triangle', 'Hexagon',
14
- 'Box', 'Layers', 'GitBranch', 'GitCommit', 'GitMerge', 'GitPullRequest',
8
+ 'Settings',
9
+ 'Database',
10
+ 'Package',
11
+ 'Server',
12
+ 'Cloud',
13
+ 'Globe',
14
+ 'File',
15
+ 'Folder',
16
+ 'Code',
17
+ 'Terminal',
18
+ 'Cpu',
19
+ 'HardDrive',
20
+ 'Network',
21
+ 'Wifi',
22
+ 'Lock',
23
+ 'Unlock',
24
+ 'Key',
25
+ 'Shield',
26
+ 'User',
27
+ 'Users',
28
+ 'Mail',
29
+ 'MessageSquare',
30
+ 'Bell',
31
+ 'Calendar',
32
+ 'Clock',
33
+ 'Timer',
34
+ 'Zap',
35
+ 'Activity',
36
+ 'BarChart',
37
+ 'PieChart',
38
+ 'CheckCircle',
39
+ 'XCircle',
40
+ 'AlertCircle',
41
+ 'Info',
42
+ 'HelpCircle',
43
+ 'Play',
44
+ 'Pause',
45
+ 'Square',
46
+ 'Circle',
47
+ 'Triangle',
48
+ 'Hexagon',
49
+ 'Box',
50
+ 'Layers',
51
+ 'GitBranch',
52
+ 'GitCommit',
53
+ 'GitMerge',
54
+ 'GitPullRequest',
15
55
  ];
16
56
 
17
57
  export interface NodeInfoPanelProps {
@@ -37,7 +77,10 @@ export const NodeInfoPanel: React.FC<NodeInfoPanelProps> = ({
37
77
  onDelete,
38
78
  onUpdate,
39
79
  }) => {
40
- const color = typeDefinition?.color || '#888';
80
+ const { theme } = useTheme();
81
+
82
+ // Color priority: node data color > type definition color > theme primary
83
+ const nodeColor = (node.data?.color as string) || typeDefinition?.color || theme.colors.primary;
41
84
  const canEdit = Boolean(onUpdate);
42
85
 
43
86
  // Local state for UI
@@ -65,7 +108,29 @@ export const NodeInfoPanel: React.FC<NodeInfoPanelProps> = ({
65
108
 
66
109
  // Always show basic node data if no schema is defined
67
110
  const hasSchemaFields = displayFields.length > 0;
68
- const nodeDataEntries = node.data ? Object.entries(node.data).filter(([key]) => !['icon', 'name', 'description', 'sources'].includes(key)) : [];
111
+ // Internal fields that should not be displayed in the popup
112
+ const internalFields = [
113
+ 'icon',
114
+ 'name',
115
+ 'description',
116
+ 'sources',
117
+ 'color',
118
+ 'stroke',
119
+ 'width',
120
+ 'height',
121
+ 'canvasType',
122
+ 'text',
123
+ 'file',
124
+ 'url',
125
+ 'shape',
126
+ 'states',
127
+ 'actions',
128
+ 'nodeType',
129
+ ];
130
+
131
+ const nodeDataEntries = node.data
132
+ ? Object.entries(node.data).filter(([key]) => !internalFields.includes(key))
133
+ : [];
69
134
 
70
135
  // Get sources from node data
71
136
  const sources = (node.data?.sources as string[]) || [];
@@ -91,26 +156,30 @@ export const NodeInfoPanel: React.FC<NodeInfoPanelProps> = ({
91
156
  position: 'absolute',
92
157
  top: '60px',
93
158
  right: '20px',
94
- backgroundColor: 'white',
159
+ backgroundColor: theme.colors.background,
160
+ color: theme.colors.text,
95
161
  borderRadius: '8px',
96
162
  boxShadow: '0 4px 12px rgba(0,0,0,0.15)',
97
163
  padding: '16px',
98
164
  minWidth: '250px',
99
165
  maxWidth: '350px',
100
166
  zIndex: 1000,
167
+ border: `1px solid ${theme.colors.border}`,
101
168
  }}
102
169
  >
103
170
  {/* Header - shows node name */}
104
- <div style={{
105
- display: 'flex',
106
- justifyContent: 'space-between',
107
- alignItems: 'center',
108
- marginBottom: '12px',
109
- paddingBottom: '8px',
110
- borderBottom: `2px solid ${color}`,
111
- }}>
112
- <div style={{ fontWeight: 'bold', fontSize: '14px' }}>
113
- {node.data?.name || node.id}
171
+ <div
172
+ style={{
173
+ display: 'flex',
174
+ justifyContent: 'space-between',
175
+ alignItems: 'center',
176
+ marginBottom: '12px',
177
+ paddingBottom: '8px',
178
+ borderBottom: `2px solid ${nodeColor}`,
179
+ }}
180
+ >
181
+ <div style={{ fontWeight: 'bold', fontSize: '14px', color: nodeColor }}>
182
+ {node.name || node.id}
114
183
  </div>
115
184
  <button
116
185
  onClick={onClose}
@@ -119,7 +188,7 @@ export const NodeInfoPanel: React.FC<NodeInfoPanelProps> = ({
119
188
  background: 'none',
120
189
  cursor: 'pointer',
121
190
  fontSize: '18px',
122
- color: '#666',
191
+ color: theme.colors.textSecondary,
123
192
  padding: '0',
124
193
  width: '24px',
125
194
  height: '24px',
@@ -135,22 +204,17 @@ export const NodeInfoPanel: React.FC<NodeInfoPanelProps> = ({
135
204
  {/* Description - first field under header */}
136
205
  {node.data?.description && (
137
206
  <div style={{ marginBottom: '12px' }}>
138
- <div style={{ fontSize: '10px', color: '#666', marginBottom: '4px' }}>
207
+ <div style={{ fontSize: '10px', color: theme.colors.textSecondary, marginBottom: '4px' }}>
139
208
  Description
140
209
  </div>
141
- <div style={{
142
- fontSize: '12px',
143
- color: '#333',
144
- }}>
145
- {String(node.data.description)}
146
- </div>
210
+ <div style={{ fontSize: '12px' }}>{String(node.data.description)}</div>
147
211
  </div>
148
212
  )}
149
213
 
150
214
  {/* Sources - shown after description */}
151
215
  {sources.length > 0 && (
152
216
  <div style={{ marginBottom: '12px' }}>
153
- <div style={{ fontSize: '10px', color: '#666', marginBottom: '4px' }}>
217
+ <div style={{ fontSize: '10px', color: theme.colors.textSecondary, marginBottom: '4px' }}>
154
218
  Sources
155
219
  </div>
156
220
  <div style={{ display: 'flex', flexWrap: 'wrap', gap: '4px' }}>
@@ -160,9 +224,9 @@ export const NodeInfoPanel: React.FC<NodeInfoPanelProps> = ({
160
224
  style={{
161
225
  fontSize: '11px',
162
226
  padding: '2px 8px',
163
- backgroundColor: '#f0f0f0',
227
+ backgroundColor: theme.colors.muted,
164
228
  borderRadius: '4px',
165
- color: '#555',
229
+ color: theme.colors.textSecondary,
166
230
  }}
167
231
  >
168
232
  {source}
@@ -178,12 +242,12 @@ export const NodeInfoPanel: React.FC<NodeInfoPanelProps> = ({
178
242
  style={{
179
243
  width: '100%',
180
244
  padding: '8px',
181
- backgroundColor: '#f5f5f5',
182
- border: '1px solid #ddd',
245
+ backgroundColor: theme.colors.surface,
246
+ border: `1px solid ${theme.colors.border}`,
183
247
  borderRadius: '4px',
184
248
  cursor: 'pointer',
185
249
  fontSize: '12px',
186
- color: '#666',
250
+ color: theme.colors.textSecondary,
187
251
  display: 'flex',
188
252
  alignItems: 'center',
189
253
  justifyContent: 'center',
@@ -191,7 +255,12 @@ export const NodeInfoPanel: React.FC<NodeInfoPanelProps> = ({
191
255
  marginBottom: showDetails ? '12px' : '0',
192
256
  }}
193
257
  >
194
- <span style={{ transform: showDetails ? 'rotate(180deg)' : 'rotate(0deg)', transition: 'transform 0.2s' }}>
258
+ <span
259
+ style={{
260
+ transform: showDetails ? 'rotate(180deg)' : 'rotate(0deg)',
261
+ transition: 'transform 0.2s',
262
+ }}
263
+ >
195
264
 
196
265
  </span>
197
266
  {showDetails ? 'Hide Details' : 'Show Details'}
@@ -202,7 +271,7 @@ export const NodeInfoPanel: React.FC<NodeInfoPanelProps> = ({
202
271
  <>
203
272
  {/* Icon Selector */}
204
273
  <div style={{ marginBottom: '12px' }}>
205
- <div style={{ fontSize: '10px', color: '#666', marginBottom: '4px' }}>
274
+ <div style={{ fontSize: '10px', color: theme.colors.textSecondary, marginBottom: '4px' }}>
206
275
  Icon
207
276
  </div>
208
277
  <div style={{ position: 'relative' }}>
@@ -214,20 +283,27 @@ export const NodeInfoPanel: React.FC<NodeInfoPanelProps> = ({
214
283
  alignItems: 'center',
215
284
  gap: '8px',
216
285
  padding: '6px 10px',
217
- backgroundColor: '#f5f5f5',
218
- border: canEdit ? '1px dashed #ccc' : '1px solid #eee',
286
+ backgroundColor: theme.colors.surface,
287
+ border: canEdit
288
+ ? `1px dashed ${theme.colors.border}`
289
+ : `1px solid ${theme.colors.border}`,
219
290
  borderRadius: '4px',
220
291
  cursor: canEdit ? 'pointer' : 'default',
221
292
  fontSize: '12px',
222
293
  width: '100%',
223
294
  justifyContent: 'flex-start',
295
+ color: theme.colors.text,
224
296
  }}
225
297
  >
226
298
  <span style={{ display: 'flex', alignItems: 'center' }}>
227
299
  {resolveIcon(currentIcon, 18)}
228
300
  </span>
229
301
  <span>{currentIcon || 'No icon'}</span>
230
- {canEdit && <span style={{ marginLeft: 'auto', color: '#999', fontSize: '10px' }}>✎</span>}
302
+ {canEdit && (
303
+ <span style={{ marginLeft: 'auto', color: theme.colors.textMuted, fontSize: '10px' }}>
304
+
305
+ </span>
306
+ )}
231
307
  </button>
232
308
 
233
309
  {/* Icon Picker Dropdown */}
@@ -239,8 +315,8 @@ export const NodeInfoPanel: React.FC<NodeInfoPanelProps> = ({
239
315
  left: 0,
240
316
  right: 0,
241
317
  marginTop: '4px',
242
- backgroundColor: 'white',
243
- border: '1px solid #ddd',
318
+ backgroundColor: theme.colors.background,
319
+ border: `1px solid ${theme.colors.border}`,
244
320
  borderRadius: '4px',
245
321
  boxShadow: '0 4px 12px rgba(0,0,0,0.15)',
246
322
  padding: '8px',
@@ -256,20 +332,25 @@ export const NodeInfoPanel: React.FC<NodeInfoPanelProps> = ({
256
332
  gap: '4px',
257
333
  }}
258
334
  >
259
- {COMMON_ICONS.map(iconName => (
335
+ {COMMON_ICONS.map((iconName) => (
260
336
  <button
261
337
  key={iconName}
262
338
  onClick={() => handleIconSelect(iconName)}
263
339
  title={iconName}
264
340
  style={{
265
341
  padding: '6px',
266
- border: currentIcon === iconName ? `2px solid ${color}` : '1px solid #eee',
342
+ border:
343
+ currentIcon === iconName
344
+ ? `2px solid ${nodeColor}`
345
+ : `1px solid ${theme.colors.border}`,
267
346
  borderRadius: '4px',
268
- backgroundColor: currentIcon === iconName ? '#f0f7ff' : 'white',
347
+ backgroundColor:
348
+ currentIcon === iconName ? theme.colors.highlight : theme.colors.background,
269
349
  cursor: 'pointer',
270
350
  display: 'flex',
271
351
  alignItems: 'center',
272
352
  justifyContent: 'center',
353
+ color: theme.colors.text,
273
354
  }}
274
355
  >
275
356
  {resolveIcon(iconName, 16)}
@@ -283,7 +364,7 @@ export const NodeInfoPanel: React.FC<NodeInfoPanelProps> = ({
283
364
 
284
365
  {/* Node Type - Editable if availableNodeTypes provided */}
285
366
  <div style={{ marginBottom: '12px' }}>
286
- <div style={{ fontSize: '10px', color: '#666', marginBottom: '4px' }}>
367
+ <div style={{ fontSize: '10px', color: theme.colors.textSecondary, marginBottom: '4px' }}>
287
368
  Type
288
369
  </div>
289
370
  {canEdit && availableNodeTypes && Object.keys(availableNodeTypes).length > 1 ? (
@@ -294,8 +375,9 @@ export const NodeInfoPanel: React.FC<NodeInfoPanelProps> = ({
294
375
  fontSize: '12px',
295
376
  padding: '4px 8px',
296
377
  borderRadius: '4px',
297
- border: '1px solid #ccc',
298
- backgroundColor: 'white',
378
+ border: `1px solid ${theme.colors.border}`,
379
+ backgroundColor: theme.colors.background,
380
+ color: theme.colors.text,
299
381
  cursor: 'pointer',
300
382
  width: '100%',
301
383
  }}
@@ -307,14 +389,16 @@ export const NodeInfoPanel: React.FC<NodeInfoPanelProps> = ({
307
389
  ))}
308
390
  </select>
309
391
  ) : (
310
- <div style={{
311
- fontSize: '12px',
312
- padding: '4px 8px',
313
- backgroundColor: color,
314
- color: 'white',
315
- borderRadius: '4px',
316
- display: 'inline-block',
317
- }}>
392
+ <div
393
+ style={{
394
+ fontSize: '12px',
395
+ padding: '4px 8px',
396
+ backgroundColor: nodeColor,
397
+ color: theme.colors.background,
398
+ borderRadius: '4px',
399
+ display: 'inline-block',
400
+ }}
401
+ >
318
402
  {node.type}
319
403
  </div>
320
404
  )}
@@ -323,57 +407,88 @@ export const NodeInfoPanel: React.FC<NodeInfoPanelProps> = ({
323
407
  {/* Node State */}
324
408
  {node.state && (
325
409
  <div style={{ marginBottom: '12px' }}>
326
- <div style={{ fontSize: '10px', color: '#666', marginBottom: '4px' }}>
410
+ <div style={{ fontSize: '10px', color: theme.colors.textSecondary, marginBottom: '4px' }}>
327
411
  State
328
412
  </div>
329
- <div style={{
330
- fontSize: '12px',
331
- padding: '4px 8px',
332
- backgroundColor: typeDefinition?.states?.[node.state]?.color || '#888',
333
- color: 'white',
334
- borderRadius: '4px',
335
- display: 'inline-block',
336
- }}>
413
+ <div
414
+ style={{
415
+ fontSize: '12px',
416
+ padding: '4px 8px',
417
+ backgroundColor:
418
+ typeDefinition?.states?.[node.state]?.color || theme.colors.secondary,
419
+ color: theme.colors.background,
420
+ borderRadius: '4px',
421
+ display: 'inline-block',
422
+ }}
423
+ >
337
424
  {typeDefinition?.states?.[node.state]?.label || node.state}
338
425
  </div>
339
426
  </div>
340
427
  )}
341
428
 
342
429
  {/* Display other schema-defined fields (non-editable for now) */}
343
- {hasSchemaFields && displayFields.filter(f => f.field !== nameField).length > 0 && (
430
+ {hasSchemaFields && displayFields.filter((f) => f.field !== nameField).length > 0 && (
344
431
  <div style={{ marginBottom: '12px' }}>
345
- <div style={{ fontSize: '10px', color: '#666', marginBottom: '8px', fontWeight: 'bold' }}>
432
+ <div
433
+ style={{
434
+ fontSize: '10px',
435
+ color: theme.colors.textSecondary,
436
+ marginBottom: '8px',
437
+ fontWeight: 'bold',
438
+ }}
439
+ >
346
440
  Properties
347
441
  </div>
348
- {displayFields.filter(f => f.field !== nameField).map(({ field, label, value }) => (
349
- <div key={field} style={{ marginBottom: '8px' }}>
350
- <div style={{ fontSize: '10px', color: '#666', marginBottom: '2px' }}>
351
- {label}
352
- </div>
353
- <div style={{ fontSize: '12px', color: '#333' }}>
354
- {value !== undefined && value !== null
355
- ? typeof value === 'object'
356
- ? JSON.stringify(value, null, 2)
357
- : String(value)
358
- : '-'}
442
+ {displayFields
443
+ .filter((f) => f.field !== nameField)
444
+ .map(({ field, label, value }) => (
445
+ <div key={field} style={{ marginBottom: '8px' }}>
446
+ <div
447
+ style={{
448
+ fontSize: '10px',
449
+ color: theme.colors.textSecondary,
450
+ marginBottom: '2px',
451
+ }}
452
+ >
453
+ {label}
454
+ </div>
455
+ <div style={{ fontSize: '12px' }}>
456
+ {value !== undefined && value !== null
457
+ ? typeof value === 'object'
458
+ ? JSON.stringify(value, null, 2)
459
+ : String(value)
460
+ : '-'}
461
+ </div>
359
462
  </div>
360
- </div>
361
- ))}
463
+ ))}
362
464
  </div>
363
465
  )}
364
466
 
365
467
  {/* Show all node data if no schema is defined */}
366
468
  {!hasSchemaFields && nodeDataEntries.length > 0 && (
367
469
  <div style={{ marginBottom: '12px' }}>
368
- <div style={{ fontSize: '10px', color: '#666', marginBottom: '8px', fontWeight: 'bold' }}>
470
+ <div
471
+ style={{
472
+ fontSize: '10px',
473
+ color: theme.colors.textSecondary,
474
+ marginBottom: '8px',
475
+ fontWeight: 'bold',
476
+ }}
477
+ >
369
478
  Data
370
479
  </div>
371
480
  {nodeDataEntries.map(([key, value]) => (
372
481
  <div key={key} style={{ marginBottom: '8px' }}>
373
- <div style={{ fontSize: '10px', color: '#666', marginBottom: '2px' }}>
482
+ <div
483
+ style={{
484
+ fontSize: '10px',
485
+ color: theme.colors.textSecondary,
486
+ marginBottom: '2px',
487
+ }}
488
+ >
374
489
  {key}
375
490
  </div>
376
- <div style={{ fontSize: '12px', color: '#333', wordBreak: 'break-word' }}>
491
+ <div style={{ fontSize: '12px', wordBreak: 'break-word' }}>
377
492
  {value !== undefined && value !== null
378
493
  ? typeof value === 'object'
379
494
  ? JSON.stringify(value, null, 2)
@@ -386,7 +501,15 @@ export const NodeInfoPanel: React.FC<NodeInfoPanelProps> = ({
386
501
  )}
387
502
 
388
503
  {/* Metadata */}
389
- <div style={{ fontSize: '10px', color: '#999', marginTop: '12px', paddingTop: '8px', borderTop: '1px solid #eee' }}>
504
+ <div
505
+ style={{
506
+ fontSize: '10px',
507
+ color: theme.colors.textMuted,
508
+ marginTop: '12px',
509
+ paddingTop: '8px',
510
+ borderTop: `1px solid ${theme.colors.border}`,
511
+ }}
512
+ >
390
513
  ID: {node.id}
391
514
  </div>
392
515
  </>
@@ -403,8 +526,8 @@ export const NodeInfoPanel: React.FC<NodeInfoPanelProps> = ({
403
526
  marginTop: '12px',
404
527
  width: '100%',
405
528
  padding: '8px 12px',
406
- backgroundColor: '#dc3545',
407
- color: 'white',
529
+ backgroundColor: theme.colors.error,
530
+ color: theme.colors.background,
408
531
  border: 'none',
409
532
  borderRadius: '4px',
410
533
  cursor: 'pointer',
@@ -36,7 +36,7 @@ export const CustomEdge: React.FC<EdgeProps<any>> = ({
36
36
  data: edgeData,
37
37
  animationType,
38
38
  animationDuration = 1000,
39
- animationDirection = 'forward'
39
+ animationDirection = 'forward',
40
40
  } = edgeProps || ({} as CustomEdgeData);
41
41
 
42
42
  const [particlePosition, setParticlePosition] = useState(0);
@@ -64,7 +64,7 @@ export const CustomEdge: React.FC<EdgeProps<any>> = ({
64
64
 
65
65
  // Color priority: violations > edge data color > type definition color > default
66
66
  const edgeColor = edgeData?.color as string | undefined;
67
- const color = hasViolations ? '#D0021B' : (edgeColor || typeDefinition.color || '#888');
67
+ const color = hasViolations ? '#D0021B' : edgeColor || typeDefinition.color || '#888';
68
68
  const width = typeDefinition.width || 2;
69
69
 
70
70
  // Get Bezier path
@@ -127,7 +127,8 @@ export const CustomEdge: React.FC<EdgeProps<any>> = ({
127
127
  const getParticleTransform = () => {
128
128
  if (!pathRef.current) {
129
129
  // Fallback to linear interpolation if path ref not available yet
130
- const progress = animationDirection === 'backward' ? 1 - particlePosition / 100 : particlePosition / 100;
130
+ const progress =
131
+ animationDirection === 'backward' ? 1 - particlePosition / 100 : particlePosition / 100;
131
132
  const x = sourceX + (targetX - sourceX) * progress;
132
133
  const y = sourceY + (targetY - sourceY) * progress;
133
134
  return { x, y };
@@ -135,7 +136,8 @@ export const CustomEdge: React.FC<EdgeProps<any>> = ({
135
136
 
136
137
  // Use actual path to get point along the curve
137
138
  const pathLength = pathRef.current.getTotalLength();
138
- const progress = animationDirection === 'backward' ? 1 - particlePosition / 100 : particlePosition / 100;
139
+ const progress =
140
+ animationDirection === 'backward' ? 1 - particlePosition / 100 : particlePosition / 100;
139
141
  const distance = pathLength * progress;
140
142
  const point = pathRef.current.getPointAtLength(distance);
141
143
 
@@ -19,12 +19,8 @@ export interface GenericEdgeProps {
19
19
  * Generic edge renderer that adapts based on EdgeTypeDefinition
20
20
  * TODO: Implement different styles, animations, and labels
21
21
  */
22
- export const GenericEdge: React.FC<GenericEdgeProps> = ({
23
- id,
24
- typeDefinition,
25
- hasViolations,
26
- }) => {
27
- const color = hasViolations ? 'red' : (typeDefinition.color || '#888');
22
+ export const GenericEdge: React.FC<GenericEdgeProps> = ({ id, typeDefinition, hasViolations }) => {
23
+ const color = hasViolations ? 'red' : typeDefinition.color || '#888';
28
24
 
29
25
  return (
30
26
  <div>