@likec4/diagram 1.39.5 → 1.41.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/bundle/{chunk-CW_KClZe.js → chunk-FGcODVxo.js} +1059 -1023
- package/bundle/custom.js +61 -60
- package/bundle/index.js +2932 -764
- package/dist/LikeC4Diagram.d.ts +1 -1
- package/dist/LikeC4Diagram.js +7 -4
- package/dist/LikeC4Diagram.props.d.ts +6 -1
- package/dist/base/const.d.ts +9 -0
- package/dist/base/const.js +10 -1
- package/dist/base/index.d.ts +1 -0
- package/dist/base/primitives/MarkdownBlock.js +2 -0
- package/dist/base/primitives/edge/EdgeLabel.js +2 -1
- package/dist/base/primitives/edge/EdgeLabelContainer.js +10 -4
- package/dist/base/primitives/edge/EdgePath.js +17 -8
- package/dist/base/primitives/edge/edge.css.d.ts +0 -1
- package/dist/base/primitives/edge/edge.css.js +6 -14
- package/dist/base/primitives/element/ElementActionButtons.js +1 -3
- package/dist/base/primitives/element/ElementNodeContainer.d.ts +0 -6
- package/dist/base/primitives/element/ElementNodeContainer.js +3 -26
- package/dist/base/primitives/element/ElementTitle.js +2 -2
- package/dist/base/types.d.ts +3 -3
- package/dist/bundle/LikeC4View.js +4 -12
- package/dist/bundle/LikeC4View.props.d.ts +12 -3
- package/dist/bundle/custom.js +1 -1
- package/dist/components/Link.js +28 -20
- package/dist/custom/customNodes.d.ts +6 -0
- package/dist/custom/customNodes.js +2 -1
- package/dist/custom/index.js +1 -1
- package/dist/hooks/useDiagram.d.ts +5 -1
- package/dist/hooks/useDiagram.js +3 -0
- package/dist/hooks/useXYFlow.d.ts +4 -439
- package/dist/likec4diagram/DiagramUI.js +1 -1
- package/dist/likec4diagram/DiagramXYFlow.js +8 -4
- package/dist/likec4diagram/convert-to-xyflow.d.ts +14 -0
- package/dist/likec4diagram/convert-to-xyflow.js +29 -0
- package/dist/likec4diagram/custom/edges/RelationshipEdge.d.ts +4 -4
- package/dist/likec4diagram/custom/edges/RelationshipEdge.js +0 -1
- package/dist/likec4diagram/custom/edges/SequenceStepEdge.d.ts +3 -0
- package/dist/likec4diagram/custom/edges/SequenceStepEdge.js +71 -0
- package/dist/likec4diagram/custom/index.js +7 -2
- package/dist/likec4diagram/custom/nodes/ElementActions.d.ts +2 -1
- package/dist/likec4diagram/custom/nodes/SequenceActorNode.d.ts +4 -0
- package/dist/likec4diagram/custom/nodes/SequenceActorNode.js +157 -0
- package/dist/likec4diagram/custom/nodes/index.d.ts +1 -0
- package/dist/likec4diagram/custom/nodes/nodes.d.ts +1 -2
- package/dist/likec4diagram/relationship-popover/RelationshipPopover.js +31 -27
- package/dist/likec4diagram/types.d.ts +41 -7
- package/dist/likec4diagram/xyflow-diagram/diagram-view.d.ts +11 -0
- package/dist/likec4diagram/{useViewToNodesEdges.js → xyflow-diagram/diagram-view.js} +4 -13
- package/dist/likec4diagram/xyflow-sequence/_types.d.ts +41 -0
- package/dist/likec4diagram/xyflow-sequence/const.d.ts +17 -0
- package/dist/likec4diagram/xyflow-sequence/const.js +16 -0
- package/dist/likec4diagram/xyflow-sequence/layouter.d.ts +46 -0
- package/dist/likec4diagram/xyflow-sequence/layouter.js +408 -0
- package/dist/likec4diagram/xyflow-sequence/sequence-view.d.ts +7 -0
- package/dist/likec4diagram/xyflow-sequence/sequence-view.js +273 -0
- package/dist/likec4diagram/xyflow-sequence/utils.d.ts +14 -0
- package/dist/likec4diagram/xyflow-sequence/utils.js +92 -0
- package/dist/navigationpanel/NavigationPanelControls.js +2 -2
- package/dist/navigationpanel/controls/ViewDetailsCard.js +27 -12
- package/dist/navigationpanel/dropdown/ProjectsMenu.js +53 -44
- package/dist/navigationpanel/walkthrough/ActiveWalkthroughControls.d.ts +1 -2
- package/dist/navigationpanel/walkthrough/ActiveWalkthroughControls.js +10 -41
- package/dist/navigationpanel/walkthrough/DynamicViewControls.d.ts +292 -0
- package/dist/navigationpanel/walkthrough/DynamicViewControls.js +119 -0
- package/dist/navigationpanel/walkthrough/index.d.ts +2 -1
- package/dist/overlays/element-details/ElementDetailsCard.css.js +7 -1
- package/dist/overlays/element-details/ElementDetailsCard.js +17 -19
- package/dist/overlays/relationship-details/RelationshipDetails.js +4 -1
- package/dist/overlays/relationship-details/layout.d.ts +3 -2
- package/dist/overlays/relationship-details/layout.js +1 -2
- package/dist/overlays/relationships-browser/RelationshipsBrowser.js +2 -1
- package/dist/overlays/relationships-browser/layout.js +1 -1
- package/dist/search/components/ElementsColumn.js +1 -1
- package/dist/state/DiagramActorProvider.d.ts +3 -2
- package/dist/state/DiagramActorProvider.js +40 -41
- package/dist/state/assign.js +11 -4
- package/dist/state/diagram-machine.d.ts +224 -194
- package/dist/state/diagram-machine.js +170 -63
- package/dist/state/utils.d.ts +7 -1
- package/dist/state/utils.js +67 -7
- package/dist/styles-min.css +1 -1
- package/dist/styles.css +1 -1
- package/dist/styles.css2.js +1 -1
- package/package.json +8 -7
- package/panda.buildinfo.json +45 -24
- package/src/LikeC4Diagram.props.ts +14 -1
- package/src/LikeC4Diagram.tsx +7 -4
- package/src/base/const.ts +12 -0
- package/src/base/index.ts +2 -0
- package/src/base/primitives/MarkdownBlock.tsx +2 -0
- package/src/base/primitives/edge/EdgeLabel.tsx +23 -19
- package/src/base/primitives/edge/EdgeLabelContainer.tsx +12 -7
- package/src/base/primitives/edge/EdgePath.tsx +25 -14
- package/src/base/primitives/edge/edge.css.ts +5 -14
- package/src/base/primitives/element/ElementActionButtons.tsx +1 -3
- package/src/base/primitives/element/ElementNodeContainer.tsx +3 -30
- package/src/base/primitives/element/ElementTitle.tsx +2 -3
- package/src/base/types.ts +7 -5
- package/src/bundle/LikeC4View.props.ts +14 -3
- package/src/bundle/LikeC4View.tsx +4 -14
- package/src/bundle/ReactLikeC4.tsx +1 -2
- package/src/components/Link.tsx +21 -18
- package/src/custom/customNodes.ts +7 -0
- package/src/hooks/useDiagram.ts +10 -0
- package/src/likec4diagram/DiagramUI.tsx +1 -1
- package/src/likec4diagram/DiagramXYFlow.tsx +10 -5
- package/src/likec4diagram/convert-to-xyflow.ts +45 -0
- package/src/likec4diagram/custom/edges/RelationshipEdge.tsx +0 -1
- package/src/likec4diagram/custom/edges/SequenceStepEdge.tsx +65 -0
- package/src/likec4diagram/custom/index.ts +7 -1
- package/src/likec4diagram/custom/nodes/ElementActions.tsx +4 -2
- package/src/likec4diagram/custom/nodes/SequenceActorNode.tsx +175 -0
- package/src/likec4diagram/custom/nodes/index.ts +1 -0
- package/src/likec4diagram/custom/nodes/nodes.tsx +1 -1
- package/src/likec4diagram/relationship-popover/RelationshipPopover.tsx +36 -30
- package/src/likec4diagram/types.ts +96 -13
- package/src/likec4diagram/{useViewToNodesEdges.ts → xyflow-diagram/diagram-view.ts} +7 -28
- package/src/likec4diagram/xyflow-sequence/_types.ts +45 -0
- package/src/likec4diagram/xyflow-sequence/const.ts +37 -0
- package/src/likec4diagram/xyflow-sequence/layouter.ts +567 -0
- package/src/likec4diagram/xyflow-sequence/sequence-view.ts +337 -0
- package/src/likec4diagram/xyflow-sequence/utils.ts +112 -0
- package/src/navigationpanel/NavigationPanelControls.tsx +2 -2
- package/src/navigationpanel/controls/ViewDetailsCard.tsx +29 -12
- package/src/navigationpanel/dropdown/ProjectsMenu.tsx +5 -1
- package/src/navigationpanel/walkthrough/ActiveWalkthroughControls.tsx +5 -40
- package/src/navigationpanel/walkthrough/DynamicViewControls.tsx +125 -0
- package/src/navigationpanel/walkthrough/index.tsx +2 -1
- package/src/overlays/element-details/ElementDetailsCard.css.ts +7 -1
- package/src/overlays/element-details/ElementDetailsCard.tsx +24 -25
- package/src/overlays/relationship-details/RelationshipDetails.tsx +5 -2
- package/src/overlays/relationship-details/layout.ts +4 -3
- package/src/overlays/relationships-browser/RelationshipsBrowser.tsx +2 -1
- package/src/overlays/relationships-browser/layout.ts +1 -1
- package/src/search/components/ElementsColumn.tsx +1 -1
- package/src/state/DiagramActorProvider.tsx +46 -51
- package/src/state/assign.ts +18 -5
- package/src/state/diagram-machine.ts +207 -75
- package/src/state/utils.ts +81 -7
- package/dist/likec4diagram/useViewToNodesEdges.d.ts +0 -12
|
@@ -2,11 +2,12 @@ import { nonNullable, invariant, nonexhaustive, BBox, isStepEdgeId, getParallelS
|
|
|
2
2
|
import { getViewportForBounds, applyEdgeChanges, applyNodeChanges } from '@xyflow/react';
|
|
3
3
|
import { nodeToRect } from '@xyflow/system';
|
|
4
4
|
import { hasAtLeast, prop, clamp, first } from 'remeda';
|
|
5
|
-
import { setup, emit,
|
|
5
|
+
import { setup, assign, emit, sendTo, enqueueActions, assertEvent, cancel, stopChild, raise, spawnChild, and, or } from 'xstate';
|
|
6
6
|
import { MinZoom } from '../base/const.js';
|
|
7
7
|
import { Base } from '../base/types.js';
|
|
8
8
|
import { AllDisabled } from '../context/DiagramFeatures.js';
|
|
9
9
|
import { createLayoutConstraints } from '../likec4diagram/useLayoutConstraints.js';
|
|
10
|
+
import { SeqParallelAreaColor } from '../likec4diagram/xyflow-sequence/const.js';
|
|
10
11
|
import { overlaysActorLogic } from '../overlays/overlaysActor.js';
|
|
11
12
|
import { searchActorLogic } from '../search/searchActor.js';
|
|
12
13
|
import { getAligner, toNodeRect } from './aligners.js';
|
|
@@ -14,7 +15,7 @@ import { updateActiveWalkthrough, focusNodesEdges, lastClickedNode, updateNaviga
|
|
|
14
15
|
import { hotkeyActorLogic } from './hotkeyActor.js';
|
|
15
16
|
import { DiagramToggledFeaturesPersistence } from './persistence.js';
|
|
16
17
|
import { syncManualLayoutActorLogic } from './syncManualLayoutActor.js';
|
|
17
|
-
import { findDiagramEdge, findDiagramNode, typedSystem, focusedBounds } from './utils.js';
|
|
18
|
+
import { findDiagramEdge, findDiagramNode, typedSystem, activeSequenceBounds, focusedBounds } from './utils.js';
|
|
18
19
|
|
|
19
20
|
const _diagramMachine = setup({
|
|
20
21
|
types: {
|
|
@@ -33,10 +34,11 @@ const _diagramMachine = setup({
|
|
|
33
34
|
guards: {
|
|
34
35
|
"isReady": ({ context }) => context.initialized.xydata && context.initialized.xyflow,
|
|
35
36
|
"enabled: FitView": ({ context }) => context.features.enableFitView,
|
|
36
|
-
"enabled: FocusMode": ({ context }) => context.features.enableFocusMode,
|
|
37
|
+
"enabled: FocusMode": ({ context }) => context.features.enableFocusMode && (context.view._type !== "dynamic" || context.dynamicViewVariant !== "sequence"),
|
|
37
38
|
"enabled: Readonly": ({ context }) => context.features.enableReadOnly,
|
|
38
39
|
"enabled: RelationshipDetails": ({ context }) => context.features.enableRelationshipDetails,
|
|
39
40
|
"enabled: Search": ({ context }) => context.features.enableSearch,
|
|
41
|
+
"enabled: ElementDetails": ({ context }) => context.features.enableElementDetails,
|
|
40
42
|
"not readonly": ({ context }) => !context.features.enableReadOnly,
|
|
41
43
|
"is dynamic view": ({ context }) => context.view._type === "dynamic",
|
|
42
44
|
"is another view": ({ context, event }) => {
|
|
@@ -49,6 +51,10 @@ const _diagramMachine = setup({
|
|
|
49
51
|
}
|
|
50
52
|
nonexhaustive(event.type);
|
|
51
53
|
},
|
|
54
|
+
"click: node has modelFqn": ({ event }) => {
|
|
55
|
+
assertEvent(event, "xyflow.nodeClick");
|
|
56
|
+
return "modelFqn" in event.node.data;
|
|
57
|
+
},
|
|
52
58
|
"click: selected node": ({ event }) => {
|
|
53
59
|
assertEvent(event, "xyflow.nodeClick");
|
|
54
60
|
return event.node.selected === true;
|
|
@@ -85,6 +91,22 @@ const _diagramMachine = setup({
|
|
|
85
91
|
lastClickedNode: lastClickedNode({ context, event })
|
|
86
92
|
};
|
|
87
93
|
}),
|
|
94
|
+
"assign: focusedNode": assign(({ context, event }) => {
|
|
95
|
+
let focusedNode;
|
|
96
|
+
switch (event.type) {
|
|
97
|
+
case "xyflow.nodeClick":
|
|
98
|
+
focusedNode = event.node.data.id;
|
|
99
|
+
break;
|
|
100
|
+
case "focus.node":
|
|
101
|
+
focusedNode = event.nodeId;
|
|
102
|
+
break;
|
|
103
|
+
default:
|
|
104
|
+
throw new Error(`Unexpected event type: ${event.type} in action 'assign: focusedNode'`);
|
|
105
|
+
}
|
|
106
|
+
return {
|
|
107
|
+
focusedNode
|
|
108
|
+
};
|
|
109
|
+
}),
|
|
88
110
|
"reset lastClickedNode": assign(() => ({
|
|
89
111
|
lastClickedNode: null
|
|
90
112
|
})),
|
|
@@ -119,7 +141,8 @@ const _diagramMachine = setup({
|
|
|
119
141
|
panZoom?.setViewport(viewport, duration > 0 ? { duration } : void 0);
|
|
120
142
|
},
|
|
121
143
|
"xyflow:fitFocusedBounds": ({ context }) => {
|
|
122
|
-
const
|
|
144
|
+
const isActiveSequenceWalkthrough = !!context.activeWalkthrough && context.dynamicViewVariant === "sequence";
|
|
145
|
+
const { bounds, duration = 450 } = isActiveSequenceWalkthrough ? activeSequenceBounds({ context }) : focusedBounds({ context });
|
|
123
146
|
const { width, height, panZoom, transform } = nonNullable(context.xystore).getState();
|
|
124
147
|
const maxZoom = Math.max(1, transform[2]);
|
|
125
148
|
const viewport = getViewportForBounds(
|
|
@@ -340,6 +363,50 @@ const _diagramMachine = setup({
|
|
|
340
363
|
}))
|
|
341
364
|
})),
|
|
342
365
|
"update active walkthrough": assign(updateActiveWalkthrough),
|
|
366
|
+
"open element details": sendTo(
|
|
367
|
+
({ system }) => typedSystem(system).overlaysActorRef,
|
|
368
|
+
({ context, event }, params) => {
|
|
369
|
+
let initiatedFrom = null;
|
|
370
|
+
let fromNodeId, subject;
|
|
371
|
+
if (params) {
|
|
372
|
+
subject = params.fqn;
|
|
373
|
+
fromNodeId = params.fromNode ?? context.view.nodes.find((n) => n.modelRef === params.fqn)?.id;
|
|
374
|
+
} else if (event.type === "xyflow.nodeClick") {
|
|
375
|
+
invariant("modelFqn" in event.node.data && !!event.node.data.modelFqn, "No modelFqn in event node data");
|
|
376
|
+
subject = event.node.data.modelFqn;
|
|
377
|
+
fromNodeId = event.node.data.id;
|
|
378
|
+
} else if (event.type === "open.elementDetails") {
|
|
379
|
+
subject = event.fqn;
|
|
380
|
+
fromNodeId = event.fromNode;
|
|
381
|
+
} else {
|
|
382
|
+
invariant(context.lastClickedNode, "No last clicked node");
|
|
383
|
+
fromNodeId = nonNullable(context.lastClickedNode).id;
|
|
384
|
+
const node = nonNullable(context.xynodes.find((n) => n.id === fromNodeId));
|
|
385
|
+
invariant("modelFqn" in node.data && !!node.data.modelFqn, "No modelFqn in last clicked node");
|
|
386
|
+
subject = node.data.modelFqn;
|
|
387
|
+
}
|
|
388
|
+
const internalNode = fromNodeId ? context.xystore.getState().nodeLookup.get(fromNodeId) : null;
|
|
389
|
+
if (fromNodeId && internalNode) {
|
|
390
|
+
const nodeRect = nodeToRect(internalNode);
|
|
391
|
+
const zoom = context.xyflow.getZoom();
|
|
392
|
+
const clientRect = {
|
|
393
|
+
...context.xyflow.flowToScreenPosition(nodeRect),
|
|
394
|
+
width: nodeRect.width * zoom,
|
|
395
|
+
height: nodeRect.height * zoom
|
|
396
|
+
};
|
|
397
|
+
initiatedFrom = {
|
|
398
|
+
node: fromNodeId,
|
|
399
|
+
clientRect
|
|
400
|
+
};
|
|
401
|
+
}
|
|
402
|
+
return {
|
|
403
|
+
type: "open.elementDetails",
|
|
404
|
+
subject,
|
|
405
|
+
currentView: context.view,
|
|
406
|
+
...initiatedFrom && { initiatedFrom }
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
),
|
|
343
410
|
"emit: walkthroughStarted": emit(({ context }) => {
|
|
344
411
|
const edge = context.xyedges.find((x) => x.id === context.activeWalkthrough?.stepId);
|
|
345
412
|
invariant(edge, "Invalid walkthrough state");
|
|
@@ -387,6 +454,12 @@ const _diagramMachine = setup({
|
|
|
387
454
|
edge,
|
|
388
455
|
xyedge: event.edge
|
|
389
456
|
};
|
|
457
|
+
}),
|
|
458
|
+
"assign: dynamicViewVariant": assign(({ event }) => {
|
|
459
|
+
assertEvent(event, "switch.dynamicViewVariant");
|
|
460
|
+
return {
|
|
461
|
+
dynamicViewVariant: event.variant
|
|
462
|
+
};
|
|
390
463
|
})
|
|
391
464
|
}
|
|
392
465
|
}).createMachine({
|
|
@@ -416,6 +489,7 @@ const _diagramMachine = setup({
|
|
|
416
489
|
viewport: { x: 0, y: 0, zoom: 1 },
|
|
417
490
|
xyflow: null,
|
|
418
491
|
syncLayoutActorRef: null,
|
|
492
|
+
dynamicViewVariant: input.dynamicViewVariant ?? (input.view._type === "dynamic" ? input.view.variant : "diagram") ?? "diagram",
|
|
419
493
|
activeWalkthrough: null
|
|
420
494
|
}),
|
|
421
495
|
// entry: ({ spawn }) => spawn(layoutActor, { id: 'layout', input: { parent: self } }),
|
|
@@ -520,30 +594,8 @@ const _diagramMachine = setup({
|
|
|
520
594
|
]
|
|
521
595
|
},
|
|
522
596
|
"open.elementDetails": {
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
const fromNodeId = event.fromNode ?? context.view.nodes.find((n) => n.modelRef === event.fqn)?.id;
|
|
526
|
-
const internalNode = fromNodeId ? nonNullable(context.xystore).getState().nodeLookup.get(fromNodeId) : null;
|
|
527
|
-
if (fromNodeId && internalNode) {
|
|
528
|
-
const nodeRect = nodeToRect(internalNode);
|
|
529
|
-
const zoom = context.xyflow.getZoom();
|
|
530
|
-
const clientRect = {
|
|
531
|
-
...context.xyflow.flowToScreenPosition(nodeRect),
|
|
532
|
-
width: nodeRect.width * zoom,
|
|
533
|
-
height: nodeRect.height * zoom
|
|
534
|
-
};
|
|
535
|
-
initiatedFrom = {
|
|
536
|
-
node: fromNodeId,
|
|
537
|
-
clientRect
|
|
538
|
-
};
|
|
539
|
-
}
|
|
540
|
-
return {
|
|
541
|
-
type: "open.elementDetails",
|
|
542
|
-
subject: event.fqn,
|
|
543
|
-
currentView: context.view,
|
|
544
|
-
...initiatedFrom && { initiatedFrom }
|
|
545
|
-
};
|
|
546
|
-
})
|
|
597
|
+
guard: "enabled: ElementDetails",
|
|
598
|
+
actions: "open element details"
|
|
547
599
|
},
|
|
548
600
|
"open.relationshipsBrowser": {
|
|
549
601
|
actions: sendTo(({ system }) => typedSystem(system).overlaysActorRef, ({ context, event }) => ({
|
|
@@ -655,14 +707,29 @@ const _diagramMachine = setup({
|
|
|
655
707
|
])
|
|
656
708
|
]),
|
|
657
709
|
actions: [
|
|
658
|
-
assign
|
|
659
|
-
|
|
660
|
-
focusedNode: ({ event }) => event.node.id
|
|
661
|
-
}),
|
|
710
|
+
"assign lastClickedNode",
|
|
711
|
+
"assign: focusedNode",
|
|
662
712
|
"emit: nodeClick"
|
|
663
713
|
],
|
|
664
714
|
target: "focused"
|
|
665
715
|
},
|
|
716
|
+
{
|
|
717
|
+
// TODO: xstate fails to infer the type of the guard
|
|
718
|
+
guard: and([
|
|
719
|
+
"enabled: ElementDetails",
|
|
720
|
+
"click: node has modelFqn",
|
|
721
|
+
or([
|
|
722
|
+
"click: same node",
|
|
723
|
+
"click: selected node"
|
|
724
|
+
])
|
|
725
|
+
]),
|
|
726
|
+
actions: [
|
|
727
|
+
"assign lastClickedNode",
|
|
728
|
+
"open source of focused or last clicked node",
|
|
729
|
+
"open element details",
|
|
730
|
+
"emit: nodeClick"
|
|
731
|
+
]
|
|
732
|
+
},
|
|
666
733
|
{
|
|
667
734
|
actions: [
|
|
668
735
|
"assign lastClickedNode",
|
|
@@ -686,9 +753,7 @@ const _diagramMachine = setup({
|
|
|
686
753
|
},
|
|
687
754
|
"focus.node": {
|
|
688
755
|
guard: "enabled: FocusMode",
|
|
689
|
-
actions: assign
|
|
690
|
-
focusedNode: ({ event }) => event.nodeId
|
|
691
|
-
}),
|
|
756
|
+
actions: "assign: focusedNode",
|
|
692
757
|
target: "focused"
|
|
693
758
|
},
|
|
694
759
|
"xyflow.edgeClick": {
|
|
@@ -731,6 +796,16 @@ const _diagramMachine = setup({
|
|
|
731
796
|
}),
|
|
732
797
|
on: {
|
|
733
798
|
"xyflow.nodeClick": [
|
|
799
|
+
{
|
|
800
|
+
guard: and([
|
|
801
|
+
"click: focused node",
|
|
802
|
+
"click: node has modelFqn"
|
|
803
|
+
]),
|
|
804
|
+
actions: [
|
|
805
|
+
"open element details",
|
|
806
|
+
"emit: nodeClick"
|
|
807
|
+
]
|
|
808
|
+
},
|
|
734
809
|
{
|
|
735
810
|
guard: "click: focused node",
|
|
736
811
|
actions: "emit: nodeClick",
|
|
@@ -738,9 +813,7 @@ const _diagramMachine = setup({
|
|
|
738
813
|
},
|
|
739
814
|
{
|
|
740
815
|
actions: [
|
|
741
|
-
assign
|
|
742
|
-
lastClickedNode
|
|
743
|
-
}),
|
|
816
|
+
"assign lastClickedNode",
|
|
744
817
|
raise(({ event }) => ({
|
|
745
818
|
type: "focus.node",
|
|
746
819
|
nodeId: event.node.id
|
|
@@ -751,9 +824,7 @@ const _diagramMachine = setup({
|
|
|
751
824
|
],
|
|
752
825
|
"focus.node": {
|
|
753
826
|
actions: [
|
|
754
|
-
assign
|
|
755
|
-
focusedNode: ({ event }) => event.nodeId
|
|
756
|
-
}),
|
|
827
|
+
"assign: focusedNode",
|
|
757
828
|
"focus on nodes and edges",
|
|
758
829
|
"open source of focused or last clicked node",
|
|
759
830
|
"xyflow:fitFocusedBounds"
|
|
@@ -795,6 +866,32 @@ const _diagramMachine = setup({
|
|
|
795
866
|
"xyflow:fitFocusedBounds",
|
|
796
867
|
"emit: walkthroughStarted"
|
|
797
868
|
],
|
|
869
|
+
exit: enqueueActions(({ enqueue, context, event }) => {
|
|
870
|
+
enqueue.stopChild("hotkey");
|
|
871
|
+
if (context.viewportBeforeFocus) {
|
|
872
|
+
enqueue({ type: "xyflow:setViewport", params: { viewport: context.viewportBeforeFocus } });
|
|
873
|
+
} else {
|
|
874
|
+
enqueue("xyflow:fitDiagram");
|
|
875
|
+
}
|
|
876
|
+
if (context.dynamicViewVariant === "sequence" && context.activeWalkthrough?.parallelPrefix) {
|
|
877
|
+
enqueue.assign({
|
|
878
|
+
xynodes: context.xynodes.map((n) => {
|
|
879
|
+
if (n.type === "seq-parallel") {
|
|
880
|
+
return Base.setData(n, {
|
|
881
|
+
color: SeqParallelAreaColor.default
|
|
882
|
+
});
|
|
883
|
+
}
|
|
884
|
+
return n;
|
|
885
|
+
})
|
|
886
|
+
});
|
|
887
|
+
}
|
|
888
|
+
enqueue("undim everything");
|
|
889
|
+
enqueue.assign({
|
|
890
|
+
activeWalkthrough: null,
|
|
891
|
+
viewportBeforeFocus: null
|
|
892
|
+
});
|
|
893
|
+
enqueue("emit: walkthroughStopped");
|
|
894
|
+
}),
|
|
798
895
|
on: {
|
|
799
896
|
"key.esc": {
|
|
800
897
|
target: "idle"
|
|
@@ -867,21 +964,7 @@ const _diagramMachine = setup({
|
|
|
867
964
|
actions: raise(({ event }) => event, { delay: 50 }),
|
|
868
965
|
target: "idle"
|
|
869
966
|
}
|
|
870
|
-
}
|
|
871
|
-
exit: enqueueActions(({ enqueue, context, event }) => {
|
|
872
|
-
enqueue.stopChild("hotkey");
|
|
873
|
-
if (context.viewportBeforeFocus) {
|
|
874
|
-
enqueue({ type: "xyflow:setViewport", params: { viewport: context.viewportBeforeFocus } });
|
|
875
|
-
} else {
|
|
876
|
-
enqueue("xyflow:fitDiagram");
|
|
877
|
-
}
|
|
878
|
-
enqueue("undim everything");
|
|
879
|
-
enqueue.assign({
|
|
880
|
-
activeWalkthrough: null,
|
|
881
|
-
viewportBeforeFocus: null
|
|
882
|
-
});
|
|
883
|
-
enqueue("emit: walkthroughStopped");
|
|
884
|
-
})
|
|
967
|
+
}
|
|
885
968
|
}
|
|
886
969
|
}
|
|
887
970
|
},
|
|
@@ -904,8 +987,8 @@ const _diagramMachine = setup({
|
|
|
904
987
|
params: {
|
|
905
988
|
fromNode: fromNode.id,
|
|
906
989
|
toPosition: {
|
|
907
|
-
x: toNode.position[0],
|
|
908
|
-
y: toNode.position[1]
|
|
990
|
+
x: toNode.data.position[0],
|
|
991
|
+
y: toNode.data.position[1]
|
|
909
992
|
}
|
|
910
993
|
}
|
|
911
994
|
});
|
|
@@ -989,8 +1072,8 @@ const _diagramMachine = setup({
|
|
|
989
1072
|
params: {
|
|
990
1073
|
fromNode: fromNode.id,
|
|
991
1074
|
toPosition: {
|
|
992
|
-
x: toNode.position[0],
|
|
993
|
-
y: toNode.position[1]
|
|
1075
|
+
x: toNode.data.position[0],
|
|
1076
|
+
y: toNode.data.position[1]
|
|
994
1077
|
}
|
|
995
1078
|
}
|
|
996
1079
|
});
|
|
@@ -1002,6 +1085,14 @@ const _diagramMachine = setup({
|
|
|
1002
1085
|
});
|
|
1003
1086
|
enqueue.raise({ type: "fitDiagram", duration: 200 }, { id: "fitDiagram", delay: 25 });
|
|
1004
1087
|
}
|
|
1088
|
+
} else {
|
|
1089
|
+
const nextView = event.view;
|
|
1090
|
+
if (nextView._type === "dynamic" && context.view._type === "dynamic" && nextView.variant !== context.view.variant) {
|
|
1091
|
+
enqueue({
|
|
1092
|
+
type: "xyflow:setViewportCenter",
|
|
1093
|
+
params: BBox.center(nextView.bounds)
|
|
1094
|
+
});
|
|
1095
|
+
}
|
|
1005
1096
|
}
|
|
1006
1097
|
enqueue.assign({
|
|
1007
1098
|
...mergeXYNodesEdges({ context, event }),
|
|
@@ -1027,6 +1118,9 @@ const _diagramMachine = setup({
|
|
|
1027
1118
|
"ensure overlays actor state",
|
|
1028
1119
|
"ensure search actor state"
|
|
1029
1120
|
]
|
|
1121
|
+
},
|
|
1122
|
+
"switch.dynamicViewVariant": {
|
|
1123
|
+
actions: "assign: dynamicViewVariant"
|
|
1030
1124
|
}
|
|
1031
1125
|
},
|
|
1032
1126
|
exit: [
|
|
@@ -1049,13 +1143,26 @@ const _diagramMachine = setup({
|
|
|
1049
1143
|
]
|
|
1050
1144
|
});
|
|
1051
1145
|
function nodeRef(node) {
|
|
1052
|
-
|
|
1146
|
+
switch (node.type) {
|
|
1147
|
+
case "element":
|
|
1148
|
+
case "compound-element":
|
|
1149
|
+
case "seq-actor":
|
|
1150
|
+
return node.data.modelFqn;
|
|
1151
|
+
case "deployment":
|
|
1152
|
+
case "compound-deployment":
|
|
1153
|
+
return node.data.modelFqn ?? node.data.deploymentFqn;
|
|
1154
|
+
case "seq-parallel":
|
|
1155
|
+
case "view-group":
|
|
1156
|
+
return null;
|
|
1157
|
+
default:
|
|
1158
|
+
nonexhaustive(node);
|
|
1159
|
+
}
|
|
1053
1160
|
}
|
|
1054
1161
|
function findCorrespondingNode(context, event) {
|
|
1055
1162
|
const fromNodeId = context.lastOnNavigate?.fromNode;
|
|
1056
|
-
const fromNode = fromNodeId && context.
|
|
1163
|
+
const fromNode = fromNodeId && context.xynodes.find((n) => n.id === fromNodeId);
|
|
1057
1164
|
const fromRef = fromNode && nodeRef(fromNode);
|
|
1058
|
-
const toNode = fromRef && event.
|
|
1165
|
+
const toNode = fromRef && event.xynodes.find((n) => nodeRef(n) === fromRef);
|
|
1059
1166
|
return { fromNode, toNode };
|
|
1060
1167
|
}
|
|
1061
1168
|
const diagramMachine = _diagramMachine;
|
package/dist/state/utils.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { DiagramEdge, DiagramNode, BBox } from '@likec4/core/types';
|
|
2
2
|
import { ActorSystem } from 'xstate';
|
|
3
3
|
import { OverlaysActorRef } from '../overlays/overlaysActor';
|
|
4
4
|
import { SearchActorRef } from '../search/searchActor';
|
|
@@ -17,3 +17,9 @@ export declare function focusedBounds(params: {
|
|
|
17
17
|
bounds: BBox;
|
|
18
18
|
duration?: number;
|
|
19
19
|
};
|
|
20
|
+
export declare function activeSequenceBounds(params: {
|
|
21
|
+
context: Context;
|
|
22
|
+
}): {
|
|
23
|
+
bounds: BBox;
|
|
24
|
+
duration?: number;
|
|
25
|
+
};
|
package/dist/state/utils.js
CHANGED
|
@@ -1,3 +1,7 @@
|
|
|
1
|
+
import { BBox } from '@likec4/core/types';
|
|
2
|
+
import { nonNullable } from '@likec4/core/utils';
|
|
3
|
+
import { getNodesBounds, getNodeDimensions, getEdgePosition } from '@xyflow/system';
|
|
4
|
+
|
|
1
5
|
function typedSystem(system) {
|
|
2
6
|
return {
|
|
3
7
|
get overlaysActorRef() {
|
|
@@ -34,12 +38,11 @@ function focusedBounds(params) {
|
|
|
34
38
|
}
|
|
35
39
|
const width = node.measured?.width ?? node.width ?? node.initialWidth;
|
|
36
40
|
const height = node.measured?.height ?? node.height ?? node.initialHeight;
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
};
|
|
41
|
+
acc.minX = Math.min(acc.minX, position.x);
|
|
42
|
+
acc.minY = Math.min(acc.minY, position.y);
|
|
43
|
+
acc.maxX = Math.max(acc.maxX, position.x + width);
|
|
44
|
+
acc.maxY = Math.max(acc.maxY, position.y + height);
|
|
45
|
+
return acc;
|
|
43
46
|
}, {
|
|
44
47
|
minX: Infinity,
|
|
45
48
|
minY: Infinity,
|
|
@@ -61,5 +64,62 @@ function focusedBounds(params) {
|
|
|
61
64
|
}
|
|
62
65
|
};
|
|
63
66
|
}
|
|
67
|
+
const MARGIN = 32;
|
|
68
|
+
function activeSequenceBounds(params) {
|
|
69
|
+
const activeWalkthrough = nonNullable(params.context.activeWalkthrough);
|
|
70
|
+
const stepEdge = nonNullable(params.context.xyedges.find((e) => e.id === activeWalkthrough.stepId));
|
|
71
|
+
const xystate = params.context.xystore.getState();
|
|
72
|
+
const sourceNode = nonNullable(xystate.nodeLookup.get(stepEdge.source));
|
|
73
|
+
const targetNode = nonNullable(xystate.nodeLookup.get(stepEdge.target));
|
|
74
|
+
const actorsBounds = getNodesBounds([sourceNode, targetNode], xystate);
|
|
75
|
+
let stepBounds;
|
|
76
|
+
if (activeWalkthrough.parallelPrefix) {
|
|
77
|
+
const parallelArea = params.context.xynodes.find(
|
|
78
|
+
(n) => n.type === "seq-parallel" && n.data.parallelPrefix === activeWalkthrough.parallelPrefix
|
|
79
|
+
);
|
|
80
|
+
if (parallelArea) {
|
|
81
|
+
stepBounds = {
|
|
82
|
+
x: parallelArea.position.x,
|
|
83
|
+
y: parallelArea.position.y,
|
|
84
|
+
...getNodeDimensions(parallelArea)
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
stepBounds ??= getEdgeBounds(stepEdge, xystate);
|
|
89
|
+
if (stepBounds) {
|
|
90
|
+
stepBounds = BBox.merge(stepBounds, actorsBounds);
|
|
91
|
+
} else {
|
|
92
|
+
stepBounds = actorsBounds;
|
|
93
|
+
}
|
|
94
|
+
return {
|
|
95
|
+
duration: 350,
|
|
96
|
+
bounds: BBox.expand(
|
|
97
|
+
stepBounds,
|
|
98
|
+
MARGIN
|
|
99
|
+
)
|
|
100
|
+
};
|
|
101
|
+
}
|
|
102
|
+
function getEdgeBounds(edge, store) {
|
|
103
|
+
const sourceNode = store.nodeLookup.get(edge.source);
|
|
104
|
+
const targetNode = store.nodeLookup.get(edge.target);
|
|
105
|
+
if (!sourceNode || !targetNode) {
|
|
106
|
+
return null;
|
|
107
|
+
}
|
|
108
|
+
const edgePosition = getEdgePosition({
|
|
109
|
+
id: edge.id,
|
|
110
|
+
sourceNode,
|
|
111
|
+
targetNode,
|
|
112
|
+
sourceHandle: edge.sourceHandle || null,
|
|
113
|
+
targetHandle: edge.targetHandle || null,
|
|
114
|
+
connectionMode: store.connectionMode
|
|
115
|
+
});
|
|
116
|
+
if (!edgePosition) {
|
|
117
|
+
return null;
|
|
118
|
+
}
|
|
119
|
+
return BBox.fromPoints([
|
|
120
|
+
[edgePosition.sourceX, edgePosition.sourceY],
|
|
121
|
+
[edgePosition.targetX, edgePosition.targetY]
|
|
122
|
+
]);
|
|
123
|
+
}
|
|
64
124
|
|
|
65
|
-
export { findDiagramEdge, findDiagramNode, focusedBounds, typedSystem };
|
|
125
|
+
export { activeSequenceBounds, findDiagramEdge, findDiagramNode, focusedBounds, typedSystem };
|