@principal-ai/subsystems-react 0.17.0 → 0.18.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.ts +7 -44
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -32
- package/dist/index.js.map +1 -1
- package/package.json +2 -2
- package/src/index.ts +9 -199
- package/src/components/ConfigurationSelector.tsx +0 -133
- package/src/components/GraphRenderer.tsx +0 -3195
- package/src/components/MultiCanvasRenderer.tsx +0 -295
- package/src/components/NodeTooltip.tsx +0 -279
- package/src/components/PendingChanges.test.tsx +0 -375
- package/src/components/SelectionSidebar.tsx +0 -352
- package/src/components/SequenceDiagramRenderer.tsx +0 -1156
- package/src/components/WorkflowSequenceDiagram.tsx +0 -270
- package/src/components/dashboard/DashboardRenderer.tsx +0 -317
- package/src/components/dashboard/MetricPanel.tsx +0 -254
- package/src/components/dashboard/MockDataProvider.ts +0 -330
- package/src/components/dashboard/components/BarChart.tsx +0 -299
- package/src/components/dashboard/components/LineChart.tsx +0 -279
- package/src/components/dashboard/components/MetricCard.tsx +0 -270
- package/src/components/dashboard/components/SourceLink.tsx +0 -63
- package/src/components/dashboard/components/TimeRangeSelector.tsx +0 -280
- package/src/components/dashboard/components/index.ts +0 -5
- package/src/components/dashboard/index.ts +0 -47
- package/src/components/dashboard/types.ts +0 -126
- package/src/components/state-view/PipelineView.tsx +0 -347
- package/src/components/state-view/index.ts +0 -14
- package/src/components/state-view/types.ts +0 -261
- package/src/components/state-view/useStateView.ts +0 -205
- package/src/contexts/GraphEditContext.tsx +0 -27
- package/src/contexts/TooltipPortalContext.ts +0 -8
- package/src/edges/CustomEdge.tsx +0 -402
- package/src/edges/GenericEdge.tsx +0 -36
- package/src/hooks/usePathBasedEvents.ts +0 -192
- package/src/hooks/useSequenceLayout.ts +0 -543
- package/src/hooks/useUndoRedo.ts +0 -144
- package/src/nodes/CustomNode.tsx +0 -1231
- package/src/nodes/GenericNode.tsx +0 -55
- package/src/nodes/otel/OtelBoundaryNode.tsx +0 -224
- package/src/nodes/otel/OtelEventNode.tsx +0 -225
- package/src/nodes/otel/OtelResourceNode.tsx +0 -251
- package/src/nodes/otel/OtelScopeNode.tsx +0 -221
- package/src/nodes/otel/OtelSpanConventionNode.tsx +0 -295
- package/src/nodes/otel/index.ts +0 -23
- package/src/nodes/otel/shared/NodeBadges.tsx +0 -295
- package/src/nodes/otel/shared/NodeContent.tsx +0 -204
- package/src/nodes/otel/shared/index.ts +0 -8
- package/src/nodes/otel/shared/types.ts +0 -138
- package/src/nodes/otel/shared/useNodeBehavior.ts +0 -114
- package/src/stories/Audit/BoundaryNodes.stories.tsx +0 -385
- package/src/stories/Audit/CanvasEdgeTypes.stories.tsx +0 -1448
- package/src/stories/Audit/CanvasNodeTypes.stories.tsx +0 -1049
- package/src/stories/Audit/ColorPriority.stories.tsx +0 -895
- package/src/stories/Audit/DiamondBadges.stories.tsx +0 -629
- package/src/stories/Audit/NodeDimensionsTesting.stories.tsx +0 -724
- package/src/stories/Audit/NodeFieldsAudit.stories.tsx +0 -996
- package/src/stories/Audit/NodeFontSizeTesting.stories.tsx +0 -715
- package/src/stories/Audit/NodeShapes.stories.tsx +0 -1208
- package/src/stories/Audit/WideNodesTesting.stories.tsx +0 -1045
- package/src/stories/Components/DashboardRenderer.stories.tsx +0 -263
- package/src/stories/Components/GraphRenderer.stories.tsx +0 -3236
- package/src/stories/Components/MultiCanvasRenderer.stories.tsx +0 -370
- package/src/stories/Components/SequenceDiagram.stories.tsx +0 -255
- package/src/stories/Components/StateView.stories.tsx +0 -417
- package/src/stories/Components/TraceViewer.stories.tsx +0 -442
- package/src/stories/Components/WorkflowSequenceDiagram.stories.tsx +0 -802
- package/src/stories/Features/AnimationWorkshop.stories.tsx +0 -727
- package/src/stories/Features/ChangeTypeVisual.stories.tsx +0 -67
- package/src/stories/Features/EventDrivenAnimations.stories.tsx +0 -513
- package/src/stories/Features/MultiConfig.stories.tsx +0 -539
- package/src/stories/Layout/ElkEdgeRouting.stories.tsx +0 -539
- package/src/stories/Layout/GraphOrientation.stories.tsx +0 -500
- package/src/stories/Layout/MultiDirectionalConnections.stories.tsx +0 -352
- package/src/stories/Nodes/NodeDefinitionComparison.stories.tsx +0 -560
- package/src/stories/Nodes/NodeNameFallbacks.stories.tsx +0 -491
- package/src/stories/Nodes/NumericColors.stories.tsx +0 -440
- package/src/stories/OTEL/EventNameDisplay.stories.tsx +0 -694
- package/src/stories/OTEL/EventNameFallback.stories.tsx +0 -578
- package/src/stories/OTEL/OtelComponents.stories.tsx +0 -422
- package/src/stories/OTEL/OtelNodeTypesPrototype.stories.tsx +0 -806
- package/src/stories/OTEL/RawEventCards.stories.tsx +0 -57
- package/src/stories/OTEL/SpanBadges.stories.tsx +0 -840
- package/src/stories/OTEL/ValidationEventsCanvas.stories.tsx +0 -209
- package/src/stories/RealWorld/BacklogMdCanvases.stories.tsx +0 -721
- package/src/stories/RealWorld/FileCitySequence.stories.tsx +0 -516
- package/src/stories/RealWorld/RealCanvasFiles.stories.tsx +0 -336
- package/src/stories/__traces__/test-run.canvas.json +0 -241
- package/src/stories/data/activity-feed-analytics.dashboard.json +0 -300
- package/src/stories/data/file-city-images-transformed.otel.canvas.json +0 -295
- package/src/stories/data/file-city-workflows.json +0 -269
- package/src/stories/data/graph-converter-test-execution.json +0 -443
- package/src/stories/data/graph-converter-test.workflow.json +0 -105
- package/src/stories/data/graph-converter-validated-execution.json +0 -58
- package/src/utils/animationMapping.ts +0 -166
- package/src/utils/canvasBounds.ts +0 -146
- package/src/utils/graphConverter.ts +0 -148
- package/src/utils/iconResolver.tsx +0 -53
- package/src/utils/orientationUtils.ts +0 -73
|
@@ -1,500 +0,0 @@
|
|
|
1
|
-
import React, { useState, useMemo } from 'react';
|
|
2
|
-
import type { Meta, StoryObj } from '@storybook/react';
|
|
3
|
-
import { GraphRenderer } from '../../components/GraphRenderer';
|
|
4
|
-
import type { ExtendedCanvas } from '@principal-ai/subsystems-core';
|
|
5
|
-
import { ThemeProvider, defaultEditorTheme } from '@principal-ade/industry-theme';
|
|
6
|
-
import { swapGraphOrientation } from '../../utils/orientationUtils';
|
|
7
|
-
import { CanvasConverter } from '@principal-ai/subsystems-core';
|
|
8
|
-
|
|
9
|
-
const meta = {
|
|
10
|
-
title: 'Layout/GraphOrientation',
|
|
11
|
-
component: GraphRenderer,
|
|
12
|
-
parameters: {
|
|
13
|
-
layout: 'centered',
|
|
14
|
-
},
|
|
15
|
-
tags: ['autodocs'],
|
|
16
|
-
decorators: [
|
|
17
|
-
(Story) => (
|
|
18
|
-
<ThemeProvider theme={defaultEditorTheme}>
|
|
19
|
-
<Story />
|
|
20
|
-
</ThemeProvider>
|
|
21
|
-
),
|
|
22
|
-
],
|
|
23
|
-
} satisfies Meta<typeof GraphRenderer>;
|
|
24
|
-
|
|
25
|
-
export default meta;
|
|
26
|
-
type Story = StoryObj<typeof meta>;
|
|
27
|
-
|
|
28
|
-
/**
|
|
29
|
-
* Canvas with horizontal flow (left to right)
|
|
30
|
-
*/
|
|
31
|
-
const horizontalCanvas: ExtendedCanvas = {
|
|
32
|
-
nodes: [
|
|
33
|
-
{
|
|
34
|
-
id: 'start',
|
|
35
|
-
type: 'text',
|
|
36
|
-
x: 100,
|
|
37
|
-
y: 200,
|
|
38
|
-
width: 120,
|
|
39
|
-
height: 80,
|
|
40
|
-
text: 'Start',
|
|
41
|
-
color: 4,
|
|
42
|
-
pv: {
|
|
43
|
-
nodeType: 'process',
|
|
44
|
-
shape: 'circle',
|
|
45
|
-
icon: 'Play',
|
|
46
|
-
},
|
|
47
|
-
},
|
|
48
|
-
{
|
|
49
|
-
id: 'process-1',
|
|
50
|
-
type: 'text',
|
|
51
|
-
x: 300,
|
|
52
|
-
y: 200,
|
|
53
|
-
width: 140,
|
|
54
|
-
height: 80,
|
|
55
|
-
text: 'Process 1',
|
|
56
|
-
color: 6,
|
|
57
|
-
pv: {
|
|
58
|
-
nodeType: 'process',
|
|
59
|
-
shape: 'rectangle',
|
|
60
|
-
icon: 'Box',
|
|
61
|
-
},
|
|
62
|
-
},
|
|
63
|
-
{
|
|
64
|
-
id: 'decision',
|
|
65
|
-
type: 'text',
|
|
66
|
-
x: 520,
|
|
67
|
-
y: 200,
|
|
68
|
-
width: 100,
|
|
69
|
-
height: 100,
|
|
70
|
-
text: 'Decision',
|
|
71
|
-
color: 2,
|
|
72
|
-
pv: {
|
|
73
|
-
nodeType: 'decision',
|
|
74
|
-
shape: 'diamond',
|
|
75
|
-
icon: 'GitBranch',
|
|
76
|
-
},
|
|
77
|
-
},
|
|
78
|
-
{
|
|
79
|
-
id: 'process-2a',
|
|
80
|
-
type: 'text',
|
|
81
|
-
x: 700,
|
|
82
|
-
y: 120,
|
|
83
|
-
width: 140,
|
|
84
|
-
height: 80,
|
|
85
|
-
text: 'Process 2A',
|
|
86
|
-
color: 6,
|
|
87
|
-
pv: {
|
|
88
|
-
nodeType: 'process',
|
|
89
|
-
shape: 'rectangle',
|
|
90
|
-
icon: 'Box',
|
|
91
|
-
},
|
|
92
|
-
},
|
|
93
|
-
{
|
|
94
|
-
id: 'process-2b',
|
|
95
|
-
type: 'text',
|
|
96
|
-
x: 700,
|
|
97
|
-
y: 280,
|
|
98
|
-
width: 140,
|
|
99
|
-
height: 80,
|
|
100
|
-
text: 'Process 2B',
|
|
101
|
-
color: 6,
|
|
102
|
-
pv: {
|
|
103
|
-
nodeType: 'process',
|
|
104
|
-
shape: 'rectangle',
|
|
105
|
-
icon: 'Box',
|
|
106
|
-
},
|
|
107
|
-
},
|
|
108
|
-
{
|
|
109
|
-
id: 'end',
|
|
110
|
-
type: 'text',
|
|
111
|
-
x: 920,
|
|
112
|
-
y: 200,
|
|
113
|
-
width: 120,
|
|
114
|
-
height: 80,
|
|
115
|
-
text: 'End',
|
|
116
|
-
color: 5,
|
|
117
|
-
pv: {
|
|
118
|
-
nodeType: 'process',
|
|
119
|
-
shape: 'circle',
|
|
120
|
-
icon: 'CheckCircle',
|
|
121
|
-
},
|
|
122
|
-
},
|
|
123
|
-
],
|
|
124
|
-
edges: [
|
|
125
|
-
{
|
|
126
|
-
id: 'e1',
|
|
127
|
-
fromNode: 'start',
|
|
128
|
-
toNode: 'process-1',
|
|
129
|
-
fromSide: 'right',
|
|
130
|
-
toSide: 'left',
|
|
131
|
-
pv: {
|
|
132
|
-
edgeType: 'flow',
|
|
133
|
-
},
|
|
134
|
-
},
|
|
135
|
-
{
|
|
136
|
-
id: 'e2',
|
|
137
|
-
fromNode: 'process-1',
|
|
138
|
-
toNode: 'decision',
|
|
139
|
-
fromSide: 'right',
|
|
140
|
-
toSide: 'left',
|
|
141
|
-
pv: {
|
|
142
|
-
edgeType: 'flow',
|
|
143
|
-
},
|
|
144
|
-
},
|
|
145
|
-
{
|
|
146
|
-
id: 'e3',
|
|
147
|
-
fromNode: 'decision',
|
|
148
|
-
toNode: 'process-2a',
|
|
149
|
-
fromSide: 'top',
|
|
150
|
-
toSide: 'left',
|
|
151
|
-
pv: {
|
|
152
|
-
edgeType: 'flow',
|
|
153
|
-
},
|
|
154
|
-
},
|
|
155
|
-
{
|
|
156
|
-
id: 'e4',
|
|
157
|
-
fromNode: 'decision',
|
|
158
|
-
toNode: 'process-2b',
|
|
159
|
-
fromSide: 'bottom',
|
|
160
|
-
toSide: 'left',
|
|
161
|
-
pv: {
|
|
162
|
-
edgeType: 'flow',
|
|
163
|
-
},
|
|
164
|
-
},
|
|
165
|
-
{
|
|
166
|
-
id: 'e5',
|
|
167
|
-
fromNode: 'process-2a',
|
|
168
|
-
toNode: 'end',
|
|
169
|
-
fromSide: 'right',
|
|
170
|
-
toSide: 'top',
|
|
171
|
-
pv: {
|
|
172
|
-
edgeType: 'flow',
|
|
173
|
-
},
|
|
174
|
-
},
|
|
175
|
-
{
|
|
176
|
-
id: 'e6',
|
|
177
|
-
fromNode: 'process-2b',
|
|
178
|
-
toNode: 'end',
|
|
179
|
-
fromSide: 'right',
|
|
180
|
-
toSide: 'bottom',
|
|
181
|
-
pv: {
|
|
182
|
-
edgeType: 'flow',
|
|
183
|
-
},
|
|
184
|
-
},
|
|
185
|
-
],
|
|
186
|
-
pv: {
|
|
187
|
-
version: '1.0.0',
|
|
188
|
-
name: 'Horizontal Flow',
|
|
189
|
-
description: 'Graph with horizontal (left-to-right) orientation',
|
|
190
|
-
edgeTypes: {
|
|
191
|
-
flow: {
|
|
192
|
-
description: 'Flow connection',
|
|
193
|
-
style: 'solid',
|
|
194
|
-
color: '#888',
|
|
195
|
-
},
|
|
196
|
-
},
|
|
197
|
-
},
|
|
198
|
-
};
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* Interactive story demonstrating orientation swap
|
|
202
|
-
*/
|
|
203
|
-
const OrientationSwapTemplate = () => {
|
|
204
|
-
const [isVertical, setIsVertical] = useState(false);
|
|
205
|
-
|
|
206
|
-
const canvas = useMemo(() => {
|
|
207
|
-
if (!isVertical) {
|
|
208
|
-
return horizontalCanvas;
|
|
209
|
-
}
|
|
210
|
-
|
|
211
|
-
// Convert canvas to internal format
|
|
212
|
-
const { nodes: nodeStates, edges: edgeStates } =
|
|
213
|
-
CanvasConverter.canvasToGraph(horizontalCanvas);
|
|
214
|
-
|
|
215
|
-
// Swap orientation
|
|
216
|
-
const { nodes: swappedNodes, edges: swappedEdges } = swapGraphOrientation(
|
|
217
|
-
nodeStates,
|
|
218
|
-
edgeStates
|
|
219
|
-
);
|
|
220
|
-
|
|
221
|
-
// Convert back to canvas format for rendering
|
|
222
|
-
return {
|
|
223
|
-
...horizontalCanvas,
|
|
224
|
-
nodes: swappedNodes.map((node, idx) => ({
|
|
225
|
-
...horizontalCanvas.nodes[idx],
|
|
226
|
-
x: node.position?.x ?? 0,
|
|
227
|
-
y: node.position?.y ?? 0,
|
|
228
|
-
})),
|
|
229
|
-
edges: swappedEdges.map((edge, idx) => {
|
|
230
|
-
const data = edge.data as Record<string, unknown> | undefined;
|
|
231
|
-
return {
|
|
232
|
-
...horizontalCanvas.edges[idx],
|
|
233
|
-
fromSide: (data?.fromSide as 'top' | 'right' | 'bottom' | 'left') ?? 'bottom',
|
|
234
|
-
toSide: (data?.toSide as 'top' | 'right' | 'bottom' | 'left') ?? 'top',
|
|
235
|
-
};
|
|
236
|
-
}),
|
|
237
|
-
};
|
|
238
|
-
}, [isVertical]);
|
|
239
|
-
|
|
240
|
-
return (
|
|
241
|
-
<div style={{ padding: 20 }}>
|
|
242
|
-
<div style={{ marginBottom: 20, display: 'flex', alignItems: 'center', gap: 20 }}>
|
|
243
|
-
<h2 style={{ margin: 0, fontFamily: 'system-ui' }}>Graph Orientation</h2>
|
|
244
|
-
<button
|
|
245
|
-
onClick={() => setIsVertical(!isVertical)}
|
|
246
|
-
style={{
|
|
247
|
-
padding: '8px 16px',
|
|
248
|
-
fontSize: 14,
|
|
249
|
-
fontFamily: 'system-ui',
|
|
250
|
-
backgroundColor: '#3b82f6',
|
|
251
|
-
color: 'white',
|
|
252
|
-
border: 'none',
|
|
253
|
-
borderRadius: 6,
|
|
254
|
-
cursor: 'pointer',
|
|
255
|
-
}}
|
|
256
|
-
>
|
|
257
|
-
Switch to {isVertical ? 'Horizontal' : 'Vertical'}
|
|
258
|
-
</button>
|
|
259
|
-
<div style={{ fontSize: 14, color: '#666', fontFamily: 'system-ui' }}>
|
|
260
|
-
Current: <strong>{isVertical ? 'Vertical (Top-to-Bottom)' : 'Horizontal (Left-to-Right)'}</strong>
|
|
261
|
-
</div>
|
|
262
|
-
</div>
|
|
263
|
-
|
|
264
|
-
<GraphRenderer
|
|
265
|
-
key={isVertical ? 'vertical' : 'horizontal'}
|
|
266
|
-
canvas={canvas}
|
|
267
|
-
width={isVertical ? 500 : 1100}
|
|
268
|
-
height={isVertical ? 1100 : 500}
|
|
269
|
-
/>
|
|
270
|
-
|
|
271
|
-
<div style={{ marginTop: 30, padding: 16, backgroundColor: '#f5f5f5', borderRadius: 8 }}>
|
|
272
|
-
<h4 style={{ marginBottom: 10, fontFamily: 'system-ui' }}>How It Works</h4>
|
|
273
|
-
<ul style={{ fontSize: 13, lineHeight: 1.8, margin: 0, paddingLeft: 20 }}>
|
|
274
|
-
<li>
|
|
275
|
-
<strong>Position Swap</strong>: Swaps x and y coordinates of all nodes
|
|
276
|
-
</li>
|
|
277
|
-
<li>
|
|
278
|
-
<strong>Edge Side Rotation</strong>: Both sides rotate <strong>clockwise</strong>
|
|
279
|
-
<ul style={{ marginTop: 5 }}>
|
|
280
|
-
<li><code>top → right → bottom → left → top</code></li>
|
|
281
|
-
<li>Example: <code>right → left</code> becomes <code>bottom → top</code></li>
|
|
282
|
-
</ul>
|
|
283
|
-
</li>
|
|
284
|
-
<li>
|
|
285
|
-
<strong>Usage</strong>: <code>swapGraphOrientation(nodes, edges)</code>
|
|
286
|
-
</li>
|
|
287
|
-
</ul>
|
|
288
|
-
</div>
|
|
289
|
-
</div>
|
|
290
|
-
);
|
|
291
|
-
};
|
|
292
|
-
|
|
293
|
-
export const InteractiveOrientationSwap: Story = {
|
|
294
|
-
render: () => <OrientationSwapTemplate />,
|
|
295
|
-
parameters: {
|
|
296
|
-
docs: {
|
|
297
|
-
description: {
|
|
298
|
-
story: `
|
|
299
|
-
**Interactive Orientation Swap**
|
|
300
|
-
|
|
301
|
-
Click the button to toggle between horizontal (left-to-right) and vertical (top-to-bottom) orientations.
|
|
302
|
-
|
|
303
|
-
The \`swapGraphOrientation\` utility:
|
|
304
|
-
1. Swaps x/y coordinates for all node positions
|
|
305
|
-
2. Rotates edge connection sides clockwise (both fromSide and toSide)
|
|
306
|
-
- Rotation: top → right → bottom → left → top
|
|
307
|
-
- Example: \`right → left\` becomes \`bottom → top\`
|
|
308
|
-
3. Preserves the graph structure while rotating it 90 degrees
|
|
309
|
-
`,
|
|
310
|
-
},
|
|
311
|
-
},
|
|
312
|
-
},
|
|
313
|
-
};
|
|
314
|
-
|
|
315
|
-
/**
|
|
316
|
-
* Horizontal flow example
|
|
317
|
-
*/
|
|
318
|
-
export const HorizontalFlow: Story = {
|
|
319
|
-
args: {
|
|
320
|
-
canvas: horizontalCanvas,
|
|
321
|
-
width: 1100,
|
|
322
|
-
height: 450,
|
|
323
|
-
},
|
|
324
|
-
parameters: {
|
|
325
|
-
docs: {
|
|
326
|
-
description: {
|
|
327
|
-
story: `
|
|
328
|
-
**Horizontal Flow (Left-to-Right)**
|
|
329
|
-
|
|
330
|
-
Traditional left-to-right flowchart layout:
|
|
331
|
-
- Primary flow uses \`right → left\` connections
|
|
332
|
-
- Branches use \`top\` and \`bottom\` connections for splitting
|
|
333
|
-
- Typical for flowcharts and process diagrams
|
|
334
|
-
`,
|
|
335
|
-
},
|
|
336
|
-
},
|
|
337
|
-
},
|
|
338
|
-
};
|
|
339
|
-
|
|
340
|
-
/**
|
|
341
|
-
* Vertical flow example (using swapped canvas)
|
|
342
|
-
*/
|
|
343
|
-
const VerticalFlowTemplate = () => {
|
|
344
|
-
const verticalCanvas = useMemo(() => {
|
|
345
|
-
const { nodes: nodeStates, edges: edgeStates } =
|
|
346
|
-
CanvasConverter.canvasToGraph(horizontalCanvas);
|
|
347
|
-
|
|
348
|
-
const { nodes: swappedNodes, edges: swappedEdges } = swapGraphOrientation(
|
|
349
|
-
nodeStates,
|
|
350
|
-
edgeStates
|
|
351
|
-
);
|
|
352
|
-
|
|
353
|
-
return {
|
|
354
|
-
...horizontalCanvas,
|
|
355
|
-
pv: {
|
|
356
|
-
...horizontalCanvas.pv,
|
|
357
|
-
name: 'Vertical Flow',
|
|
358
|
-
description: 'Graph with vertical (top-to-bottom) orientation',
|
|
359
|
-
},
|
|
360
|
-
nodes: swappedNodes.map((node, idx) => ({
|
|
361
|
-
...horizontalCanvas.nodes[idx],
|
|
362
|
-
x: node.position?.x ?? 0,
|
|
363
|
-
y: node.position?.y ?? 0,
|
|
364
|
-
})),
|
|
365
|
-
edges: swappedEdges.map((edge, idx) => {
|
|
366
|
-
const data = edge.data as Record<string, unknown> | undefined;
|
|
367
|
-
return {
|
|
368
|
-
...horizontalCanvas.edges[idx],
|
|
369
|
-
fromSide: (data?.fromSide as 'top' | 'right' | 'bottom' | 'left') ?? 'bottom',
|
|
370
|
-
toSide: (data?.toSide as 'top' | 'right' | 'bottom' | 'left') ?? 'top',
|
|
371
|
-
};
|
|
372
|
-
}),
|
|
373
|
-
};
|
|
374
|
-
}, []);
|
|
375
|
-
|
|
376
|
-
return <GraphRenderer canvas={verticalCanvas} width={500} height={1100} />;
|
|
377
|
-
};
|
|
378
|
-
|
|
379
|
-
export const VerticalFlow: Story = {
|
|
380
|
-
render: () => <VerticalFlowTemplate />,
|
|
381
|
-
parameters: {
|
|
382
|
-
docs: {
|
|
383
|
-
description: {
|
|
384
|
-
story: `
|
|
385
|
-
**Vertical Flow (Top-to-Bottom)**
|
|
386
|
-
|
|
387
|
-
Top-to-bottom layout using \`swapGraphOrientation\`:
|
|
388
|
-
- Primary flow uses \`bottom → top\` connections
|
|
389
|
-
- Branches use \`left\` and \`right\` connections for splitting
|
|
390
|
-
- Common for hierarchical diagrams and org charts
|
|
391
|
-
`,
|
|
392
|
-
},
|
|
393
|
-
},
|
|
394
|
-
},
|
|
395
|
-
};
|
|
396
|
-
|
|
397
|
-
/**
|
|
398
|
-
* Side-by-side comparison
|
|
399
|
-
*/
|
|
400
|
-
const SideBySideTemplate = () => {
|
|
401
|
-
const verticalCanvas = useMemo(() => {
|
|
402
|
-
const { nodes: nodeStates, edges: edgeStates } =
|
|
403
|
-
CanvasConverter.canvasToGraph(horizontalCanvas);
|
|
404
|
-
|
|
405
|
-
const { nodes: swappedNodes, edges: swappedEdges } = swapGraphOrientation(
|
|
406
|
-
nodeStates,
|
|
407
|
-
edgeStates
|
|
408
|
-
);
|
|
409
|
-
|
|
410
|
-
return {
|
|
411
|
-
...horizontalCanvas,
|
|
412
|
-
nodes: swappedNodes.map((node, idx) => ({
|
|
413
|
-
...horizontalCanvas.nodes[idx],
|
|
414
|
-
x: node.position?.x ?? 0,
|
|
415
|
-
y: node.position?.y ?? 0,
|
|
416
|
-
})),
|
|
417
|
-
edges: swappedEdges.map((edge, idx) => {
|
|
418
|
-
const data = edge.data as Record<string, unknown> | undefined;
|
|
419
|
-
return {
|
|
420
|
-
...horizontalCanvas.edges[idx],
|
|
421
|
-
fromSide: (data?.fromSide as 'top' | 'right' | 'bottom' | 'left') ?? 'bottom',
|
|
422
|
-
toSide: (data?.toSide as 'top' | 'right' | 'bottom' | 'left') ?? 'top',
|
|
423
|
-
};
|
|
424
|
-
}),
|
|
425
|
-
};
|
|
426
|
-
}, []);
|
|
427
|
-
|
|
428
|
-
return (
|
|
429
|
-
<div style={{ padding: 20 }}>
|
|
430
|
-
<h2 style={{ marginBottom: 20, fontFamily: 'system-ui' }}>Orientation Comparison</h2>
|
|
431
|
-
|
|
432
|
-
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 40 }}>
|
|
433
|
-
<div>
|
|
434
|
-
<h3 style={{ fontFamily: 'system-ui', marginBottom: 10 }}>
|
|
435
|
-
Horizontal (Left-to-Right)
|
|
436
|
-
</h3>
|
|
437
|
-
<div style={{ border: '1px solid #ddd', borderRadius: 8, overflow: 'hidden' }}>
|
|
438
|
-
<GraphRenderer canvas={horizontalCanvas} width={550} height={400} />
|
|
439
|
-
</div>
|
|
440
|
-
<div style={{ marginTop: 10, fontSize: 13, color: '#666' }}>
|
|
441
|
-
Original orientation with right→left primary flow
|
|
442
|
-
</div>
|
|
443
|
-
</div>
|
|
444
|
-
|
|
445
|
-
<div>
|
|
446
|
-
<h3 style={{ fontFamily: 'system-ui', marginBottom: 10 }}>
|
|
447
|
-
Vertical (Top-to-Bottom)
|
|
448
|
-
</h3>
|
|
449
|
-
<div style={{ border: '1px solid #ddd', borderRadius: 8, overflow: 'hidden' }}>
|
|
450
|
-
<GraphRenderer canvas={verticalCanvas} width={550} height={400} />
|
|
451
|
-
</div>
|
|
452
|
-
<div style={{ marginTop: 10, fontSize: 13, color: '#666' }}>
|
|
453
|
-
Swapped orientation with bottom→top primary flow
|
|
454
|
-
</div>
|
|
455
|
-
</div>
|
|
456
|
-
</div>
|
|
457
|
-
|
|
458
|
-
<div style={{ marginTop: 30, padding: 16, backgroundColor: '#f5f5f5', borderRadius: 8 }}>
|
|
459
|
-
<h4 style={{ marginBottom: 10, fontFamily: 'system-ui' }}>
|
|
460
|
-
Edge Side Rotation (Both Clockwise)
|
|
461
|
-
</h4>
|
|
462
|
-
<div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 20 }}>
|
|
463
|
-
<div>
|
|
464
|
-
<strong>Clockwise Rotation:</strong>
|
|
465
|
-
<ul style={{ fontSize: 13, lineHeight: 1.8, marginTop: 8, paddingLeft: 20 }}>
|
|
466
|
-
<li><code>top</code> → <code>right</code></li>
|
|
467
|
-
<li><code>right</code> → <code>bottom</code></li>
|
|
468
|
-
<li><code>bottom</code> → <code>left</code></li>
|
|
469
|
-
<li><code>left</code> → <code>top</code></li>
|
|
470
|
-
</ul>
|
|
471
|
-
</div>
|
|
472
|
-
<div>
|
|
473
|
-
<strong>Examples:</strong>
|
|
474
|
-
<ul style={{ fontSize: 13, lineHeight: 1.8, marginTop: 8, paddingLeft: 20 }}>
|
|
475
|
-
<li><code>right → left</code> becomes <code>bottom → top</code></li>
|
|
476
|
-
<li><code>top → left</code> becomes <code>right → top</code></li>
|
|
477
|
-
<li><code>bottom → left</code> becomes <code>left → top</code></li>
|
|
478
|
-
</ul>
|
|
479
|
-
</div>
|
|
480
|
-
</div>
|
|
481
|
-
</div>
|
|
482
|
-
</div>
|
|
483
|
-
);
|
|
484
|
-
};
|
|
485
|
-
|
|
486
|
-
export const SideBySideComparison: Story = {
|
|
487
|
-
render: () => <SideBySideTemplate />,
|
|
488
|
-
parameters: {
|
|
489
|
-
docs: {
|
|
490
|
-
description: {
|
|
491
|
-
story: `
|
|
492
|
-
**Side-by-Side Comparison**
|
|
493
|
-
|
|
494
|
-
Visual comparison of the same graph in both orientations, showing how \`swapGraphOrientation\`
|
|
495
|
-
transforms the layout while preserving the graph structure and flow logic.
|
|
496
|
-
`,
|
|
497
|
-
},
|
|
498
|
-
},
|
|
499
|
-
},
|
|
500
|
-
};
|