@likec4/diagram 1.0.2 → 1.1.1

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.
Files changed (50) hide show
  1. package/dist/KeepAspectRatioContainer.d.ts +9 -0
  2. package/dist/LikeC4Diagram.css.d.ts +1 -0
  3. package/dist/LikeC4Diagram.d.ts +1 -1
  4. package/dist/LikeC4Diagram.props.d.ts +16 -11
  5. package/dist/index.mjs +639 -762
  6. package/dist/state/DiagramContext.d.ts +54 -18
  7. package/dist/state/diagramStore.d.ts +61 -21
  8. package/dist/state/useDiagramStore.d.ts +54 -18
  9. package/dist/style.css +690 -79
  10. package/dist/ui/DiagramTitlePanel.css.d.ts +4 -0
  11. package/dist/ui/DiagramTitlePanel.d.ts +2 -0
  12. package/dist/ui/OptionsPanel.d.ts +1 -2
  13. package/dist/ui/index.d.ts +0 -1
  14. package/dist/xyflow/SelectEdgesOnNodeFocus.d.ts +1 -0
  15. package/dist/xyflow/{XYFlowWrapper.d.ts → XYFlow.d.ts} +2 -2
  16. package/dist/xyflow/XYFlowEvents.d.ts +133 -13
  17. package/dist/xyflow/edges/RelationshipEdge.d.ts +2 -2
  18. package/dist/xyflow/edges/edges.css.d.ts +1 -0
  19. package/dist/xyflow/hooks/useXYFlow.d.ts +20 -20
  20. package/dist/xyflow/nodes/compound/CompoundNode.css.d.ts +7 -5
  21. package/dist/xyflow/types.d.ts +2 -2
  22. package/package.json +5 -3
  23. package/src/{ui/KeepAspectRatio.tsx → KeepAspectRatioContainer.tsx} +7 -6
  24. package/src/LikeC4Diagram.css.ts +8 -1
  25. package/src/LikeC4Diagram.props.ts +17 -12
  26. package/src/LikeC4Diagram.tsx +9 -6
  27. package/src/StaticLikeC4Diagram.tsx +1 -0
  28. package/src/globals.css.ts +48 -38
  29. package/src/state/diagramStore.ts +125 -68
  30. package/src/ui/DiagramTitlePanel.css.ts +32 -0
  31. package/src/ui/DiagramTitlePanel.tsx +139 -0
  32. package/src/ui/OptionsPanel.tsx +4 -23
  33. package/src/ui/index.ts +0 -1
  34. package/src/ui/options/NodeOptions.tsx +107 -30
  35. package/src/xyflow/FitviewOnDiagramChange.tsx +26 -20
  36. package/src/xyflow/SelectEdgesOnNodeFocus.tsx +57 -0
  37. package/src/xyflow/SyncWithDiagram.tsx +35 -26
  38. package/src/xyflow/{XYFlowWrapper.tsx → XYFlow.tsx} +24 -27
  39. package/src/xyflow/XYFlowEvents.tsx +175 -81
  40. package/src/xyflow/diagram-to-xyflow.ts +4 -4
  41. package/src/xyflow/edges/RelationshipEdge.tsx +43 -47
  42. package/src/xyflow/edges/edges.css.ts +77 -36
  43. package/src/xyflow/nodes/compound/CompoundNode.css.ts +94 -44
  44. package/src/xyflow/nodes/compound/CompoundNode.tsx +29 -31
  45. package/src/xyflow/nodes/element/ElementNode.tsx +2 -2
  46. package/src/xyflow/nodes/element/element.css.ts +1 -0
  47. package/src/xyflow/nodes/shared/NavigateToBtn.tsx +2 -1
  48. package/dist/ui/KeepAspectRatio.css.d.ts +0 -1
  49. package/dist/ui/KeepAspectRatio.d.ts +0 -9
  50. package/src/ui/KeepAspectRatio.css.ts +0 -7
@@ -0,0 +1,4 @@
1
+ export declare const container: string;
2
+ export declare const paper: string;
3
+ export declare const title: string;
4
+ export declare const description: string;
@@ -0,0 +1,2 @@
1
+ /// <reference types="react" />
2
+ export default function DiagramTitlePanel(): JSX.Element;
@@ -1,3 +1,2 @@
1
1
  /// <reference types="react" />
2
- declare const OptionsPanelMemo: import('react').NamedExoticComponent<object>;
3
- export default OptionsPanelMemo;
2
+ export default function OptionsPanel(): JSX.Element;
@@ -1,2 +1 @@
1
- export { KeepAspectRatio } from './KeepAspectRatio';
2
1
  export { default as OptionsPanel } from './OptionsPanel';
@@ -0,0 +1 @@
1
+ export declare function SelectEdgesOnNodeFocus(): null;
@@ -3,12 +3,12 @@ import { LikeC4DiagramProperties } from '../LikeC4Diagram.props';
3
3
  import { SetNonNullable, Simplify } from 'type-fest';
4
4
  import { CSSProperties, PropsWithChildren } from 'react';
5
5
 
6
- type OnlyExpectedProps = Required<Pick<LikeC4DiagramProperties, 'className' | 'controls' | 'pannable' | 'zoomable' | 'background'>>;
6
+ type OnlyExpectedProps = Required<Pick<LikeC4DiagramProperties, 'className' | 'controls' | 'background'>>;
7
7
  type XYFlowWrapperProps = Simplify<PropsWithChildren<SetNonNullable<OnlyExpectedProps> & {
8
8
  defaultNodes: XYFlowNode[];
9
9
  defaultEdges: XYFlowEdge[];
10
10
  style?: CSSProperties | undefined;
11
11
  }>>;
12
- declare function XYFlowWrapper({ className, children, defaultNodes, defaultEdges, pannable, zoomable, controls, background, style }: XYFlowWrapperProps): JSX.Element;
12
+ declare function XYFlowWrapper({ className, children, defaultNodes, defaultEdges, controls, background, style }: XYFlowWrapperProps): JSX.Element;
13
13
  export declare const XYFlow: typeof XYFlowWrapper;
14
14
  export {};
@@ -1,15 +1,135 @@
1
- import { XYFlowEdge, XYFlowNode } from './types';
2
- import { MouseEvent as ReactMouseEvent } from 'react';
3
- import { EdgeMouseHandler, NodeMouseHandler, OnMoveEnd } from '@xyflow/react';
1
+ import { XYFlowNode } from './types';
4
2
 
5
- type XYFlowEventHandlers = {
6
- onPaneClick: (event: ReactMouseEvent) => void;
7
- onNodeContextMenu: NodeMouseHandler<XYFlowNode>;
8
- onEdgeContextMenu: EdgeMouseHandler<XYFlowEdge>;
9
- onPaneContextMenu: (event: ReactMouseEvent | MouseEvent) => void;
10
- onNodeClick: NodeMouseHandler<XYFlowNode>;
11
- onEdgeClick: EdgeMouseHandler<XYFlowEdge>;
12
- onMoveEnd: OnMoveEnd;
3
+ export declare function useXYFlowEvents(): {
4
+ onDoubleClick: (event: import('react').MouseEvent<HTMLDivElement, MouseEvent>) => void;
5
+ onPaneClick: (event: import('react').MouseEvent<Element, MouseEvent>) => void;
6
+ onNodeContextMenu: (event: import('react').MouseEvent<Element, MouseEvent>, xynode: XYFlowNode) => void;
7
+ onPaneContextMenu: (event: MouseEvent | import('react').MouseEvent<Element, MouseEvent>) => void;
8
+ onEdgeContextMenu: (event: import('react').MouseEvent<Element, MouseEvent>, xyedge: {
9
+ source: string;
10
+ target: string;
11
+ style?: import('react').CSSProperties;
12
+ id: string;
13
+ zIndex?: number;
14
+ markerEnd?: import('@xyflow/react').EdgeMarkerType;
15
+ markerStart?: import('@xyflow/react').EdgeMarkerType;
16
+ hidden?: boolean;
17
+ className?: string;
18
+ label?: import('react').ReactNode;
19
+ selected?: boolean;
20
+ selectable?: boolean;
21
+ deletable?: boolean;
22
+ ariaLabel?: string;
23
+ focusable?: boolean;
24
+ sourceHandle?: string | null;
25
+ targetHandle?: string | null;
26
+ animated?: boolean;
27
+ interactionWidth?: number;
28
+ labelStyle?: import('react').CSSProperties;
29
+ labelShowBg?: boolean;
30
+ labelBgStyle?: import('react').CSSProperties;
31
+ labelBgPadding?: [number, number];
32
+ labelBgBorderRadius?: number;
33
+ updatable?: import('@xyflow/react').EdgeUpdatable;
34
+ data: import('./types').RelationshipData;
35
+ type: "relationship";
36
+ }) => void;
37
+ onNodeClick: (event: import('react').MouseEvent<Element, MouseEvent>, xynode: XYFlowNode) => void;
38
+ onNodeDoubleClick: (event: import('react').MouseEvent<Element, MouseEvent>, xynode: XYFlowNode) => void;
39
+ onEdgeClick: (event: import('react').MouseEvent<Element, MouseEvent>, xyedge: {
40
+ source: string;
41
+ target: string;
42
+ style?: import('react').CSSProperties;
43
+ id: string;
44
+ zIndex?: number;
45
+ markerEnd?: import('@xyflow/react').EdgeMarkerType;
46
+ markerStart?: import('@xyflow/react').EdgeMarkerType;
47
+ hidden?: boolean;
48
+ className?: string;
49
+ label?: import('react').ReactNode;
50
+ selected?: boolean;
51
+ selectable?: boolean;
52
+ deletable?: boolean;
53
+ ariaLabel?: string;
54
+ focusable?: boolean;
55
+ sourceHandle?: string | null;
56
+ targetHandle?: string | null;
57
+ animated?: boolean;
58
+ interactionWidth?: number;
59
+ labelStyle?: import('react').CSSProperties;
60
+ labelShowBg?: boolean;
61
+ labelBgStyle?: import('react').CSSProperties;
62
+ labelBgPadding?: [number, number];
63
+ labelBgBorderRadius?: number;
64
+ updatable?: import('@xyflow/react').EdgeUpdatable;
65
+ data: import('./types').RelationshipData;
66
+ type: "relationship";
67
+ }) => void;
68
+ onMoveEnd: (event: MouseEvent | TouchEvent | null, _viewport: import('@xyflow/react').Viewport) => void;
69
+ onNodeMouseEnter: (event: import('react').MouseEvent<Element, MouseEvent>, xynode: XYFlowNode) => void;
70
+ onNodeMouseLeave: (event: import('react').MouseEvent<Element, MouseEvent>, xynode: XYFlowNode) => void;
71
+ onEdgeMouseEnter: (event: import('react').MouseEvent<Element, MouseEvent>, xyedge: {
72
+ source: string;
73
+ target: string;
74
+ style?: import('react').CSSProperties;
75
+ id: string;
76
+ zIndex?: number;
77
+ markerEnd?: import('@xyflow/react').EdgeMarkerType;
78
+ markerStart?: import('@xyflow/react').EdgeMarkerType;
79
+ hidden?: boolean;
80
+ className?: string;
81
+ label?: import('react').ReactNode;
82
+ selected?: boolean;
83
+ selectable?: boolean;
84
+ deletable?: boolean;
85
+ ariaLabel?: string;
86
+ focusable?: boolean;
87
+ sourceHandle?: string | null;
88
+ targetHandle?: string | null;
89
+ animated?: boolean;
90
+ interactionWidth?: number;
91
+ labelStyle?: import('react').CSSProperties;
92
+ labelShowBg?: boolean;
93
+ labelBgStyle?: import('react').CSSProperties;
94
+ labelBgPadding?: [number, number];
95
+ labelBgBorderRadius?: number;
96
+ updatable?: import('@xyflow/react').EdgeUpdatable;
97
+ data: import('./types').RelationshipData;
98
+ type: "relationship";
99
+ }) => void;
100
+ onEdgeMouseLeave: (event: import('react').MouseEvent<Element, MouseEvent>, xyedge: {
101
+ source: string;
102
+ target: string;
103
+ style?: import('react').CSSProperties;
104
+ id: string;
105
+ zIndex?: number;
106
+ markerEnd?: import('@xyflow/react').EdgeMarkerType;
107
+ markerStart?: import('@xyflow/react').EdgeMarkerType;
108
+ hidden?: boolean;
109
+ className?: string;
110
+ label?: import('react').ReactNode;
111
+ selected?: boolean;
112
+ selectable?: boolean;
113
+ deletable?: boolean;
114
+ ariaLabel?: string;
115
+ focusable?: boolean;
116
+ sourceHandle?: string | null;
117
+ targetHandle?: string | null;
118
+ animated?: boolean;
119
+ interactionWidth?: number;
120
+ labelStyle?: import('react').CSSProperties;
121
+ labelShowBg?: boolean;
122
+ labelBgStyle?: import('react').CSSProperties;
123
+ labelBgPadding?: [number, number];
124
+ labelBgBorderRadius?: number;
125
+ updatable?: import('@xyflow/react').EdgeUpdatable;
126
+ data: import('./types').RelationshipData;
127
+ type: "relationship";
128
+ }) => void;
129
+ /**
130
+ * WOKAROUND:
131
+ * Viewport transform is not rounded to integers which results in blurry nodes on some resolution
132
+ * https://github.com/xyflow/xyflow/issues/3282
133
+ */
134
+ onViewportChange: ({ x, y, zoom }: import('@xyflow/react').Viewport) => void;
13
135
  };
14
- export declare function useXYFlowEvents(): XYFlowEventHandlers;
15
- export {};
@@ -10,13 +10,13 @@ export declare const RelationshipEdge: import('react').NamedExoticComponent<Edge
10
10
  markerEnd?: import("@xyflow/react").EdgeMarkerType;
11
11
  markerStart?: import("@xyflow/react").EdgeMarkerType;
12
12
  hidden?: boolean;
13
+ className?: string;
14
+ label?: import("react").ReactNode;
13
15
  selected?: boolean;
14
16
  selectable?: boolean;
15
17
  deletable?: boolean;
16
18
  ariaLabel?: string;
17
- className?: string;
18
19
  focusable?: boolean;
19
- label?: import("react").ReactNode;
20
20
  sourceHandle?: string | null;
21
21
  targetHandle?: string | null;
22
22
  animated?: boolean;
@@ -1,6 +1,7 @@
1
1
  export declare const container: string;
2
2
  export declare const edgePathBg: string;
3
3
  export declare const fillStrokeCtx: string;
4
+ export declare const controlPoint: string;
4
5
  export declare const cssEdgePath: string;
5
6
  export declare const varLabelX: `var(--${string})` | `var(--${string}, ${string})` | `var(--${string}, ${number})`;
6
7
  export declare const varLabelY: `var(--${string})` | `var(--${string}, ${string})` | `var(--${string}, ${number})`;
@@ -9,13 +9,13 @@ export declare const useXYFlow: () => import('@xyflow/react').ReactFlowInstance<
9
9
  markerEnd?: import("@xyflow/react").EdgeMarkerType;
10
10
  markerStart?: import("@xyflow/react").EdgeMarkerType;
11
11
  hidden?: boolean;
12
+ className?: string;
13
+ label?: import("react").ReactNode;
12
14
  selected?: boolean;
13
15
  selectable?: boolean;
14
16
  deletable?: boolean;
15
17
  ariaLabel?: string;
16
- className?: string;
17
18
  focusable?: boolean;
18
- label?: import("react").ReactNode;
19
19
  sourceHandle?: string | null;
20
20
  targetHandle?: string | null;
21
21
  animated?: boolean;
@@ -30,8 +30,8 @@ export declare const useXYFlow: () => import('@xyflow/react').ReactFlowInstance<
30
30
  type: "relationship";
31
31
  }>;
32
32
  export declare const useXYNodesData: {
33
- (nodeId: string): Pick<XYFlowNode, "id" | "type" | "data"> | null;
34
- (nodeIds: string[]): Pick<XYFlowNode, "id" | "type" | "data">[];
33
+ (nodeId: string): Pick<XYFlowNode, "id" | "data" | "type"> | null;
34
+ (nodeIds: string[]): Pick<XYFlowNode, "id" | "data" | "type">[];
35
35
  };
36
36
  export declare function useXYStore<StateSlice = unknown>(selector: (state: XYFlowState) => StateSlice, equalityFn?: (a: StateSlice, b: StateSlice) => boolean): StateSlice;
37
37
  export declare const useXYStoreApi: () => {
@@ -44,13 +44,13 @@ export declare const useXYStoreApi: () => {
44
44
  markerEnd?: import("@xyflow/react").EdgeMarkerType;
45
45
  markerStart?: import("@xyflow/react").EdgeMarkerType;
46
46
  hidden?: boolean;
47
+ className?: string;
48
+ label?: import("react").ReactNode;
47
49
  selected?: boolean;
48
50
  selectable?: boolean;
49
51
  deletable?: boolean;
50
52
  ariaLabel?: string;
51
- className?: string;
52
53
  focusable?: boolean;
53
- label?: import("react").ReactNode;
54
54
  sourceHandle?: string | null;
55
55
  targetHandle?: string | null;
56
56
  animated?: boolean;
@@ -73,13 +73,13 @@ export declare const useXYStoreApi: () => {
73
73
  markerEnd?: import("@xyflow/react").EdgeMarkerType;
74
74
  markerStart?: import("@xyflow/react").EdgeMarkerType;
75
75
  hidden?: boolean;
76
+ className?: string;
77
+ label?: import("react").ReactNode;
76
78
  selected?: boolean;
77
79
  selectable?: boolean;
78
80
  deletable?: boolean;
79
81
  ariaLabel?: string;
80
- className?: string;
81
82
  focusable?: boolean;
82
- label?: import("react").ReactNode;
83
83
  sourceHandle?: string | null;
84
84
  targetHandle?: string | null;
85
85
  animated?: boolean;
@@ -101,13 +101,13 @@ export declare const useXYStoreApi: () => {
101
101
  markerEnd?: import("@xyflow/react").EdgeMarkerType;
102
102
  markerStart?: import("@xyflow/react").EdgeMarkerType;
103
103
  hidden?: boolean;
104
+ className?: string;
105
+ label?: import("react").ReactNode;
104
106
  selected?: boolean;
105
107
  selectable?: boolean;
106
108
  deletable?: boolean;
107
109
  ariaLabel?: string;
108
- className?: string;
109
110
  focusable?: boolean;
110
- label?: import("react").ReactNode;
111
111
  sourceHandle?: string | null;
112
112
  targetHandle?: string | null;
113
113
  animated?: boolean;
@@ -129,13 +129,13 @@ export declare const useXYStoreApi: () => {
129
129
  markerEnd?: import("@xyflow/react").EdgeMarkerType;
130
130
  markerStart?: import("@xyflow/react").EdgeMarkerType;
131
131
  hidden?: boolean;
132
+ className?: string;
133
+ label?: import("react").ReactNode;
132
134
  selected?: boolean;
133
135
  selectable?: boolean;
134
136
  deletable?: boolean;
135
137
  ariaLabel?: string;
136
- className?: string;
137
138
  focusable?: boolean;
138
- label?: import("react").ReactNode;
139
139
  sourceHandle?: string | null;
140
140
  targetHandle?: string | null;
141
141
  animated?: boolean;
@@ -157,13 +157,13 @@ export declare const useXYStoreApi: () => {
157
157
  markerEnd?: import("@xyflow/react").EdgeMarkerType;
158
158
  markerStart?: import("@xyflow/react").EdgeMarkerType;
159
159
  hidden?: boolean;
160
+ className?: string;
161
+ label?: import("react").ReactNode;
160
162
  selected?: boolean;
161
163
  selectable?: boolean;
162
164
  deletable?: boolean;
163
165
  ariaLabel?: string;
164
- className?: string;
165
166
  focusable?: boolean;
166
- label?: import("react").ReactNode;
167
167
  sourceHandle?: string | null;
168
168
  targetHandle?: string | null;
169
169
  animated?: boolean;
@@ -185,13 +185,13 @@ export declare const useXYStoreApi: () => {
185
185
  markerEnd?: import("@xyflow/react").EdgeMarkerType;
186
186
  markerStart?: import("@xyflow/react").EdgeMarkerType;
187
187
  hidden?: boolean;
188
+ className?: string;
189
+ label?: import("react").ReactNode;
188
190
  selected?: boolean;
189
191
  selectable?: boolean;
190
192
  deletable?: boolean;
191
193
  ariaLabel?: string;
192
- className?: string;
193
194
  focusable?: boolean;
194
- label?: import("react").ReactNode;
195
195
  sourceHandle?: string | null;
196
196
  targetHandle?: string | null;
197
197
  animated?: boolean;
@@ -214,13 +214,13 @@ export declare const useXYStoreApi: () => {
214
214
  markerEnd?: import("@xyflow/react").EdgeMarkerType;
215
215
  markerStart?: import("@xyflow/react").EdgeMarkerType;
216
216
  hidden?: boolean;
217
+ className?: string;
218
+ label?: import("react").ReactNode;
217
219
  selected?: boolean;
218
220
  selectable?: boolean;
219
221
  deletable?: boolean;
220
222
  ariaLabel?: string;
221
- className?: string;
222
223
  focusable?: boolean;
223
- label?: import("react").ReactNode;
224
224
  sourceHandle?: string | null;
225
225
  targetHandle?: string | null;
226
226
  animated?: boolean;
@@ -242,13 +242,13 @@ export declare const useXYStoreApi: () => {
242
242
  markerEnd?: import("@xyflow/react").EdgeMarkerType;
243
243
  markerStart?: import("@xyflow/react").EdgeMarkerType;
244
244
  hidden?: boolean;
245
+ className?: string;
246
+ label?: import("react").ReactNode;
245
247
  selected?: boolean;
246
248
  selectable?: boolean;
247
249
  deletable?: boolean;
248
250
  ariaLabel?: string;
249
- className?: string;
250
251
  focusable?: boolean;
251
- label?: import("react").ReactNode;
252
252
  sourceHandle?: string | null;
253
253
  targetHandle?: string | null;
254
254
  animated?: boolean;
@@ -1,5 +1,7 @@
1
- export declare const cssContainer: string;
2
- export declare const cssCompound: string;
3
- export declare const cssTitle: string;
4
- export declare const cssIndicator: string;
5
- export declare const cssNavigateBtn: string;
1
+ export declare const container: string;
2
+ export declare const varTransparency: `var(--${string})` | `var(--${string}, ${string})` | `var(--${string}, ${number})`;
3
+ export declare const compoundBody: string;
4
+ export declare const transparent: string;
5
+ export declare const title: string;
6
+ export declare const indicator: string;
7
+ export declare const navigateBtn: string;
@@ -48,13 +48,13 @@ export declare namespace XYFlowEdge {
48
48
  markerEnd?: import('@xyflow/react').EdgeMarkerType;
49
49
  markerStart?: import('@xyflow/react').EdgeMarkerType;
50
50
  hidden?: boolean;
51
+ className?: string;
52
+ label?: import('react').ReactNode;
51
53
  selected?: boolean;
52
54
  selectable?: boolean;
53
55
  deletable?: boolean;
54
56
  ariaLabel?: string;
55
- className?: string;
56
57
  focusable?: boolean;
57
- label?: import('react').ReactNode;
58
58
  sourceHandle?: string | null;
59
59
  targetHandle?: string | null;
60
60
  animated?: boolean;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@likec4/diagram",
3
- "version": "1.0.2",
3
+ "version": "1.1.1",
4
4
  "license": "MIT",
5
5
  "bugs": "https://github.com/likec4/likec4/issues",
6
6
  "homepage": "https://likec4.dev",
@@ -50,8 +50,9 @@
50
50
  "clean": "run -T rimraf -v -g 'dist/*' .tsbuildinfo"
51
51
  },
52
52
  "dependencies": {
53
- "@likec4/core": "1.0.2",
53
+ "@likec4/core": "1.1.1",
54
54
  "@react-hookz/web": "^24.0.4",
55
+ "d3-shape": "^3.2.0",
55
56
  "esm-env": "^1.0.0",
56
57
  "fast-equals": "^5.0.1",
57
58
  "framer-motion": "^11.2.2",
@@ -70,6 +71,7 @@
70
71
  "@mantine/hooks": "^7.9.2",
71
72
  "@mantine/vanilla-extract": "^7.9.2",
72
73
  "@total-typescript/ts-reset": "^0.5.1",
74
+ "@types/d3-shape": "^3",
73
75
  "@types/react": "18.2.0",
74
76
  "@types/react-dom": "18.2.4",
75
77
  "@vanilla-extract/css": "^1.15.1",
@@ -78,7 +80,7 @@
78
80
  "@vitejs/plugin-react": "^4.2.1",
79
81
  "@xyflow/react": "^12.0.0-next",
80
82
  "clsx": "^2.1.1",
81
- "execa": "^8.0.1",
83
+ "execa": "^9.1.0",
82
84
  "khroma": "^2.1.0",
83
85
  "react": "^18.2.0",
84
86
  "react-dom": "^18.2.0",
@@ -1,15 +1,16 @@
1
1
  import { Box } from '@mantine/core'
2
2
  import clsx from 'clsx'
3
- import type { HTMLAttributes } from 'react'
4
- import { wrapper } from './KeepAspectRatio.css'
3
+ import { type HTMLAttributes, useId } from 'react'
4
+ import * as css from './LikeC4Diagram.css'
5
5
 
6
- type KeepAspectRatioProps = HTMLAttributes<HTMLDivElement> & {
6
+ type KeepAspectRatioContainerProps = HTMLAttributes<HTMLDivElement> & {
7
+ // Whether to keep the aspect ratio
7
8
  enabled: boolean
8
9
  width: number
9
10
  height: number
10
11
  }
11
12
 
12
- export function KeepAspectRatio({
13
+ export function KeepAspectRatioContainer({
13
14
  children,
14
15
  width,
15
16
  height,
@@ -17,11 +18,11 @@ export function KeepAspectRatio({
17
18
  className,
18
19
  style,
19
20
  ...rest
20
- }: KeepAspectRatioProps) {
21
+ }: KeepAspectRatioContainerProps) {
21
22
  return (
22
23
  <Box
23
24
  {...rest}
24
- className={clsx(wrapper, className)}
25
+ className={clsx(css.keepAspectRatioContainer, className)}
25
26
  style={enabled
26
27
  ? {
27
28
  ...style,
@@ -1,6 +1,12 @@
1
1
  import { globalStyle, style } from '@vanilla-extract/css'
2
2
  import { vars, xyvars } from './theme.css'
3
3
 
4
+ export const keepAspectRatioContainer = style({
5
+ width: '100%',
6
+ height: '100%',
7
+ padding: 0
8
+ })
9
+
4
10
  export const cssReactFlow = style({})
5
11
 
6
12
  globalStyle(`.react-flow${cssReactFlow}`, {
@@ -10,7 +16,8 @@ globalStyle(`.react-flow${cssReactFlow}`, {
10
16
  }
11
17
  })
12
18
  globalStyle(`.react-flow${cssReactFlow} .react-flow__viewport`, {
13
- willChange: 'transform'
19
+ // willChange: 'transform'
20
+ backfaceVisibility: 'hidden'
14
21
  })
15
22
 
16
23
  export const cssDisablePan = style({})
@@ -1,4 +1,5 @@
1
1
  import type {
2
+ BorderStyle,
2
3
  DiagramEdge,
3
4
  DiagramNode,
4
5
  DiagramView,
@@ -10,8 +11,8 @@ import type {
10
11
  } from '@likec4/core'
11
12
  import type { MouseEvent as ReactMouseEvent } from 'react'
12
13
  import type { SetRequired, Simplify } from 'type-fest'
13
- import type { XYFlowEdge, XYFlowNode } from './xyflow/types'
14
14
  import type { XYBackgroundProps } from './xyflow/XYFlowBackground'
15
+ import type { XYFlowEdge, XYFlowNode } from './xyflow/types'
15
16
 
16
17
  export type DiagramNodeWithNavigate = Simplify<SetRequired<DiagramNode, 'navigateTo'>>
17
18
 
@@ -44,22 +45,20 @@ export type OnEdgeClick = (
44
45
  export type OnCanvasClick = (event: ReactMouseEvent) => void
45
46
 
46
47
  export namespace Changes {
47
- export interface ChangeColor {
48
- op: 'change-color'
49
- color: ThemeColor
50
- targets: NonEmptyArray<Fqn>
51
- }
52
-
53
- export interface ChangeShape {
54
- op: 'change-shape'
55
- shape: ElementShape
48
+ export interface ChangeElementStyle {
49
+ op: 'change-element-style'
50
+ style: {
51
+ border?: BorderStyle
52
+ opacity?: number
53
+ shape?: ElementShape
54
+ color?: ThemeColor
55
+ }
56
56
  targets: NonEmptyArray<Fqn>
57
57
  }
58
58
  }
59
59
 
60
60
  export type Change =
61
- | Changes.ChangeColor
62
- | Changes.ChangeShape
61
+ | Changes.ChangeElementStyle
63
62
 
64
63
  export type ChangeEvent = {
65
64
  changes: NonEmptyArray<Change>
@@ -139,6 +138,12 @@ export interface LikeC4DiagramProperties {
139
138
  * @default true
140
139
  */
141
140
  showElementLinks?: boolean | undefined
141
+
142
+ /**
143
+ * Display panel with diagram title / description
144
+ * @default true
145
+ */
146
+ showDiagramTitle?: boolean | undefined
142
147
  }
143
148
 
144
149
  export interface LikeC4DiagramEventHandlers {
@@ -2,18 +2,19 @@ import { ReactFlowProvider as XYFlowProvider } from '@xyflow/react'
2
2
  import clsx from 'clsx'
3
3
  import { useRef } from 'react'
4
4
  import { rootClassName } from './globals.css'
5
+ import { KeepAspectRatioContainer } from './KeepAspectRatioContainer'
5
6
  import { cssDisablePan, cssNoControls, cssReactFlow, cssTransparentBg } from './LikeC4Diagram.css'
6
7
  import { type LikeC4DiagramEventHandlers, type LikeC4DiagramProperties } from './LikeC4Diagram.props'
7
8
  import { EnsureMantine } from './mantine/EnsureMantine'
8
9
  import { DiagramContextProvider } from './state/DiagramContext'
9
10
  import { WhenInitialized } from './state/WhenInitialized'
10
- import { KeepAspectRatio } from './ui/KeepAspectRatio'
11
+ import DiagramTitlePanel from './ui/DiagramTitlePanel'
11
12
  import OptionsPanel from './ui/OptionsPanel'
12
13
  import { diagramViewToXYFlowData } from './xyflow/diagram-to-xyflow'
13
14
  import { FitViewOnDiagramChange } from './xyflow/FitviewOnDiagramChange'
14
15
  import { SyncWithDiagram } from './xyflow/SyncWithDiagram'
15
16
  import type { XYFlowData } from './xyflow/types'
16
- import { XYFlow } from './xyflow/XYFlowWrapper'
17
+ import { XYFlow } from './xyflow/XYFlow'
17
18
 
18
19
  export type LikeC4DiagramProps = LikeC4DiagramProperties & LikeC4DiagramEventHandlers
19
20
  export function LikeC4Diagram({
@@ -29,6 +30,7 @@ export function LikeC4Diagram({
29
30
  background = 'dots',
30
31
  controls = false,
31
32
  showElementLinks = true,
33
+ showDiagramTitle = true,
32
34
  initialWidth,
33
35
  initialHeight,
34
36
  keepAspectRatio = false,
@@ -69,6 +71,8 @@ export function LikeC4Diagram({
69
71
  <DiagramContextProvider
70
72
  view={view}
71
73
  readonly={readonly}
74
+ pannable={pannable}
75
+ zoomable={zoomable}
72
76
  fitViewEnabled={fitView}
73
77
  fitViewPadding={fitViewPadding}
74
78
  showElementLinks={showElementLinks}
@@ -84,7 +88,7 @@ export function LikeC4Diagram({
84
88
  onNavigateTo={onNavigateTo}
85
89
  onCanvasDblClick={onCanvasDblClick}
86
90
  >
87
- <KeepAspectRatio
91
+ <KeepAspectRatioContainer
88
92
  className={clsx(rootClassName, className)}
89
93
  enabled={keepAspectRatio}
90
94
  width={view.width}
@@ -102,12 +106,11 @@ export function LikeC4Diagram({
102
106
  controls={controls}
103
107
  defaultNodes={initialRef.current.defaultNodes}
104
108
  defaultEdges={initialRef.current.defaultEdges}
105
- pannable={pannable}
106
- zoomable={zoomable}
107
109
  >
108
110
  {readonly !== true && <OptionsPanel />}
111
+ {showDiagramTitle === true && <DiagramTitlePanel />}
109
112
  </XYFlow>
110
- </KeepAspectRatio>
113
+ </KeepAspectRatioContainer>
111
114
  <WhenInitialized>
112
115
  <SyncWithDiagram />
113
116
  <FitViewOnDiagramChange />
@@ -31,6 +31,7 @@ export function StaticLikeC4Diagram({
31
31
  controls={false}
32
32
  background={background}
33
33
  showElementLinks
34
+ showDiagramTitle={false}
34
35
  nodesSelectable={false}
35
36
  nodesDraggable={false}
36
37
  {...rest}