@likec4/diagram 1.2.2 → 1.4.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/LikeC4Diagram.d.ts +1 -1
- package/dist/LikeC4Diagram.props.d.ts +27 -4
- package/dist/index.mjs +1543 -1346
- package/dist/state/DiagramContext.d.ts +2353 -264
- package/dist/state/diagramStore.d.ts +2360 -268
- package/dist/state/index.d.ts +0 -1
- package/dist/state/useDiagramStore.d.ts +3 -2534
- package/dist/state/useNavigationHistory.d.ts +5 -0
- package/dist/style.css +194 -131
- package/dist/theme.css.d.ts +5 -1
- package/dist/ui/BackwardForwardPanel.css.d.ts +1 -0
- package/dist/ui/BackwardForwardPanel.d.ts +1 -0
- package/dist/ui/DiagramTitlePanel.css.d.ts +1 -1
- package/dist/xyflow/XYFlow.d.ts +2 -1
- package/dist/xyflow/XYFlowEvents.d.ts +4 -4
- package/dist/xyflow/XYFlowInner.d.ts +2 -1
- package/dist/xyflow/const.d.ts +1 -1
- package/dist/xyflow/diagram-to-xyflow.d.ts +1 -1
- package/dist/xyflow/edges/RelationshipEdge.d.ts +4 -5
- package/dist/xyflow/edges/utils.d.ts +4 -2
- package/dist/xyflow/hooks/useXYFlow.d.ts +9 -9
- package/dist/xyflow/nodes/compound/CompoundNode.css.d.ts +3 -1
- package/dist/xyflow/nodes/element/ElementNode.d.ts +1 -1
- package/dist/xyflow/nodes/element/element.css.d.ts +1 -0
- package/dist/xyflow/nodes/element/index.d.ts +1 -1
- package/dist/xyflow/types.d.ts +3 -3
- package/dist/xyflow/utils.d.ts +3 -0
- package/package.json +18 -17
- package/src/LikeC4Diagram.css.ts +15 -5
- package/src/LikeC4Diagram.props.ts +33 -5
- package/src/LikeC4Diagram.tsx +103 -32
- package/src/globals.css.ts +1 -2
- package/src/mantine/theme.ts +1 -0
- package/src/state/DiagramContext.tsx +3 -4
- package/src/state/diagramStore.ts +177 -103
- package/src/state/index.ts +0 -1
- package/src/state/useDiagramStore.ts +6 -13
- package/src/state/useNavigationHistory.ts +39 -0
- package/src/theme.css.ts +5 -1
- package/src/ui/BackwardForwardPanel.css.ts +22 -0
- package/src/ui/BackwardForwardPanel.tsx +59 -0
- package/src/ui/DiagramTitlePanel.css.ts +11 -5
- package/src/ui/DiagramTitlePanel.tsx +108 -96
- package/src/ui/DynamicViewWalkthrough.css.ts +3 -2
- package/src/ui/DynamicViewWalkthrough.tsx +36 -17
- package/src/ui/OptionsPanel.tsx +28 -19
- package/src/ui/options/NodeOptions.tsx +16 -19
- package/src/xyflow/FitviewOnDiagramChange.tsx +15 -23
- package/src/xyflow/SelectEdgesOnNodeFocus.tsx +3 -6
- package/src/xyflow/SyncWithDiagram.tsx +21 -2
- package/src/xyflow/XYFlow.tsx +20 -23
- package/src/xyflow/XYFlowEvents.tsx +26 -8
- package/src/xyflow/XYFlowInner.tsx +10 -6
- package/src/xyflow/const.ts +1 -1
- package/src/xyflow/diagram-to-xyflow.ts +4 -41
- package/src/xyflow/edges/RelationshipEdge.tsx +160 -111
- package/src/xyflow/edges/edges.css.ts +41 -26
- package/src/xyflow/edges/utils.ts +5 -2
- package/src/xyflow/hooks/useLayoutConstraints.ts +19 -4
- package/src/xyflow/nodes/compound/CompoundNode.css.ts +45 -37
- package/src/xyflow/nodes/compound/CompoundNode.tsx +36 -26
- package/src/xyflow/nodes/element/ElementNode.tsx +27 -14
- package/src/xyflow/nodes/element/element.css.ts +31 -18
- package/src/xyflow/nodes/element/index.ts +1 -1
- package/src/xyflow/nodes/shared/NavigateToBtn.tsx +7 -3
- package/src/xyflow/types.ts +5 -2
- package/src/xyflow/utils.ts +48 -0
- package/dist/ui/index.d.ts +0 -2
- package/src/ui/index.ts +0 -3
package/dist/xyflow/XYFlow.d.ts
CHANGED
|
@@ -2,10 +2,11 @@ import { CSSProperties, PropsWithChildren } from 'react';
|
|
|
2
2
|
import { XYFlowEdge, XYFlowNode } from './types';
|
|
3
3
|
|
|
4
4
|
type XYFlowWrapperProps = PropsWithChildren<{
|
|
5
|
+
colorMode?: 'system' | 'light' | 'dark';
|
|
5
6
|
className?: string | undefined;
|
|
6
7
|
defaultNodes: XYFlowNode[];
|
|
7
8
|
defaultEdges: XYFlowEdge[];
|
|
8
9
|
style?: CSSProperties | undefined;
|
|
9
10
|
}>;
|
|
10
|
-
export declare function XYFlow({ className, children, defaultNodes, defaultEdges, style }: XYFlowWrapperProps): import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
export declare function XYFlow({ colorMode, className, children, defaultNodes, defaultEdges, style }: XYFlowWrapperProps): import("react/jsx-runtime").JSX.Element;
|
|
11
12
|
export {};
|
|
@@ -28,7 +28,7 @@ export declare function useXYFlowEvents(): {
|
|
|
28
28
|
labelBgBorderRadius?: number;
|
|
29
29
|
style?: import('react').CSSProperties;
|
|
30
30
|
className?: string;
|
|
31
|
-
|
|
31
|
+
reconnectable?: boolean | import('@xyflow/react').HandleType;
|
|
32
32
|
focusable?: boolean;
|
|
33
33
|
data: import('./types').RelationshipData;
|
|
34
34
|
readonly id: string;
|
|
@@ -59,7 +59,7 @@ export declare function useXYFlowEvents(): {
|
|
|
59
59
|
labelBgBorderRadius?: number;
|
|
60
60
|
style?: import('react').CSSProperties;
|
|
61
61
|
className?: string;
|
|
62
|
-
|
|
62
|
+
reconnectable?: boolean | import('@xyflow/react').HandleType;
|
|
63
63
|
focusable?: boolean;
|
|
64
64
|
data: import('./types').RelationshipData;
|
|
65
65
|
readonly id: string;
|
|
@@ -91,7 +91,7 @@ export declare function useXYFlowEvents(): {
|
|
|
91
91
|
labelBgBorderRadius?: number;
|
|
92
92
|
style?: import('react').CSSProperties;
|
|
93
93
|
className?: string;
|
|
94
|
-
|
|
94
|
+
reconnectable?: boolean | import('@xyflow/react').HandleType;
|
|
95
95
|
focusable?: boolean;
|
|
96
96
|
data: import('./types').RelationshipData;
|
|
97
97
|
readonly id: string;
|
|
@@ -120,7 +120,7 @@ export declare function useXYFlowEvents(): {
|
|
|
120
120
|
labelBgBorderRadius?: number;
|
|
121
121
|
style?: import('react').CSSProperties;
|
|
122
122
|
className?: string;
|
|
123
|
-
|
|
123
|
+
reconnectable?: boolean | import('@xyflow/react').HandleType;
|
|
124
124
|
focusable?: boolean;
|
|
125
125
|
data: import('./types').RelationshipData;
|
|
126
126
|
readonly id: string;
|
|
@@ -5,7 +5,8 @@ type XYFlowInnerProps = PropsWithChildren<{
|
|
|
5
5
|
background: NonNullable<LikeC4DiagramProperties['background']>;
|
|
6
6
|
controls: boolean;
|
|
7
7
|
showDiagramTitle: boolean;
|
|
8
|
+
showNavigationButtons: boolean;
|
|
8
9
|
enableDynamicViewWalkthrough: boolean;
|
|
9
10
|
}>;
|
|
10
|
-
export declare
|
|
11
|
+
export declare const XYFlowInner: import('react').NamedExoticComponent<XYFlowInnerProps>;
|
|
11
12
|
export {};
|
package/dist/xyflow/const.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { DiagramView } from '@likec4/core';
|
|
2
2
|
import { XYFlowData } from '../xyflow/types';
|
|
3
3
|
|
|
4
|
-
export declare function diagramViewToXYFlowData(view: Pick<DiagramView, 'nodes' | 'edges' | '__'>, opts: {
|
|
4
|
+
export declare function diagramViewToXYFlowData(view: Pick<DiagramView, 'id' | 'nodes' | 'edges' | '__' | 'manualLayout'>, opts: {
|
|
5
5
|
draggable: boolean;
|
|
6
6
|
selectable: boolean;
|
|
7
7
|
}): XYFlowData;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { EdgeProps } from '@xyflow/react';
|
|
2
|
-
import { CSSProperties } from 'react';
|
|
3
2
|
|
|
4
3
|
export declare const RelationshipEdge: import('react').NamedExoticComponent<EdgeProps<{
|
|
5
4
|
source: string;
|
|
@@ -17,14 +16,14 @@ export declare const RelationshipEdge: import('react').NamedExoticComponent<Edge
|
|
|
17
16
|
ariaLabel?: string;
|
|
18
17
|
interactionWidth?: number;
|
|
19
18
|
label?: import('react').ReactNode;
|
|
20
|
-
labelStyle?: CSSProperties;
|
|
19
|
+
labelStyle?: import('react').CSSProperties;
|
|
21
20
|
labelShowBg?: boolean;
|
|
22
|
-
labelBgStyle?: CSSProperties;
|
|
21
|
+
labelBgStyle?: import('react').CSSProperties;
|
|
23
22
|
labelBgPadding?: [number, number];
|
|
24
23
|
labelBgBorderRadius?: number;
|
|
25
|
-
style?: CSSProperties;
|
|
24
|
+
style?: import('react').CSSProperties;
|
|
26
25
|
className?: string;
|
|
27
|
-
|
|
26
|
+
reconnectable?: boolean | import('@xyflow/react').HandleType;
|
|
28
27
|
focusable?: boolean;
|
|
29
28
|
data: import('../types').RelationshipData;
|
|
30
29
|
readonly id: string;
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import { Point } from '@likec4/core';
|
|
2
1
|
import { Position, XYPosition } from '@xyflow/react';
|
|
3
2
|
import { InternalXYFlowNode } from '../types';
|
|
4
3
|
|
|
5
|
-
export declare function getNodeIntersectionFromCenterToPoint(intersectionNode: InternalXYFlowNode,
|
|
4
|
+
export declare function getNodeIntersectionFromCenterToPoint(intersectionNode: InternalXYFlowNode, { x: x1, y: y1 }: XYPosition): {
|
|
5
|
+
x: number;
|
|
6
|
+
y: number;
|
|
7
|
+
};
|
|
6
8
|
export declare function getPointPosition(node: InternalXYFlowNode, intersectionPoint: XYPosition): readonly [number, number, Position];
|
|
7
9
|
export declare function getEdgeParams(source: InternalXYFlowNode, target: InternalXYFlowNode): {
|
|
8
10
|
sx: number;
|
|
@@ -23,7 +23,7 @@ export declare const useXYFlow: () => import('@xyflow/react').ReactFlowInstance<
|
|
|
23
23
|
labelBgBorderRadius?: number;
|
|
24
24
|
style?: import('react').CSSProperties;
|
|
25
25
|
className?: string;
|
|
26
|
-
|
|
26
|
+
reconnectable?: boolean | import('@xyflow/react').HandleType;
|
|
27
27
|
focusable?: boolean;
|
|
28
28
|
data: import('../types').RelationshipData;
|
|
29
29
|
readonly id: string;
|
|
@@ -58,7 +58,7 @@ export declare const useXYStoreApi: () => {
|
|
|
58
58
|
labelBgBorderRadius?: number;
|
|
59
59
|
style?: import('react').CSSProperties;
|
|
60
60
|
className?: string;
|
|
61
|
-
|
|
61
|
+
reconnectable?: boolean | import('@xyflow/react').HandleType;
|
|
62
62
|
focusable?: boolean;
|
|
63
63
|
data: import('../types').RelationshipData;
|
|
64
64
|
readonly id: string;
|
|
@@ -87,7 +87,7 @@ export declare const useXYStoreApi: () => {
|
|
|
87
87
|
labelBgBorderRadius?: number;
|
|
88
88
|
style?: import('react').CSSProperties;
|
|
89
89
|
className?: string;
|
|
90
|
-
|
|
90
|
+
reconnectable?: boolean | import('@xyflow/react').HandleType;
|
|
91
91
|
focusable?: boolean;
|
|
92
92
|
data: import('../types').RelationshipData;
|
|
93
93
|
readonly id: string;
|
|
@@ -115,7 +115,7 @@ export declare const useXYStoreApi: () => {
|
|
|
115
115
|
labelBgBorderRadius?: number;
|
|
116
116
|
style?: import('react').CSSProperties;
|
|
117
117
|
className?: string;
|
|
118
|
-
|
|
118
|
+
reconnectable?: boolean | import('@xyflow/react').HandleType;
|
|
119
119
|
focusable?: boolean;
|
|
120
120
|
data: import('../types').RelationshipData;
|
|
121
121
|
readonly id: string;
|
|
@@ -143,7 +143,7 @@ export declare const useXYStoreApi: () => {
|
|
|
143
143
|
labelBgBorderRadius?: number;
|
|
144
144
|
style?: import('react').CSSProperties;
|
|
145
145
|
className?: string;
|
|
146
|
-
|
|
146
|
+
reconnectable?: boolean | import('@xyflow/react').HandleType;
|
|
147
147
|
focusable?: boolean;
|
|
148
148
|
data: import('../types').RelationshipData;
|
|
149
149
|
readonly id: string;
|
|
@@ -171,7 +171,7 @@ export declare const useXYStoreApi: () => {
|
|
|
171
171
|
labelBgBorderRadius?: number;
|
|
172
172
|
style?: import('react').CSSProperties;
|
|
173
173
|
className?: string;
|
|
174
|
-
|
|
174
|
+
reconnectable?: boolean | import('@xyflow/react').HandleType;
|
|
175
175
|
focusable?: boolean;
|
|
176
176
|
data: import('../types').RelationshipData;
|
|
177
177
|
readonly id: string;
|
|
@@ -199,7 +199,7 @@ export declare const useXYStoreApi: () => {
|
|
|
199
199
|
labelBgBorderRadius?: number;
|
|
200
200
|
style?: import('react').CSSProperties;
|
|
201
201
|
className?: string;
|
|
202
|
-
|
|
202
|
+
reconnectable?: boolean | import('@xyflow/react').HandleType;
|
|
203
203
|
focusable?: boolean;
|
|
204
204
|
data: import('../types').RelationshipData;
|
|
205
205
|
readonly id: string;
|
|
@@ -228,7 +228,7 @@ export declare const useXYStoreApi: () => {
|
|
|
228
228
|
labelBgBorderRadius?: number;
|
|
229
229
|
style?: import('react').CSSProperties;
|
|
230
230
|
className?: string;
|
|
231
|
-
|
|
231
|
+
reconnectable?: boolean | import('@xyflow/react').HandleType;
|
|
232
232
|
focusable?: boolean;
|
|
233
233
|
data: import('../types').RelationshipData;
|
|
234
234
|
readonly id: string;
|
|
@@ -256,7 +256,7 @@ export declare const useXYStoreApi: () => {
|
|
|
256
256
|
labelBgBorderRadius?: number;
|
|
257
257
|
style?: import('react').CSSProperties;
|
|
258
258
|
className?: string;
|
|
259
|
-
|
|
259
|
+
reconnectable?: boolean | import('@xyflow/react').HandleType;
|
|
260
260
|
focusable?: boolean;
|
|
261
261
|
data: import('../types').RelationshipData;
|
|
262
262
|
readonly id: string;
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
export declare const container: string;
|
|
2
2
|
export declare const dimmed: string;
|
|
3
|
-
export declare const
|
|
3
|
+
export declare const varOpacity: `var(--${string})` | `var(--${string}, ${string})` | `var(--${string}, ${number})`;
|
|
4
|
+
export declare const varBorderTransparency: `var(--${string})` | `var(--${string}, ${string})` | `var(--${string}, ${number})`;
|
|
4
5
|
export declare const compoundBody: string;
|
|
5
6
|
export declare const transparent: string;
|
|
6
7
|
export declare const title: string;
|
|
8
|
+
export declare const titleWithNavigation: string;
|
|
7
9
|
export declare const indicator: string;
|
|
8
10
|
export declare const navigateBtn: string;
|
|
@@ -2,5 +2,5 @@ import { NodeProps } from '@xyflow/react';
|
|
|
2
2
|
import { ElementXYFlowNode } from '../../types';
|
|
3
3
|
|
|
4
4
|
type ElementNodeProps = NodeProps<ElementXYFlowNode>;
|
|
5
|
-
export declare
|
|
5
|
+
export declare const ElementNodeMemo: import('react').NamedExoticComponent<ElementNodeProps>;
|
|
6
6
|
export {};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
export declare const stokeFillMix: `var(--${string})` | `var(--${string}, ${string})` | `var(--${string}, ${number})`;
|
|
2
2
|
export declare const container: string;
|
|
3
|
+
export declare const containerAnimated: string;
|
|
3
4
|
export declare const dimmed: string;
|
|
4
5
|
export declare const indicator: string;
|
|
5
6
|
export declare const fillElementFill: string;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
export { ElementNode } from './ElementNode';
|
|
1
|
+
export { ElementNodeMemo as ElementNode } from './ElementNode';
|
package/dist/xyflow/types.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { BBox, DiagramEdge, DiagramNode, Fqn, Point } from '@likec4/core';
|
|
1
|
+
import { BBox, DiagramEdge, DiagramNode, Fqn, Point, XYPosition } from '@likec4/core';
|
|
2
2
|
import { Edge, EdgeMouseHandler, InternalNode, Node, NodeMouseHandler, OnMoveEnd, OnMoveStart, ReactFlowInstance, ReactFlowState } from '@xyflow/react';
|
|
3
3
|
import { MouseEvent as ReactMouseEvent } from 'react';
|
|
4
4
|
import { SetReadonly, SetRequired } from 'type-fest';
|
|
@@ -25,7 +25,7 @@ export declare namespace XYFlowNode {
|
|
|
25
25
|
}
|
|
26
26
|
export type RelationshipData = {
|
|
27
27
|
edge: DiagramEdge;
|
|
28
|
-
controlPoints:
|
|
28
|
+
controlPoints: XYPosition[] | null;
|
|
29
29
|
headPoint: Point | null;
|
|
30
30
|
tailPoint: Point | null;
|
|
31
31
|
type: 'bezier' | 'poly';
|
|
@@ -62,7 +62,7 @@ export declare namespace XYFlowEdge {
|
|
|
62
62
|
labelBgBorderRadius?: number;
|
|
63
63
|
style?: import("react").CSSProperties;
|
|
64
64
|
className?: string;
|
|
65
|
-
|
|
65
|
+
reconnectable?: boolean | import("@xyflow/react").HandleType;
|
|
66
66
|
focusable?: boolean;
|
|
67
67
|
data: RelationshipData;
|
|
68
68
|
readonly id: string;
|
package/dist/xyflow/utils.d.ts
CHANGED
|
@@ -1,4 +1,7 @@
|
|
|
1
|
+
import { DiagramEdge, Point } from '@likec4/core/types';
|
|
1
2
|
import { XYPosition } from '@xyflow/react';
|
|
2
3
|
|
|
3
4
|
export declare function toDomPrecision(v: number | null): number;
|
|
4
5
|
export declare function distance(a: XYPosition, b: XYPosition): number;
|
|
6
|
+
export declare function bezierControlPoints(diagramEdge: DiagramEdge): XYPosition[];
|
|
7
|
+
export declare function isSamePoint(a: XYPosition | Point, b: XYPosition | Point): boolean;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@likec4/diagram",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.4.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"bugs": "https://github.com/likec4/likec4/issues",
|
|
6
6
|
"homepage": "https://likec4.dev",
|
|
@@ -48,38 +48,40 @@
|
|
|
48
48
|
"clean": "run -T rimraf -v -g 'dist/*' .tsbuildinfo"
|
|
49
49
|
},
|
|
50
50
|
"dependencies": {
|
|
51
|
-
"@likec4/core": "1.
|
|
51
|
+
"@likec4/core": "1.4.0",
|
|
52
52
|
"@react-hookz/web": "^24.0.4",
|
|
53
|
-
"@tabler/icons-react": "^3.
|
|
53
|
+
"@tabler/icons-react": "^3.7.0",
|
|
54
|
+
"@vanilla-extract/css": "^1.15.3",
|
|
55
|
+
"@vanilla-extract/css-utils": "^0.1.4",
|
|
56
|
+
"@vanilla-extract/dynamic": "^2.1.1",
|
|
54
57
|
"d3-shape": "^3.2.0",
|
|
55
58
|
"esm-env": "^1.0.0",
|
|
56
59
|
"fast-equals": "^5.0.1",
|
|
57
|
-
"framer-motion": "^11.2.
|
|
60
|
+
"framer-motion": "^11.2.12",
|
|
58
61
|
"remeda": "^1.61.0",
|
|
59
|
-
"zustand": "^4.5.
|
|
62
|
+
"zustand": "^4.5.4"
|
|
60
63
|
},
|
|
61
64
|
"peerDependencies": {
|
|
62
|
-
"@mantine/core": "
|
|
63
|
-
"@mantine/hooks": "
|
|
65
|
+
"@mantine/core": "7.10.2",
|
|
66
|
+
"@mantine/hooks": "7.10.2",
|
|
64
67
|
"react": "^18.3.1",
|
|
65
68
|
"react-dom": "^18.3.1"
|
|
66
69
|
},
|
|
67
70
|
"devDependencies": {
|
|
68
|
-
"@likec4/tsconfig": "1.
|
|
71
|
+
"@likec4/tsconfig": "1.4.0",
|
|
69
72
|
"@lume/kiwi": "^0.4.3",
|
|
70
|
-
"@mantine/core": "
|
|
71
|
-
"@mantine/hooks": "
|
|
72
|
-
"@mantine/vanilla-extract": "
|
|
73
|
+
"@mantine/core": "7.10.2",
|
|
74
|
+
"@mantine/hooks": "7.10.2",
|
|
75
|
+
"@mantine/vanilla-extract": "7.10.2",
|
|
73
76
|
"@total-typescript/ts-reset": "^0.5.1",
|
|
74
77
|
"@types/bezier-js": "^4.1.3",
|
|
75
78
|
"@types/d3-shape": "^3",
|
|
76
79
|
"@types/react": "^18.3.3",
|
|
77
80
|
"@types/react-dom": "^18.3.0",
|
|
78
|
-
"@vanilla-extract/
|
|
79
|
-
"@vanilla-extract/dynamic": "^2.1.1",
|
|
80
|
-
"@vanilla-extract/esbuild-plugin": "^2.3.6",
|
|
81
|
+
"@vanilla-extract/esbuild-plugin": "^2.3.8",
|
|
81
82
|
"@vitejs/plugin-react": "^4.3.1",
|
|
82
|
-
"@xyflow/react": "
|
|
83
|
+
"@xyflow/react": "12.0.0-next.24",
|
|
84
|
+
"@xyflow/system": "0.0.30",
|
|
83
85
|
"bezier-js": "^6.1.4",
|
|
84
86
|
"clsx": "^2.1.1",
|
|
85
87
|
"execa": "^9.1.0",
|
|
@@ -89,8 +91,7 @@
|
|
|
89
91
|
"tilg": "^0.1.1",
|
|
90
92
|
"type-fest": "^4.18.2",
|
|
91
93
|
"typescript": "^5.4.5",
|
|
92
|
-
"
|
|
93
|
-
"vite": "5.3.0",
|
|
94
|
+
"vite": "5.3.2",
|
|
94
95
|
"vite-plugin-dts": "^3.9.1"
|
|
95
96
|
}
|
|
96
97
|
}
|
package/src/LikeC4Diagram.css.ts
CHANGED
|
@@ -9,7 +9,17 @@ export const keepAspectRatioContainer = style({
|
|
|
9
9
|
padding: 0
|
|
10
10
|
})
|
|
11
11
|
|
|
12
|
-
export const cssReactFlow = style({
|
|
12
|
+
export const cssReactFlow = style({
|
|
13
|
+
'@supports': {
|
|
14
|
+
// https://wojtek.im/journal/targeting-safari-with-css-media-query
|
|
15
|
+
'(hanging-punctuation: first) and (font: -apple-system-body) and (-webkit-appearance: none)': {
|
|
16
|
+
// TODO: this workaround disables animations in Safari (to improve performance)
|
|
17
|
+
vars: {
|
|
18
|
+
[vars.safariAnimationHook]: ''
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
})
|
|
13
23
|
|
|
14
24
|
globalStyle(`.react-flow${cssReactFlow}`, {
|
|
15
25
|
vars: {
|
|
@@ -17,10 +27,10 @@ globalStyle(`.react-flow${cssReactFlow}`, {
|
|
|
17
27
|
[xyvars.background.pattern.color]: vars.likec4.background.pattern.color
|
|
18
28
|
}
|
|
19
29
|
})
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
})
|
|
30
|
+
|
|
31
|
+
// globalStyle(`.react-flow${cssReactFlow} .react-flow__node`, {
|
|
32
|
+
// willChange: 'transform'
|
|
33
|
+
// })
|
|
24
34
|
|
|
25
35
|
export const cssDisablePan = style({})
|
|
26
36
|
|
|
@@ -3,12 +3,14 @@ import type {
|
|
|
3
3
|
DiagramEdge,
|
|
4
4
|
DiagramNode,
|
|
5
5
|
DiagramView,
|
|
6
|
+
EdgeId,
|
|
6
7
|
ElementShape,
|
|
7
8
|
Fqn,
|
|
8
9
|
NonEmptyArray,
|
|
9
10
|
ThemeColor,
|
|
10
11
|
ViewID
|
|
11
12
|
} from '@likec4/core'
|
|
13
|
+
import type { XYPosition } from '@xyflow/system'
|
|
12
14
|
import type { MouseEvent as ReactMouseEvent } from 'react'
|
|
13
15
|
import type { SetRequired, Simplify } from 'type-fest'
|
|
14
16
|
import type { XYFlowEdge, XYFlowNode } from './xyflow/types'
|
|
@@ -19,9 +21,10 @@ export type DiagramNodeWithNavigate = Simplify<SetRequired<DiagramNode, 'navigat
|
|
|
19
21
|
export type OnNavigateTo = {
|
|
20
22
|
(
|
|
21
23
|
to: ViewID,
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
24
|
+
// These fields present if navigateTo triggered by a node click
|
|
25
|
+
event?: ReactMouseEvent,
|
|
26
|
+
element?: DiagramNodeWithNavigate,
|
|
27
|
+
xynode?: XYFlowNode
|
|
25
28
|
): void
|
|
26
29
|
}
|
|
27
30
|
export type OnNodeClick = (
|
|
@@ -55,12 +58,25 @@ export namespace Changes {
|
|
|
55
58
|
}
|
|
56
59
|
targets: NonEmptyArray<Fqn>
|
|
57
60
|
}
|
|
61
|
+
|
|
62
|
+
export interface SaveManualLayout {
|
|
63
|
+
op: 'save-manual-layout'
|
|
64
|
+
nodes: Record<Fqn, {
|
|
65
|
+
x: number
|
|
66
|
+
y: number
|
|
67
|
+
width: number
|
|
68
|
+
height: number
|
|
69
|
+
}>
|
|
70
|
+
edges: Record<EdgeId, {
|
|
71
|
+
controlPoints: XYPosition[]
|
|
72
|
+
}>
|
|
73
|
+
}
|
|
58
74
|
}
|
|
59
75
|
|
|
60
|
-
export type Change = Changes.ChangeElementStyle
|
|
76
|
+
export type Change = Changes.ChangeElementStyle | Changes.SaveManualLayout
|
|
61
77
|
|
|
62
78
|
export type ChangeEvent = {
|
|
63
|
-
|
|
79
|
+
change: Change
|
|
64
80
|
}
|
|
65
81
|
export type OnChange = {
|
|
66
82
|
(event: ChangeEvent): void
|
|
@@ -144,11 +160,23 @@ export interface LikeC4DiagramProperties {
|
|
|
144
160
|
*/
|
|
145
161
|
showDiagramTitle?: boolean | undefined
|
|
146
162
|
|
|
163
|
+
/**
|
|
164
|
+
* Show back/forward navigation buttons
|
|
165
|
+
* @default false
|
|
166
|
+
*/
|
|
167
|
+
showNavigationButtons?: undefined | boolean
|
|
168
|
+
|
|
147
169
|
/**
|
|
148
170
|
* If Walkthrough for dynamic views should be enabled
|
|
149
171
|
* @default false
|
|
150
172
|
*/
|
|
151
173
|
enableDynamicViewWalkthrough?: boolean | undefined
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Experimental feature to enable edge editing
|
|
177
|
+
* @default false
|
|
178
|
+
*/
|
|
179
|
+
experimentalEdgeEditing?: boolean | undefined
|
|
152
180
|
}
|
|
153
181
|
|
|
154
182
|
export interface LikeC4DiagramEventHandlers {
|
package/src/LikeC4Diagram.tsx
CHANGED
|
@@ -1,19 +1,23 @@
|
|
|
1
|
-
import '@xyflow/react/dist/style.css'
|
|
2
1
|
import { ReactFlowProvider as XYFlowProvider } from '@xyflow/react'
|
|
2
|
+
import '@xyflow/react/dist/style.css'
|
|
3
3
|
import clsx from 'clsx'
|
|
4
|
-
import {
|
|
4
|
+
import { DEV } from 'esm-env'
|
|
5
|
+
import { shallowEqual } from 'fast-equals'
|
|
6
|
+
import { domAnimation, LazyMotion } from 'framer-motion'
|
|
7
|
+
import { memo, useEffect, useRef, useState } from 'react'
|
|
8
|
+
import useTilg from 'tilg'
|
|
5
9
|
import { rootClassName } from './globals.css'
|
|
6
10
|
import { KeepAspectRatioContainer } from './KeepAspectRatioContainer'
|
|
7
11
|
import { cssDisablePan, cssNoControls, cssReactFlow, cssTransparentBg } from './LikeC4Diagram.css'
|
|
8
12
|
import { type LikeC4DiagramEventHandlers, type LikeC4DiagramProperties } from './LikeC4Diagram.props'
|
|
9
13
|
import { EnsureMantine } from './mantine/EnsureMantine'
|
|
10
14
|
import { DiagramContextProvider } from './state/DiagramContext'
|
|
11
|
-
import {
|
|
15
|
+
import { useDiagramStoreApi } from './state/useDiagramStore'
|
|
12
16
|
import { diagramViewToXYFlowData } from './xyflow/diagram-to-xyflow'
|
|
13
17
|
import { FitViewOnDiagramChange } from './xyflow/FitviewOnDiagramChange'
|
|
14
18
|
import { SelectEdgesOnNodeFocus } from './xyflow/SelectEdgesOnNodeFocus'
|
|
15
19
|
import { SyncWithDiagram } from './xyflow/SyncWithDiagram'
|
|
16
|
-
import type { XYFlowData } from './xyflow/types'
|
|
20
|
+
import type { XYFlowData, XYFlowEdge, XYFlowNode } from './xyflow/types'
|
|
17
21
|
import { XYFlow } from './xyflow/XYFlow'
|
|
18
22
|
import { XYFlowInner } from './xyflow/XYFlowInner'
|
|
19
23
|
|
|
@@ -29,13 +33,15 @@ export function LikeC4Diagram({
|
|
|
29
33
|
nodesSelectable = !readonly,
|
|
30
34
|
nodesDraggable = !readonly,
|
|
31
35
|
background = 'dots',
|
|
32
|
-
controls =
|
|
36
|
+
controls = false,
|
|
33
37
|
showElementLinks = true,
|
|
34
38
|
showDiagramTitle = true,
|
|
39
|
+
showNavigationButtons = false,
|
|
35
40
|
enableDynamicViewWalkthrough = true,
|
|
36
41
|
initialWidth,
|
|
37
42
|
initialHeight,
|
|
38
43
|
keepAspectRatio = false,
|
|
44
|
+
experimentalEdgeEditing = false,
|
|
39
45
|
onCanvasClick,
|
|
40
46
|
onCanvasContextMenu,
|
|
41
47
|
onCanvasDblClick,
|
|
@@ -46,7 +52,7 @@ export function LikeC4Diagram({
|
|
|
46
52
|
onNodeClick,
|
|
47
53
|
onNodeContextMenu
|
|
48
54
|
}: LikeC4DiagramProps) {
|
|
49
|
-
|
|
55
|
+
DEV && useTilg()
|
|
50
56
|
const initialRef = useRef<{
|
|
51
57
|
defaultNodes: XYFlowData['nodes']
|
|
52
58
|
defaultEdges: XYFlowData['edges']
|
|
@@ -81,6 +87,7 @@ export function LikeC4Diagram({
|
|
|
81
87
|
showElementLinks={showElementLinks}
|
|
82
88
|
nodesDraggable={nodesDraggable}
|
|
83
89
|
nodesSelectable={nodesSelectable}
|
|
90
|
+
experimentalEdgeEditing={experimentalEdgeEditing}
|
|
84
91
|
onCanvasClick={onCanvasClick}
|
|
85
92
|
onCanvasContextMenu={onCanvasContextMenu}
|
|
86
93
|
onEdgeClick={onEdgeClick}
|
|
@@ -91,38 +98,102 @@ export function LikeC4Diagram({
|
|
|
91
98
|
onNavigateTo={onNavigateTo}
|
|
92
99
|
onCanvasDblClick={onCanvasDblClick}
|
|
93
100
|
>
|
|
94
|
-
<
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
<XYFlow
|
|
101
|
-
className={clsx(
|
|
102
|
-
'likec4-diagram',
|
|
103
|
-
cssReactFlow,
|
|
104
|
-
controls === false && cssNoControls,
|
|
105
|
-
pannable !== true && cssDisablePan,
|
|
106
|
-
background === 'transparent' && cssTransparentBg
|
|
107
|
-
)}
|
|
108
|
-
defaultNodes={initialRef.current.defaultNodes}
|
|
109
|
-
defaultEdges={initialRef.current.defaultEdges}
|
|
101
|
+
<LazyMotion features={domAnimation} strict>
|
|
102
|
+
<KeepAspectRatioContainer
|
|
103
|
+
className={clsx(rootClassName, className)}
|
|
104
|
+
enabled={keepAspectRatio}
|
|
105
|
+
width={view.width}
|
|
106
|
+
height={view.height}
|
|
110
107
|
>
|
|
111
|
-
<
|
|
112
|
-
|
|
113
|
-
|
|
108
|
+
<LikeC4DiagramInnerMemo
|
|
109
|
+
defaultNodes={initialRef.current.defaultNodes}
|
|
110
|
+
defaultEdges={initialRef.current.defaultEdges}
|
|
111
|
+
fitView={fitView}
|
|
112
|
+
zoomable={zoomable}
|
|
114
113
|
background={background}
|
|
115
114
|
controls={controls}
|
|
115
|
+
pannable={pannable}
|
|
116
|
+
showDiagramTitle={showDiagramTitle}
|
|
117
|
+
showNavigationButtons={showNavigationButtons}
|
|
118
|
+
enableDynamicViewWalkthrough={enableDynamicViewWalkthrough}
|
|
116
119
|
/>
|
|
117
|
-
</
|
|
118
|
-
|
|
119
|
-
<SyncWithDiagram />
|
|
120
|
-
{fitView && <FitViewOnDiagramChange />}
|
|
121
|
-
{fitView && zoomable && <SelectEdgesOnNodeFocus />}
|
|
122
|
-
</WhenInitialized>
|
|
123
|
-
</KeepAspectRatioContainer>
|
|
120
|
+
</KeepAspectRatioContainer>
|
|
121
|
+
</LazyMotion>
|
|
124
122
|
</DiagramContextProvider>
|
|
125
123
|
</XYFlowProvider>
|
|
126
124
|
</EnsureMantine>
|
|
127
125
|
)
|
|
128
126
|
}
|
|
127
|
+
|
|
128
|
+
type LikeC4DiagramInnerProps = {
|
|
129
|
+
background: NonNullable<LikeC4DiagramProperties['background']>
|
|
130
|
+
fitView: boolean
|
|
131
|
+
zoomable: boolean
|
|
132
|
+
pannable: boolean
|
|
133
|
+
controls: boolean
|
|
134
|
+
defaultNodes: XYFlowNode[]
|
|
135
|
+
defaultEdges: XYFlowEdge[]
|
|
136
|
+
showDiagramTitle: boolean
|
|
137
|
+
showNavigationButtons: boolean
|
|
138
|
+
enableDynamicViewWalkthrough: boolean
|
|
139
|
+
}
|
|
140
|
+
const LikeC4DiagramInnerMemo = memo<LikeC4DiagramInnerProps>(function LikeC4DiagramInner({
|
|
141
|
+
background,
|
|
142
|
+
fitView,
|
|
143
|
+
zoomable,
|
|
144
|
+
controls,
|
|
145
|
+
pannable,
|
|
146
|
+
defaultNodes,
|
|
147
|
+
defaultEdges,
|
|
148
|
+
showDiagramTitle,
|
|
149
|
+
showNavigationButtons,
|
|
150
|
+
enableDynamicViewWalkthrough
|
|
151
|
+
}) {
|
|
152
|
+
DEV && useTilg()
|
|
153
|
+
const diagramApi = useDiagramStoreApi()
|
|
154
|
+
const [isInitialized, setIsInitialized] = useState(diagramApi.getState().initialized)
|
|
155
|
+
|
|
156
|
+
useEffect(() => {
|
|
157
|
+
if (isInitialized) {
|
|
158
|
+
return
|
|
159
|
+
}
|
|
160
|
+
return diagramApi.subscribe(
|
|
161
|
+
s => s.initialized,
|
|
162
|
+
setIsInitialized,
|
|
163
|
+
{
|
|
164
|
+
fireImmediately: true
|
|
165
|
+
}
|
|
166
|
+
)
|
|
167
|
+
}, [isInitialized])
|
|
168
|
+
|
|
169
|
+
return (
|
|
170
|
+
<>
|
|
171
|
+
<XYFlow
|
|
172
|
+
defaultNodes={defaultNodes}
|
|
173
|
+
defaultEdges={defaultEdges}
|
|
174
|
+
className={clsx(
|
|
175
|
+
'likec4-diagram',
|
|
176
|
+
cssReactFlow,
|
|
177
|
+
controls === false && cssNoControls,
|
|
178
|
+
pannable !== true && cssDisablePan,
|
|
179
|
+
background === 'transparent' && cssTransparentBg
|
|
180
|
+
)}
|
|
181
|
+
>
|
|
182
|
+
<XYFlowInner
|
|
183
|
+
showNavigationButtons={showNavigationButtons}
|
|
184
|
+
showDiagramTitle={showDiagramTitle}
|
|
185
|
+
enableDynamicViewWalkthrough={enableDynamicViewWalkthrough}
|
|
186
|
+
background={background}
|
|
187
|
+
controls={controls}
|
|
188
|
+
/>
|
|
189
|
+
</XYFlow>
|
|
190
|
+
{isInitialized && (
|
|
191
|
+
<>
|
|
192
|
+
<SyncWithDiagram />
|
|
193
|
+
{fitView && <FitViewOnDiagramChange />}
|
|
194
|
+
{fitView && zoomable && <SelectEdgesOnNodeFocus />}
|
|
195
|
+
</>
|
|
196
|
+
)}
|
|
197
|
+
</>
|
|
198
|
+
)
|
|
199
|
+
}, shallowEqual)
|
package/src/globals.css.ts
CHANGED
|
@@ -13,7 +13,7 @@ globalStyle(`.${rootClassName}`, {
|
|
|
13
13
|
})
|
|
14
14
|
|
|
15
15
|
createGlobalTheme(`.${rootClassName}`, {
|
|
16
|
-
...omit(vars, ['optionsPanel', 'default'])
|
|
16
|
+
...omit(vars, ['optionsPanel', 'navigationPanel', 'safariAnimationHook', 'default'])
|
|
17
17
|
}, {
|
|
18
18
|
likec4: {
|
|
19
19
|
font:
|
|
@@ -25,7 +25,6 @@ createGlobalTheme(`.${rootClassName}`, {
|
|
|
25
25
|
}
|
|
26
26
|
}
|
|
27
27
|
},
|
|
28
|
-
filterDimmed: 'brightness(.6) grayscale(.8) opacity(.5) blur(1px)',
|
|
29
28
|
compound: {
|
|
30
29
|
font: vars.likec4.font,
|
|
31
30
|
titleColor: vars.element.loContrast
|