@likec4/diagram 1.20.0 → 1.20.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/LikeC4Diagram.css.d.ts +1 -0
- package/dist/LikeC4Diagram.css.js +3 -1
- package/dist/base/BaseXYFlow.js +15 -14
- package/dist/base/Link.css.d.ts +3 -0
- package/dist/base/Link.css.js +9 -0
- package/dist/base/Link.d.ts +5 -0
- package/dist/base/Link.js +58 -0
- package/dist/base/const.d.ts +1 -0
- package/dist/base/const.js +2 -1
- package/dist/base/example/custom.d.ts +1 -1
- package/dist/base/index.d.ts +1 -0
- package/dist/base/primitives/compound/CompoundActionButton.js +2 -1
- package/dist/base/primitives/compound/CompoundDetailsButton.js +2 -1
- package/dist/base/primitives/compound/CompoundNodeContainer.css.d.ts +0 -1
- package/dist/base/primitives/compound/CompoundNodeContainer.css.js +4 -6
- package/dist/base/primitives/compound/CompoundNodeContainer.js +2 -2
- package/dist/base/primitives/customEdge.d.ts +1 -1
- package/dist/base/primitives/customEdge.js +1 -1
- package/dist/base/primitives/customNode.js +1 -1
- package/dist/base/primitives/edge/EdgeLabel.js +3 -1
- package/dist/base/primitives/edge/EdgePath.d.ts +2 -1
- package/dist/base/primitives/edge/EdgePath.js +2 -0
- package/dist/base/primitives/element/ElementActionButtons.js +2 -1
- package/dist/base/primitives/element/ElementDetailsButton.js +2 -1
- package/dist/base/primitives/element/ElementNodeContainer.css.d.ts +0 -1
- package/dist/base/primitives/element/ElementNodeContainer.css.js +1 -3
- package/dist/base/primitives/element/ElementNodeContainer.js +2 -3
- package/dist/base/primitives/element/ElementShape.js +4 -2
- package/dist/base/primitives/element/ElementTitle.js +2 -1
- package/dist/base/updateEdges.js +3 -3
- package/dist/base/updateNodes.js +2 -2
- package/dist/context/FramerMotionConfig.js +1 -1
- package/dist/hooks/useDiagram.d.ts +313 -90
- package/dist/hooks/useDiagramActor.d.ts +2 -2
- package/dist/hooks/useDiagramContext.d.ts +1 -1
- package/dist/hooks/useXYFlow.d.ts +2 -1
- package/dist/hooks/useXYFlow.js +5 -0
- package/dist/likec4diagram/XYFlow.js +12 -10
- package/dist/likec4diagram/custom/edges/RelationshipEdge.d.ts +1 -1
- package/dist/likec4diagram/custom/edges/RelationshipsDropdownMenu.js +2 -2
- package/dist/likec4diagram/custom/edges/utils.js +0 -1
- package/dist/likec4diagram/custom/index.d.ts +1 -1
- package/dist/likec4diagram/custom/nodes/nodeTypes.js +2 -2
- package/dist/likec4diagram/state/actorContext.d.ts +1438 -364
- package/dist/likec4diagram/state/assign.js +2 -2
- package/dist/likec4diagram/state/machine.d.ts +321 -93
- package/dist/likec4diagram/state/syncManualLayoutActor.d.ts +1 -1
- package/dist/likec4diagram/types.d.ts +1 -0
- package/dist/likec4diagram/ui/diagram-title/DiagramTitlePanel.js +4 -3
- package/dist/likec4diagram/useViewToNodesEdges.js +3 -1
- package/dist/overlays/element-details/ElementDetailsCard.css.d.ts +0 -1
- package/dist/overlays/element-details/ElementDetailsCard.css.js +1 -3
- package/dist/overlays/element-details/ElementDetailsCard.js +5 -30
- package/dist/overlays/relationship-details/RelationshipDetails.js +4 -4
- package/dist/overlays/relationship-details/custom/ElementActions.js +1 -3
- package/dist/overlays/relationship-details/custom/edgeTypes.d.ts +1 -1
- package/dist/overlays/relationship-details/hooks.d.ts +2 -2
- package/dist/overlays/relationship-details/hooks.js +7 -7
- package/dist/overlays/relationship-details/useLayoutedDetails.js +7 -10
- package/dist/overlays/relationships-browser/-useRelationshipsView.d.ts +4 -1
- package/dist/overlays/relationships-browser/-useRelationshipsView.js +12 -11
- package/dist/overlays/relationships-browser/RelationshipsBrowser.js +81 -66
- package/dist/overlays/relationships-browser/SelectElement.js +0 -1
- package/dist/overlays/relationships-browser/_types.d.ts +2 -1
- package/dist/overlays/relationships-browser/actor.d.ts +15 -2
- package/dist/overlays/relationships-browser/actor.js +262 -65
- package/dist/overlays/relationships-browser/const.d.ts +1 -0
- package/dist/overlays/relationships-browser/const.js +4 -0
- package/dist/overlays/relationships-browser/custom/ElementActions.js +1 -1
- package/dist/overlays/relationships-browser/custom/edgeTypes.d.ts +3 -2
- package/dist/overlays/relationships-browser/custom/edgeTypes.js +24 -6
- package/dist/overlays/relationships-browser/custom/nodeTypes.js +3 -2
- package/dist/overlays/relationships-browser/hooks.d.ts +6 -3
- package/dist/overlays/relationships-browser/hooks.js +4 -2
- package/dist/overlays/relationships-browser/useViewToNodesEdges.js +7 -2
- package/dist/style.css +1 -1
- package/dist/utils/xyflow.js +9 -1
- package/package.json +8 -8
- package/src/LikeC4Diagram.css.ts +8 -0
- package/src/base/BaseXYFlow.tsx +23 -14
- package/src/base/Link.css.ts +49 -0
- package/src/base/Link.tsx +66 -0
- package/src/base/const.ts +1 -0
- package/src/base/index.ts +2 -0
- package/src/base/primitives/compound/CompoundActionButton.tsx +2 -1
- package/src/base/primitives/compound/CompoundDetailsButton.tsx +2 -1
- package/src/base/primitives/compound/CompoundNodeContainer.css.ts +16 -10
- package/src/base/primitives/compound/CompoundNodeContainer.tsx +1 -1
- package/src/base/primitives/customEdge.ts +2 -0
- package/src/base/primitives/customNode.ts +3 -0
- package/src/base/primitives/edge/EdgeLabel.tsx +3 -1
- package/src/base/primitives/edge/EdgePath.tsx +3 -0
- package/src/base/primitives/element/ElementActionButtons.tsx +2 -1
- package/src/base/primitives/element/ElementDetailsButton.tsx +2 -1
- package/src/base/primitives/element/ElementNodeContainer.css.ts +9 -4
- package/src/base/primitives/element/ElementNodeContainer.tsx +1 -2
- package/src/base/primitives/element/ElementShape.tsx +4 -3
- package/src/base/primitives/element/ElementTitle.tsx +2 -1
- package/src/base/updateEdges.ts +3 -2
- package/src/base/updateNodes.ts +3 -2
- package/src/context/DiagramFeatures.tsx +1 -0
- package/src/context/FramerMotionConfig.tsx +1 -1
- package/src/hooks/useDiagramActor.ts +7 -5
- package/src/hooks/useDiagramContext.ts +4 -1
- package/src/hooks/useXYFlow.ts +6 -1
- package/src/likec4diagram/XYFlow.tsx +20 -9
- package/src/likec4diagram/custom/edges/RelationshipsDropdownMenu.tsx +2 -2
- package/src/likec4diagram/custom/edges/utils.ts +0 -1
- package/src/likec4diagram/custom/nodes/nodeTypes.tsx +2 -2
- package/src/likec4diagram/types.ts +1 -0
- package/src/likec4diagram/ui/diagram-title/DiagramTitlePanel.tsx +4 -3
- package/src/likec4diagram/useViewToNodesEdges.ts +1 -0
- package/src/overlays/element-details/ElementDetailsCard.css.ts +0 -28
- package/src/overlays/element-details/ElementDetailsCard.tsx +2 -50
- package/src/overlays/relationship-details/RelationshipDetails.tsx +4 -4
- package/src/overlays/relationship-details/custom/ElementActions.tsx +1 -2
- package/src/overlays/relationship-details/custom/edgeTypes.tsx +0 -5
- package/src/overlays/relationship-details/hooks.ts +6 -6
- package/src/overlays/relationship-details/useLayoutedDetails.ts +7 -10
- package/src/overlays/relationships-browser/-useRelationshipsView.ts +16 -12
- package/src/overlays/relationships-browser/RelationshipsBrowser.tsx +105 -68
- package/src/overlays/relationships-browser/SelectElement.tsx +0 -1
- package/src/overlays/relationships-browser/_types.ts +2 -1
- package/src/overlays/relationships-browser/actor.ts +321 -62
- package/src/overlays/relationships-browser/const.ts +1 -0
- package/src/overlays/relationships-browser/custom/ElementActions.tsx +1 -1
- package/src/overlays/relationships-browser/custom/edgeTypes.tsx +25 -6
- package/src/overlays/relationships-browser/custom/nodeTypes.tsx +3 -2
- package/src/overlays/relationships-browser/hooks.ts +3 -1
- package/src/overlays/relationships-browser/useViewToNodesEdges.ts +8 -2
- package/dist/likec4diagram/ui/diagram-title/Link.js +0 -36
- package/dist/ui/Link.d.ts +0 -4
- package/src/ui/Link.tsx +0 -40
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import { BBox, DiagramView, Fqn } from '@likec4/core';
|
|
2
|
-
import { EdgeChange, NodeChange, ReactFlowInstance } from '@xyflow/react';
|
|
2
|
+
import { EdgeChange, NodeChange, ReactFlowInstance, useStoreApi } from '@xyflow/react';
|
|
3
3
|
import { ActorLogic, ActorRefFromLogic, MachineSnapshot, SnapshotFrom } from 'xstate';
|
|
4
4
|
import { LayoutRelationshipsViewResult } from './-useRelationshipsView';
|
|
5
5
|
import { RelationshipsBrowserTypes } from './_types';
|
|
6
6
|
type XYFLowInstance = ReactFlowInstance<RelationshipsBrowserTypes.Node, RelationshipsBrowserTypes.Edge>;
|
|
7
|
+
export type XYStoreApi = ReturnType<typeof useStoreApi<RelationshipsBrowserTypes.Node, RelationshipsBrowserTypes.Edge>>;
|
|
7
8
|
export type Input = {
|
|
8
9
|
subject: Fqn;
|
|
9
10
|
scope?: DiagramView | null;
|
|
@@ -14,14 +15,17 @@ export type Context = Readonly<Input & {
|
|
|
14
15
|
closeable: boolean;
|
|
15
16
|
enableNavigationMenu: boolean;
|
|
16
17
|
xyflow: XYFLowInstance | null;
|
|
18
|
+
xystore: XYStoreApi | null;
|
|
17
19
|
initialized: boolean;
|
|
18
20
|
layouted: LayoutRelationshipsViewResult | null;
|
|
21
|
+
navigateFromNode: string | null;
|
|
19
22
|
xynodes: RelationshipsBrowserTypes.Node[];
|
|
20
23
|
xyedges: RelationshipsBrowserTypes.Edge[];
|
|
21
24
|
}>;
|
|
22
25
|
export type Events = {
|
|
23
26
|
type: 'xyflow.init';
|
|
24
27
|
instance: XYFLowInstance;
|
|
28
|
+
store: XYStoreApi;
|
|
25
29
|
} | {
|
|
26
30
|
type: 'xyflow.nodeClick';
|
|
27
31
|
node: RelationshipsBrowserTypes.Node;
|
|
@@ -46,6 +50,8 @@ export type Events = {
|
|
|
46
50
|
} | {
|
|
47
51
|
type: 'xyflow.edgeMouseLeave';
|
|
48
52
|
edge: RelationshipsBrowserTypes.Edge;
|
|
53
|
+
} | {
|
|
54
|
+
type: 'xyflow.updateNodeInternals';
|
|
49
55
|
} | {
|
|
50
56
|
type: 'fitDiagram';
|
|
51
57
|
duration?: number;
|
|
@@ -53,13 +59,20 @@ export type Events = {
|
|
|
53
59
|
} | {
|
|
54
60
|
type: 'navigate.to';
|
|
55
61
|
subject: Fqn;
|
|
62
|
+
fromNode?: string | undefined;
|
|
63
|
+
} | {
|
|
64
|
+
type: 'update.xydata';
|
|
65
|
+
xynodes: RelationshipsBrowserTypes.Node[];
|
|
66
|
+
xyedges: RelationshipsBrowserTypes.Edge[];
|
|
56
67
|
} | {
|
|
57
68
|
type: 'update.view';
|
|
58
69
|
layouted: LayoutRelationshipsViewResult;
|
|
59
70
|
} | {
|
|
60
71
|
type: 'close';
|
|
61
72
|
};
|
|
62
|
-
export declare const relationshipsBrowserActor: ActorLogic<MachineSnapshot<Context, Events, any, "
|
|
73
|
+
export declare const relationshipsBrowserActor: ActorLogic<MachineSnapshot<Context, Events, any, "initializing" | "waiting-data" | "closed" | {
|
|
74
|
+
active: "idle" | "layouting";
|
|
75
|
+
}, "active", any, any, any>, Events, Input, any, any>;
|
|
63
76
|
export type RelationshipsBrowserLogic = typeof relationshipsBrowserActor;
|
|
64
77
|
export type RelationshipsBrowserActorRef = ActorRefFromLogic<typeof relationshipsBrowserActor>;
|
|
65
78
|
export type RelationshipsBrowserSnapshot = SnapshotFrom<RelationshipsBrowserActorRef>;
|
|
@@ -1,85 +1,276 @@
|
|
|
1
|
-
import { invariant } from "@likec4/core";
|
|
1
|
+
import { invariant, nonNullable, delay } from "@likec4/core";
|
|
2
2
|
import { applyNodeChanges, applyEdgeChanges } from "@xyflow/react";
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
3
|
+
import { getViewportForBounds, getNodeDimensions } from "@xyflow/system";
|
|
4
|
+
import { omit, prop, isNullish } from "remeda";
|
|
5
|
+
import { setup, fromPromise, assign, raise, enqueueActions, cancel } from "xstate";
|
|
6
|
+
import { MinZoom, ZIndexes } from "../../base/const.js";
|
|
6
7
|
import { updateEdges } from "../../base/updateEdges.js";
|
|
7
8
|
import { updateNodes } from "../../base/updateNodes.js";
|
|
9
|
+
import { ViewPadding } from "./const.js";
|
|
8
10
|
import { viewToNodesEdge } from "./useViewToNodesEdges.js";
|
|
11
|
+
import { centerXYInternalNode } from "../../utils/xyflow.js";
|
|
12
|
+
import { Base } from "../../base/types.js";
|
|
13
|
+
const findRootSubject = (nodes) => nodes.find(
|
|
14
|
+
(n) => n.data.column === "subjects" && isNullish(n.parentId)
|
|
15
|
+
);
|
|
9
16
|
const relationshipsBrowserActor = setup({
|
|
10
17
|
types: {
|
|
11
18
|
context: {},
|
|
19
|
+
tags: "",
|
|
12
20
|
input: {},
|
|
13
21
|
events: {}
|
|
14
22
|
},
|
|
15
23
|
actions: {
|
|
24
|
+
"xyflow:updateNodeInternals": ({ context }) => {
|
|
25
|
+
invariant(context.xystore, "xystore is not initialized");
|
|
26
|
+
const { domNode, updateNodeInternals } = context.xystore.getState();
|
|
27
|
+
const nodeIds = new Set(context.xyedges.flatMap((e) => [e.source, e.target]));
|
|
28
|
+
if (nodeIds.size === 0 || !domNode) {
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
const updates = /* @__PURE__ */ new Map();
|
|
32
|
+
for (const updateId of nodeIds) {
|
|
33
|
+
const nodeElement = domNode.querySelector(`.react-flow__node[data-id="${updateId}"]`);
|
|
34
|
+
if (nodeElement) {
|
|
35
|
+
updates.set(updateId, { id: updateId, nodeElement, force: true });
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
requestAnimationFrame(() => updateNodeInternals(updates, { triggerFitView: false }));
|
|
39
|
+
},
|
|
16
40
|
"xyflow:fitDiagram": ({ context }, params) => {
|
|
17
|
-
|
|
41
|
+
var _a;
|
|
42
|
+
let {
|
|
18
43
|
duration = 450,
|
|
19
44
|
bounds
|
|
20
45
|
} = params ?? {};
|
|
21
|
-
const { xyflow } = context;
|
|
46
|
+
const { xyflow, xystore } = context;
|
|
22
47
|
invariant(xyflow, "xyflow is not initialized");
|
|
48
|
+
invariant(xystore, "xystore is not initialized");
|
|
49
|
+
bounds ?? (bounds = (_a = context.layouted) == null ? void 0 : _a.bounds);
|
|
50
|
+
const maxZoom = Math.max(xyflow.getZoom(), 1);
|
|
23
51
|
if (bounds) {
|
|
24
|
-
|
|
52
|
+
const { width, height } = xystore.getState();
|
|
53
|
+
const viewport = getViewportForBounds(bounds, width, height, MinZoom, maxZoom, ViewPadding);
|
|
54
|
+
requestAnimationFrame(() => xyflow.setViewport(viewport, duration > 0 ? { duration } : void 0));
|
|
25
55
|
} else {
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
56
|
+
requestAnimationFrame(
|
|
57
|
+
() => xyflow.fitView({
|
|
58
|
+
minZoom: MinZoom,
|
|
59
|
+
maxZoom,
|
|
60
|
+
padding: ViewPadding,
|
|
61
|
+
...duration > 0 && { duration }
|
|
62
|
+
})
|
|
63
|
+
);
|
|
33
64
|
}
|
|
34
65
|
}
|
|
35
66
|
},
|
|
36
67
|
guards: {
|
|
37
|
-
"enable: navigate.to": () => true
|
|
68
|
+
"enable: navigate.to": () => true,
|
|
69
|
+
"closeable": ({ context }) => context.closeable
|
|
70
|
+
},
|
|
71
|
+
actors: {
|
|
72
|
+
layouter: fromPromise(async ({ input, self, signal }) => {
|
|
73
|
+
const {
|
|
74
|
+
subjectId,
|
|
75
|
+
navigateFromNode,
|
|
76
|
+
xyflow,
|
|
77
|
+
xystore,
|
|
78
|
+
update
|
|
79
|
+
} = input;
|
|
80
|
+
let {
|
|
81
|
+
nodes: currentNodes,
|
|
82
|
+
setNodes,
|
|
83
|
+
setEdges,
|
|
84
|
+
width,
|
|
85
|
+
height
|
|
86
|
+
} = xystore.getState();
|
|
87
|
+
const next = viewToNodesEdge(update);
|
|
88
|
+
const updateXYData = () => {
|
|
89
|
+
const { nodes, edges } = xystore.getState();
|
|
90
|
+
return {
|
|
91
|
+
xynodes: updateNodes(nodes, next.xynodes),
|
|
92
|
+
xyedges: updateEdges(edges, next.xyedges)
|
|
93
|
+
};
|
|
94
|
+
};
|
|
95
|
+
const parent = nonNullable(self._parent);
|
|
96
|
+
let zoom = xyflow.getZoom();
|
|
97
|
+
const maxZoom = Math.max(zoom, 1);
|
|
98
|
+
const nextviewport = getViewportForBounds(update.bounds, width, height, MinZoom, maxZoom, ViewPadding);
|
|
99
|
+
const nextSubjectNode = next.xynodes.find(
|
|
100
|
+
(n) => n.type !== "empty" && n.data.column === "subjects" && n.data.fqn === subjectId
|
|
101
|
+
) ?? findRootSubject(next.xynodes);
|
|
102
|
+
const currentSubjectNode = findRootSubject(currentNodes);
|
|
103
|
+
const existingNode = navigateFromNode ? currentNodes.find((n) => n.id === navigateFromNode) : currentNodes.find((n) => n.type !== "empty" && n.data.column !== "subjects" && n.data.fqn === subjectId);
|
|
104
|
+
if (!nextSubjectNode || !existingNode || nextSubjectNode.type === "empty" || !currentSubjectNode || nextSubjectNode.data.fqn === currentSubjectNode.data.fqn) {
|
|
105
|
+
xyflow.setViewport(nextviewport);
|
|
106
|
+
return updateXYData();
|
|
107
|
+
}
|
|
108
|
+
const nextSubjectCenter = {
|
|
109
|
+
x: nextSubjectNode.position.x + (nextSubjectNode.initialWidth ?? 0) / 2,
|
|
110
|
+
y: nextSubjectNode.position.y + (nextSubjectNode.initialHeight ?? 0) / 2
|
|
111
|
+
};
|
|
112
|
+
const currentSubjectInternalNode = xyflow.getInternalNode(currentSubjectNode.id);
|
|
113
|
+
const currentSubjectCenter = centerXYInternalNode(currentSubjectInternalNode);
|
|
114
|
+
const existingInternalNode = xyflow.getInternalNode(existingNode.id);
|
|
115
|
+
const existingDimensions = getNodeDimensions(existingInternalNode);
|
|
116
|
+
const nested = /* @__PURE__ */ new Set();
|
|
117
|
+
currentNodes.forEach((n) => {
|
|
118
|
+
if (n.id === existingNode.id) {
|
|
119
|
+
return;
|
|
120
|
+
}
|
|
121
|
+
if (n.data.column === "subjects") {
|
|
122
|
+
nested.add(n.id);
|
|
123
|
+
return;
|
|
124
|
+
}
|
|
125
|
+
if (n.parentId && (n.parentId === existingNode.id || nested.has(n.parentId))) {
|
|
126
|
+
nested.add(n.id);
|
|
127
|
+
}
|
|
128
|
+
});
|
|
129
|
+
currentNodes = updateNodes(
|
|
130
|
+
currentNodes,
|
|
131
|
+
currentNodes.flatMap((n) => {
|
|
132
|
+
if (nested.has(n.id)) {
|
|
133
|
+
return [];
|
|
134
|
+
}
|
|
135
|
+
if (n.id !== existingNode.id) {
|
|
136
|
+
return {
|
|
137
|
+
...n,
|
|
138
|
+
data: {
|
|
139
|
+
...n.data,
|
|
140
|
+
dimmed: n.data.column === "subjects" ? "immediate" : true
|
|
141
|
+
}
|
|
142
|
+
};
|
|
143
|
+
}
|
|
144
|
+
return {
|
|
145
|
+
...omit(n, ["parentId"]),
|
|
146
|
+
position: {
|
|
147
|
+
x: currentSubjectCenter.x - existingDimensions.width / 2,
|
|
148
|
+
y: currentSubjectCenter.y - existingDimensions.height / 2
|
|
149
|
+
},
|
|
150
|
+
zIndex: ZIndexes.Max,
|
|
151
|
+
hidden: false,
|
|
152
|
+
data: {
|
|
153
|
+
...n.data,
|
|
154
|
+
dimmed: false
|
|
155
|
+
}
|
|
156
|
+
};
|
|
157
|
+
})
|
|
158
|
+
);
|
|
159
|
+
parent.send({
|
|
160
|
+
type: "update.xydata",
|
|
161
|
+
xynodes: currentNodes,
|
|
162
|
+
xyedges: []
|
|
163
|
+
});
|
|
164
|
+
zoom = Math.min(
|
|
165
|
+
zoom,
|
|
166
|
+
nextviewport.zoom
|
|
167
|
+
);
|
|
168
|
+
await delay(180);
|
|
169
|
+
next.xynodes = next.xynodes.map(Base.setDimmed(false));
|
|
170
|
+
if (signal.aborted) {
|
|
171
|
+
return updateXYData();
|
|
172
|
+
}
|
|
173
|
+
await xyflow.setCenter(currentSubjectCenter.x, currentSubjectCenter.y, { zoom, duration: 350 });
|
|
174
|
+
xyflow.setCenter(nextSubjectCenter.x, nextSubjectCenter.y, { zoom });
|
|
175
|
+
return updateXYData();
|
|
176
|
+
})
|
|
38
177
|
}
|
|
39
178
|
}).createMachine({
|
|
40
|
-
initial: "
|
|
179
|
+
initial: "initializing",
|
|
41
180
|
context: ({ input }) => ({
|
|
42
181
|
...input,
|
|
43
182
|
closeable: input.closeable ?? true,
|
|
44
183
|
enableNavigationMenu: input.enableNavigationMenu ?? true,
|
|
45
184
|
initialized: false,
|
|
46
185
|
xyflow: null,
|
|
186
|
+
xystore: null,
|
|
47
187
|
layouted: null,
|
|
188
|
+
navigateFromNode: null,
|
|
48
189
|
xynodes: [],
|
|
49
190
|
xyedges: []
|
|
50
191
|
}),
|
|
51
192
|
states: {
|
|
52
|
-
"
|
|
193
|
+
"initializing": {
|
|
53
194
|
on: {
|
|
54
|
-
"
|
|
55
|
-
actions:
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
195
|
+
"xyflow.init": {
|
|
196
|
+
actions: [
|
|
197
|
+
assign({
|
|
198
|
+
initialized: true,
|
|
199
|
+
xyflow: ({ event }) => event.instance,
|
|
200
|
+
xystore: ({ event }) => event.store
|
|
201
|
+
})
|
|
202
|
+
],
|
|
203
|
+
target: "waiting-data"
|
|
204
|
+
},
|
|
205
|
+
"close": {
|
|
206
|
+
target: "closed"
|
|
62
207
|
}
|
|
63
208
|
}
|
|
64
209
|
},
|
|
65
|
-
"
|
|
210
|
+
"waiting-data": {
|
|
66
211
|
on: {
|
|
67
|
-
"
|
|
68
|
-
actions:
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
212
|
+
"update.view": {
|
|
213
|
+
actions: [
|
|
214
|
+
assign(({ event }) => {
|
|
215
|
+
return {
|
|
216
|
+
layouted: event.layouted,
|
|
217
|
+
...viewToNodesEdge(event.layouted)
|
|
218
|
+
};
|
|
219
|
+
}),
|
|
220
|
+
raise({ type: "fitDiagram", duration: 0 })
|
|
221
|
+
],
|
|
72
222
|
target: "active"
|
|
73
|
-
},
|
|
74
|
-
"close": {
|
|
75
|
-
target: "closed"
|
|
76
223
|
}
|
|
77
224
|
}
|
|
78
225
|
},
|
|
79
226
|
"active": {
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
227
|
+
initial: "idle",
|
|
228
|
+
tags: ["active"],
|
|
229
|
+
states: {
|
|
230
|
+
"idle": {},
|
|
231
|
+
"layouting": {
|
|
232
|
+
invoke: {
|
|
233
|
+
id: "layouter",
|
|
234
|
+
src: "layouter",
|
|
235
|
+
input: ({ context }) => {
|
|
236
|
+
return {
|
|
237
|
+
subjectId: context.subject,
|
|
238
|
+
navigateFromNode: context.navigateFromNode,
|
|
239
|
+
xyflow: nonNullable(context.xyflow),
|
|
240
|
+
xystore: nonNullable(context.xystore),
|
|
241
|
+
update: nonNullable(context.layouted)
|
|
242
|
+
};
|
|
243
|
+
},
|
|
244
|
+
onDone: {
|
|
245
|
+
target: "idle",
|
|
246
|
+
actions: [
|
|
247
|
+
assign({
|
|
248
|
+
xynodes: ({ event }) => event.output.xynodes,
|
|
249
|
+
xyedges: ({ event }) => event.output.xyedges,
|
|
250
|
+
navigateFromNode: null
|
|
251
|
+
}),
|
|
252
|
+
raise({ type: "fitDiagram" }, { id: "fitDiagram", delay: 80 }),
|
|
253
|
+
raise({ type: "xyflow.updateNodeInternals" }, { delay: 100 }),
|
|
254
|
+
raise({ type: "xyflow.updateNodeInternals" }, { delay: 250 }),
|
|
255
|
+
raise({ type: "xyflow.updateNodeInternals" }, { delay: 500 })
|
|
256
|
+
]
|
|
257
|
+
}
|
|
258
|
+
},
|
|
259
|
+
on: {
|
|
260
|
+
"update.xydata": {
|
|
261
|
+
actions: assign({
|
|
262
|
+
xynodes: ({ event }) => event.xynodes,
|
|
263
|
+
xyedges: ({ event }) => event.xyedges
|
|
264
|
+
})
|
|
265
|
+
},
|
|
266
|
+
"xyflow.applyEdgeChages": {
|
|
267
|
+
// actions: log('layouting: ignore xyflow.applyEdgeChages'),
|
|
268
|
+
},
|
|
269
|
+
"xyflow.applyNodeChages": {
|
|
270
|
+
// actions: log('layouting: ignore xyflow.applyNodeChages'),
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
}
|
|
83
274
|
},
|
|
84
275
|
on: {
|
|
85
276
|
"xyflow.nodeClick": {
|
|
@@ -87,8 +278,10 @@ const relationshipsBrowserActor = setup({
|
|
|
87
278
|
actions: enqueueActions(({ event, enqueue }) => {
|
|
88
279
|
if ("fqn" in event.node.data) {
|
|
89
280
|
const fqn = event.node.data.fqn;
|
|
90
|
-
enqueue.
|
|
91
|
-
|
|
281
|
+
enqueue.raise({
|
|
282
|
+
type: "navigate.to",
|
|
283
|
+
subject: fqn,
|
|
284
|
+
fromNode: event.node.id
|
|
92
285
|
});
|
|
93
286
|
}
|
|
94
287
|
})
|
|
@@ -97,7 +290,8 @@ const relationshipsBrowserActor = setup({
|
|
|
97
290
|
guard: "enable: navigate.to",
|
|
98
291
|
actions: [
|
|
99
292
|
assign({
|
|
100
|
-
subject: ({ event }) => event.subject
|
|
293
|
+
subject: ({ event }) => event.subject,
|
|
294
|
+
navigateFromNode: ({ event }) => event.fromNode ?? null
|
|
101
295
|
})
|
|
102
296
|
]
|
|
103
297
|
},
|
|
@@ -105,24 +299,35 @@ const relationshipsBrowserActor = setup({
|
|
|
105
299
|
actions: "xyflow:fitDiagram"
|
|
106
300
|
},
|
|
107
301
|
"update.view": {
|
|
108
|
-
actions:
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
302
|
+
actions: assign({
|
|
303
|
+
layouted: ({ event }) => event.layouted
|
|
304
|
+
}),
|
|
305
|
+
target: ".layouting"
|
|
306
|
+
},
|
|
307
|
+
"xyflow.updateNodeInternals": {
|
|
308
|
+
actions: "xyflow:updateNodeInternals"
|
|
309
|
+
},
|
|
310
|
+
"fitDiagram": {
|
|
311
|
+
actions: {
|
|
312
|
+
type: "xyflow:fitDiagram",
|
|
313
|
+
params: prop("event")
|
|
314
|
+
}
|
|
315
|
+
},
|
|
316
|
+
"xyflow.resized": {
|
|
317
|
+
actions: [
|
|
318
|
+
cancel("fitDiagram"),
|
|
319
|
+
raise({ type: "fitDiagram" }, { id: "fitDiagram", delay: 300 })
|
|
320
|
+
]
|
|
117
321
|
},
|
|
118
322
|
"close": {
|
|
119
|
-
guard:
|
|
323
|
+
guard: "closeable",
|
|
120
324
|
target: "closed"
|
|
121
325
|
}
|
|
122
326
|
},
|
|
123
327
|
exit: assign({
|
|
124
328
|
initialized: false,
|
|
125
|
-
xyflow: null
|
|
329
|
+
xyflow: null,
|
|
330
|
+
xystore: null
|
|
126
331
|
})
|
|
127
332
|
},
|
|
128
333
|
"closed": {
|
|
@@ -130,26 +335,18 @@ const relationshipsBrowserActor = setup({
|
|
|
130
335
|
}
|
|
131
336
|
},
|
|
132
337
|
on: {
|
|
133
|
-
"fitDiagram": {
|
|
134
|
-
actions: {
|
|
135
|
-
type: "xyflow:fitDiagram",
|
|
136
|
-
params: prop("event")
|
|
137
|
-
}
|
|
138
|
-
},
|
|
139
|
-
"xyflow.resized": {
|
|
140
|
-
actions: [
|
|
141
|
-
cancel("fitDiagram"),
|
|
142
|
-
raise({ type: "fitDiagram" }, { id: "fitDiagram", delay: 200 })
|
|
143
|
-
]
|
|
144
|
-
},
|
|
145
338
|
"xyflow.applyNodeChages": {
|
|
146
339
|
actions: assign({
|
|
147
|
-
xynodes: ({ context, event }) =>
|
|
340
|
+
xynodes: ({ context, event }) => {
|
|
341
|
+
return applyNodeChanges(event.changes, context.xynodes);
|
|
342
|
+
}
|
|
148
343
|
})
|
|
149
344
|
},
|
|
150
345
|
"xyflow.applyEdgeChages": {
|
|
151
346
|
actions: assign({
|
|
152
|
-
xyedges: ({ context, event }) =>
|
|
347
|
+
xyedges: ({ context, event }) => {
|
|
348
|
+
return applyEdgeChanges(event.changes, context.xyedges);
|
|
349
|
+
}
|
|
153
350
|
})
|
|
154
351
|
}
|
|
155
352
|
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare const ViewPadding = 0.08;
|
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
import { NamedExoticComponent, CSSProperties, ReactNode } from 'react';
|
|
2
2
|
import { Position } from '@xyflow/system';
|
|
3
|
-
import { Color, ViewId, RelationshipLineType } from '@likec4/core';
|
|
3
|
+
import { NonEmptyArray, RelationId, Color, ViewId, RelationshipLineType } from '@likec4/core';
|
|
4
4
|
export declare const edgeTypes: {
|
|
5
5
|
relationships: NamedExoticComponent<{
|
|
6
6
|
source: string;
|
|
7
7
|
target: string;
|
|
8
8
|
style?: CSSProperties;
|
|
9
9
|
id: string;
|
|
10
|
-
selected?: boolean;
|
|
11
10
|
selectable?: boolean;
|
|
12
11
|
deletable?: boolean;
|
|
12
|
+
selected?: boolean;
|
|
13
13
|
animated?: boolean;
|
|
14
14
|
sourceX: number;
|
|
15
15
|
sourceY: number;
|
|
@@ -34,6 +34,7 @@ export declare const edgeTypes: {
|
|
|
34
34
|
active?: boolean;
|
|
35
35
|
dimmed?: import("../../../base").Base.Dimmed;
|
|
36
36
|
} & {
|
|
37
|
+
relations: NonEmptyArray<RelationId>;
|
|
37
38
|
color: Color | undefined;
|
|
38
39
|
label: string | null;
|
|
39
40
|
navigateTo: ViewId | null;
|
|
@@ -11,18 +11,36 @@ const edgeTypes = {
|
|
|
11
11
|
relationships: customEdge((props) => {
|
|
12
12
|
const { enableNavigateTo } = useEnabledFeature("NavigateTo");
|
|
13
13
|
const {
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
14
|
+
data: {
|
|
15
|
+
navigateTo,
|
|
16
|
+
relations
|
|
17
|
+
}
|
|
17
18
|
} = props;
|
|
18
19
|
const [svgPath, labelX, labelY] = getBezierPath(props);
|
|
19
20
|
const diagram = useDiagram();
|
|
20
|
-
|
|
21
|
-
|
|
21
|
+
const edgeProps = relations.length > 1 ? {
|
|
22
|
+
...props,
|
|
23
|
+
data: {
|
|
24
|
+
...props.data,
|
|
25
|
+
line: "solid",
|
|
26
|
+
color: "amber"
|
|
27
|
+
}
|
|
28
|
+
} : props;
|
|
29
|
+
return /* @__PURE__ */ jsxs(EdgeContainer, { ...edgeProps, children: [
|
|
30
|
+
/* @__PURE__ */ jsx(
|
|
31
|
+
EdgePath,
|
|
32
|
+
{
|
|
33
|
+
...edgeProps,
|
|
34
|
+
svgPath,
|
|
35
|
+
...relations.length > 1 && {
|
|
36
|
+
strokeWidth: 5
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
),
|
|
22
40
|
/* @__PURE__ */ jsx(
|
|
23
41
|
EdgeLabel,
|
|
24
42
|
{
|
|
25
|
-
edgeProps
|
|
43
|
+
edgeProps,
|
|
26
44
|
labelPosition: {
|
|
27
45
|
x: labelX,
|
|
28
46
|
y: labelY,
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { jsxs, jsx, Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { Handle } from "@xyflow/react";
|
|
3
3
|
import { Position } from "@xyflow/system";
|
|
4
|
+
import { m } from "framer-motion";
|
|
4
5
|
import { ElementActions } from "./ElementActions.js";
|
|
5
6
|
import { EmptyNode } from "./EmptyNode.js";
|
|
6
7
|
import { customNode } from "../../../base/primitives/customNode.js";
|
|
@@ -11,7 +12,7 @@ import { CompoundNodeContainer } from "../../../base/primitives/compound/Compoun
|
|
|
11
12
|
import { CompoundTitle } from "../../../base/primitives/compound/CompoundTitle.js";
|
|
12
13
|
const nodeTypes = {
|
|
13
14
|
element: customNode((props) => {
|
|
14
|
-
return /* @__PURE__ */ jsxs(ElementNodeContainer, { nodeProps: props, children: [
|
|
15
|
+
return /* @__PURE__ */ jsxs(ElementNodeContainer, { component: m.div, layoutId: props.id, nodeProps: props, children: [
|
|
15
16
|
/* @__PURE__ */ jsx(ElementShape, { ...props }),
|
|
16
17
|
/* @__PURE__ */ jsx(ElementTitle, { ...props, iconSize: 40 }),
|
|
17
18
|
/* @__PURE__ */ jsx(ElementActions, { ...props }),
|
|
@@ -19,7 +20,7 @@ const nodeTypes = {
|
|
|
19
20
|
] });
|
|
20
21
|
}),
|
|
21
22
|
compound: customNode((props) => {
|
|
22
|
-
return /* @__PURE__ */ jsxs(CompoundNodeContainer, { nodeProps: props, children: [
|
|
23
|
+
return /* @__PURE__ */ jsxs(CompoundNodeContainer, { component: m.div, layoutId: props.id, nodeProps: props, children: [
|
|
23
24
|
/* @__PURE__ */ jsx(CompoundTitle, { ...props }),
|
|
24
25
|
/* @__PURE__ */ jsx(CompoundPorts, { ...props })
|
|
25
26
|
] });
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { Fqn, Color, ViewId, RelationshipLineType } from '@likec4/core';
|
|
2
|
-
import { RelationshipsBrowserActorRef, RelationshipsBrowserSnapshot, Input, Events } from './actor';
|
|
1
|
+
import { Fqn, NonEmptyArray, RelationId, Color, ViewId, RelationshipLineType } from '@likec4/core';
|
|
2
|
+
import { RelationshipsBrowserActorRef, RelationshipsBrowserSnapshot, Input, XYStoreApi, Events } from './actor';
|
|
3
3
|
import { Context, ReactNode, CSSProperties } from 'react';
|
|
4
4
|
import { GeneralHelpers, ViewportHelperFunctions } from '@xyflow/react';
|
|
5
5
|
import { EdgeMarkerType, HandleType } from '@xyflow/system';
|
|
@@ -39,6 +39,7 @@ export declare function useRelationshipsBrowser(): {
|
|
|
39
39
|
focusable?: boolean;
|
|
40
40
|
type: "relationships";
|
|
41
41
|
data: {
|
|
42
|
+
relations: NonEmptyArray<RelationId>;
|
|
42
43
|
color: Color | undefined;
|
|
43
44
|
label: string | null;
|
|
44
45
|
navigateTo: ViewId | null;
|
|
@@ -50,13 +51,15 @@ export declare function useRelationshipsBrowser(): {
|
|
|
50
51
|
}> & Omit< ViewportHelperFunctions, "initialized"> & {
|
|
51
52
|
viewportInitialized: boolean;
|
|
52
53
|
}) | null;
|
|
54
|
+
xystore: XYStoreApi | null;
|
|
53
55
|
initialized: boolean;
|
|
54
56
|
layouted: LayoutRelationshipsViewResult | null;
|
|
57
|
+
navigateFromNode: string | null;
|
|
55
58
|
xynodes: import("./_types").RelationshipsBrowserTypes.Node[];
|
|
56
59
|
xyedges: import("./_types").RelationshipsBrowserTypes.Edge[];
|
|
57
60
|
}>;
|
|
58
61
|
send: (event: Events) => void;
|
|
59
|
-
navigateTo: (subject: Fqn) => void;
|
|
62
|
+
navigateTo: (subject: Fqn, fromNode?: string) => void;
|
|
60
63
|
fitDiagram: () => void;
|
|
61
64
|
close: () => void;
|
|
62
65
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { nonNullable } from "@likec4/core";
|
|
2
2
|
import { useCallbackRef } from "@mantine/hooks";
|
|
3
3
|
import { useSelector } from "@xstate/react";
|
|
4
|
+
import "@xyflow/react";
|
|
4
5
|
import { shallowEqual } from "fast-equals";
|
|
5
6
|
import { createContext, useTransition, useMemo, useContext } from "react";
|
|
6
7
|
const RelationshipsBrowserActorContext = createContext(null);
|
|
@@ -18,11 +19,12 @@ function useRelationshipsBrowser() {
|
|
|
18
19
|
return useMemo(() => ({
|
|
19
20
|
getState: () => actor.getSnapshot().context,
|
|
20
21
|
send: actor.send,
|
|
21
|
-
navigateTo: (subject) => {
|
|
22
|
+
navigateTo: (subject, fromNode) => {
|
|
22
23
|
startTransition(() => {
|
|
23
24
|
actor.send({
|
|
24
25
|
type: "navigate.to",
|
|
25
|
-
subject
|
|
26
|
+
subject,
|
|
27
|
+
fromNode
|
|
26
28
|
});
|
|
27
29
|
});
|
|
28
30
|
},
|
|
@@ -122,18 +122,23 @@ function viewToNodesEdge(view) {
|
|
|
122
122
|
console.error("edge should have at least 2 points", edge);
|
|
123
123
|
continue;
|
|
124
124
|
}
|
|
125
|
+
if (!hasAtLeast(edge.relations, 1)) {
|
|
126
|
+
console.error("edge should have at least 1 relation", edge);
|
|
127
|
+
continue;
|
|
128
|
+
}
|
|
125
129
|
xyedges.push({
|
|
126
130
|
id,
|
|
127
131
|
type: "relationships",
|
|
128
132
|
source: ns + source,
|
|
129
133
|
target: ns + target,
|
|
130
|
-
sourceHandle:
|
|
131
|
-
targetHandle:
|
|
134
|
+
sourceHandle: edge.sourceHandle,
|
|
135
|
+
targetHandle: edge.targetHandle,
|
|
132
136
|
zIndex: ZIndexes.Edge,
|
|
133
137
|
// selectable: selectable,
|
|
134
138
|
// hidden: !visiblePredicate(edge),
|
|
135
139
|
deletable: false,
|
|
136
140
|
data: {
|
|
141
|
+
relations: edge.relations,
|
|
137
142
|
color: edge.color ?? "gray",
|
|
138
143
|
label: edge.label,
|
|
139
144
|
navigateTo: edge.navigateTo ?? null,
|