@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
@@ -0,0 +1,898 @@
1
+ import React from 'react';
2
+ import type { Meta, StoryObj } from '@storybook/react';
3
+ import { GraphRenderer } from '../components/GraphRenderer';
4
+ import type { ExtendedCanvas } from '@principal-ai/principal-view-core';
5
+ import { ThemeProvider, defaultEditorTheme } from '@principal-ade/industry-theme';
6
+
7
+ const meta = {
8
+ title: 'Audit/CanvasNodeTypes',
9
+ component: GraphRenderer,
10
+ parameters: {
11
+ layout: 'centered',
12
+ },
13
+ tags: ['autodocs'],
14
+ decorators: [
15
+ (Story) => (
16
+ <ThemeProvider theme={defaultEditorTheme}>
17
+ <Story />
18
+ </ThemeProvider>
19
+ ),
20
+ ],
21
+ } satisfies Meta<typeof GraphRenderer>;
22
+
23
+ export default meta;
24
+ type Story = StoryObj<typeof meta>;
25
+
26
+ /**
27
+ * Canvas showing all standard JSON Canvas node types
28
+ */
29
+ const allNodeTypesCanvas: ExtendedCanvas = {
30
+ nodes: [
31
+ // Text Node
32
+ {
33
+ id: 'text-node',
34
+ type: 'text',
35
+ x: 100,
36
+ y: 100,
37
+ width: 180,
38
+ height: 100,
39
+ text: '# Text Node\n\nMarkdown content here',
40
+ color: 6, // purple
41
+ pv: {
42
+ nodeType: 'text-example',
43
+ shape: 'rectangle',
44
+ icon: 'FileText',
45
+ },
46
+ },
47
+ // File Node
48
+ {
49
+ id: 'file-node',
50
+ type: 'file',
51
+ x: 350,
52
+ y: 100,
53
+ width: 180,
54
+ height: 100,
55
+ file: 'src/components/App.tsx',
56
+ color: 4, // green
57
+ pv: {
58
+ nodeType: 'file-example',
59
+ shape: 'rectangle',
60
+ icon: 'FileCode',
61
+ },
62
+ },
63
+ // Link Node
64
+ {
65
+ id: 'link-node',
66
+ type: 'link',
67
+ x: 600,
68
+ y: 100,
69
+ width: 180,
70
+ height: 100,
71
+ url: 'https://github.com/example/repo',
72
+ color: 5, // cyan
73
+ pv: {
74
+ nodeType: 'link-example',
75
+ shape: 'rectangle',
76
+ icon: 'Link',
77
+ },
78
+ },
79
+ // Group Node (rendered as container)
80
+ {
81
+ id: 'group-node',
82
+ type: 'group',
83
+ x: 100,
84
+ y: 280,
85
+ width: 300,
86
+ height: 150,
87
+ label: 'Group Container',
88
+ color: 3, // yellow
89
+ pv: {
90
+ nodeType: 'group-example',
91
+ shape: 'rectangle',
92
+ icon: 'Folder',
93
+ },
94
+ },
95
+ // Text node inside group
96
+ {
97
+ id: 'grouped-text',
98
+ type: 'text',
99
+ x: 130,
100
+ y: 320,
101
+ width: 120,
102
+ height: 60,
103
+ text: 'Inside Group',
104
+ color: 6,
105
+ pv: {
106
+ nodeType: 'grouped-item',
107
+ shape: 'rectangle',
108
+ },
109
+ },
110
+ ],
111
+ edges: [],
112
+ pv: {
113
+ version: '1.0.0',
114
+ name: 'Canvas Node Types',
115
+ description: 'All standard JSON Canvas node types',
116
+ edgeTypes: {},
117
+ },
118
+ };
119
+
120
+ export const AllNodeTypes: Story = {
121
+ args: {
122
+ canvas: allNodeTypesCanvas,
123
+ width: 900,
124
+ height: 500,
125
+ },
126
+ parameters: {
127
+ docs: {
128
+ description: {
129
+ story: `
130
+ **All JSON Canvas Node Types**
131
+
132
+ This story displays the 4 standard JSON Canvas node types:
133
+
134
+ - **Text Node** - Contains markdown text content (\`text\` field)
135
+ - **File Node** - References a file path (\`file\` field)
136
+ - **Link Node** - References a URL (\`url\` field)
137
+ - **Group Node** - Container for grouping other nodes (\`label\` field)
138
+ `,
139
+ },
140
+ },
141
+ },
142
+ };
143
+
144
+ /**
145
+ * Canvas showing text nodes with different content types
146
+ */
147
+ const textNodesCanvas: ExtendedCanvas = {
148
+ nodes: [
149
+ {
150
+ id: 'text-plain',
151
+ type: 'text',
152
+ x: 100,
153
+ y: 100,
154
+ width: 160,
155
+ height: 80,
156
+ text: 'Plain text content',
157
+ color: 6,
158
+ pv: {
159
+ nodeType: 'text-plain',
160
+ shape: 'rectangle',
161
+ icon: 'Type',
162
+ },
163
+ },
164
+ {
165
+ id: 'text-heading',
166
+ type: 'text',
167
+ x: 300,
168
+ y: 100,
169
+ width: 160,
170
+ height: 80,
171
+ text: '# Heading\n\nWith paragraph',
172
+ color: 6,
173
+ pv: {
174
+ nodeType: 'text-heading',
175
+ shape: 'rectangle',
176
+ icon: 'Heading',
177
+ },
178
+ },
179
+ {
180
+ id: 'text-list',
181
+ type: 'text',
182
+ x: 500,
183
+ y: 100,
184
+ width: 180,
185
+ height: 100,
186
+ text: '# Todo List\n\n- Item 1\n- Item 2\n- Item 3',
187
+ color: 6,
188
+ pv: {
189
+ nodeType: 'text-list',
190
+ shape: 'rectangle',
191
+ icon: 'List',
192
+ },
193
+ },
194
+ {
195
+ id: 'text-code',
196
+ type: 'text',
197
+ x: 100,
198
+ y: 240,
199
+ width: 200,
200
+ height: 100,
201
+ text: '# Code Block\n\n```js\nconst x = 1;\n```',
202
+ color: 6,
203
+ pv: {
204
+ nodeType: 'text-code',
205
+ shape: 'rectangle',
206
+ icon: 'Code',
207
+ },
208
+ },
209
+ {
210
+ id: 'text-long',
211
+ type: 'text',
212
+ x: 340,
213
+ y: 240,
214
+ width: 220,
215
+ height: 120,
216
+ text: '# Long Content\n\nThis is a longer text node with multiple paragraphs.\n\nIt demonstrates how text wraps within the node bounds.',
217
+ color: 6,
218
+ pv: {
219
+ nodeType: 'text-long',
220
+ shape: 'rectangle',
221
+ icon: 'AlignLeft',
222
+ },
223
+ },
224
+ ],
225
+ edges: [],
226
+ pv: {
227
+ version: '1.0.0',
228
+ name: 'Text Node Variations',
229
+ description: 'Different text content types',
230
+ edgeTypes: {},
231
+ },
232
+ };
233
+
234
+ export const TextNodes: Story = {
235
+ args: {
236
+ canvas: textNodesCanvas,
237
+ width: 800,
238
+ height: 420,
239
+ },
240
+ parameters: {
241
+ docs: {
242
+ description: {
243
+ story: `
244
+ **Text Node Variations**
245
+
246
+ Text nodes (\`type: 'text'\`) can contain various markdown content:
247
+ - Plain text
248
+ - Headings with paragraphs
249
+ - Lists
250
+ - Code blocks
251
+ - Long multi-paragraph content
252
+ `,
253
+ },
254
+ },
255
+ },
256
+ };
257
+
258
+ /**
259
+ * Canvas showing file nodes with different file types
260
+ */
261
+ const fileNodesCanvas: ExtendedCanvas = {
262
+ nodes: [
263
+ {
264
+ id: 'file-ts',
265
+ type: 'file',
266
+ x: 100,
267
+ y: 100,
268
+ width: 180,
269
+ height: 80,
270
+ file: 'src/index.ts',
271
+ color: 4,
272
+ pv: {
273
+ nodeType: 'file-typescript',
274
+ shape: 'rectangle',
275
+ icon: 'FileCode',
276
+ },
277
+ },
278
+ {
279
+ id: 'file-tsx',
280
+ type: 'file',
281
+ x: 320,
282
+ y: 100,
283
+ width: 200,
284
+ height: 80,
285
+ file: 'src/components/App.tsx',
286
+ color: 5,
287
+ pv: {
288
+ nodeType: 'file-react',
289
+ shape: 'rectangle',
290
+ icon: 'Component',
291
+ },
292
+ },
293
+ {
294
+ id: 'file-json',
295
+ type: 'file',
296
+ x: 560,
297
+ y: 100,
298
+ width: 160,
299
+ height: 80,
300
+ file: 'package.json',
301
+ color: 3,
302
+ pv: {
303
+ nodeType: 'file-json',
304
+ shape: 'rectangle',
305
+ icon: 'Braces',
306
+ },
307
+ },
308
+ {
309
+ id: 'file-md',
310
+ type: 'file',
311
+ x: 100,
312
+ y: 220,
313
+ width: 160,
314
+ height: 80,
315
+ file: 'docs/README.md',
316
+ color: 6,
317
+ pv: {
318
+ nodeType: 'file-markdown',
319
+ shape: 'rectangle',
320
+ icon: 'BookOpen',
321
+ },
322
+ },
323
+ {
324
+ id: 'file-subpath',
325
+ type: 'file',
326
+ x: 300,
327
+ y: 220,
328
+ width: 220,
329
+ height: 100,
330
+ file: 'docs/architecture.md',
331
+ subpath: '#database-schema',
332
+ color: 6,
333
+ pv: {
334
+ nodeType: 'file-with-subpath',
335
+ shape: 'rectangle',
336
+ icon: 'Hash',
337
+ },
338
+ },
339
+ {
340
+ id: 'file-image',
341
+ type: 'file',
342
+ x: 560,
343
+ y: 220,
344
+ width: 160,
345
+ height: 80,
346
+ file: 'assets/logo.png',
347
+ color: 2,
348
+ pv: {
349
+ nodeType: 'file-image',
350
+ shape: 'rectangle',
351
+ icon: 'Image',
352
+ },
353
+ },
354
+ ],
355
+ edges: [],
356
+ pv: {
357
+ version: '1.0.0',
358
+ name: 'File Node Variations',
359
+ description: 'Different file types and subpaths',
360
+ edgeTypes: {},
361
+ },
362
+ };
363
+
364
+ export const FileNodes: Story = {
365
+ args: {
366
+ canvas: fileNodesCanvas,
367
+ width: 800,
368
+ height: 380,
369
+ },
370
+ parameters: {
371
+ docs: {
372
+ description: {
373
+ story: `
374
+ **File Node Variations**
375
+
376
+ File nodes (\`type: 'file'\`) reference external files:
377
+ - TypeScript files
378
+ - React components (TSX)
379
+ - JSON config files
380
+ - Markdown documentation
381
+ - Files with subpath (heading/block link)
382
+ - Image assets
383
+
384
+ The \`file\` field contains the path, and optional \`subpath\` can reference a specific section.
385
+ `,
386
+ },
387
+ },
388
+ },
389
+ };
390
+
391
+ /**
392
+ * Canvas showing link nodes with different URL types
393
+ */
394
+ const linkNodesCanvas: ExtendedCanvas = {
395
+ nodes: [
396
+ {
397
+ id: 'link-github',
398
+ type: 'link',
399
+ x: 100,
400
+ y: 100,
401
+ width: 200,
402
+ height: 80,
403
+ url: 'https://github.com/anthropics/claude',
404
+ color: 0, // default/gray
405
+ pv: {
406
+ nodeType: 'link-github',
407
+ shape: 'rectangle',
408
+ icon: 'Github',
409
+ },
410
+ },
411
+ {
412
+ id: 'link-docs',
413
+ type: 'link',
414
+ x: 340,
415
+ y: 100,
416
+ width: 200,
417
+ height: 80,
418
+ url: 'https://docs.example.com/api',
419
+ color: 5,
420
+ pv: {
421
+ nodeType: 'link-documentation',
422
+ shape: 'rectangle',
423
+ icon: 'Book',
424
+ },
425
+ },
426
+ {
427
+ id: 'link-api',
428
+ type: 'link',
429
+ x: 580,
430
+ y: 100,
431
+ width: 180,
432
+ height: 80,
433
+ url: 'https://api.example.com/v1',
434
+ color: 4,
435
+ pv: {
436
+ nodeType: 'link-api',
437
+ shape: 'rectangle',
438
+ icon: 'Cloud',
439
+ },
440
+ },
441
+ {
442
+ id: 'link-jira',
443
+ type: 'link',
444
+ x: 100,
445
+ y: 220,
446
+ width: 200,
447
+ height: 80,
448
+ url: 'https://jira.example.com/browse/PROJ-123',
449
+ color: 5,
450
+ pv: {
451
+ nodeType: 'link-ticket',
452
+ shape: 'rectangle',
453
+ icon: 'Ticket',
454
+ },
455
+ },
456
+ {
457
+ id: 'link-figma',
458
+ type: 'link',
459
+ x: 340,
460
+ y: 220,
461
+ width: 200,
462
+ height: 80,
463
+ url: 'https://figma.com/file/abc123',
464
+ color: 6,
465
+ pv: {
466
+ nodeType: 'link-design',
467
+ shape: 'rectangle',
468
+ icon: 'Palette',
469
+ },
470
+ },
471
+ {
472
+ id: 'link-slack',
473
+ type: 'link',
474
+ x: 580,
475
+ y: 220,
476
+ width: 180,
477
+ height: 80,
478
+ url: 'https://slack.com/channel/dev',
479
+ color: 2,
480
+ pv: {
481
+ nodeType: 'link-chat',
482
+ shape: 'rectangle',
483
+ icon: 'MessageCircle',
484
+ },
485
+ },
486
+ ],
487
+ edges: [],
488
+ pv: {
489
+ version: '1.0.0',
490
+ name: 'Link Node Variations',
491
+ description: 'Different URL/link types',
492
+ edgeTypes: {},
493
+ },
494
+ };
495
+
496
+ export const LinkNodes: Story = {
497
+ args: {
498
+ canvas: linkNodesCanvas,
499
+ width: 850,
500
+ height: 380,
501
+ },
502
+ parameters: {
503
+ docs: {
504
+ description: {
505
+ story: `
506
+ **Link Node Variations**
507
+
508
+ Link nodes (\`type: 'link'\`) reference external URLs:
509
+ - GitHub repositories
510
+ - Documentation sites
511
+ - API endpoints
512
+ - Issue trackers (Jira, Linear)
513
+ - Design tools (Figma)
514
+ - Communication tools (Slack)
515
+
516
+ The \`url\` field contains the full URL.
517
+ `,
518
+ },
519
+ },
520
+ },
521
+ };
522
+
523
+ /**
524
+ * Canvas showing a realistic mixed-type diagram
525
+ */
526
+ const mixedTypesCanvas: ExtendedCanvas = {
527
+ nodes: [
528
+ // Documentation (file)
529
+ {
530
+ id: 'docs',
531
+ type: 'file',
532
+ x: 100,
533
+ y: 100,
534
+ width: 160,
535
+ height: 80,
536
+ file: 'docs/architecture.md',
537
+ color: 6,
538
+ pv: {
539
+ nodeType: 'documentation',
540
+ shape: 'rectangle',
541
+ icon: 'BookOpen',
542
+ },
543
+ },
544
+ // Design link
545
+ {
546
+ id: 'design',
547
+ type: 'link',
548
+ x: 100,
549
+ y: 220,
550
+ width: 160,
551
+ height: 80,
552
+ url: 'https://figma.com/file/design',
553
+ color: 6,
554
+ pv: {
555
+ nodeType: 'design-spec',
556
+ shape: 'rectangle',
557
+ icon: 'Palette',
558
+ },
559
+ },
560
+ // Main component (file)
561
+ {
562
+ id: 'component',
563
+ type: 'file',
564
+ x: 350,
565
+ y: 160,
566
+ width: 180,
567
+ height: 80,
568
+ file: 'src/components/Feature.tsx',
569
+ color: 4,
570
+ pv: {
571
+ nodeType: 'component',
572
+ shape: 'rectangle',
573
+ icon: 'Component',
574
+ },
575
+ },
576
+ // Notes (text)
577
+ {
578
+ id: 'notes',
579
+ type: 'text',
580
+ x: 350,
581
+ y: 280,
582
+ width: 180,
583
+ height: 100,
584
+ text: '# Implementation Notes\n\n- Check edge cases\n- Add tests\n- Update docs',
585
+ color: 3,
586
+ pv: {
587
+ nodeType: 'notes',
588
+ shape: 'rectangle',
589
+ icon: 'StickyNote',
590
+ },
591
+ },
592
+ // API endpoint (link)
593
+ {
594
+ id: 'api',
595
+ type: 'link',
596
+ x: 600,
597
+ y: 100,
598
+ width: 160,
599
+ height: 80,
600
+ url: 'https://api.example.com/feature',
601
+ color: 5,
602
+ pv: {
603
+ nodeType: 'api-endpoint',
604
+ shape: 'rectangle',
605
+ icon: 'Cloud',
606
+ },
607
+ },
608
+ // Test file (file)
609
+ {
610
+ id: 'tests',
611
+ type: 'file',
612
+ x: 600,
613
+ y: 220,
614
+ width: 160,
615
+ height: 80,
616
+ file: 'src/components/Feature.test.tsx',
617
+ color: 4,
618
+ pv: {
619
+ nodeType: 'test-file',
620
+ shape: 'rectangle',
621
+ icon: 'TestTube',
622
+ },
623
+ },
624
+ // Issue tracker (link)
625
+ {
626
+ id: 'ticket',
627
+ type: 'link',
628
+ x: 600,
629
+ y: 340,
630
+ width: 160,
631
+ height: 80,
632
+ url: 'https://jira.example.com/PROJ-456',
633
+ color: 5,
634
+ pv: {
635
+ nodeType: 'ticket',
636
+ shape: 'rectangle',
637
+ icon: 'Ticket',
638
+ },
639
+ },
640
+ ],
641
+ edges: [
642
+ {
643
+ id: 'docs-to-component',
644
+ fromNode: 'docs',
645
+ toNode: 'component',
646
+ fromSide: 'right',
647
+ toSide: 'left',
648
+ pv: { edgeType: 'reference' },
649
+ },
650
+ {
651
+ id: 'design-to-component',
652
+ fromNode: 'design',
653
+ toNode: 'component',
654
+ fromSide: 'right',
655
+ toSide: 'left',
656
+ pv: { edgeType: 'reference' },
657
+ },
658
+ {
659
+ id: 'component-to-api',
660
+ fromNode: 'component',
661
+ toNode: 'api',
662
+ fromSide: 'right',
663
+ toSide: 'left',
664
+ pv: { edgeType: 'uses' },
665
+ },
666
+ {
667
+ id: 'component-to-tests',
668
+ fromNode: 'component',
669
+ toNode: 'tests',
670
+ fromSide: 'right',
671
+ toSide: 'left',
672
+ pv: { edgeType: 'tested-by' },
673
+ },
674
+ {
675
+ id: 'notes-to-ticket',
676
+ fromNode: 'notes',
677
+ toNode: 'ticket',
678
+ fromSide: 'right',
679
+ toSide: 'left',
680
+ pv: { edgeType: 'tracks' },
681
+ },
682
+ ],
683
+ pv: {
684
+ version: '1.0.0',
685
+ name: 'Feature Development Map',
686
+ description: 'Mixed node types showing a feature development context',
687
+ edgeTypes: {
688
+ reference: {
689
+ style: 'dashed',
690
+ color: '#8b5cf6',
691
+ directed: true,
692
+ },
693
+ uses: {
694
+ style: 'solid',
695
+ color: '#22c55e',
696
+ directed: true,
697
+ },
698
+ 'tested-by': {
699
+ style: 'dotted',
700
+ color: '#3b82f6',
701
+ directed: true,
702
+ },
703
+ tracks: {
704
+ style: 'dashed',
705
+ color: '#f97316',
706
+ directed: true,
707
+ },
708
+ },
709
+ },
710
+ };
711
+
712
+ export const MixedTypes: Story = {
713
+ args: {
714
+ canvas: mixedTypesCanvas,
715
+ width: 850,
716
+ height: 500,
717
+ },
718
+ parameters: {
719
+ docs: {
720
+ description: {
721
+ story: `
722
+ **Mixed Node Types - Feature Development Map**
723
+
724
+ A realistic example showing how different node types work together:
725
+ - **File nodes**: Source code, tests, documentation
726
+ - **Link nodes**: API endpoints, design specs, issue trackers
727
+ - **Text nodes**: Notes and annotations
728
+
729
+ This demonstrates a typical feature development context where you'd reference:
730
+ - Architecture docs (file)
731
+ - Figma designs (link)
732
+ - Source components (file)
733
+ - API endpoints (link)
734
+ - Test files (file)
735
+ - Issue tickets (link)
736
+ - Implementation notes (text)
737
+ `,
738
+ },
739
+ },
740
+ },
741
+ };
742
+
743
+ /**
744
+ * Interactive comparison template
745
+ */
746
+ const NodeTypeComparisonTemplate = () => {
747
+ return (
748
+ <div style={{ padding: 20, fontFamily: 'system-ui' }}>
749
+ <h2 style={{ marginBottom: 20 }}>JSON Canvas Node Types Comparison</h2>
750
+
751
+ <div
752
+ style={{
753
+ display: 'grid',
754
+ gridTemplateColumns: 'repeat(4, 1fr)',
755
+ gap: 20,
756
+ marginBottom: 30,
757
+ }}
758
+ >
759
+ <div
760
+ style={{
761
+ padding: 16,
762
+ backgroundColor: '#f3e8ff',
763
+ borderRadius: 8,
764
+ border: '2px solid #8b5cf6',
765
+ }}
766
+ >
767
+ <h4 style={{ margin: '0 0 8px 0', color: '#6b21a8' }}>Text Node</h4>
768
+ <code style={{ fontSize: 11, display: 'block', marginBottom: 8 }}>type: 'text'</code>
769
+ <div style={{ fontSize: 12, color: '#6b21a8' }}>
770
+ <strong>Fields:</strong>
771
+ <ul style={{ margin: '4px 0', paddingLeft: 16 }}>
772
+ <li>
773
+ <code>text</code> - Markdown content
774
+ </li>
775
+ </ul>
776
+ </div>
777
+ </div>
778
+
779
+ <div
780
+ style={{
781
+ padding: 16,
782
+ backgroundColor: '#dcfce7',
783
+ borderRadius: 8,
784
+ border: '2px solid #22c55e',
785
+ }}
786
+ >
787
+ <h4 style={{ margin: '0 0 8px 0', color: '#166534' }}>File Node</h4>
788
+ <code style={{ fontSize: 11, display: 'block', marginBottom: 8 }}>type: 'file'</code>
789
+ <div style={{ fontSize: 12, color: '#166534' }}>
790
+ <strong>Fields:</strong>
791
+ <ul style={{ margin: '4px 0', paddingLeft: 16 }}>
792
+ <li>
793
+ <code>file</code> - File path
794
+ </li>
795
+ <li>
796
+ <code>subpath?</code> - Section link
797
+ </li>
798
+ </ul>
799
+ </div>
800
+ </div>
801
+
802
+ <div
803
+ style={{
804
+ padding: 16,
805
+ backgroundColor: '#cffafe',
806
+ borderRadius: 8,
807
+ border: '2px solid #06b6d4',
808
+ }}
809
+ >
810
+ <h4 style={{ margin: '0 0 8px 0', color: '#0e7490' }}>Link Node</h4>
811
+ <code style={{ fontSize: 11, display: 'block', marginBottom: 8 }}>type: 'link'</code>
812
+ <div style={{ fontSize: 12, color: '#0e7490' }}>
813
+ <strong>Fields:</strong>
814
+ <ul style={{ margin: '4px 0', paddingLeft: 16 }}>
815
+ <li>
816
+ <code>url</code> - Full URL
817
+ </li>
818
+ </ul>
819
+ </div>
820
+ </div>
821
+
822
+ <div
823
+ style={{
824
+ padding: 16,
825
+ backgroundColor: '#fef9c3',
826
+ borderRadius: 8,
827
+ border: '2px solid #eab308',
828
+ }}
829
+ >
830
+ <h4 style={{ margin: '0 0 8px 0', color: '#a16207' }}>Group Node</h4>
831
+ <code style={{ fontSize: 11, display: 'block', marginBottom: 8 }}>type: 'group'</code>
832
+ <div style={{ fontSize: 12, color: '#a16207' }}>
833
+ <strong>Fields:</strong>
834
+ <ul style={{ margin: '4px 0', paddingLeft: 16 }}>
835
+ <li>
836
+ <code>label?</code> - Group name
837
+ </li>
838
+ <li>
839
+ <code>background?</code> - Image
840
+ </li>
841
+ </ul>
842
+ </div>
843
+ </div>
844
+ </div>
845
+
846
+ <h3 style={{ marginBottom: 16 }}>Live Example: All Node Types</h3>
847
+ <GraphRenderer canvas={allNodeTypesCanvas} width={900} height={500} />
848
+
849
+ <div
850
+ style={{
851
+ marginTop: 24,
852
+ padding: 16,
853
+ backgroundColor: '#f5f5f5',
854
+ borderRadius: 8,
855
+ }}
856
+ >
857
+ <h4 style={{ margin: '0 0 12px 0' }}>JSON Canvas Spec</h4>
858
+ <p style={{ fontSize: 13, margin: 0, lineHeight: 1.6 }}>
859
+ These node types follow the{' '}
860
+ <a
861
+ href="https://jsoncanvas.org/"
862
+ target="_blank"
863
+ rel="noopener noreferrer"
864
+ style={{ color: '#3b82f6' }}
865
+ >
866
+ JSON Canvas specification
867
+ </a>
868
+ . Each node type serves a specific purpose:
869
+ </p>
870
+ <ul style={{ fontSize: 13, lineHeight: 1.8, margin: '8px 0 0 0', paddingLeft: 20 }}>
871
+ <li>
872
+ <strong>Text</strong> - For notes, descriptions, and embedded markdown content
873
+ </li>
874
+ <li>
875
+ <strong>File</strong> - For referencing local files in your project
876
+ </li>
877
+ <li>
878
+ <strong>Link</strong> - For external resources, APIs, documentation, tools
879
+ </li>
880
+ <li>
881
+ <strong>Group</strong> - For visually organizing related nodes together
882
+ </li>
883
+ </ul>
884
+ </div>
885
+ </div>
886
+ );
887
+ };
888
+
889
+ export const NodeTypeComparison: Story = {
890
+ render: () => <NodeTypeComparisonTemplate />,
891
+ parameters: {
892
+ docs: {
893
+ description: {
894
+ story: 'Interactive comparison view showing all JSON Canvas node types with field documentation.',
895
+ },
896
+ },
897
+ },
898
+ };