@likec4/diagram 1.44.0 → 1.45.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/index.js +18160 -17671
- package/dist/LikeC4Diagram.js +7 -5
- package/dist/LikeC4Diagram.props.d.ts +9 -8
- package/dist/LikeC4Styles.js +0 -3
- package/dist/LikeC4View.d.ts +3 -3
- package/dist/LikeC4View.js +7 -3
- package/dist/ReactLikeC4.d.ts +2 -2
- package/dist/base/Base.d.ts +1 -1
- package/dist/base/updateEdges.js +25 -15
- package/dist/base/updateNodes.d.ts +14 -0
- package/dist/base/updateNodes.js +51 -18
- package/dist/base-primitives/Markdown.d.ts +30 -4
- package/dist/base-primitives/Markdown.js +3 -2
- package/dist/base-primitives/compound/CompoundActionButton.d.ts +3 -2
- package/dist/base-primitives/compound/CompoundDetailsButton.d.ts +3 -2
- package/dist/base-primitives/edge/EdgeActionButton.d.ts +3 -2
- package/dist/base-primitives/edge/EdgeContainer.d.ts +1 -1
- package/dist/base-primitives/edge/EdgeContainer.js +4 -1
- package/dist/base-primitives/edge/EdgeLabel.d.ts +2 -2
- package/dist/base-primitives/edge/EdgePath.js +24 -4
- package/dist/base-primitives/element/ElementActionButtons.d.ts +3 -2
- package/dist/base-primitives/element/ElementActionButtons.js +2 -2
- package/dist/base-primitives/element/ElementData.d.ts +3 -3
- package/dist/base-primitives/element/ElementData.js +13 -7
- package/dist/base-primitives/element/ElementDetailsButton.d.ts +3 -2
- package/dist/base-primitives/element/ElementDetailsButton.js +3 -0
- package/dist/base-primitives/element/ElementShape.js +5 -5
- package/dist/base-primitives/element/ElementTags.d.ts +6 -4
- package/dist/context/DiagramFeatures.d.ts +1 -0
- package/dist/context/TagStylesContext.js +1 -1
- package/dist/custom/hooks.d.ts +2 -2
- package/dist/custom/index.js +1 -1
- package/dist/hooks/index.d.ts +2 -1
- package/dist/hooks/useDiagramCompareLayout.js +7 -2
- package/dist/hooks/useLikeC4Project.d.ts +6 -1
- package/dist/hooks/useLikeC4Project.js +14 -2
- package/dist/hooks/useMediaPrint.d.ts +6 -0
- package/dist/likec4diagram/DiagramXYFlow.js +11 -6
- package/dist/likec4diagram/custom/edges/EdgeDrifts.d.ts +6 -0
- package/dist/likec4diagram/custom/edges/EdgeDrifts.js +38 -0
- package/dist/likec4diagram/custom/edges/RelationshipEdge.js +24 -14
- package/dist/likec4diagram/custom/edges/SequenceStepEdge.js +3 -1
- package/dist/likec4diagram/custom/edges/useControlPoints.js +3 -3
- package/dist/likec4diagram/custom/edges/useRelationshipEdgePath.js +5 -5
- package/dist/likec4diagram/custom/nodes/NodeDrifts.d.ts +6 -0
- package/dist/likec4diagram/custom/nodes/{ElementNodeDrifts.js → NodeDrifts.js} +8 -4
- package/dist/likec4diagram/custom/nodes/SequenceActorNode.js +4 -2
- package/dist/likec4diagram/custom/nodes/index.d.ts +1 -0
- package/dist/likec4diagram/custom/nodes/nodes.js +64 -23
- package/dist/likec4diagram/relationship-popover/RelationshipPopover.js +3 -3
- package/dist/likec4diagram/relationship-popover/actor.d.ts +1 -1
- package/dist/likec4diagram/state/DiagramActorProvider.d.ts +2 -2
- package/dist/likec4diagram/state/DiagramActorProvider.js +0 -1
- package/dist/likec4diagram/state/assign.d.ts +10 -6
- package/dist/likec4diagram/state/assign.js +17 -192
- package/dist/likec4diagram/state/createViewChange.js +15 -26
- package/dist/likec4diagram/state/diagram-api.d.ts +2 -6
- package/dist/likec4diagram/state/diagram-api.js +2 -10
- package/dist/likec4diagram/state/hotkeyActor.d.ts +0 -7
- package/dist/likec4diagram/state/hotkeyActor.js +1 -17
- package/dist/likec4diagram/state/machine.actions.d.ts +430 -746
- package/dist/likec4diagram/state/machine.actions.js +193 -284
- package/dist/likec4diagram/state/machine.actions.layout.d.ts +579 -0
- package/dist/likec4diagram/state/machine.actions.layout.js +129 -0
- package/dist/likec4diagram/state/machine.d.ts +17 -3712
- package/dist/likec4diagram/state/machine.js +59 -73
- package/dist/likec4diagram/state/machine.setup.d.ts +61 -18
- package/dist/likec4diagram/state/machine.setup.js +27 -5
- package/dist/likec4diagram/state/machine.state.initializing.d.ts +25 -0
- package/dist/likec4diagram/state/machine.state.initializing.js +5 -5
- package/dist/likec4diagram/state/machine.state.navigating.d.ts +5 -108
- package/dist/likec4diagram/state/machine.state.navigating.js +167 -34
- package/dist/likec4diagram/state/machine.state.ready.d.ts +2316 -2851
- package/dist/likec4diagram/state/machine.state.ready.focused.d.ts +386 -0
- package/dist/likec4diagram/state/machine.state.ready.focused.js +85 -0
- package/dist/likec4diagram/state/machine.state.ready.idle.d.ts +474 -0
- package/dist/likec4diagram/state/machine.state.ready.idle.js +96 -0
- package/dist/likec4diagram/state/machine.state.ready.js +144 -319
- package/dist/likec4diagram/state/machine.state.ready.printing.d.ts +128 -0
- package/dist/likec4diagram/state/machine.state.ready.printing.js +40 -0
- package/dist/likec4diagram/state/machine.state.ready.walkthrough.d.ts +511 -0
- package/dist/likec4diagram/state/machine.state.ready.walkthrough.js +177 -0
- package/dist/likec4diagram/state/mediaPrintActor.d.ts +12 -0
- package/dist/likec4diagram/state/mediaPrintActor.js +18 -0
- package/dist/likec4diagram/state/syncManualLayoutActor.d.ts +6 -240
- package/dist/likec4diagram/state/syncManualLayoutActor.js +150 -89
- package/dist/likec4diagram/state/types.d.ts +5 -7
- package/dist/likec4diagram/state/utils.d.ts +15 -2
- package/dist/likec4diagram/state/utils.js +43 -3
- package/dist/likec4diagram/types.d.ts +8 -13
- package/dist/likec4diagram/ui/notation/NotationPanel.css.js +5 -2
- package/dist/likec4diagram/useLayoutConstraints.js +107 -102
- package/dist/likec4diagram/xyflow-diagram/diagram-view.js +12 -15
- package/dist/likec4diagram/xyflow-sequence/sequence-layout.js +11 -8
- package/dist/navigationpanel/NavigationPanel.js +5 -1
- package/dist/navigationpanel/actor.d.ts +4 -204
- package/dist/navigationpanel/actor.js +1 -1
- package/dist/navigationpanel/controls/ToggleReadonly.js +8 -3
- package/dist/navigationpanel/walkthrough/DynamicViewControls.d.ts +66 -66
- package/dist/navigationpanel/walkthrough/WalkthroughPanel.js +4 -3
- package/dist/overlays/element-details/ElementDetailsCard.css.js +3 -3
- package/dist/overlays/element-details/MetadataValue.d.ts +2 -1
- package/dist/overlays/element-details/actor.d.ts +8 -83
- package/dist/overlays/element-details/actor.js +0 -8
- package/dist/overlays/overlay/Overlay.js +10 -10
- package/dist/overlays/overlaysActor.d.ts +7 -392
- package/dist/overlays/overlaysActor.js +67 -46
- package/dist/overlays/relationship-details/_types.d.ts +3 -4
- package/dist/overlays/relationship-details/actor.d.ts +6 -562
- package/dist/overlays/relationship-details/actor.js +1 -0
- package/dist/overlays/relationship-details/layout-to-xyflow.js +3 -5
- package/dist/overlays/relationship-details/layout.d.ts +3 -3
- package/dist/overlays/relationship-details/layout.js +4 -4
- package/dist/overlays/relationships-browser/_types.d.ts +2 -3
- package/dist/overlays/relationships-browser/actor.d.ts +7 -739
- package/dist/overlays/relationships-browser/layout.d.ts +2 -2
- package/dist/overlays/relationships-browser/layout.js +3 -3
- package/dist/overlays/relationships-browser/useViewToNodesEdges.js +0 -3
- package/dist/overlays/types.d.ts +12 -13
- package/dist/search/components/_shared.css.d.ts +1 -1
- package/dist/search/searchActor.d.ts +3 -66
- package/dist/shadowroot/ShadowRoot.d.ts +5 -7
- package/dist/shadowroot/ShadowRoot.js +7 -5
- package/dist/styles.css2.js +1 -1
- package/dist/utils/vector.d.ts +5 -0
- package/dist/utils/vector.js +7 -0
- package/dist/utils/view-bounds.js +7 -6
- package/dist/utils/xyflow.d.ts +4 -2
- package/dist/utils/xyflow.js +18 -50
- package/package.json +19 -18
- package/panda.buildinfo.json +17 -5
- package/styles-min.css +1 -1
- package/styles.css +1 -1
- package/dist/likec4diagram/custom/nodes/ElementNodeDrifts.d.ts +0 -4
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { BBox } from '@likec4/core/types';
|
|
2
|
-
import { nonNullable } from '@likec4/core/utils';
|
|
3
|
-
import { getNodesBounds, getNodeDimensions, getEdgePosition } from '@xyflow/system';
|
|
2
|
+
import { nonNullable, nonexhaustive } from '@likec4/core/utils';
|
|
3
|
+
import { getViewportForBounds, getNodesBounds, getNodeDimensions, getEdgePosition } from '@xyflow/system';
|
|
4
|
+
import { MinZoom } from '../../base/const.js';
|
|
4
5
|
|
|
5
6
|
function typedSystem(system) {
|
|
6
7
|
return {
|
|
@@ -124,5 +125,44 @@ function getEdgeBounds(edge, store) {
|
|
|
124
125
|
[edgePosition.targetX, edgePosition.targetY]
|
|
125
126
|
]);
|
|
126
127
|
}
|
|
128
|
+
function nodeRef(node) {
|
|
129
|
+
switch (node.type) {
|
|
130
|
+
case "element":
|
|
131
|
+
case "compound-element":
|
|
132
|
+
case "seq-actor":
|
|
133
|
+
return node.data.modelFqn;
|
|
134
|
+
case "deployment":
|
|
135
|
+
case "compound-deployment":
|
|
136
|
+
return node.data.modelFqn ?? node.data.deploymentFqn;
|
|
137
|
+
case "seq-parallel":
|
|
138
|
+
case "view-group":
|
|
139
|
+
return null;
|
|
140
|
+
default:
|
|
141
|
+
nonexhaustive(node);
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
function findCorrespondingNode(context, event) {
|
|
145
|
+
const fromNodeId = context.lastOnNavigate?.fromNode;
|
|
146
|
+
const fromNode = fromNodeId && context.xynodes.find((n) => n.id === fromNodeId);
|
|
147
|
+
const fromRef = fromNode && nodeRef(fromNode);
|
|
148
|
+
const toNode = fromRef && event.xynodes.find((n) => nodeRef(n) === fromRef);
|
|
149
|
+
return { fromNode, toNode };
|
|
150
|
+
}
|
|
151
|
+
function calcViewportForBounds(context, bounds) {
|
|
152
|
+
let currentZoom = context.xyflow.getZoom();
|
|
153
|
+
let {
|
|
154
|
+
width,
|
|
155
|
+
height
|
|
156
|
+
} = context.xystore.getState();
|
|
157
|
+
const maxZoom = Math.max(currentZoom, 1);
|
|
158
|
+
return getViewportForBounds(
|
|
159
|
+
bounds,
|
|
160
|
+
width,
|
|
161
|
+
height,
|
|
162
|
+
MinZoom,
|
|
163
|
+
maxZoom,
|
|
164
|
+
context.fitViewPadding
|
|
165
|
+
);
|
|
166
|
+
}
|
|
127
167
|
|
|
128
|
-
export { activeSequenceBounds, findDiagramEdge, findDiagramNode, focusedBounds, typedSystem };
|
|
168
|
+
export { activeSequenceBounds, calcViewportForBounds, findCorrespondingNode, findDiagramEdge, findDiagramNode, focusedBounds, nodeRef, typedSystem };
|
|
@@ -1,18 +1,17 @@
|
|
|
1
|
-
import { BBox, DeploymentFqn, DiagramEdge,
|
|
1
|
+
import { BBox, DeploymentFqn, DiagramEdge, DiagramNode, DiagramNodeDriftReason, ExclusiveUnion, Fqn, IconUrl, MarkdownOrString, NonEmptyReadonlyArray, ViewId } from '@likec4/core/types';
|
|
2
2
|
import { XYPosition } from '@xyflow/system';
|
|
3
3
|
import { FunctionComponent } from 'react';
|
|
4
4
|
import { Simplify } from 'type-fest';
|
|
5
5
|
import { BaseEdge, BaseEdgeData, BaseEdgeProps, BaseNode, BaseNodeData, BaseNodeProps, NonOptional } from '../base/types';
|
|
6
6
|
export declare namespace Types {
|
|
7
|
-
type LeafNodeData = Simplify<BaseNodeData & NonOptional<Pick<DiagramNode, 'id' | 'title' | 'color' | 'shape' | 'width' | 'level' | 'height' | 'style' | 'tags' | 'x' | 'y'>> & {
|
|
8
|
-
technology: string | null;
|
|
9
|
-
description: RichTextOrEmpty;
|
|
7
|
+
type LeafNodeData = Simplify<BaseNodeData & NonOptional<Pick<DiagramNode, 'id' | 'title' | 'technology' | 'description' | 'color' | 'shape' | 'width' | 'level' | 'height' | 'style' | 'tags' | 'x' | 'y'>> & {
|
|
10
8
|
/**
|
|
11
9
|
* View this node belongs to
|
|
12
10
|
*/
|
|
13
11
|
viewId: ViewId;
|
|
14
12
|
isMultiple?: boolean | undefined;
|
|
15
13
|
icon: string | null;
|
|
14
|
+
drifts: NonEmptyReadonlyArray<DiagramNodeDriftReason> | null;
|
|
16
15
|
}>;
|
|
17
16
|
/**
|
|
18
17
|
* Represents element from logical model
|
|
@@ -24,7 +23,6 @@ export declare namespace Types {
|
|
|
24
23
|
* If set - this node has navigation to another view and diagram has handler for this
|
|
25
24
|
*/
|
|
26
25
|
navigateTo: ViewId | null;
|
|
27
|
-
drifts: NonEmptyReadonlyArray<DiagramNodeDriftReason> | null;
|
|
28
26
|
}>;
|
|
29
27
|
/**
|
|
30
28
|
* Represents element from deployment model
|
|
@@ -33,7 +31,6 @@ export declare namespace Types {
|
|
|
33
31
|
navigateTo: ViewId | null;
|
|
34
32
|
deploymentFqn: DeploymentFqn;
|
|
35
33
|
modelFqn: Fqn | null;
|
|
36
|
-
drifts: NonEmptyReadonlyArray<DiagramNodeDriftReason> | null;
|
|
37
34
|
}>;
|
|
38
35
|
type SequenceActorNodePort = {
|
|
39
36
|
id: string;
|
|
@@ -59,6 +56,7 @@ export declare namespace Types {
|
|
|
59
56
|
viewId: ViewId;
|
|
60
57
|
depth: number;
|
|
61
58
|
icon?: IconUrl;
|
|
59
|
+
drifts: NonEmptyReadonlyArray<DiagramNodeDriftReason> | null;
|
|
62
60
|
}>;
|
|
63
61
|
type CompoundElementNodeData = Simplify<CompoundNodeData & {
|
|
64
62
|
modelFqn: Fqn;
|
|
@@ -67,7 +65,6 @@ export declare namespace Types {
|
|
|
67
65
|
* If set - this node has navigation to another view and diagram has handler for this
|
|
68
66
|
*/
|
|
69
67
|
navigateTo: ViewId | null;
|
|
70
|
-
drifts: NonEmptyReadonlyArray<DiagramNodeDriftReason> | null;
|
|
71
68
|
}>;
|
|
72
69
|
type CompoundDeploymentNodeData = Simplify<CompoundNodeData & {
|
|
73
70
|
deploymentFqn: DeploymentFqn;
|
|
@@ -79,7 +76,6 @@ export declare namespace Types {
|
|
|
79
76
|
* If set - this node has navigation to another view and diagram has handler for this
|
|
80
77
|
*/
|
|
81
78
|
navigateTo: ViewId | null;
|
|
82
|
-
drifts: NonEmptyReadonlyArray<DiagramNodeDriftReason> | null;
|
|
83
79
|
}>;
|
|
84
80
|
type ViewGroupNodeData = Simplify<CompoundNodeData & {
|
|
85
81
|
isViewGroup: true;
|
|
@@ -106,14 +102,13 @@ export declare namespace Types {
|
|
|
106
102
|
type: Type;
|
|
107
103
|
}>;
|
|
108
104
|
type NodeProps<Type extends NodeType = NodeType> = BaseNodeProps<Node<Type>>;
|
|
109
|
-
type RelationshipEdgeData = Simplify<BaseEdgeData & NonOptional<Pick<DiagramEdge, 'id' | 'label' | 'labelBBox' | 'technology' | 'points' | 'dir' | 'color' | 'line' | 'head' | 'tail' | 'navigateTo' | 'astPath'>> & {
|
|
110
|
-
notes:
|
|
105
|
+
type RelationshipEdgeData = Simplify<BaseEdgeData & NonOptional<Pick<DiagramEdge, 'id' | 'label' | 'labelBBox' | 'technology' | 'points' | 'dir' | 'color' | 'line' | 'head' | 'tail' | 'navigateTo' | 'astPath' | 'drifts'>> & {
|
|
106
|
+
notes: MarkdownOrString | null;
|
|
111
107
|
labelXY: XYPosition | null;
|
|
112
108
|
controlPoints: XYPosition[] | undefined | null;
|
|
113
|
-
drifts: NonEmptyReadonlyArray<DiagramEdgeDriftReason> | null;
|
|
114
109
|
}>;
|
|
115
|
-
type SequenceStepEdgeData = Simplify<BaseEdgeData & NonOptional<Pick<DiagramEdge, 'id' | 'label' | 'technology' | 'points' | 'dir' | 'color' | 'line' | 'head' | 'tail' | 'navigateTo' | 'astPath'>> & {
|
|
116
|
-
notes:
|
|
110
|
+
type SequenceStepEdgeData = Simplify<BaseEdgeData & NonOptional<Pick<DiagramEdge, 'id' | 'label' | 'technology' | 'points' | 'dir' | 'color' | 'line' | 'head' | 'tail' | 'navigateTo' | 'astPath' | 'drifts'>> & {
|
|
111
|
+
notes: MarkdownOrString | null;
|
|
117
112
|
labelXY: XYPosition | null;
|
|
118
113
|
labelBBox: BBox;
|
|
119
114
|
controlPoints: XYPosition[] | undefined | null;
|
|
@@ -7,7 +7,10 @@ const container = css({
|
|
|
7
7
|
padding: "2",
|
|
8
8
|
margin: "0",
|
|
9
9
|
width: "min-content",
|
|
10
|
-
height: "min-content"
|
|
10
|
+
height: "min-content",
|
|
11
|
+
_print: {
|
|
12
|
+
display: "none"
|
|
13
|
+
}
|
|
11
14
|
});
|
|
12
15
|
const icon = css({
|
|
13
16
|
["--ai-radius"]: "0px",
|
|
@@ -43,7 +46,7 @@ const elementNotation = css({
|
|
|
43
46
|
// WebkitBackdropFilter: fallbackVar(vars.safariAnimationHook, 'blur(8px)'),
|
|
44
47
|
// backdropFilter: fallbackVar(vars.safariAnimationHook, 'blur(8px)'),
|
|
45
48
|
// vars: {
|
|
46
|
-
// // [stokeFillMix]: `color-mix(in
|
|
49
|
+
// // [stokeFillMix]: `color-mix(in oklab, ${vars.element.stroke} 90%, ${vars.element.fill})`
|
|
47
50
|
// },
|
|
48
51
|
_hover: {
|
|
49
52
|
transition: "all 120ms ease-out",
|
|
@@ -1,13 +1,13 @@
|
|
|
1
|
-
import { DefaultMap, nonNullable } from '@likec4/core';
|
|
2
|
-
import { isome } from '@likec4/core/utils';
|
|
1
|
+
import { DefaultMap, nonNullable, BBox } from '@likec4/core';
|
|
2
|
+
import { isome, invariant } from '@likec4/core/utils';
|
|
3
3
|
import { getNodeDimensions } from '@xyflow/system';
|
|
4
4
|
import { produce } from 'immer';
|
|
5
5
|
import { useRef, useMemo } from 'react';
|
|
6
|
-
import { pipe, filter, hasAtLeast,
|
|
6
|
+
import { pipe, filter, map, hasAtLeast, flatMap, unique, difference, clamp } from 'remeda';
|
|
7
7
|
import '@xstate/react';
|
|
8
8
|
import 'fast-equals';
|
|
9
9
|
import { useDiagram } from '../hooks/safeContext.js';
|
|
10
|
-
import {
|
|
10
|
+
import { nodeToRect, bezierControlPoints } from '../utils/xyflow.js';
|
|
11
11
|
import { useXYStoreApi } from '../hooks/useXYFlow.js';
|
|
12
12
|
import { vector } from '../utils/vector.js';
|
|
13
13
|
|
|
@@ -45,14 +45,14 @@ class Rect {
|
|
|
45
45
|
}
|
|
46
46
|
get dimensions() {
|
|
47
47
|
return {
|
|
48
|
-
width: this.maxX - this.minX,
|
|
49
|
-
height: this.maxY - this.minY
|
|
48
|
+
width: Math.round(this.maxX - this.minX),
|
|
49
|
+
height: Math.round(this.maxY - this.minY)
|
|
50
50
|
};
|
|
51
51
|
}
|
|
52
52
|
get diff() {
|
|
53
53
|
return {
|
|
54
|
-
x: this.positionAbsolute.x - this.initialX,
|
|
55
|
-
y: this.positionAbsolute.y - this.initialY
|
|
54
|
+
x: Math.round(this.positionAbsolute.x - this.initialX),
|
|
55
|
+
y: Math.round(this.positionAbsolute.y - this.initialY)
|
|
56
56
|
};
|
|
57
57
|
}
|
|
58
58
|
get isMoved() {
|
|
@@ -100,6 +100,7 @@ class Leaf extends Rect {
|
|
|
100
100
|
}
|
|
101
101
|
}
|
|
102
102
|
function makeEdgeModifier(edge, anchor) {
|
|
103
|
+
const controlPoints = edge.data.controlPoints ?? null;
|
|
103
104
|
return (edgeLookup) => {
|
|
104
105
|
const current = nonNullable(edgeLookup.get(edge.id), `Edge ${edge.id} not found`);
|
|
105
106
|
const { x: dx, y: dy } = anchor.diff;
|
|
@@ -109,8 +110,7 @@ function makeEdgeModifier(edge, anchor) {
|
|
|
109
110
|
type: "replace",
|
|
110
111
|
item: produce(current, (draft) => {
|
|
111
112
|
draft.data.points = edge.data.points;
|
|
112
|
-
draft.data.controlPoints =
|
|
113
|
-
draft.data.labelXY = edge.data.labelXY;
|
|
113
|
+
draft.data.controlPoints = controlPoints;
|
|
114
114
|
draft.data.labelBBox = edge.data.labelBBox;
|
|
115
115
|
})
|
|
116
116
|
};
|
|
@@ -120,18 +120,12 @@ function makeEdgeModifier(edge, anchor) {
|
|
|
120
120
|
type: "replace",
|
|
121
121
|
item: produce(current, (draft) => {
|
|
122
122
|
draft.data.points = map(edge.data.points, (pt) => [pt[0] + dx, pt[1] + dy]);
|
|
123
|
-
if (
|
|
124
|
-
draft.data.controlPoints =
|
|
123
|
+
if (controlPoints) {
|
|
124
|
+
draft.data.controlPoints = controlPoints.map((pt) => ({
|
|
125
125
|
x: pt.x + dx,
|
|
126
126
|
y: pt.y + dy
|
|
127
127
|
}));
|
|
128
128
|
}
|
|
129
|
-
if (edge.data.labelXY) {
|
|
130
|
-
draft.data.labelXY = {
|
|
131
|
-
x: edge.data.labelXY.x + dx,
|
|
132
|
-
y: edge.data.labelXY.y + dy
|
|
133
|
-
};
|
|
134
|
-
}
|
|
135
129
|
if (edge.data.labelBBox) {
|
|
136
130
|
draft.data.labelBBox = {
|
|
137
131
|
x: edge.data.labelBBox.x + dx,
|
|
@@ -144,6 +138,56 @@ function makeEdgeModifier(edge, anchor) {
|
|
|
144
138
|
};
|
|
145
139
|
};
|
|
146
140
|
}
|
|
141
|
+
function makeRelativeEdgeModifier(edge, movingRect, anchorNode, staticNode) {
|
|
142
|
+
const controlPoints = edge.data.controlPoints ?? bezierControlPoints(edge.data.points);
|
|
143
|
+
const anchorV = vector(BBox.center(anchorNode));
|
|
144
|
+
const staticV = vector(BBox.center(staticNode));
|
|
145
|
+
const staticToAnchor = anchorV.subtract(staticV);
|
|
146
|
+
const staticToAnchorLength = staticToAnchor.length();
|
|
147
|
+
return (edgeLookup) => {
|
|
148
|
+
const current = nonNullable(edgeLookup.get(edge.id), `Edge ${edge.id} not found`);
|
|
149
|
+
const { x: dx, y: dy } = movingRect.diff;
|
|
150
|
+
if (dx === 0 && dy === 0) {
|
|
151
|
+
return {
|
|
152
|
+
id: edge.id,
|
|
153
|
+
type: "replace",
|
|
154
|
+
item: produce(current, (draft) => {
|
|
155
|
+
draft.data.points = edge.data.points;
|
|
156
|
+
draft.data.controlPoints = edge.data.controlPoints;
|
|
157
|
+
draft.data.labelBBox = edge.data.labelBBox;
|
|
158
|
+
})
|
|
159
|
+
};
|
|
160
|
+
}
|
|
161
|
+
const d = vector(dx, dy);
|
|
162
|
+
const relativePoint = (pt) => {
|
|
163
|
+
const p = vector(pt);
|
|
164
|
+
const staticToP = p.subtract(staticV);
|
|
165
|
+
const projLength = staticToP.dot(staticToAnchor);
|
|
166
|
+
const coeff = clamp(projLength / staticToAnchorLength ** 2, {
|
|
167
|
+
min: -1,
|
|
168
|
+
max: 1
|
|
169
|
+
});
|
|
170
|
+
const newP = p.add(d.multiply(coeff)).round();
|
|
171
|
+
return {
|
|
172
|
+
x: newP.x,
|
|
173
|
+
y: newP.y
|
|
174
|
+
};
|
|
175
|
+
};
|
|
176
|
+
return {
|
|
177
|
+
id: edge.id,
|
|
178
|
+
type: "replace",
|
|
179
|
+
item: produce(current, (draft) => {
|
|
180
|
+
draft.data.controlPoints = controlPoints.map(relativePoint);
|
|
181
|
+
if (edge.data.labelBBox) {
|
|
182
|
+
draft.data.labelBBox ??= edge.data.labelBBox;
|
|
183
|
+
const { x, y } = relativePoint(edge.data.labelBBox);
|
|
184
|
+
draft.data.labelBBox.x = x;
|
|
185
|
+
draft.data.labelBBox.y = y;
|
|
186
|
+
}
|
|
187
|
+
})
|
|
188
|
+
};
|
|
189
|
+
};
|
|
190
|
+
}
|
|
147
191
|
function createLayoutConstraints(xyflowApi, editingNodeIds) {
|
|
148
192
|
const { parentLookup, nodeLookup, edges, edgeLookup } = xyflowApi.getState();
|
|
149
193
|
const rects = /* @__PURE__ */ new Map();
|
|
@@ -169,6 +213,16 @@ function createLayoutConstraints(xyflowApi, editingNodeIds) {
|
|
|
169
213
|
}
|
|
170
214
|
return nested;
|
|
171
215
|
});
|
|
216
|
+
if (hasAtLeast(editingNodeIds, 2)) {
|
|
217
|
+
const leafsOnly = pipe(
|
|
218
|
+
editingNodeIds,
|
|
219
|
+
flatMap((id) => [...nestedOf.get(id)]),
|
|
220
|
+
unique(),
|
|
221
|
+
(exclude) => difference(editingNodeIds, exclude)
|
|
222
|
+
);
|
|
223
|
+
invariant(hasAtLeast(leafsOnly, 1), "All editing nodes are nested within each other");
|
|
224
|
+
editingNodeIds = leafsOnly;
|
|
225
|
+
}
|
|
172
226
|
const ancestorsOfDraggingNodes = new Set(
|
|
173
227
|
editingNodeIds.flatMap((i) => ancestorsOf.get(i))
|
|
174
228
|
);
|
|
@@ -188,40 +242,21 @@ function createLayoutConstraints(xyflowApi, editingNodeIds) {
|
|
|
188
242
|
parent: rect
|
|
189
243
|
});
|
|
190
244
|
});
|
|
191
|
-
|
|
192
|
-
rects.set(xynode.id, new Leaf(xynode, parent));
|
|
245
|
+
continue;
|
|
193
246
|
}
|
|
247
|
+
rects.set(xynode.id, new Leaf(xynode, parent));
|
|
194
248
|
}
|
|
195
249
|
const rectsToUpdate = [...rects.values()];
|
|
196
250
|
const edgeModifiers = /* @__PURE__ */ new Map();
|
|
197
|
-
for (const r of rectsToUpdate) {
|
|
198
|
-
if (r instanceof CompoundRect) {
|
|
199
|
-
continue;
|
|
200
|
-
}
|
|
201
|
-
const nested = nestedOf.get(r.id);
|
|
202
|
-
if (nested.size === 0) {
|
|
203
|
-
continue;
|
|
204
|
-
}
|
|
205
|
-
pipe(
|
|
206
|
-
edges,
|
|
207
|
-
filter((e) => !edgeModifiers.has(e) && nested.has(e.source) && nested.has(e.target)),
|
|
208
|
-
forEach((e) => {
|
|
209
|
-
edgeModifiers.set(e, makeEdgeModifier(e, r));
|
|
210
|
-
})
|
|
211
|
-
);
|
|
212
|
-
}
|
|
213
251
|
const findMovingAncestor = (nodeId) => {
|
|
214
252
|
return rects.get(nodeId) ?? ancestorsOf.get(nodeId).map((id) => rects.get(id)).find((s) => !!s) ?? null;
|
|
215
253
|
};
|
|
216
254
|
const movingNodes = new Set(editingNodeIds.flatMap((id) => [id, ...nestedOf.get(id)]));
|
|
217
255
|
for (const edge of edges) {
|
|
218
|
-
if (edgeModifiers.has(edge)) {
|
|
219
|
-
continue;
|
|
220
|
-
}
|
|
221
256
|
const isSourceMoving = movingNodes.has(edge.source);
|
|
222
257
|
const isTargetMoving = movingNodes.has(edge.target);
|
|
223
258
|
if (isSourceMoving && isTargetMoving) {
|
|
224
|
-
let r = rects.get(edge.source) ?? rects.get(edge.target) ??
|
|
259
|
+
let r = rects.get(edge.source) ?? rects.get(edge.target) ?? findMovingAncestor(edge.source) ?? findMovingAncestor(edge.target);
|
|
225
260
|
if (r) {
|
|
226
261
|
edgeModifiers.set(edge, makeEdgeModifier(edge, r));
|
|
227
262
|
}
|
|
@@ -232,61 +267,21 @@ function createLayoutConstraints(xyflowApi, editingNodeIds) {
|
|
|
232
267
|
if (!movingRect) {
|
|
233
268
|
continue;
|
|
234
269
|
}
|
|
235
|
-
const
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
const [
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
item: produce(current, (draft) => {
|
|
251
|
-
draft.data.points = edge.data.points;
|
|
252
|
-
draft.data.controlPoints = edge.data.controlPoints;
|
|
253
|
-
draft.data.labelXY = edge.data.labelXY;
|
|
254
|
-
draft.data.labelBBox = edge.data.labelBBox;
|
|
255
|
-
})
|
|
256
|
-
};
|
|
257
|
-
}
|
|
258
|
-
const d = vector(dx, dy);
|
|
259
|
-
const relativePoint = (pt) => {
|
|
260
|
-
const p = vector(pt);
|
|
261
|
-
const staticToP = p.subtract(staticV);
|
|
262
|
-
const projLength = staticToP.dot(staticToAnchor);
|
|
263
|
-
const coeff = Math.min(projLength / staticToAnchorLength ** 2, 1);
|
|
264
|
-
const newP = p.add(d.multiply(coeff));
|
|
265
|
-
return {
|
|
266
|
-
x: Math.round(newP.x),
|
|
267
|
-
y: Math.round(newP.y)
|
|
268
|
-
};
|
|
269
|
-
};
|
|
270
|
-
return {
|
|
271
|
-
id: edge.id,
|
|
272
|
-
type: "replace",
|
|
273
|
-
item: produce(current, (draft) => {
|
|
274
|
-
draft.data.controlPoints = controlPoints.map(relativePoint);
|
|
275
|
-
if (edge.data.labelBBox) {
|
|
276
|
-
const { x, y } = relativePoint(edge.data.labelBBox);
|
|
277
|
-
draft.data.labelBBox = {
|
|
278
|
-
x,
|
|
279
|
-
y,
|
|
280
|
-
width: edge.data.labelBBox.width,
|
|
281
|
-
height: edge.data.labelBBox.height
|
|
282
|
-
};
|
|
283
|
-
}
|
|
284
|
-
if (edge.data.labelXY) {
|
|
285
|
-
draft.data.labelXY = relativePoint(edge.data.labelXY);
|
|
286
|
-
}
|
|
287
|
-
})
|
|
288
|
-
};
|
|
289
|
-
});
|
|
270
|
+
const [sourceNode, targetNode] = pipe(
|
|
271
|
+
[edge.source, edge.target],
|
|
272
|
+
map((id) => nonNullable(nodeLookup.get(id), `Node ${id} not found`)),
|
|
273
|
+
map(nodeToRect)
|
|
274
|
+
);
|
|
275
|
+
const [anchorNode, staticNode] = isSourceMoving ? [sourceNode, targetNode] : [targetNode, sourceNode];
|
|
276
|
+
edgeModifiers.set(
|
|
277
|
+
edge,
|
|
278
|
+
makeRelativeEdgeModifier(
|
|
279
|
+
edge,
|
|
280
|
+
movingRect,
|
|
281
|
+
anchorNode,
|
|
282
|
+
staticNode
|
|
283
|
+
)
|
|
284
|
+
);
|
|
290
285
|
continue;
|
|
291
286
|
}
|
|
292
287
|
}
|
|
@@ -335,10 +330,11 @@ function createLayoutConstraints(xyflowApi, editingNodeIds) {
|
|
|
335
330
|
}
|
|
336
331
|
return acc;
|
|
337
332
|
}, []);
|
|
338
|
-
xyflowApi.getState()
|
|
339
|
-
|
|
333
|
+
const { edgeLookup: edgeLookup2, triggerNodeChanges, triggerEdgeChanges } = xyflowApi.getState();
|
|
334
|
+
triggerNodeChanges(nodeUpdates);
|
|
335
|
+
const changes = _edgeModifiers.map((fm) => fm(edgeLookup2));
|
|
340
336
|
if (changes.length > 0) {
|
|
341
|
-
|
|
337
|
+
triggerEdgeChanges(changes);
|
|
342
338
|
}
|
|
343
339
|
}
|
|
344
340
|
let animationFrameId = null;
|
|
@@ -349,8 +345,16 @@ function createLayoutConstraints(xyflowApi, editingNodeIds) {
|
|
|
349
345
|
animationFrameId ??= requestAnimationFrame(() => {
|
|
350
346
|
animationFrameId = null;
|
|
351
347
|
for (const id of editingNodeIds) {
|
|
352
|
-
const rect =
|
|
353
|
-
|
|
348
|
+
const rect = rects.get(id);
|
|
349
|
+
if (!rect) {
|
|
350
|
+
console.warn(`Rect not found for id ${id}`);
|
|
351
|
+
continue;
|
|
352
|
+
}
|
|
353
|
+
const node = nodeLookup.get(id);
|
|
354
|
+
if (!node) {
|
|
355
|
+
console.warn(`Node not found for id ${id}`);
|
|
356
|
+
continue;
|
|
357
|
+
}
|
|
354
358
|
rect.positionAbsolute = node.internals.positionAbsolute;
|
|
355
359
|
}
|
|
356
360
|
updateXYFlow();
|
|
@@ -373,10 +377,11 @@ function useLayoutConstraints() {
|
|
|
373
377
|
const { nodeLookup } = xystore.getState();
|
|
374
378
|
const draggingNodes = pipe(
|
|
375
379
|
Array.from(nodeLookup.values()),
|
|
376
|
-
filter((n) => n.
|
|
380
|
+
filter((n) => n.dragging === true || n.id === xynode.id || n.selected === true),
|
|
381
|
+
map((n) => n.id)
|
|
377
382
|
);
|
|
378
383
|
if (hasAtLeast(draggingNodes, 1)) {
|
|
379
|
-
solverRef.current = createLayoutConstraints(xystore,
|
|
384
|
+
solverRef.current = createLayoutConstraints(xystore, draggingNodes);
|
|
380
385
|
}
|
|
381
386
|
},
|
|
382
387
|
onNodeDrag: (_event) => {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { Queue, whereOperatorAsPredicate, nonNullable, GroupElementKind,
|
|
1
|
+
import { Queue, whereOperatorAsPredicate, nonNullable, GroupElementKind, invariant } from '@likec4/core';
|
|
2
2
|
import { pick, hasAtLeast } from 'remeda';
|
|
3
3
|
import { ZIndexes } from '../../base/const.js';
|
|
4
4
|
|
|
@@ -50,7 +50,6 @@ function diagramToXY(opts) {
|
|
|
50
50
|
position.y -= parent.y;
|
|
51
51
|
}
|
|
52
52
|
const id = ns + node.id;
|
|
53
|
-
const drifts = node.drifts ?? null;
|
|
54
53
|
const base = {
|
|
55
54
|
id,
|
|
56
55
|
deletable: false,
|
|
@@ -78,14 +77,15 @@ function diagramToXY(opts) {
|
|
|
78
77
|
icon: node.icon ?? "none",
|
|
79
78
|
tags: node.tags ?? null,
|
|
80
79
|
x: node.x,
|
|
81
|
-
y: node.y
|
|
80
|
+
y: node.y,
|
|
81
|
+
drifts: node.drifts ?? null
|
|
82
82
|
};
|
|
83
83
|
const leafNodeData = {
|
|
84
84
|
viewId: view.id,
|
|
85
85
|
id: node.id,
|
|
86
86
|
title: node.title,
|
|
87
87
|
technology: node.technology ?? null,
|
|
88
|
-
description:
|
|
88
|
+
description: node.description ?? null,
|
|
89
89
|
height: node.height,
|
|
90
90
|
width: node.width,
|
|
91
91
|
level: node.level,
|
|
@@ -96,7 +96,8 @@ function diagramToXY(opts) {
|
|
|
96
96
|
tags: node.tags,
|
|
97
97
|
x: node.x,
|
|
98
98
|
y: node.y,
|
|
99
|
-
isMultiple: node.style?.multiple ?? false
|
|
99
|
+
isMultiple: node.style?.multiple ?? false,
|
|
100
|
+
drifts: node.drifts ?? null
|
|
100
101
|
};
|
|
101
102
|
if (node.kind === GroupElementKind) {
|
|
102
103
|
xynodes.push({
|
|
@@ -127,8 +128,7 @@ function diagramToXY(opts) {
|
|
|
127
128
|
...compoundData,
|
|
128
129
|
...navigateTo,
|
|
129
130
|
deploymentFqn,
|
|
130
|
-
modelFqn
|
|
131
|
-
drifts
|
|
131
|
+
modelFqn
|
|
132
132
|
}
|
|
133
133
|
}
|
|
134
134
|
);
|
|
@@ -143,8 +143,7 @@ function diagramToXY(opts) {
|
|
|
143
143
|
data: {
|
|
144
144
|
...compoundData,
|
|
145
145
|
...navigateTo,
|
|
146
|
-
modelFqn
|
|
147
|
-
drifts
|
|
146
|
+
modelFqn
|
|
148
147
|
}
|
|
149
148
|
}
|
|
150
149
|
);
|
|
@@ -159,8 +158,7 @@ function diagramToXY(opts) {
|
|
|
159
158
|
...leafNodeData,
|
|
160
159
|
...navigateTo,
|
|
161
160
|
deploymentFqn,
|
|
162
|
-
modelFqn
|
|
163
|
-
drifts
|
|
161
|
+
modelFqn
|
|
164
162
|
}
|
|
165
163
|
}
|
|
166
164
|
);
|
|
@@ -175,8 +173,7 @@ function diagramToXY(opts) {
|
|
|
175
173
|
data: {
|
|
176
174
|
...leafNodeData,
|
|
177
175
|
...navigateTo,
|
|
178
|
-
modelFqn
|
|
179
|
-
drifts
|
|
176
|
+
modelFqn
|
|
180
177
|
}
|
|
181
178
|
}
|
|
182
179
|
);
|
|
@@ -203,11 +200,11 @@ function diagramToXY(opts) {
|
|
|
203
200
|
id: edge.id,
|
|
204
201
|
label: edge.label,
|
|
205
202
|
technology: edge.technology,
|
|
206
|
-
notes:
|
|
203
|
+
notes: edge.notes ?? null,
|
|
207
204
|
navigateTo: edge.navigateTo,
|
|
208
205
|
controlPoints: edge.controlPoints ?? null,
|
|
209
206
|
labelBBox: edge.labelBBox ?? null,
|
|
210
|
-
labelXY:
|
|
207
|
+
labelXY: null,
|
|
211
208
|
points: edge.points,
|
|
212
209
|
color: edge.color ?? "gray",
|
|
213
210
|
line: edge.line ?? "dashed",
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { nonNullable } from '@likec4/core';
|
|
2
|
-
import { RichText } from '@likec4/core/types';
|
|
3
2
|
import { SeqZIndex, SeqParallelAreaColor } from './const.js';
|
|
4
3
|
|
|
5
4
|
function sequenceLayoutToXY(view) {
|
|
@@ -46,7 +45,8 @@ function toCompoundArea({ id, x, y, width, height, depth }, node, view) {
|
|
|
46
45
|
y,
|
|
47
46
|
viewId: view.id,
|
|
48
47
|
depth,
|
|
49
|
-
isViewGroup: true
|
|
48
|
+
isViewGroup: true,
|
|
49
|
+
drifts: node.drifts ?? null
|
|
50
50
|
},
|
|
51
51
|
// zIndex: SeqZIndex.compound,
|
|
52
52
|
position: {
|
|
@@ -83,9 +83,10 @@ function toSeqParallelArea({ parallelPrefix, x, y, width, height }, view) {
|
|
|
83
83
|
icon: null,
|
|
84
84
|
width,
|
|
85
85
|
height,
|
|
86
|
-
description:
|
|
86
|
+
description: null,
|
|
87
87
|
viewId: view.id,
|
|
88
|
-
parallelPrefix
|
|
88
|
+
parallelPrefix,
|
|
89
|
+
drifts: null
|
|
89
90
|
},
|
|
90
91
|
zIndex: SeqZIndex.parallel,
|
|
91
92
|
position: {
|
|
@@ -126,10 +127,11 @@ function toSeqActorNode({ id, x, y, width, height, ports }, actor, bounds, view)
|
|
|
126
127
|
tags: actor.tags,
|
|
127
128
|
modelFqn: actor.modelRef ?? null,
|
|
128
129
|
technology: actor.technology ?? null,
|
|
129
|
-
description:
|
|
130
|
+
description: actor.description ?? null,
|
|
130
131
|
viewHeight: bounds.height,
|
|
131
132
|
viewId: view.id,
|
|
132
|
-
ports
|
|
133
|
+
ports,
|
|
134
|
+
drifts: actor.drifts ?? null
|
|
133
135
|
},
|
|
134
136
|
deletable: false,
|
|
135
137
|
selectable: true,
|
|
@@ -149,7 +151,7 @@ function toSeqStepEdge({ id, labelBBox, sourceHandle, targetHandle }, edge) {
|
|
|
149
151
|
id,
|
|
150
152
|
label: edge.label,
|
|
151
153
|
technology: edge.technology,
|
|
152
|
-
notes:
|
|
154
|
+
notes: edge.notes ?? null,
|
|
153
155
|
navigateTo: edge.navigateTo,
|
|
154
156
|
controlPoints: null,
|
|
155
157
|
labelBBox: {
|
|
@@ -165,7 +167,8 @@ function toSeqStepEdge({ id, labelBBox, sourceHandle, targetHandle }, edge) {
|
|
|
165
167
|
dir: "forward",
|
|
166
168
|
head: edge.head ?? "normal",
|
|
167
169
|
tail: edge.tail ?? "none",
|
|
168
|
-
astPath: edge.astPath
|
|
170
|
+
astPath: edge.astPath,
|
|
171
|
+
drifts: edge.drifts ?? null
|
|
169
172
|
},
|
|
170
173
|
selectable: true,
|
|
171
174
|
focusable: false,
|
|
@@ -69,6 +69,9 @@ const NavigationPanel = memo(() => {
|
|
|
69
69
|
"calc(100vw - 2 * {spacing.md})",
|
|
70
70
|
"calc(100cqw - 2 * {spacing.md})"
|
|
71
71
|
]
|
|
72
|
+
},
|
|
73
|
+
_print: {
|
|
74
|
+
display: "none"
|
|
72
75
|
}
|
|
73
76
|
},
|
|
74
77
|
children: /* @__PURE__ */ jsxs(NavigationPanelActorContextProvider, { value: actorRef, children: [
|
|
@@ -109,6 +112,7 @@ const NavigationPanelPopoverTarget = ({ actor }) => {
|
|
|
109
112
|
m.div,
|
|
110
113
|
{
|
|
111
114
|
layout: true,
|
|
115
|
+
layoutDependency: isActiveWalkthrough,
|
|
112
116
|
className: hstack({
|
|
113
117
|
layerStyle: "likec4.panel",
|
|
114
118
|
position: "relative",
|
|
@@ -118,7 +122,7 @@ const NavigationPanelPopoverTarget = ({ actor }) => {
|
|
|
118
122
|
width: "100%"
|
|
119
123
|
}),
|
|
120
124
|
onMouseLeave: () => actor.send({ type: "breadcrumbs.mouseLeave" }),
|
|
121
|
-
children: /* @__PURE__ */ jsx(AnimatePresence, {
|
|
125
|
+
children: /* @__PURE__ */ jsx(AnimatePresence, { children: isActiveWalkthrough ? /* @__PURE__ */ jsx(ActiveWalkthroughControls, {}) : /* @__PURE__ */ jsx(NavigationPanelControls, {}) })
|
|
122
126
|
}
|
|
123
127
|
) }) });
|
|
124
128
|
};
|