@principal-ai/principal-view-react 0.6.7 → 0.6.9
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.
- package/dist/components/GraphRenderer.d.ts.map +1 -1
- package/dist/components/GraphRenderer.js +7 -3
- package/dist/components/GraphRenderer.js.map +1 -1
- package/dist/components/NodeInfoPanel.d.ts.map +1 -1
- package/dist/components/NodeInfoPanel.js +91 -108
- package/dist/components/NodeInfoPanel.js.map +1 -1
- package/dist/edges/CustomEdge.d.ts.map +1 -1
- package/dist/edges/CustomEdge.js +3 -1
- package/dist/edges/CustomEdge.js.map +1 -1
- package/dist/nodes/CustomNode.d.ts +1 -1
- package/dist/nodes/CustomNode.d.ts.map +1 -1
- package/dist/nodes/CustomNode.js +11 -10
- package/dist/nodes/CustomNode.js.map +1 -1
- package/dist/utils/graphConverter.d.ts.map +1 -1
- package/dist/utils/graphConverter.js +4 -2
- package/dist/utils/graphConverter.js.map +1 -1
- package/package.json +2 -2
- package/src/components/GraphRenderer.tsx +11 -4
- package/src/components/NodeInfoPanel.tsx +232 -237
- package/src/edges/CustomEdge.tsx +3 -1
- package/src/nodes/CustomNode.tsx +12 -13
- package/src/stories/ColorPriority.stories.tsx +630 -0
- package/src/stories/EventDrivenAnimations.stories.tsx +6 -6
- package/src/stories/GraphRenderer.stories.tsx +27 -27
- package/src/stories/MultiConfig.stories.tsx +24 -24
- package/src/stories/MultiDirectionalConnections.stories.tsx +20 -20
- package/src/stories/NodeFieldsAudit.stories.tsx +1095 -0
- package/src/stories/NodeShapes.stories.tsx +37 -37
- package/src/utils/graphConverter.ts +4 -2
|
@@ -0,0 +1,630 @@
|
|
|
1
|
+
import React, { useState, useEffect } from 'react';
|
|
2
|
+
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
|
+
import { GraphRenderer } from '../components/GraphRenderer';
|
|
4
|
+
import type { ExtendedCanvas, GraphEvent } from '@principal-ai/principal-view-core';
|
|
5
|
+
|
|
6
|
+
// Helper component that sets initial node states via events
|
|
7
|
+
const GraphWithInitialStates: React.FC<{
|
|
8
|
+
canvas: ExtendedCanvas;
|
|
9
|
+
width: number;
|
|
10
|
+
height: number;
|
|
11
|
+
showMinimap: boolean;
|
|
12
|
+
initialStates?: Record<string, string>;
|
|
13
|
+
}> = ({ canvas, width, height, showMinimap, initialStates }) => {
|
|
14
|
+
const [events, setEvents] = useState<GraphEvent[]>([]);
|
|
15
|
+
|
|
16
|
+
useEffect(() => {
|
|
17
|
+
if (initialStates) {
|
|
18
|
+
const stateEvents: GraphEvent[] = Object.entries(initialStates).map(([nodeId, newState], idx) => ({
|
|
19
|
+
id: `init-state-${idx}`,
|
|
20
|
+
type: 'state_changed',
|
|
21
|
+
timestamp: Date.now(),
|
|
22
|
+
category: 'state' as const,
|
|
23
|
+
payload: { nodeId, newState },
|
|
24
|
+
}));
|
|
25
|
+
setEvents(stateEvents);
|
|
26
|
+
}
|
|
27
|
+
}, []);
|
|
28
|
+
|
|
29
|
+
return (
|
|
30
|
+
<GraphRenderer
|
|
31
|
+
canvas={canvas}
|
|
32
|
+
width={width}
|
|
33
|
+
height={height}
|
|
34
|
+
showMinimap={showMinimap}
|
|
35
|
+
events={events}
|
|
36
|
+
/>
|
|
37
|
+
);
|
|
38
|
+
};
|
|
39
|
+
|
|
40
|
+
const meta = {
|
|
41
|
+
title: 'Audit/ColorPriority',
|
|
42
|
+
component: GraphRenderer,
|
|
43
|
+
parameters: {
|
|
44
|
+
layout: 'centered',
|
|
45
|
+
},
|
|
46
|
+
tags: ['autodocs'],
|
|
47
|
+
} satisfies Meta<typeof GraphRenderer>;
|
|
48
|
+
|
|
49
|
+
export default meta;
|
|
50
|
+
type Story = StoryObj<typeof meta>;
|
|
51
|
+
|
|
52
|
+
// ============================================================================
|
|
53
|
+
// Node Color Priority Story
|
|
54
|
+
// Priority: state color > node data color (pv.fill) > node.color > type definition color > default (#888)
|
|
55
|
+
// ============================================================================
|
|
56
|
+
|
|
57
|
+
const nodeColorPriorityCanvas: ExtendedCanvas = {
|
|
58
|
+
nodes: [
|
|
59
|
+
// 1. Default color only (no color specified anywhere)
|
|
60
|
+
{
|
|
61
|
+
id: 'default-only',
|
|
62
|
+
type: 'text',
|
|
63
|
+
x: 100,
|
|
64
|
+
y: 100,
|
|
65
|
+
width: 180,
|
|
66
|
+
height: 100,
|
|
67
|
+
text: 'SOURCE: Default\nEXPECT: Gray',
|
|
68
|
+
pv: {
|
|
69
|
+
nodeType: 'default-demo',
|
|
70
|
+
shape: 'rectangle',
|
|
71
|
+
},
|
|
72
|
+
},
|
|
73
|
+
// 2. Type definition color via node.color
|
|
74
|
+
{
|
|
75
|
+
id: 'node-color',
|
|
76
|
+
type: 'text',
|
|
77
|
+
x: 320,
|
|
78
|
+
y: 100,
|
|
79
|
+
width: 180,
|
|
80
|
+
height: 100,
|
|
81
|
+
text: 'SOURCE: node.color\nEXPECT: BLUE',
|
|
82
|
+
color: '#0000FF',
|
|
83
|
+
pv: {
|
|
84
|
+
nodeType: 'color-demo',
|
|
85
|
+
shape: 'rectangle',
|
|
86
|
+
},
|
|
87
|
+
},
|
|
88
|
+
// 3. pv.fill overrides node.color
|
|
89
|
+
{
|
|
90
|
+
id: 'pv-fill',
|
|
91
|
+
type: 'text',
|
|
92
|
+
x: 540,
|
|
93
|
+
y: 100,
|
|
94
|
+
width: 180,
|
|
95
|
+
height: 100,
|
|
96
|
+
text: 'SOURCE: pv.fill\nEXPECT: GREEN\n(node.color=BLUE ignored)',
|
|
97
|
+
color: '#0000FF', // This should be overridden
|
|
98
|
+
pv: {
|
|
99
|
+
nodeType: 'fill-demo',
|
|
100
|
+
shape: 'rectangle',
|
|
101
|
+
fill: '#00FF00', // This wins
|
|
102
|
+
},
|
|
103
|
+
},
|
|
104
|
+
// 4. State color overrides everything (idle state)
|
|
105
|
+
{
|
|
106
|
+
id: 'state-color-idle',
|
|
107
|
+
type: 'text',
|
|
108
|
+
x: 760,
|
|
109
|
+
y: 100,
|
|
110
|
+
width: 180,
|
|
111
|
+
height: 100,
|
|
112
|
+
text: 'SOURCE: state.idle.color\nEXPECT: RED\n(pv.fill & node.color ignored)',
|
|
113
|
+
color: '#0000FF', // Overridden
|
|
114
|
+
pv: {
|
|
115
|
+
nodeType: 'state-demo',
|
|
116
|
+
shape: 'rectangle',
|
|
117
|
+
fill: '#00FF00', // Overridden
|
|
118
|
+
states: {
|
|
119
|
+
idle: { label: 'Idle', color: '#FF0000' },
|
|
120
|
+
active: { label: 'Active', color: '#FFFF00' },
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
],
|
|
125
|
+
edges: [],
|
|
126
|
+
pv: {
|
|
127
|
+
version: '1.0.0',
|
|
128
|
+
name: 'Node Color Priority Demo',
|
|
129
|
+
description: 'Shows how node colors are prioritized',
|
|
130
|
+
edgeTypes: {},
|
|
131
|
+
},
|
|
132
|
+
};
|
|
133
|
+
|
|
134
|
+
export const NodeColorPriority: Story = {
|
|
135
|
+
render: () => (
|
|
136
|
+
<GraphWithInitialStates
|
|
137
|
+
canvas={nodeColorPriorityCanvas}
|
|
138
|
+
width={1050}
|
|
139
|
+
height={320}
|
|
140
|
+
showMinimap={false}
|
|
141
|
+
initialStates={{ 'state-color-idle': 'idle' }}
|
|
142
|
+
/>
|
|
143
|
+
),
|
|
144
|
+
parameters: {
|
|
145
|
+
docs: {
|
|
146
|
+
description: {
|
|
147
|
+
story: `
|
|
148
|
+
**Node Fill Color Priority** (highest to lowest):
|
|
149
|
+
|
|
150
|
+
1. **State color** - When a node has an active state with a color defined
|
|
151
|
+
2. **pv.fill** - Explicit fill color in the PV extension
|
|
152
|
+
3. **node.color** - The standard canvas node color property
|
|
153
|
+
4. **Type definition color** - Color defined in the node type
|
|
154
|
+
5. **Default** - Falls back to #888
|
|
155
|
+
|
|
156
|
+
In this demo:
|
|
157
|
+
- Node 1: No color specified → uses default #888
|
|
158
|
+
- Node 2: Only node.color → shows blue
|
|
159
|
+
- Node 3: Both node.color AND pv.fill → pv.fill (green) wins
|
|
160
|
+
- Node 4: Has state "idle" with purple color → state color wins over everything
|
|
161
|
+
`,
|
|
162
|
+
},
|
|
163
|
+
},
|
|
164
|
+
},
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
// ============================================================================
|
|
168
|
+
// Node Stroke Color Priority Story
|
|
169
|
+
// Priority: pv.stroke > type definition stroke > fill color
|
|
170
|
+
// ============================================================================
|
|
171
|
+
|
|
172
|
+
const strokeColorPriorityCanvas: ExtendedCanvas = {
|
|
173
|
+
nodes: [
|
|
174
|
+
// 1. Stroke defaults to fill color
|
|
175
|
+
{
|
|
176
|
+
id: 'stroke-default',
|
|
177
|
+
type: 'text',
|
|
178
|
+
x: 100,
|
|
179
|
+
y: 100,
|
|
180
|
+
width: 200,
|
|
181
|
+
height: 100,
|
|
182
|
+
text: 'SOURCE: Default (=fill)\nEXPECT BORDER: BLUE\n(same as fill color)',
|
|
183
|
+
color: '#0000FF',
|
|
184
|
+
pv: {
|
|
185
|
+
nodeType: 'stroke-default-demo',
|
|
186
|
+
shape: 'rectangle',
|
|
187
|
+
},
|
|
188
|
+
},
|
|
189
|
+
// 2. Explicit stroke color
|
|
190
|
+
{
|
|
191
|
+
id: 'stroke-explicit',
|
|
192
|
+
type: 'text',
|
|
193
|
+
x: 340,
|
|
194
|
+
y: 100,
|
|
195
|
+
width: 200,
|
|
196
|
+
height: 100,
|
|
197
|
+
text: 'SOURCE: pv.stroke\nEXPECT BORDER: RED\n(fill is BLUE)',
|
|
198
|
+
color: '#0000FF', // Fill is blue
|
|
199
|
+
pv: {
|
|
200
|
+
nodeType: 'stroke-explicit-demo',
|
|
201
|
+
shape: 'rectangle',
|
|
202
|
+
stroke: '#FF0000', // But stroke is red
|
|
203
|
+
},
|
|
204
|
+
},
|
|
205
|
+
// 3. Different fill and stroke
|
|
206
|
+
{
|
|
207
|
+
id: 'fill-and-stroke',
|
|
208
|
+
type: 'text',
|
|
209
|
+
x: 580,
|
|
210
|
+
y: 100,
|
|
211
|
+
width: 200,
|
|
212
|
+
height: 100,
|
|
213
|
+
text: 'SOURCE: pv.fill + pv.stroke\nEXPECT BORDER: YELLOW\nEXPECT FILL: GREEN',
|
|
214
|
+
pv: {
|
|
215
|
+
nodeType: 'both-demo',
|
|
216
|
+
shape: 'rectangle',
|
|
217
|
+
fill: '#00FF00',
|
|
218
|
+
stroke: '#FFFF00',
|
|
219
|
+
},
|
|
220
|
+
},
|
|
221
|
+
],
|
|
222
|
+
edges: [],
|
|
223
|
+
pv: {
|
|
224
|
+
version: '1.0.0',
|
|
225
|
+
name: 'Stroke Color Priority Demo',
|
|
226
|
+
description: 'Shows how stroke colors are prioritized',
|
|
227
|
+
edgeTypes: {},
|
|
228
|
+
},
|
|
229
|
+
};
|
|
230
|
+
|
|
231
|
+
export const StrokeColorPriority: Story = {
|
|
232
|
+
args: {
|
|
233
|
+
canvas: strokeColorPriorityCanvas,
|
|
234
|
+
width: 880,
|
|
235
|
+
height: 320,
|
|
236
|
+
showMinimap: false,
|
|
237
|
+
},
|
|
238
|
+
parameters: {
|
|
239
|
+
docs: {
|
|
240
|
+
description: {
|
|
241
|
+
story: `
|
|
242
|
+
**Node Stroke Color Priority** (highest to lowest):
|
|
243
|
+
|
|
244
|
+
1. **pv.stroke** - Explicit stroke color in the PV extension
|
|
245
|
+
2. **Type definition stroke** - Stroke defined in node type
|
|
246
|
+
3. **Fill color** - Falls back to the resolved fill color
|
|
247
|
+
|
|
248
|
+
In this demo:
|
|
249
|
+
- Node 1: No stroke specified → border matches fill color (blue)
|
|
250
|
+
- Node 2: Blue fill but red pv.stroke → red border
|
|
251
|
+
- Node 3: Green fill with orange stroke → independent colors
|
|
252
|
+
`,
|
|
253
|
+
},
|
|
254
|
+
},
|
|
255
|
+
},
|
|
256
|
+
};
|
|
257
|
+
|
|
258
|
+
// ============================================================================
|
|
259
|
+
// Edge Color Priority Story
|
|
260
|
+
// Priority: edge.color > edge type definition color > default
|
|
261
|
+
// ============================================================================
|
|
262
|
+
|
|
263
|
+
const edgeColorPriorityCanvas: ExtendedCanvas = {
|
|
264
|
+
nodes: [
|
|
265
|
+
{
|
|
266
|
+
id: 'source-1',
|
|
267
|
+
type: 'text',
|
|
268
|
+
x: 100,
|
|
269
|
+
y: 100,
|
|
270
|
+
width: 180,
|
|
271
|
+
height: 70,
|
|
272
|
+
text: 'SOURCE: edgeType color\nEXPECT EDGE: BLUE',
|
|
273
|
+
color: '#888888',
|
|
274
|
+
pv: { nodeType: 'source', shape: 'rectangle' },
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
id: 'target-1',
|
|
278
|
+
type: 'text',
|
|
279
|
+
x: 450,
|
|
280
|
+
y: 100,
|
|
281
|
+
width: 100,
|
|
282
|
+
height: 70,
|
|
283
|
+
text: 'Target',
|
|
284
|
+
color: '#888888',
|
|
285
|
+
pv: { nodeType: 'target', shape: 'rectangle' },
|
|
286
|
+
},
|
|
287
|
+
{
|
|
288
|
+
id: 'source-2',
|
|
289
|
+
type: 'text',
|
|
290
|
+
x: 100,
|
|
291
|
+
y: 220,
|
|
292
|
+
width: 180,
|
|
293
|
+
height: 70,
|
|
294
|
+
text: 'SOURCE: edge.color\nEXPECT EDGE: RED\n(edgeType=BLUE ignored)',
|
|
295
|
+
color: '#888888',
|
|
296
|
+
pv: { nodeType: 'source', shape: 'rectangle' },
|
|
297
|
+
},
|
|
298
|
+
{
|
|
299
|
+
id: 'target-2',
|
|
300
|
+
type: 'text',
|
|
301
|
+
x: 450,
|
|
302
|
+
y: 220,
|
|
303
|
+
width: 100,
|
|
304
|
+
height: 70,
|
|
305
|
+
text: 'Target',
|
|
306
|
+
color: '#888888',
|
|
307
|
+
pv: { nodeType: 'target', shape: 'rectangle' },
|
|
308
|
+
},
|
|
309
|
+
{
|
|
310
|
+
id: 'source-3',
|
|
311
|
+
type: 'text',
|
|
312
|
+
x: 100,
|
|
313
|
+
y: 340,
|
|
314
|
+
width: 180,
|
|
315
|
+
height: 70,
|
|
316
|
+
text: 'SOURCE: Default\nEXPECT EDGE: Gray',
|
|
317
|
+
color: '#888888',
|
|
318
|
+
pv: { nodeType: 'source', shape: 'rectangle' },
|
|
319
|
+
},
|
|
320
|
+
{
|
|
321
|
+
id: 'target-3',
|
|
322
|
+
type: 'text',
|
|
323
|
+
x: 450,
|
|
324
|
+
y: 340,
|
|
325
|
+
width: 100,
|
|
326
|
+
height: 70,
|
|
327
|
+
text: 'Target',
|
|
328
|
+
color: '#888888',
|
|
329
|
+
pv: { nodeType: 'target', shape: 'rectangle' },
|
|
330
|
+
},
|
|
331
|
+
],
|
|
332
|
+
edges: [
|
|
333
|
+
// 1. Edge type color only (from edgeTypes definition)
|
|
334
|
+
{
|
|
335
|
+
id: 'edge-type-color',
|
|
336
|
+
fromNode: 'source-1',
|
|
337
|
+
toNode: 'target-1',
|
|
338
|
+
pv: {
|
|
339
|
+
edgeType: 'dataflow', // Uses edgeTypes.dataflow.color = BLUE
|
|
340
|
+
},
|
|
341
|
+
},
|
|
342
|
+
// 2. Edge's own color overrides edge type
|
|
343
|
+
{
|
|
344
|
+
id: 'edge-own-color',
|
|
345
|
+
fromNode: 'source-2',
|
|
346
|
+
toNode: 'target-2',
|
|
347
|
+
color: '#FF0000', // RED - overrides the edge type color
|
|
348
|
+
pv: {
|
|
349
|
+
edgeType: 'dataflow', // Would be blue, but overridden
|
|
350
|
+
},
|
|
351
|
+
},
|
|
352
|
+
// 3. No color specified (default)
|
|
353
|
+
{
|
|
354
|
+
id: 'edge-default',
|
|
355
|
+
fromNode: 'source-3',
|
|
356
|
+
toNode: 'target-3',
|
|
357
|
+
pv: {
|
|
358
|
+
edgeType: 'uncolored', // No color in edge type
|
|
359
|
+
},
|
|
360
|
+
},
|
|
361
|
+
],
|
|
362
|
+
pv: {
|
|
363
|
+
version: '1.0.0',
|
|
364
|
+
name: 'Edge Color Priority Demo',
|
|
365
|
+
description: 'Shows how edge colors are prioritized',
|
|
366
|
+
edgeTypes: {
|
|
367
|
+
dataflow: {
|
|
368
|
+
style: 'solid',
|
|
369
|
+
color: '#0000FF', // BLUE
|
|
370
|
+
directed: true,
|
|
371
|
+
},
|
|
372
|
+
uncolored: {
|
|
373
|
+
style: 'dashed',
|
|
374
|
+
directed: true,
|
|
375
|
+
// No color defined
|
|
376
|
+
},
|
|
377
|
+
},
|
|
378
|
+
},
|
|
379
|
+
};
|
|
380
|
+
|
|
381
|
+
export const EdgeColorPriority: Story = {
|
|
382
|
+
args: {
|
|
383
|
+
canvas: edgeColorPriorityCanvas,
|
|
384
|
+
width: 650,
|
|
385
|
+
height: 520,
|
|
386
|
+
showMinimap: false,
|
|
387
|
+
},
|
|
388
|
+
parameters: {
|
|
389
|
+
docs: {
|
|
390
|
+
description: {
|
|
391
|
+
story: `
|
|
392
|
+
**Edge Color Priority** (highest to lowest):
|
|
393
|
+
|
|
394
|
+
1. **edge.color** - The edge's own color property
|
|
395
|
+
2. **Edge type definition color** - Color from pv.edgeTypes[type].color
|
|
396
|
+
3. **Default** - System default edge color
|
|
397
|
+
|
|
398
|
+
In this demo:
|
|
399
|
+
- Edge 1: Uses "dataflow" type → shows cyan from edgeTypes
|
|
400
|
+
- Edge 2: Has edge.color AND uses "dataflow" type → purple (edge.color) wins
|
|
401
|
+
- Edge 3: Uses "uncolored" type with no color → default styling
|
|
402
|
+
`,
|
|
403
|
+
},
|
|
404
|
+
},
|
|
405
|
+
},
|
|
406
|
+
};
|
|
407
|
+
|
|
408
|
+
// ============================================================================
|
|
409
|
+
// Icon Priority Story
|
|
410
|
+
// Priority: node data icon > state icon > type definition icon
|
|
411
|
+
// ============================================================================
|
|
412
|
+
|
|
413
|
+
const iconPriorityCanvas: ExtendedCanvas = {
|
|
414
|
+
nodes: [
|
|
415
|
+
// 1. Type definition icon only
|
|
416
|
+
{
|
|
417
|
+
id: 'icon-type',
|
|
418
|
+
type: 'text',
|
|
419
|
+
x: 100,
|
|
420
|
+
y: 100,
|
|
421
|
+
width: 180,
|
|
422
|
+
height: 100,
|
|
423
|
+
text: 'SOURCE: pv.icon\nEXPECT ICON: Settings',
|
|
424
|
+
color: '#0000FF',
|
|
425
|
+
pv: {
|
|
426
|
+
nodeType: 'icon-type-demo',
|
|
427
|
+
shape: 'rectangle',
|
|
428
|
+
icon: 'settings',
|
|
429
|
+
},
|
|
430
|
+
},
|
|
431
|
+
// 2. State icon (when in a state)
|
|
432
|
+
{
|
|
433
|
+
id: 'icon-state',
|
|
434
|
+
type: 'text',
|
|
435
|
+
x: 320,
|
|
436
|
+
y: 100,
|
|
437
|
+
width: 180,
|
|
438
|
+
height: 100,
|
|
439
|
+
text: 'SOURCE: state.icon\nEXPECT ICON: Check\n(pv.icon=settings ignored)',
|
|
440
|
+
color: '#00FF00',
|
|
441
|
+
pv: {
|
|
442
|
+
nodeType: 'icon-state-demo',
|
|
443
|
+
shape: 'rectangle',
|
|
444
|
+
icon: 'settings', // Type icon - should be overridden
|
|
445
|
+
states: {
|
|
446
|
+
complete: { label: 'Complete', color: '#00FF00', icon: 'check' },
|
|
447
|
+
},
|
|
448
|
+
},
|
|
449
|
+
},
|
|
450
|
+
],
|
|
451
|
+
edges: [],
|
|
452
|
+
pv: {
|
|
453
|
+
version: '1.0.0',
|
|
454
|
+
name: 'Icon Priority Demo',
|
|
455
|
+
description: 'Shows how icons are prioritized',
|
|
456
|
+
edgeTypes: {},
|
|
457
|
+
},
|
|
458
|
+
};
|
|
459
|
+
|
|
460
|
+
export const IconPriority: Story = {
|
|
461
|
+
render: () => (
|
|
462
|
+
<GraphWithInitialStates
|
|
463
|
+
canvas={iconPriorityCanvas}
|
|
464
|
+
width={600}
|
|
465
|
+
height={320}
|
|
466
|
+
showMinimap={false}
|
|
467
|
+
initialStates={{ 'icon-state': 'complete' }}
|
|
468
|
+
/>
|
|
469
|
+
),
|
|
470
|
+
parameters: {
|
|
471
|
+
docs: {
|
|
472
|
+
description: {
|
|
473
|
+
story: `
|
|
474
|
+
**Icon Priority** (highest to lowest):
|
|
475
|
+
|
|
476
|
+
1. **Node data icon override** - Explicitly set icon in node data
|
|
477
|
+
2. **State icon** - Icon from the current state definition
|
|
478
|
+
3. **Type definition icon** - Icon from pv.icon
|
|
479
|
+
|
|
480
|
+
In this demo:
|
|
481
|
+
- Node 1: Only has type icon (settings) → shows settings
|
|
482
|
+
- Node 2: Has type icon (settings) BUT is in "complete" state with check icon → shows check
|
|
483
|
+
`,
|
|
484
|
+
},
|
|
485
|
+
},
|
|
486
|
+
},
|
|
487
|
+
};
|
|
488
|
+
|
|
489
|
+
// ============================================================================
|
|
490
|
+
// Combined Priority Demo - All in One
|
|
491
|
+
// ============================================================================
|
|
492
|
+
|
|
493
|
+
const combinedPriorityCanvas: ExtendedCanvas = {
|
|
494
|
+
nodes: [
|
|
495
|
+
// Row 1 label
|
|
496
|
+
{
|
|
497
|
+
id: 'label-row1',
|
|
498
|
+
type: 'text',
|
|
499
|
+
x: 50,
|
|
500
|
+
y: 50,
|
|
501
|
+
width: 700,
|
|
502
|
+
height: 40,
|
|
503
|
+
text: 'FILL COLOR PRIORITY (low to high): Default → node.color → pv.fill → state.color',
|
|
504
|
+
pv: { nodeType: 'label', shape: 'rectangle' },
|
|
505
|
+
},
|
|
506
|
+
// Lowest priority
|
|
507
|
+
{
|
|
508
|
+
id: 'fill-1',
|
|
509
|
+
type: 'text',
|
|
510
|
+
x: 50,
|
|
511
|
+
y: 120,
|
|
512
|
+
width: 150,
|
|
513
|
+
height: 80,
|
|
514
|
+
text: 'SOURCE: Default\nEXPECT: Gray',
|
|
515
|
+
pv: { nodeType: 'fill-demo', shape: 'rectangle' },
|
|
516
|
+
},
|
|
517
|
+
// node.color
|
|
518
|
+
{
|
|
519
|
+
id: 'fill-2',
|
|
520
|
+
type: 'text',
|
|
521
|
+
x: 230,
|
|
522
|
+
y: 120,
|
|
523
|
+
width: 150,
|
|
524
|
+
height: 80,
|
|
525
|
+
text: 'SOURCE: node.color\nEXPECT: BLUE',
|
|
526
|
+
color: '#0000FF',
|
|
527
|
+
pv: { nodeType: 'fill-demo', shape: 'rectangle' },
|
|
528
|
+
},
|
|
529
|
+
// pv.fill
|
|
530
|
+
{
|
|
531
|
+
id: 'fill-3',
|
|
532
|
+
type: 'text',
|
|
533
|
+
x: 410,
|
|
534
|
+
y: 120,
|
|
535
|
+
width: 150,
|
|
536
|
+
height: 80,
|
|
537
|
+
text: 'SOURCE: pv.fill\nEXPECT: GREEN',
|
|
538
|
+
color: '#0000FF',
|
|
539
|
+
pv: { nodeType: 'fill-demo', shape: 'rectangle', fill: '#00FF00' },
|
|
540
|
+
},
|
|
541
|
+
// state color
|
|
542
|
+
{
|
|
543
|
+
id: 'fill-4',
|
|
544
|
+
type: 'text',
|
|
545
|
+
x: 590,
|
|
546
|
+
y: 120,
|
|
547
|
+
width: 150,
|
|
548
|
+
height: 80,
|
|
549
|
+
text: 'SOURCE: state.color\nEXPECT: RED',
|
|
550
|
+
color: '#0000FF',
|
|
551
|
+
pv: {
|
|
552
|
+
nodeType: 'fill-demo',
|
|
553
|
+
shape: 'rectangle',
|
|
554
|
+
fill: '#00FF00',
|
|
555
|
+
states: { error: { label: 'Error', color: '#FF0000' } },
|
|
556
|
+
},
|
|
557
|
+
},
|
|
558
|
+
// Row 2 label
|
|
559
|
+
{
|
|
560
|
+
id: 'label-row2',
|
|
561
|
+
type: 'text',
|
|
562
|
+
x: 50,
|
|
563
|
+
y: 240,
|
|
564
|
+
width: 500,
|
|
565
|
+
height: 40,
|
|
566
|
+
text: 'STROKE PRIORITY (low to high): fill color → pv.stroke',
|
|
567
|
+
pv: { nodeType: 'label', shape: 'rectangle' },
|
|
568
|
+
},
|
|
569
|
+
// Stroke = fill
|
|
570
|
+
{
|
|
571
|
+
id: 'stroke-1',
|
|
572
|
+
type: 'text',
|
|
573
|
+
x: 50,
|
|
574
|
+
y: 310,
|
|
575
|
+
width: 180,
|
|
576
|
+
height: 80,
|
|
577
|
+
text: 'SOURCE: Default (=fill)\nEXPECT BORDER: BLUE',
|
|
578
|
+
color: '#0000FF',
|
|
579
|
+
pv: { nodeType: 'stroke-demo', shape: 'rectangle' },
|
|
580
|
+
},
|
|
581
|
+
// pv.stroke
|
|
582
|
+
{
|
|
583
|
+
id: 'stroke-2',
|
|
584
|
+
type: 'text',
|
|
585
|
+
x: 260,
|
|
586
|
+
y: 310,
|
|
587
|
+
width: 180,
|
|
588
|
+
height: 80,
|
|
589
|
+
text: 'SOURCE: pv.stroke\nEXPECT BORDER: YELLOW',
|
|
590
|
+
color: '#0000FF',
|
|
591
|
+
pv: { nodeType: 'stroke-demo', shape: 'rectangle', stroke: '#FFFF00' },
|
|
592
|
+
},
|
|
593
|
+
],
|
|
594
|
+
edges: [],
|
|
595
|
+
pv: {
|
|
596
|
+
version: '1.0.0',
|
|
597
|
+
name: 'Combined Color Priority Demo',
|
|
598
|
+
description: 'Overview of all color priorities',
|
|
599
|
+
edgeTypes: {},
|
|
600
|
+
},
|
|
601
|
+
};
|
|
602
|
+
|
|
603
|
+
export const CombinedPriorityOverview: Story = {
|
|
604
|
+
render: () => (
|
|
605
|
+
<GraphWithInitialStates
|
|
606
|
+
canvas={combinedPriorityCanvas}
|
|
607
|
+
width={850}
|
|
608
|
+
height={480}
|
|
609
|
+
showMinimap={false}
|
|
610
|
+
initialStates={{ 'fill-4': 'error' }}
|
|
611
|
+
/>
|
|
612
|
+
),
|
|
613
|
+
parameters: {
|
|
614
|
+
docs: {
|
|
615
|
+
description: {
|
|
616
|
+
story: `
|
|
617
|
+
**Complete Color Priority Reference**
|
|
618
|
+
|
|
619
|
+
This story shows all color priority chains at a glance:
|
|
620
|
+
|
|
621
|
+
**Fill Color:** Default (#888) → node.color → pv.fill → State color
|
|
622
|
+
|
|
623
|
+
**Stroke Color:** Fill color → pv.stroke
|
|
624
|
+
|
|
625
|
+
Higher priority always wins when multiple values are specified.
|
|
626
|
+
`,
|
|
627
|
+
},
|
|
628
|
+
},
|
|
629
|
+
},
|
|
630
|
+
};
|
|
@@ -28,7 +28,7 @@ const sampleCanvas: ExtendedCanvas = {
|
|
|
28
28
|
height: 70,
|
|
29
29
|
text: 'Source',
|
|
30
30
|
color: '#4A90E2',
|
|
31
|
-
|
|
31
|
+
pv: {
|
|
32
32
|
nodeType: 'process',
|
|
33
33
|
shape: 'rectangle',
|
|
34
34
|
icon: 'Settings',
|
|
@@ -49,7 +49,7 @@ const sampleCanvas: ExtendedCanvas = {
|
|
|
49
49
|
height: 70,
|
|
50
50
|
text: 'Processor',
|
|
51
51
|
color: '#4A90E2',
|
|
52
|
-
|
|
52
|
+
pv: {
|
|
53
53
|
nodeType: 'process',
|
|
54
54
|
shape: 'rectangle',
|
|
55
55
|
icon: 'Settings',
|
|
@@ -70,7 +70,7 @@ const sampleCanvas: ExtendedCanvas = {
|
|
|
70
70
|
height: 100,
|
|
71
71
|
text: 'Storage',
|
|
72
72
|
color: '#7B68EE',
|
|
73
|
-
|
|
73
|
+
pv: {
|
|
74
74
|
nodeType: 'data',
|
|
75
75
|
shape: 'circle',
|
|
76
76
|
icon: 'Database',
|
|
@@ -82,16 +82,16 @@ const sampleCanvas: ExtendedCanvas = {
|
|
|
82
82
|
id: 'edge-1',
|
|
83
83
|
fromNode: 'node-1',
|
|
84
84
|
toNode: 'node-2',
|
|
85
|
-
|
|
85
|
+
pv: { edgeType: 'dataflow' },
|
|
86
86
|
},
|
|
87
87
|
{
|
|
88
88
|
id: 'edge-2',
|
|
89
89
|
fromNode: 'node-2',
|
|
90
90
|
toNode: 'node-3',
|
|
91
|
-
|
|
91
|
+
pv: { edgeType: 'dataflow' },
|
|
92
92
|
},
|
|
93
93
|
],
|
|
94
|
-
|
|
94
|
+
pv: {
|
|
95
95
|
version: '1.0.0',
|
|
96
96
|
name: 'Event-Driven Animation Demo',
|
|
97
97
|
description: 'Demonstrates event-driven animations',
|