orcasvn-react-diagrams 0.2.4 → 0.2.6
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/CHANGELOG.md +42 -4
- package/README.md +15 -32
- package/ai/api-contract.json +88 -3
- package/ai/manifest.json +1 -1
- package/dist/cjs/examples.js +6519 -4423
- package/dist/cjs/index.js +1513 -120
- package/dist/cjs/types/api/createDiagramEditor.d.ts +4 -1
- package/dist/cjs/types/api/types.d.ts +43 -1
- package/dist/cjs/types/displaybox/demos/LinkColorPoolDemoTab.d.ts +3 -0
- package/dist/cjs/types/displaybox/demos/OffsetAnchorAvoidanceDemoTab.d.ts +3 -0
- package/dist/cjs/types/displaybox/demos/SimpleDemo.d.ts +4 -1
- package/dist/cjs/types/displaybox/demos/ZoomToFitElementsDemoTab.d.ts +3 -0
- package/dist/cjs/types/displaybox/demos/linkColorPoolDemo.d.ts +2 -0
- package/dist/cjs/types/displaybox/demos/offsetAnchorAvoidanceDemo.d.ts +4 -0
- package/dist/cjs/types/displaybox/demos/textDemo.d.ts +3 -0
- package/dist/cjs/types/displaybox/demos/zoomToFitElementsDemo.d.ts +4 -0
- package/dist/cjs/types/displaybox/types.d.ts +3 -1
- package/dist/cjs/types/displaybox/useDemoEditor.d.ts +4 -2
- package/dist/cjs/types/engine/AutoLayoutService.d.ts +59 -2
- package/dist/cjs/types/engine/DiagramEngine.d.ts +20 -1
- package/dist/cjs/types/engine/LinkRoutingService.d.ts +9 -0
- package/dist/cjs/types/models/TextModel.d.ts +1 -0
- package/dist/cjs/types/renderer/konva/KonvaInteraction.d.ts +6 -0
- package/dist/cjs/types/strategies/ObstacleRouter.d.ts +2 -0
- package/dist/cjs/types/strategies/RouterStrategy.d.ts +10 -0
- package/dist/esm/examples.js +6519 -4423
- package/dist/esm/examples.js.map +1 -1
- package/dist/esm/index.js +1513 -120
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/types/api/createDiagramEditor.d.ts +4 -1
- package/dist/esm/types/api/types.d.ts +43 -1
- package/dist/esm/types/displaybox/demos/LinkColorPoolDemoTab.d.ts +3 -0
- package/dist/esm/types/displaybox/demos/OffsetAnchorAvoidanceDemoTab.d.ts +3 -0
- package/dist/esm/types/displaybox/demos/SimpleDemo.d.ts +4 -1
- package/dist/esm/types/displaybox/demos/ZoomToFitElementsDemoTab.d.ts +3 -0
- package/dist/esm/types/displaybox/demos/linkColorPoolDemo.d.ts +2 -0
- package/dist/esm/types/displaybox/demos/offsetAnchorAvoidanceDemo.d.ts +4 -0
- package/dist/esm/types/displaybox/demos/textDemo.d.ts +3 -0
- package/dist/esm/types/displaybox/demos/zoomToFitElementsDemo.d.ts +4 -0
- package/dist/esm/types/displaybox/types.d.ts +3 -1
- package/dist/esm/types/displaybox/useDemoEditor.d.ts +4 -2
- package/dist/esm/types/engine/AutoLayoutService.d.ts +59 -2
- package/dist/esm/types/engine/DiagramEngine.d.ts +20 -1
- package/dist/esm/types/engine/LinkRoutingService.d.ts +9 -0
- package/dist/esm/types/models/TextModel.d.ts +1 -0
- package/dist/esm/types/renderer/konva/KonvaInteraction.d.ts +6 -0
- package/dist/esm/types/strategies/ObstacleRouter.d.ts +2 -0
- package/dist/esm/types/strategies/RouterStrategy.d.ts +10 -0
- package/dist/examples.d.ts +56 -1
- package/dist/index.d.ts +60 -2
- package/docs/API_CONTRACT.md +73 -3
- package/docs/CAPABILITIES.md +8 -0
- package/docs/COMMANDS_EVENTS.md +8 -0
- package/docs/DOCUMENTATION_WORKFLOW.md +4 -1
- package/docs/INTEGRATION_PLAYBOOK.md +3 -0
- package/docs/STATE_INVARIANTS.md +4 -0
- package/package.json +1 -1
- package/src/displaybox/demos/AutoLayoutDemoTab.tsx +515 -381
- package/src/displaybox/demos/EngineEventsDemoTab.tsx +12 -11
- package/src/displaybox/demos/LinkColorPoolDemoTab.tsx +49 -0
- package/src/displaybox/demos/ObstacleRoutingDemoTab.tsx +52 -31
- package/src/displaybox/demos/OffsetAnchorAvoidanceDemoTab.tsx +30 -0
- package/src/displaybox/demos/SimpleDemo.tsx +18 -13
- package/src/displaybox/demos/TextLayoutDemoTab.tsx +18 -1
- package/src/displaybox/demos/ZoomToFitElementsDemoTab.tsx +29 -0
- package/src/displaybox/demos/autoLayoutDemo.ts +62 -26
- package/src/displaybox/demos/index.tsx +81 -57
- package/src/displaybox/demos/linkColorPoolDemo.ts +122 -0
- package/src/displaybox/demos/obstacleRoutingDemo.ts +77 -1
- package/src/displaybox/demos/offsetAnchorAvoidanceDemo.ts +211 -0
- package/src/displaybox/demos/routingDemo.ts +5 -5
- package/src/displaybox/demos/shared.ts +17 -12
- package/src/displaybox/demos/textDemo.ts +6 -2
- package/src/displaybox/demos/zoomToFitElementsDemo.ts +83 -0
- package/src/displaybox/types.ts +10 -8
|
@@ -22,17 +22,18 @@ const engineEventOptions = [
|
|
|
22
22
|
'elementClick',
|
|
23
23
|
'elementDragged',
|
|
24
24
|
'elementMoved',
|
|
25
|
-
'elementResized',
|
|
26
|
-
'
|
|
27
|
-
'
|
|
28
|
-
'
|
|
29
|
-
'
|
|
30
|
-
'
|
|
31
|
-
'
|
|
32
|
-
'
|
|
33
|
-
'
|
|
34
|
-
'
|
|
35
|
-
|
|
25
|
+
'elementResized',
|
|
26
|
+
'gridLayoutChanged',
|
|
27
|
+
'elementDeleted',
|
|
28
|
+
'portDeleted',
|
|
29
|
+
'linkDeleted',
|
|
30
|
+
'textDeleted',
|
|
31
|
+
'elementSelected',
|
|
32
|
+
'elementLinkStarted',
|
|
33
|
+
'elementLinkConnecting',
|
|
34
|
+
'elementLinkEnded',
|
|
35
|
+
'textSelected',
|
|
36
|
+
] as const;
|
|
36
37
|
type EngineEventKey = typeof engineEventOptions[number];
|
|
37
38
|
|
|
38
39
|
const formatEventPayload = (payload: EngineEventMap[EngineEventKey] | null) =>
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import React, { useMemo, useState } from 'react';
|
|
2
|
+
import SimpleDemo from './SimpleDemo';
|
|
3
|
+
import { linkColorPoolDemoConfig } from './linkColorPoolDemo';
|
|
4
|
+
|
|
5
|
+
type LinkColorMode = 'off' | 'default' | 'custom';
|
|
6
|
+
|
|
7
|
+
const customPool = ['#0b7285', '#e8590c', '#5f3dc4'];
|
|
8
|
+
|
|
9
|
+
const LinkColorPoolDemo = () => {
|
|
10
|
+
const [mode, setMode] = useState<LinkColorMode>('off');
|
|
11
|
+
const linkColorPoolPolicy = useMemo(() => {
|
|
12
|
+
if (mode === 'off') return undefined;
|
|
13
|
+
if (mode === 'default') return { enabled: true };
|
|
14
|
+
return { enabled: true, colors: customPool };
|
|
15
|
+
}, [mode]);
|
|
16
|
+
|
|
17
|
+
return (
|
|
18
|
+
<SimpleDemo
|
|
19
|
+
demo={linkColorPoolDemoConfig}
|
|
20
|
+
linkColorPoolPolicy={linkColorPoolPolicy}
|
|
21
|
+
beforeStage={
|
|
22
|
+
<div
|
|
23
|
+
style={{
|
|
24
|
+
marginBottom: 12,
|
|
25
|
+
padding: '10px 12px',
|
|
26
|
+
borderRadius: 8,
|
|
27
|
+
border: '1px solid #2d2d2d',
|
|
28
|
+
background: '#f4f4f4',
|
|
29
|
+
}}
|
|
30
|
+
>
|
|
31
|
+
<label htmlFor="link-color-mode" style={{ display: 'inline-flex', alignItems: 'center', gap: 8, fontWeight: 600 }}>
|
|
32
|
+
Color Mode
|
|
33
|
+
<select
|
|
34
|
+
id="link-color-mode"
|
|
35
|
+
value={mode}
|
|
36
|
+
onChange={(event) => setMode(event.target.value as LinkColorMode)}
|
|
37
|
+
>
|
|
38
|
+
<option value="off">Off (default behavior)</option>
|
|
39
|
+
<option value="default">Default 20-color pool</option>
|
|
40
|
+
<option value="custom">Custom pool (#0b7285, #e8590c, #5f3dc4)</option>
|
|
41
|
+
</select>
|
|
42
|
+
</label>
|
|
43
|
+
</div>
|
|
44
|
+
}
|
|
45
|
+
/>
|
|
46
|
+
);
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export default LinkColorPoolDemo;
|
|
@@ -1,31 +1,52 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import SimpleDemo from './SimpleDemo';
|
|
3
|
-
import { obstacleRoutingDemoConfig } from './obstacleRoutingDemo';
|
|
4
|
-
|
|
5
|
-
const ObstacleRoutingDemo = () =>
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
1
|
+
import React, { useMemo, useState } from 'react';
|
|
2
|
+
import SimpleDemo from './SimpleDemo';
|
|
3
|
+
import { obstacleRoutingDemoConfig } from './obstacleRoutingDemo';
|
|
4
|
+
|
|
5
|
+
const ObstacleRoutingDemo = () => {
|
|
6
|
+
const [redrawRefreshEnabled, setRedrawRefreshEnabled] = useState(false);
|
|
7
|
+
const linkRouteRefreshPolicy = useMemo(
|
|
8
|
+
() =>
|
|
9
|
+
redrawRefreshEnabled
|
|
10
|
+
? { mode: 'redraw-two-endpoint-change' as const, includeManual: false }
|
|
11
|
+
: undefined,
|
|
12
|
+
[redrawRefreshEnabled],
|
|
13
|
+
);
|
|
14
|
+
|
|
15
|
+
return (
|
|
16
|
+
<SimpleDemo
|
|
17
|
+
demo={obstacleRoutingDemoConfig}
|
|
18
|
+
linkRouteRefreshPolicy={linkRouteRefreshPolicy}
|
|
19
|
+
beforeStage={
|
|
20
|
+
<div
|
|
21
|
+
style={{
|
|
22
|
+
marginBottom: 12,
|
|
23
|
+
padding: '10px 12px',
|
|
24
|
+
borderRadius: 8,
|
|
25
|
+
border: '1px solid #2d2d2d',
|
|
26
|
+
background: '#f4f4f4',
|
|
27
|
+
}}
|
|
28
|
+
>
|
|
29
|
+
<strong>Expected routing behavior</strong>
|
|
30
|
+
<ul style={{ margin: '6px 0 10px 16px' }}>
|
|
31
|
+
<li>Scenario A: the sibling link must not cross either child host interior.</li>
|
|
32
|
+
<li>Scenario B: parent endpoints use internal attach points while child/sibling endpoints use external attach points.</li>
|
|
33
|
+
<li>Scenario C: cross-parent link should exit source branch early, travel along the first common-ancestor corridor, then descend near target.</li>
|
|
34
|
+
<li>Use `Reroute All Links` repeatedly to verify deterministic routing output.</li>
|
|
35
|
+
<li>For redraw refresh check: keep the stale cross-branch link, toggle the option below, then click `Manual Render`.</li>
|
|
36
|
+
</ul>
|
|
37
|
+
<label htmlFor="obstacle-redraw-refresh-toggle" style={{ display: 'inline-flex', alignItems: 'center', gap: 8, fontWeight: 600 }}>
|
|
38
|
+
<input
|
|
39
|
+
id="obstacle-redraw-refresh-toggle"
|
|
40
|
+
type="checkbox"
|
|
41
|
+
checked={redrawRefreshEnabled}
|
|
42
|
+
onChange={(event) => setRedrawRefreshEnabled(event.target.checked)}
|
|
43
|
+
/>
|
|
44
|
+
Enable redraw refresh on two-endpoint change
|
|
45
|
+
</label>
|
|
46
|
+
</div>
|
|
47
|
+
}
|
|
48
|
+
/>
|
|
49
|
+
);
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
export default ObstacleRoutingDemo;
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import SimpleDemo from './SimpleDemo';
|
|
3
|
+
import { offsetAnchorAvoidanceDemoConfig } from './offsetAnchorAvoidanceDemo';
|
|
4
|
+
|
|
5
|
+
const OffsetAnchorAvoidanceDemo = () => (
|
|
6
|
+
<SimpleDemo
|
|
7
|
+
demo={offsetAnchorAvoidanceDemoConfig}
|
|
8
|
+
beforeStage={
|
|
9
|
+
<div
|
|
10
|
+
style={{
|
|
11
|
+
marginBottom: 12,
|
|
12
|
+
padding: '10px 12px',
|
|
13
|
+
borderRadius: 8,
|
|
14
|
+
border: '1px solid #2d2d2d',
|
|
15
|
+
background: '#f4f4f4',
|
|
16
|
+
}}
|
|
17
|
+
>
|
|
18
|
+
<strong>Visual checks</strong>
|
|
19
|
+
<ul style={{ margin: '6px 0 0 16px' }}>
|
|
20
|
+
<li>Sibling link should route around both child interiors even though attach coordinates are offset outside the host edges.</li>
|
|
21
|
+
<li>`parent→child` should use the parent's internal side and the child's external side.</li>
|
|
22
|
+
<li>`child→parent` should invert the same endpoint semantics without crossing either endpoint host interior.</li>
|
|
23
|
+
<li>Use `Shift targets + reroute` and `Reroute All Links` to verify stable behavior after layout changes.</li>
|
|
24
|
+
</ul>
|
|
25
|
+
</div>
|
|
26
|
+
}
|
|
27
|
+
/>
|
|
28
|
+
);
|
|
29
|
+
|
|
30
|
+
export default OffsetAnchorAvoidanceDemo;
|
|
@@ -1,14 +1,17 @@
|
|
|
1
|
-
import React from 'react';
|
|
2
|
-
import
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import type { LinkColorPoolPolicy, LinkRouteRefreshPolicy } from '../../api';
|
|
3
|
+
import DisplayBoxControls from '../DisplayBoxControls';
|
|
3
4
|
import DisplayBoxStage from '../DisplayBoxStage';
|
|
4
5
|
import useDemoControls from '../useDemoControls';
|
|
5
6
|
import useDemoEditor from '../useDemoEditor';
|
|
6
7
|
import useOffsetSequence from '../useOffsetSequence';
|
|
7
8
|
import type { DemoConfig, DemoActionHelpers } from '../types';
|
|
8
9
|
|
|
9
|
-
type SimpleDemoProps = {
|
|
10
|
-
demo: DemoConfig;
|
|
11
|
-
|
|
10
|
+
type SimpleDemoProps = {
|
|
11
|
+
demo: DemoConfig;
|
|
12
|
+
linkRouteRefreshPolicy?: LinkRouteRefreshPolicy;
|
|
13
|
+
linkColorPoolPolicy?: LinkColorPoolPolicy;
|
|
14
|
+
beforeStage?: React.ReactNode;
|
|
12
15
|
stageHandlers?: {
|
|
13
16
|
onDragOver?: (event: React.DragEvent<HTMLDivElement>) => void;
|
|
14
17
|
onDragLeave?: () => void;
|
|
@@ -16,14 +19,16 @@ type SimpleDemoProps = {
|
|
|
16
19
|
};
|
|
17
20
|
};
|
|
18
21
|
|
|
19
|
-
const SimpleDemo = ({ demo, beforeStage, stageHandlers }: SimpleDemoProps) => {
|
|
20
|
-
const { containerRef, editorRef, diagramState, selection, snapEnabled, setSnapEnabled } = useDemoEditor({
|
|
21
|
-
createState: demo.createState,
|
|
22
|
-
elementShapes: demo.elementShapes,
|
|
23
|
-
portShapes: demo.portShapes,
|
|
24
|
-
router: demo.router,
|
|
25
|
-
snapDefault: demo.snapDefault,
|
|
26
|
-
|
|
22
|
+
const SimpleDemo = ({ demo, linkRouteRefreshPolicy, linkColorPoolPolicy, beforeStage, stageHandlers }: SimpleDemoProps) => {
|
|
23
|
+
const { containerRef, editorRef, diagramState, selection, snapEnabled, setSnapEnabled } = useDemoEditor({
|
|
24
|
+
createState: demo.createState,
|
|
25
|
+
elementShapes: demo.elementShapes,
|
|
26
|
+
portShapes: demo.portShapes,
|
|
27
|
+
router: demo.router,
|
|
28
|
+
snapDefault: demo.snapDefault,
|
|
29
|
+
linkRouteRefreshPolicy: linkRouteRefreshPolicy ?? demo.linkRouteRefreshPolicy,
|
|
30
|
+
linkColorPoolPolicy: linkColorPoolPolicy ?? demo.linkColorPoolPolicy,
|
|
31
|
+
});
|
|
27
32
|
|
|
28
33
|
const nextOffset = useOffsetSequence();
|
|
29
34
|
const actionHelpers: DemoActionHelpers = React.useMemo(() => ({ nextOffset }), [nextOffset]);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import React, { useEffect, useMemo, useState } from 'react';
|
|
2
|
-
import type { TextLayout } from '../../api';
|
|
2
|
+
import type { TextInteractionPolicy, TextLayout } from '../../api';
|
|
3
3
|
import DisplayBoxControls from '../DisplayBoxControls';
|
|
4
4
|
import DisplayBoxStage from '../DisplayBoxStage';
|
|
5
5
|
import useDemoControls from '../useDemoControls';
|
|
@@ -9,8 +9,10 @@ import type { DemoActionHelpers } from '../types';
|
|
|
9
9
|
import {
|
|
10
10
|
textDemoConfig,
|
|
11
11
|
textDemoFloatingTextId,
|
|
12
|
+
textDemoFloatingInteraction,
|
|
12
13
|
textDemoLongSample,
|
|
13
14
|
textDemoOwnedTextId,
|
|
15
|
+
textDemoOwnedInteraction,
|
|
14
16
|
textDemoOwnerId,
|
|
15
17
|
} from './textDemo';
|
|
16
18
|
|
|
@@ -58,10 +60,15 @@ const TextLayoutDemo = () => {
|
|
|
58
60
|
const selectedText = diagramState?.texts.find((text) => text.id === selectedTextId);
|
|
59
61
|
const selectedDisplayContent = selectedText?.displayContent ?? selectedText?.content ?? '';
|
|
60
62
|
const ownerElement = diagramState?.elements.find((element) => element.id === textDemoOwnerId);
|
|
63
|
+
const selectedInteraction = selectedText?.interaction;
|
|
64
|
+
|
|
65
|
+
const getInteractionForTarget = (nextTarget: TextTarget): TextInteractionPolicy =>
|
|
66
|
+
nextTarget === 'owned' ? textDemoOwnedInteraction : textDemoFloatingInteraction;
|
|
61
67
|
|
|
62
68
|
const applyLayoutToTarget = (nextTarget: TextTarget, nextLayout: TextLayout) => {
|
|
63
69
|
const editor = editorRef.current;
|
|
64
70
|
if (!editor) return;
|
|
71
|
+
const interaction = getInteractionForTarget(nextTarget);
|
|
65
72
|
if (nextTarget === 'owned') {
|
|
66
73
|
editor.removeText(textDemoOwnedTextId);
|
|
67
74
|
editor.addText({
|
|
@@ -69,6 +76,7 @@ const TextLayoutDemo = () => {
|
|
|
69
76
|
content: textDemoLongSample,
|
|
70
77
|
ownerId: textDemoOwnerId,
|
|
71
78
|
position: { x: 12, y: 12 },
|
|
79
|
+
interaction,
|
|
72
80
|
layout: nextLayout,
|
|
73
81
|
});
|
|
74
82
|
editor.setSelection([textDemoOwnedTextId]);
|
|
@@ -80,6 +88,7 @@ const TextLayoutDemo = () => {
|
|
|
80
88
|
id: textDemoFloatingTextId,
|
|
81
89
|
content: textDemoLongSample,
|
|
82
90
|
position: { x: 470, y: 120 },
|
|
91
|
+
interaction,
|
|
83
92
|
layout: nextLayout,
|
|
84
93
|
});
|
|
85
94
|
editor.setSelection([textDemoFloatingTextId]);
|
|
@@ -163,6 +172,10 @@ const TextLayoutDemo = () => {
|
|
|
163
172
|
Full text content is preserved in state. Overflow and ellipsis settings only change visual output
|
|
164
173
|
(`displayContent`) for rendering.
|
|
165
174
|
</p>
|
|
175
|
+
<p style={{ marginTop: 0, marginBottom: 0, fontSize: 13 }}>
|
|
176
|
+
Owned text is fixed and read-only. Floating text remains draggable and editable. Try drag and
|
|
177
|
+
double-click on each label to compare built-in interaction policy behavior.
|
|
178
|
+
</p>
|
|
166
179
|
</div>
|
|
167
180
|
<DisplayBoxControls
|
|
168
181
|
actions={demo.actions}
|
|
@@ -370,6 +383,10 @@ const TextLayoutDemo = () => {
|
|
|
370
383
|
? `${selectedWorldX.toFixed(1)}, ${selectedWorldY.toFixed(1)}`
|
|
371
384
|
: 'n/a'}
|
|
372
385
|
</div>
|
|
386
|
+
<div>
|
|
387
|
+
interaction: movable={selectedInteraction?.movable === false ? 'false' : 'true'} | editable=
|
|
388
|
+
{selectedInteraction?.editable === false ? 'false' : 'true'}
|
|
389
|
+
</div>
|
|
373
390
|
</div>
|
|
374
391
|
|
|
375
392
|
<div style={{ display: 'grid', gap: 6 }}>
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import React from 'react';
|
|
2
|
+
import SimpleDemo from './SimpleDemo';
|
|
3
|
+
import { zoomToFitElementsDemoConfig } from './zoomToFitElementsDemo';
|
|
4
|
+
|
|
5
|
+
const ZoomToFitElementsDemo = () => (
|
|
6
|
+
<SimpleDemo
|
|
7
|
+
demo={zoomToFitElementsDemoConfig}
|
|
8
|
+
beforeStage={(
|
|
9
|
+
<div
|
|
10
|
+
style={{
|
|
11
|
+
marginBottom: 12,
|
|
12
|
+
padding: '10px 12px',
|
|
13
|
+
borderRadius: 8,
|
|
14
|
+
border: '1px solid #2d2d2d',
|
|
15
|
+
background: '#f4f4f4',
|
|
16
|
+
}}
|
|
17
|
+
>
|
|
18
|
+
<strong>Visual checks</strong>
|
|
19
|
+
<ul style={{ margin: '6px 0 0 16px' }}>
|
|
20
|
+
<li>Click `Run Zoom-To-Fit` and ensure every node is visible and centered.</li>
|
|
21
|
+
<li>Run `Spread Scene` then fit again to verify viewport recomputes from the updated layout.</li>
|
|
22
|
+
<li>Use `Run Zoom-To-Fit (Padding 48)` to confirm optional padding keeps extra breathing room around content.</li>
|
|
23
|
+
</ul>
|
|
24
|
+
</div>
|
|
25
|
+
)}
|
|
26
|
+
/>
|
|
27
|
+
);
|
|
28
|
+
|
|
29
|
+
export default ZoomToFitElementsDemo;
|
|
@@ -36,6 +36,29 @@ const createAutoLayoutState = (): DiagramState => ({
|
|
|
36
36
|
{ id: 'col-b', position: { x: 0, y: 0 }, size: { width: 70, height: 36 }, shapeId: 'default', parentId: 'layout-column' },
|
|
37
37
|
{ id: 'col-c', position: { x: 0, y: 0 }, size: { width: 92, height: 44 }, shapeId: 'default', parentId: 'layout-column' },
|
|
38
38
|
|
|
39
|
+
{
|
|
40
|
+
id: 'layout-grid',
|
|
41
|
+
position: { x: 620, y: 70 },
|
|
42
|
+
size: { width: 160, height: 110 },
|
|
43
|
+
shapeId: 'panel',
|
|
44
|
+
layout: {
|
|
45
|
+
mode: 'grid',
|
|
46
|
+
padding: { x: 10, y: 10 },
|
|
47
|
+
gap: 10,
|
|
48
|
+
align: 'center',
|
|
49
|
+
autoResize: 'grow-shrink',
|
|
50
|
+
gridTemplate: [12, 4, 8],
|
|
51
|
+
gridChildWidthResizeEnabled: false,
|
|
52
|
+
childMinWidth: 24,
|
|
53
|
+
childMinHeight: 18,
|
|
54
|
+
},
|
|
55
|
+
},
|
|
56
|
+
{ id: 'grid-a', position: { x: 0, y: 0 }, size: { width: 36, height: 26 }, shapeId: 'default', parentId: 'layout-grid' },
|
|
57
|
+
{ id: 'grid-b', position: { x: 0, y: 0 }, size: { width: 44, height: 24 }, shapeId: 'default', parentId: 'layout-grid' },
|
|
58
|
+
{ id: 'grid-c', position: { x: 0, y: 0 }, size: { width: 50, height: 20 }, shapeId: 'default', parentId: 'layout-grid' },
|
|
59
|
+
{ id: 'grid-d', position: { x: 0, y: 0 }, size: { width: 28, height: 30 }, shapeId: 'default', parentId: 'layout-grid' },
|
|
60
|
+
{ id: 'grid-e', position: { x: 0, y: 0 }, size: { width: 52, height: 28 }, shapeId: 'default', parentId: 'layout-grid' },
|
|
61
|
+
|
|
39
62
|
{
|
|
40
63
|
id: 'layout-nested',
|
|
41
64
|
position: { x: 120, y: 260 },
|
|
@@ -74,36 +97,49 @@ const createAutoLayoutState = (): DiagramState => ({
|
|
|
74
97
|
ports: [],
|
|
75
98
|
links: [],
|
|
76
99
|
texts: [
|
|
77
|
-
{
|
|
78
|
-
id: 'label-layout-row',
|
|
79
|
-
content: 'Row parent label lane',
|
|
80
|
-
position: { x: 8, y: 6 },
|
|
81
|
-
ownerId: 'layout-row',
|
|
82
|
-
layout: { boundsMode: 'owner-width', wrap: 'word', overflow: 'clip', padding: 0 },
|
|
83
|
-
},
|
|
100
|
+
{
|
|
101
|
+
id: 'label-layout-row',
|
|
102
|
+
content: 'Row parent label lane',
|
|
103
|
+
position: { x: 8, y: 6 },
|
|
104
|
+
ownerId: 'layout-row',
|
|
105
|
+
layout: { boundsMode: 'owner-width', wrap: 'word', overflow: 'clip', padding: 0 },
|
|
106
|
+
},
|
|
84
107
|
{ id: 'label-row-a', content: 'row-a', position: { x: 6, y: -14 }, ownerId: 'row-a' },
|
|
85
108
|
{ id: 'label-row-b', content: 'row-b', position: { x: 6, y: -14 }, ownerId: 'row-b' },
|
|
86
109
|
{ id: 'label-row-c', content: 'row-c', position: { x: 6, y: -14 }, ownerId: 'row-c' },
|
|
87
110
|
{ id: 'label-row-nested-owner', content: 'owns children', position: { x: 6, y: -16 }, ownerId: 'row-nested-owner' },
|
|
88
111
|
|
|
89
|
-
{
|
|
90
|
-
id: 'label-layout-column',
|
|
91
|
-
content: 'Column parent label lane',
|
|
92
|
-
position: { x: 8, y: 6 },
|
|
93
|
-
ownerId: 'layout-column',
|
|
94
|
-
layout: { boundsMode: 'owner-width', wrap: 'word', overflow: 'clip', padding: 0 },
|
|
95
|
-
},
|
|
112
|
+
{
|
|
113
|
+
id: 'label-layout-column',
|
|
114
|
+
content: 'Column parent label lane',
|
|
115
|
+
position: { x: 8, y: 6 },
|
|
116
|
+
ownerId: 'layout-column',
|
|
117
|
+
layout: { boundsMode: 'owner-width', wrap: 'word', overflow: 'clip', padding: 0 },
|
|
118
|
+
},
|
|
96
119
|
{ id: 'label-col-a', content: 'col-a', position: { x: 6, y: -14 }, ownerId: 'col-a' },
|
|
97
120
|
{ id: 'label-col-b', content: 'col-b', position: { x: 6, y: -14 }, ownerId: 'col-b' },
|
|
98
121
|
{ id: 'label-col-c', content: 'col-c', position: { x: 6, y: -14 }, ownerId: 'col-c' },
|
|
99
122
|
|
|
100
|
-
{
|
|
101
|
-
id: 'label-layout-
|
|
102
|
-
content: '
|
|
103
|
-
position: { x:
|
|
104
|
-
ownerId: 'layout-
|
|
105
|
-
layout: { boundsMode: 'owner-width', wrap: 'word', overflow: 'clip', padding: 0 },
|
|
106
|
-
},
|
|
123
|
+
{
|
|
124
|
+
id: 'label-layout-grid',
|
|
125
|
+
content: 'Grid template [12,4,8]',
|
|
126
|
+
position: { x: 8, y: 6 },
|
|
127
|
+
ownerId: 'layout-grid',
|
|
128
|
+
layout: { boundsMode: 'owner-width', wrap: 'word', overflow: 'clip', padding: 0 },
|
|
129
|
+
},
|
|
130
|
+
{ id: 'label-grid-a', content: 'grid-a', position: { x: 6, y: -14 }, ownerId: 'grid-a' },
|
|
131
|
+
{ id: 'label-grid-b', content: 'grid-b', position: { x: 6, y: -14 }, ownerId: 'grid-b' },
|
|
132
|
+
{ id: 'label-grid-c', content: 'grid-c', position: { x: 6, y: -14 }, ownerId: 'grid-c' },
|
|
133
|
+
{ id: 'label-grid-d', content: 'grid-d', position: { x: 6, y: -14 }, ownerId: 'grid-d' },
|
|
134
|
+
{ id: 'label-grid-e', content: 'grid-e', position: { x: 6, y: -14 }, ownerId: 'grid-e' },
|
|
135
|
+
|
|
136
|
+
{
|
|
137
|
+
id: 'label-layout-nested',
|
|
138
|
+
content: 'Row + nested column lane',
|
|
139
|
+
position: { x: 6, y: 6 },
|
|
140
|
+
ownerId: 'layout-nested',
|
|
141
|
+
layout: { boundsMode: 'owner-width', wrap: 'word', overflow: 'clip', padding: 0 },
|
|
142
|
+
},
|
|
107
143
|
{ id: 'label-nested-stack', content: 'nested stack', position: { x: 6, y: -16 }, ownerId: 'nested-stack' },
|
|
108
144
|
{ id: 'label-stack-a', content: 'stack-a', position: { x: 6, y: -14 }, ownerId: 'stack-a' },
|
|
109
145
|
{ id: 'label-stack-b', content: 'stack-b', position: { x: 6, y: -14 }, ownerId: 'stack-b' },
|
|
@@ -116,11 +152,11 @@ const createAutoLayoutState = (): DiagramState => ({
|
|
|
116
152
|
],
|
|
117
153
|
});
|
|
118
154
|
|
|
119
|
-
export const autoLayoutDemoConfig: DemoConfig = ({
|
|
120
|
-
id: 'auto-layout',
|
|
121
|
-
title: 'Element Auto-Layout + Label Lane',
|
|
122
|
-
description: 'Consolidated auto-layout verification with
|
|
123
|
-
createState: createAutoLayoutState,
|
|
155
|
+
export const autoLayoutDemoConfig: DemoConfig = ({
|
|
156
|
+
id: 'auto-layout',
|
|
157
|
+
title: 'Element Auto-Layout + Label Lane',
|
|
158
|
+
description: 'Consolidated auto-layout verification with horizontal/vertical/grid containers, fit options, auto-resize policies, and label reserved-space modes.',
|
|
159
|
+
createState: createAutoLayoutState,
|
|
124
160
|
elementShapes: baseElementShapes,
|
|
125
161
|
portShapes: basePortShapes,
|
|
126
162
|
defaultElementShapeId: 'default',
|
|
@@ -8,8 +8,8 @@ import { textDemoConfig } from './textDemo';
|
|
|
8
8
|
import { selectionDemoConfig } from './selectionDemo';
|
|
9
9
|
import { eventHandlersDemoConfig } from './eventHandlersDemo';
|
|
10
10
|
import { engineEventsDemoConfig } from './engineEventsDemo';
|
|
11
|
-
import { linkCancelDemoConfig } from './linkCancelDemo';
|
|
12
|
-
import { autoLayoutDemoConfig } from './autoLayoutDemo';
|
|
11
|
+
import { linkCancelDemoConfig } from './linkCancelDemo';
|
|
12
|
+
import { autoLayoutDemoConfig } from './autoLayoutDemo';
|
|
13
13
|
import { externalDragDropDemoConfig } from './externalDragDropDemo';
|
|
14
14
|
import { shapeGalleryDemoConfig } from './shapeGalleryDemo';
|
|
15
15
|
import { svgPathDemoConfig } from './svgPathDemo';
|
|
@@ -18,32 +18,38 @@ import { rotatedCreationDemoConfig } from './rotatedCreationDemo';
|
|
|
18
18
|
import { multiLevelTreeDemoConfig } from './multiLevelTreeDemo';
|
|
19
19
|
import { multipleElementsDemoConfig } from './multipleElementsDemo';
|
|
20
20
|
import { asymmetricPortMultiAnchorDemoConfig } from './asymmetricPortMultiAnchorDemo';
|
|
21
|
-
import { portConstraintsDemoConfig } from './portConstraintsDemo';
|
|
22
|
-
import { portPositionLimitsDemoConfig } from './portPositionLimitsDemo';
|
|
23
|
-
import { portBorderDemoConfig } from './portBorderDemo';
|
|
24
|
-
import { childConstraintsDemoConfig } from './childConstraintsDemo';
|
|
25
|
-
import { labelStyleDemoConfig } from './labelStyleDemo';
|
|
21
|
+
import { portConstraintsDemoConfig } from './portConstraintsDemo';
|
|
22
|
+
import { portPositionLimitsDemoConfig } from './portPositionLimitsDemo';
|
|
23
|
+
import { portBorderDemoConfig } from './portBorderDemo';
|
|
24
|
+
import { childConstraintsDemoConfig } from './childConstraintsDemo';
|
|
25
|
+
import { labelStyleDemoConfig } from './labelStyleDemo';
|
|
26
|
+
import { linkColorPoolDemoConfig } from './linkColorPoolDemo';
|
|
26
27
|
import { gridOverlayDemoConfig } from './gridOverlayDemo';
|
|
27
28
|
import { routingDemoConfig } from './routingDemo';
|
|
28
29
|
import { obstacleRoutingDemoConfig } from './obstacleRoutingDemo';
|
|
29
30
|
import { linkBendHandlesDemoConfig } from './linkBendHandlesDemo';
|
|
30
31
|
import { deletionEventsDemoConfig } from './deletionEventsDemo';
|
|
31
|
-
import { shapeBorderMovementDemoConfig } from './shapeBorderMovementDemo';
|
|
32
|
-
import { shapeHoverControlsDemoConfig } from './shapeHoverControlsDemo';
|
|
33
|
-
import { vertexControlLinkSessionDemoConfig } from './vertexControlLinkSessionDemo';
|
|
32
|
+
import { shapeBorderMovementDemoConfig } from './shapeBorderMovementDemo';
|
|
33
|
+
import { shapeHoverControlsDemoConfig } from './shapeHoverControlsDemo';
|
|
34
|
+
import { vertexControlLinkSessionDemoConfig } from './vertexControlLinkSessionDemo';
|
|
34
35
|
import EventHandlersDemo from './EventHandlersDemoTab';
|
|
35
36
|
import EngineEventsDemo from './EngineEventsDemoTab';
|
|
36
|
-
import LinkCancelDemo from './LinkCancelDemoTab';
|
|
37
|
-
import AutoLayoutDemo from './AutoLayoutDemoTab';
|
|
37
|
+
import LinkCancelDemo from './LinkCancelDemoTab';
|
|
38
|
+
import AutoLayoutDemo from './AutoLayoutDemoTab';
|
|
38
39
|
import ExternalDragDropDemo from './ExternalDragDropDemoTab';
|
|
39
40
|
import SvgPathDemo from './SvgPathDemoTab';
|
|
40
41
|
import TextLayoutDemo from './TextLayoutDemoTab';
|
|
41
42
|
import SimpleDemo from './SimpleDemo';
|
|
42
|
-
import ObstacleRoutingDemo from './ObstacleRoutingDemoTab';
|
|
43
|
-
import
|
|
43
|
+
import ObstacleRoutingDemo from './ObstacleRoutingDemoTab';
|
|
44
|
+
import OffsetAnchorAvoidanceDemo from './OffsetAnchorAvoidanceDemoTab';
|
|
45
|
+
import ZoomToFitElementsDemo from './ZoomToFitElementsDemoTab';
|
|
46
|
+
import DeletionEventsDemo from './DeletionEventsDemoTab';
|
|
44
47
|
import ShapeHoverControlsDemo from './ShapeHoverControlsDemoTab';
|
|
48
|
+
import LinkColorPoolDemo from './LinkColorPoolDemoTab';
|
|
45
49
|
import AsymmetricPortMultiAnchorDemo from './AsymmetricPortMultiAnchorDemoTab';
|
|
46
50
|
import VertexControlLinkSessionDemo from './VertexControlLinkSessionDemoTab';
|
|
51
|
+
import { offsetAnchorAvoidanceDemoConfig } from './offsetAnchorAvoidanceDemo';
|
|
52
|
+
import { zoomToFitElementsDemoConfig } from './zoomToFitElementsDemo';
|
|
47
53
|
|
|
48
54
|
export {
|
|
49
55
|
baseElementShapes,
|
|
@@ -112,12 +118,12 @@ export const demoTabs: DemoDefinition[] = [
|
|
|
112
118
|
description: deletionEventsDemoConfig.description,
|
|
113
119
|
Component: DeletionEventsDemo,
|
|
114
120
|
},
|
|
115
|
-
{
|
|
116
|
-
id: autoLayoutDemoConfig.id,
|
|
117
|
-
title: autoLayoutDemoConfig.title,
|
|
118
|
-
description: autoLayoutDemoConfig.description,
|
|
119
|
-
Component: AutoLayoutDemo,
|
|
120
|
-
},
|
|
121
|
+
{
|
|
122
|
+
id: autoLayoutDemoConfig.id,
|
|
123
|
+
title: autoLayoutDemoConfig.title,
|
|
124
|
+
description: autoLayoutDemoConfig.description,
|
|
125
|
+
Component: AutoLayoutDemo,
|
|
126
|
+
},
|
|
121
127
|
{
|
|
122
128
|
id: linkCancelDemoConfig.id,
|
|
123
129
|
title: linkCancelDemoConfig.title,
|
|
@@ -172,28 +178,34 @@ export const demoTabs: DemoDefinition[] = [
|
|
|
172
178
|
description: multipleElementsDemoConfig.description,
|
|
173
179
|
Component: wrapSimpleDemo(multipleElementsDemoConfig),
|
|
174
180
|
},
|
|
175
|
-
{
|
|
176
|
-
id: portConstraintsDemoConfig.id,
|
|
177
|
-
title: portConstraintsDemoConfig.title,
|
|
178
|
-
description: portConstraintsDemoConfig.description,
|
|
179
|
-
Component: wrapSimpleDemo(portConstraintsDemoConfig),
|
|
180
|
-
},
|
|
181
|
-
{
|
|
182
|
-
id: portPositionLimitsDemoConfig.id,
|
|
183
|
-
title: portPositionLimitsDemoConfig.title,
|
|
184
|
-
description: portPositionLimitsDemoConfig.description,
|
|
185
|
-
Component: wrapSimpleDemo(portPositionLimitsDemoConfig),
|
|
186
|
-
},
|
|
187
|
-
{
|
|
188
|
-
id: labelStyleDemoConfig.id,
|
|
189
|
-
title: labelStyleDemoConfig.title,
|
|
190
|
-
description: labelStyleDemoConfig.description,
|
|
191
|
-
Component: wrapSimpleDemo(labelStyleDemoConfig),
|
|
192
|
-
},
|
|
193
|
-
{
|
|
194
|
-
id:
|
|
195
|
-
title:
|
|
196
|
-
description:
|
|
181
|
+
{
|
|
182
|
+
id: portConstraintsDemoConfig.id,
|
|
183
|
+
title: portConstraintsDemoConfig.title,
|
|
184
|
+
description: portConstraintsDemoConfig.description,
|
|
185
|
+
Component: wrapSimpleDemo(portConstraintsDemoConfig),
|
|
186
|
+
},
|
|
187
|
+
{
|
|
188
|
+
id: portPositionLimitsDemoConfig.id,
|
|
189
|
+
title: portPositionLimitsDemoConfig.title,
|
|
190
|
+
description: portPositionLimitsDemoConfig.description,
|
|
191
|
+
Component: wrapSimpleDemo(portPositionLimitsDemoConfig),
|
|
192
|
+
},
|
|
193
|
+
{
|
|
194
|
+
id: labelStyleDemoConfig.id,
|
|
195
|
+
title: labelStyleDemoConfig.title,
|
|
196
|
+
description: labelStyleDemoConfig.description,
|
|
197
|
+
Component: wrapSimpleDemo(labelStyleDemoConfig),
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
id: linkColorPoolDemoConfig.id,
|
|
201
|
+
title: linkColorPoolDemoConfig.title,
|
|
202
|
+
description: linkColorPoolDemoConfig.description,
|
|
203
|
+
Component: LinkColorPoolDemo,
|
|
204
|
+
},
|
|
205
|
+
{
|
|
206
|
+
id: portBorderDemoConfig.id,
|
|
207
|
+
title: portBorderDemoConfig.title,
|
|
208
|
+
description: portBorderDemoConfig.description,
|
|
197
209
|
Component: wrapSimpleDemo(portBorderDemoConfig),
|
|
198
210
|
},
|
|
199
211
|
{
|
|
@@ -202,18 +214,18 @@ export const demoTabs: DemoDefinition[] = [
|
|
|
202
214
|
description: shapeBorderMovementDemoConfig.description,
|
|
203
215
|
Component: wrapSimpleDemo(shapeBorderMovementDemoConfig),
|
|
204
216
|
},
|
|
205
|
-
{
|
|
206
|
-
id: shapeHoverControlsDemoConfig.id,
|
|
207
|
-
title: shapeHoverControlsDemoConfig.title,
|
|
208
|
-
description: shapeHoverControlsDemoConfig.description,
|
|
209
|
-
Component: ShapeHoverControlsDemo,
|
|
210
|
-
},
|
|
211
|
-
{
|
|
212
|
-
id: vertexControlLinkSessionDemoConfig.id,
|
|
213
|
-
title: vertexControlLinkSessionDemoConfig.title,
|
|
214
|
-
description: vertexControlLinkSessionDemoConfig.description,
|
|
215
|
-
Component: VertexControlLinkSessionDemo,
|
|
216
|
-
},
|
|
217
|
+
{
|
|
218
|
+
id: shapeHoverControlsDemoConfig.id,
|
|
219
|
+
title: shapeHoverControlsDemoConfig.title,
|
|
220
|
+
description: shapeHoverControlsDemoConfig.description,
|
|
221
|
+
Component: ShapeHoverControlsDemo,
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
id: vertexControlLinkSessionDemoConfig.id,
|
|
225
|
+
title: vertexControlLinkSessionDemoConfig.title,
|
|
226
|
+
description: vertexControlLinkSessionDemoConfig.description,
|
|
227
|
+
Component: VertexControlLinkSessionDemo,
|
|
228
|
+
},
|
|
217
229
|
{
|
|
218
230
|
id: childConstraintsDemoConfig.id,
|
|
219
231
|
title: childConstraintsDemoConfig.title,
|
|
@@ -238,9 +250,21 @@ export const demoTabs: DemoDefinition[] = [
|
|
|
238
250
|
description: obstacleRoutingDemoConfig.description,
|
|
239
251
|
Component: ObstacleRoutingDemo,
|
|
240
252
|
},
|
|
241
|
-
{
|
|
242
|
-
id:
|
|
243
|
-
title:
|
|
253
|
+
{
|
|
254
|
+
id: offsetAnchorAvoidanceDemoConfig.id,
|
|
255
|
+
title: offsetAnchorAvoidanceDemoConfig.title,
|
|
256
|
+
description: offsetAnchorAvoidanceDemoConfig.description,
|
|
257
|
+
Component: OffsetAnchorAvoidanceDemo,
|
|
258
|
+
},
|
|
259
|
+
{
|
|
260
|
+
id: zoomToFitElementsDemoConfig.id,
|
|
261
|
+
title: zoomToFitElementsDemoConfig.title,
|
|
262
|
+
description: zoomToFitElementsDemoConfig.description,
|
|
263
|
+
Component: ZoomToFitElementsDemo,
|
|
264
|
+
},
|
|
265
|
+
{
|
|
266
|
+
id: linkBendHandlesDemoConfig.id,
|
|
267
|
+
title: linkBendHandlesDemoConfig.title,
|
|
244
268
|
description: linkBendHandlesDemoConfig.description,
|
|
245
269
|
Component: wrapSimpleDemo(linkBendHandlesDemoConfig),
|
|
246
270
|
},
|