@likec4/diagram 1.0.0-next.2 → 1.0.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.
Files changed (124) hide show
  1. package/dist/LikeC4Diagram.css.d.ts +0 -1
  2. package/dist/LikeC4Diagram.d.ts +1 -2
  3. package/dist/LikeC4Diagram.props.d.ts +24 -25
  4. package/dist/StaticLikeC4Diagram.d.ts +1 -2
  5. package/dist/globals.css.d.ts +1 -0
  6. package/dist/hooks/index.d.ts +2 -3
  7. package/dist/hooks/useSetState.d.ts +3 -0
  8. package/dist/hooks/useUpdateEffect.d.ts +4 -0
  9. package/dist/icons/Clipboard.d.ts +0 -1
  10. package/dist/icons/Link.d.ts +0 -1
  11. package/dist/icons/ZoomIn.d.ts +0 -1
  12. package/dist/icons/index.d.ts +0 -1
  13. package/dist/index.d.ts +1 -4
  14. package/dist/index.mjs +9388 -0
  15. package/dist/mantine/EnsureMantine.d.ts +2 -4
  16. package/dist/mantine/theme.d.ts +3 -0
  17. package/dist/mantine.css.d.ts +1 -0
  18. package/dist/state/DiagramContext.d.ts +386 -0
  19. package/dist/state/WhenInitialized.d.ts +3 -0
  20. package/dist/state/diagramStore.d.ts +428 -0
  21. package/dist/state/index.d.ts +4 -2
  22. package/dist/state/useDiagramStore.d.ts +387 -0
  23. package/dist/style.css +1212 -1
  24. package/dist/theme.css.d.ts +16 -2
  25. package/dist/ui/Camera.d.ts +0 -1
  26. package/dist/ui/KeepAspectRatio.css.d.ts +0 -1
  27. package/dist/ui/KeepAspectRatio.d.ts +0 -1
  28. package/dist/ui/OptionsPanel.css.d.ts +0 -1
  29. package/dist/ui/OptionsPanel.d.ts +0 -1
  30. package/dist/ui/index.d.ts +0 -1
  31. package/dist/ui/options/NodeOptions.d.ts +0 -1
  32. package/dist/xyflow/FitviewOnDiagramChange.d.ts +1 -5
  33. package/dist/xyflow/SyncWithDiagram.d.ts +5 -0
  34. package/dist/xyflow/XYFlowBackground.d.ts +0 -1
  35. package/dist/xyflow/XYFlowEvents.d.ts +5 -15
  36. package/dist/xyflow/XYFlowWrapper.d.ts +4 -5
  37. package/dist/xyflow/const.d.ts +1 -2
  38. package/dist/xyflow/diagram-to-xyflow.d.ts +4 -2
  39. package/dist/xyflow/edges/RelationshipEdge.d.ts +7 -7
  40. package/dist/xyflow/edges/edges.css.d.ts +2 -1
  41. package/dist/xyflow/edges/utils.d.ts +3 -4
  42. package/dist/xyflow/hooks/index.d.ts +2 -37
  43. package/dist/xyflow/hooks/{use-layout-/321/201onstraints.d.ts → useLayoutConstraints.d.ts} +2 -4
  44. package/dist/xyflow/hooks/useXYFlow.d.ts +266 -0
  45. package/dist/xyflow/nodes/compound/CompoundNode.css.d.ts +0 -1
  46. package/dist/xyflow/nodes/compound/CompoundNode.d.ts +0 -1
  47. package/dist/xyflow/nodes/compound/index.d.ts +0 -1
  48. package/dist/xyflow/nodes/element/ElementIcon.d.ts +1 -2
  49. package/dist/xyflow/nodes/element/ElementLink.css.d.ts +0 -1
  50. package/dist/xyflow/nodes/element/ElementLink.d.ts +1 -2
  51. package/dist/xyflow/nodes/element/ElementNode.d.ts +1 -3
  52. package/dist/xyflow/nodes/element/ElementShapeSvg.d.ts +2 -3
  53. package/dist/xyflow/nodes/element/element.css.d.ts +0 -1
  54. package/dist/xyflow/nodes/element/index.d.ts +1 -2
  55. package/dist/xyflow/nodes/shared/NavigateToBtn.d.ts +0 -1
  56. package/dist/xyflow/types.d.ts +20 -8
  57. package/dist/xyflow/utils.d.ts +0 -1
  58. package/package.json +36 -34
  59. package/src/LikeC4Diagram.css.ts +31 -0
  60. package/src/LikeC4Diagram.props.ts +154 -0
  61. package/src/LikeC4Diagram.tsx +119 -0
  62. package/src/StaticLikeC4Diagram.tsx +39 -0
  63. package/src/globals.css.ts +128 -0
  64. package/src/hooks/index.ts +2 -0
  65. package/src/hooks/useSetState.ts +19 -0
  66. package/src/hooks/useUpdateEffect.ts +28 -0
  67. package/src/icons/Clipboard.tsx +24 -0
  68. package/src/icons/Link.tsx +23 -0
  69. package/src/icons/ZoomIn.tsx +25 -0
  70. package/src/icons/index.ts +3 -0
  71. package/src/index.ts +11 -0
  72. package/src/mantine/EnsureMantine.tsx +14 -0
  73. package/src/mantine/theme.ts +19 -0
  74. package/src/mantine.css.ts +4 -0
  75. package/src/reset.d.ts +2 -0
  76. package/src/state/DiagramContext.tsx +42 -0
  77. package/src/state/WhenInitialized.tsx +24 -0
  78. package/src/state/diagramStore.ts +358 -0
  79. package/src/state/index.ts +4 -0
  80. package/src/state/useDiagramStore.ts +39 -0
  81. package/src/theme.css.ts +64 -0
  82. package/src/ui/Camera.tsx +174 -0
  83. package/src/ui/KeepAspectRatio.css.ts +7 -0
  84. package/src/ui/KeepAspectRatio.tsx +35 -0
  85. package/src/ui/OptionsPanel.css.ts +10 -0
  86. package/src/ui/OptionsPanel.tsx +65 -0
  87. package/src/ui/index.ts +3 -0
  88. package/src/ui/options/NodeOptions.tsx +253 -0
  89. package/src/xyflow/FitviewOnDiagramChange.tsx +93 -0
  90. package/src/xyflow/SyncWithDiagram.tsx +113 -0
  91. package/src/xyflow/XYFlowBackground.tsx +33 -0
  92. package/src/xyflow/XYFlowEvents.tsx +100 -0
  93. package/src/xyflow/XYFlowWrapper.tsx +166 -0
  94. package/src/xyflow/const.ts +7 -0
  95. package/src/xyflow/diagram-to-xyflow.ts +197 -0
  96. package/src/xyflow/edges/RelationshipEdge.tsx +288 -0
  97. package/src/xyflow/edges/edges.css.ts +124 -0
  98. package/src/xyflow/edges/utils.ts +110 -0
  99. package/src/xyflow/hooks/index.ts +2 -0
  100. package/src/xyflow/hooks/useLayoutConstraints.ts +289 -0
  101. package/src/xyflow/hooks/useXYFlow.ts +20 -0
  102. package/src/xyflow/nodes/compound/CompoundNode.css.ts +191 -0
  103. package/src/xyflow/nodes/compound/CompoundNode.tsx +105 -0
  104. package/src/xyflow/nodes/compound/index.ts +1 -0
  105. package/src/xyflow/nodes/element/ElementIcon.tsx +44 -0
  106. package/src/xyflow/nodes/element/ElementLink.css.ts +67 -0
  107. package/src/xyflow/nodes/element/ElementLink.tsx +94 -0
  108. package/src/xyflow/nodes/element/ElementNode.tsx +225 -0
  109. package/src/xyflow/nodes/element/ElementShapeSvg.tsx +181 -0
  110. package/src/xyflow/nodes/element/element.css.ts +261 -0
  111. package/src/xyflow/nodes/element/index.ts +1 -0
  112. package/src/xyflow/nodes/shared/NavigateToBtn.tsx +25 -0
  113. package/src/xyflow/types.ts +100 -0
  114. package/src/xyflow/utils.ts +12 -0
  115. package/dist/EmbeddedLikeC4Diagram.css.d.ts +0 -6
  116. package/dist/EmbeddedLikeC4Diagram.d.ts +0 -18
  117. package/dist/bundle.d.ts +0 -3
  118. package/dist/hooks/use-set-state.d.ts +0 -2
  119. package/dist/hooks/use-update-effect.d.ts +0 -4
  120. package/dist/index.css.d.ts +0 -2
  121. package/dist/index.js +0 -13043
  122. package/dist/mantine/index.d.ts +0 -3
  123. package/dist/state/DiagramState.d.ts +0 -162
  124. package/dist/xyflow/UpdateOnDiagramChange.d.ts +0 -10
@@ -1,19 +1,21 @@
1
1
  import { SetReadonly, SetRequired, Simplify } from 'type-fest';
2
- import { Edge, Node, ReactFlowInstance } from '@xyflow/react';
3
- import { BBox, DiagramEdge, DiagramNode, Point } from '@likec4/core';
2
+ import { MouseEvent as ReactMouseEvent } from 'react';
3
+ import { Edge, EdgeMouseHandler, InternalNode, Node, NodeMouseHandler, OnMoveEnd, OnMoveStart, ReactFlowInstance, ReactFlowState } from '@xyflow/react';
4
+ import { BBox, DiagramEdge, DiagramNode, Fqn, Point } from '@likec4/core';
4
5
 
5
6
  export type ElementNodeData = {
6
- id: string;
7
+ fqn: Fqn;
7
8
  element: DiagramNode;
8
9
  };
9
10
  type TypedXYFlowNode<D extends Record<string, unknown>, T extends string> = SetReadonly<SetRequired<Node<D, T>, 'type'>, 'id' | 'type'>;
10
11
  export type ElementXYFlowNode = TypedXYFlowNode<ElementNodeData, 'element'>;
11
12
  export type CompoundNodeData = {
12
- id: string;
13
+ fqn: Fqn;
13
14
  element: DiagramNode;
14
15
  };
15
16
  export type CompoundXYFlowNode = TypedXYFlowNode<CompoundNodeData, 'compound'>;
16
17
  export type XYFlowNode = ElementXYFlowNode | CompoundXYFlowNode;
18
+ export type InternalXYFlowNode = InternalNode<XYFlowNode>;
17
19
  export declare namespace XYFlowNode {
18
20
  type Data = ElementNodeData | CompoundNodeData;
19
21
  function isCompound(node: unknown): node is CompoundXYFlowNode;
@@ -42,11 +44,13 @@ export declare namespace XYFlowEdge {
42
44
  target: string;
43
45
  style?: import('react').CSSProperties;
44
46
  id: string;
47
+ zIndex?: number;
48
+ markerEnd?: import('@xyflow/react').EdgeMarkerType;
49
+ markerStart?: import('@xyflow/react').EdgeMarkerType;
45
50
  hidden?: boolean;
46
51
  selected?: boolean;
47
52
  selectable?: boolean;
48
53
  deletable?: boolean;
49
- zIndex?: number;
50
54
  ariaLabel?: string;
51
55
  className?: string;
52
56
  focusable?: boolean;
@@ -54,8 +58,6 @@ export declare namespace XYFlowEdge {
54
58
  sourceHandle?: string | null;
55
59
  targetHandle?: string | null;
56
60
  animated?: boolean;
57
- markerStart?: import('@xyflow/react').EdgeMarkerType;
58
- markerEnd?: import('@xyflow/react').EdgeMarkerType;
59
61
  interactionWidth?: number;
60
62
  labelStyle?: import('react').CSSProperties;
61
63
  labelShowBg?: boolean;
@@ -68,9 +70,19 @@ export declare namespace XYFlowEdge {
68
70
  };
69
71
  }
70
72
  export type XYFlowInstance = ReactFlowInstance<XYFlowNode, XYFlowEdge>;
73
+ export type XYFlowState = ReactFlowState<XYFlowNode, XYFlowEdge>;
71
74
  export type XYFlowData = {
72
75
  nodes: XYFlowNode[];
73
76
  edges: XYFlowEdge[];
74
77
  };
78
+ export type XYFlowEventHandlers = {
79
+ onPanelClick: (event: ReactMouseEvent) => void;
80
+ onNodeContextMenu: NodeMouseHandler<XYFlowNode>;
81
+ onEdgeContextMenu: EdgeMouseHandler<XYFlowEdge>;
82
+ onPaneContextMenu: (event: ReactMouseEvent | MouseEvent) => void;
83
+ onNodeClick: NodeMouseHandler<XYFlowNode>;
84
+ onEdgeClick: EdgeMouseHandler<XYFlowEdge>;
85
+ onMoveStart: OnMoveStart;
86
+ onMoveEnd: OnMoveEnd;
87
+ };
75
88
  export {};
76
- //# sourceMappingURL=types.d.ts.map
@@ -2,4 +2,3 @@ import { XYPosition } from '@xyflow/react';
2
2
 
3
3
  export declare function toDomPrecision(v: number | null): number;
4
4
  export declare function distance(a: XYPosition, b: XYPosition): number;
5
- //# sourceMappingURL=utils.d.ts.map
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@likec4/diagram",
3
- "version": "1.0.0-next.2",
3
+ "version": "1.0.0",
4
4
  "license": "MIT",
5
5
  "bugs": "https://github.com/likec4/likec4/issues",
6
6
  "homepage": "https://likec4.dev",
@@ -15,43 +15,50 @@
15
15
  "LICENSE",
16
16
  "README.md",
17
17
  "dist",
18
+ "src",
19
+ "!dist/src",
18
20
  "!**/*.spec.*",
19
- "!**/*.map"
20
- ],
21
- "sideEffects": [
22
- "**/*.css"
21
+ "!**/*.d.ts.map"
23
22
  ],
23
+ "sideEffects": false,
24
24
  "type": "module",
25
25
  "exports": {
26
26
  ".": {
27
27
  "types": "./dist/index.d.ts",
28
- "import": "./dist/index.js",
29
- "default": "./dist/index.js"
28
+ "default": "./dist/index.mjs"
30
29
  },
31
- "./style.css": "./dist/style.css",
32
- "./dist/style.css": "./dist/style.css"
30
+ "./style.css": "./dist/style.css"
33
31
  },
34
32
  "publishConfig": {
35
33
  "registry": "https://registry.npmjs.org",
36
- "access": "public"
34
+ "access": "public",
35
+ "exports": {
36
+ ".": {
37
+ "types": "./dist/index.d.ts",
38
+ "default": "./dist/index.mjs"
39
+ },
40
+ "./style.css": "./dist/style.css"
41
+ }
37
42
  },
38
43
  "packageManager": "yarn@4.1.1",
39
44
  "scripts": {
40
- "typecheck": "tsc --emitDeclarationOnly --declaration --declarationMap",
45
+ "typecheck": "tsc",
46
+ "prepack": "vite build --mode production",
41
47
  "build:turbo": "run -T turbo build --filter='diagram'",
42
- "build": "vite build && run typecheck",
48
+ "build": "vite build --mode development && tsc -b",
43
49
  "lint": "run -T eslint src/ --fix",
44
- "clean": "run -T rimraf dist bundle"
50
+ "clean": "run -T rimraf -v dist/* .tsbuildinfo"
45
51
  },
46
52
  "dependencies": {
47
- "@likec4/core": "1.0.0-next.2",
48
- "@mantine/core": "^7.7.0",
49
- "@mantine/hooks": "^7.7.0",
50
- "framer-motion": "^11.0.22",
51
- "react-tracked": "^1.7.11",
52
- "remeda": "^1.56.0",
53
- "scheduler": "^0.23.0",
54
- "type-fest": "^4.13.1"
53
+ "@likec4/core": "1.0.0",
54
+ "@mantine/core": "^7.9.0",
55
+ "@mantine/hooks": "^7.9.0",
56
+ "@react-hookz/web": "^24.0.4",
57
+ "esm-env": "^1.0.0",
58
+ "fast-equals": "^5.0.1",
59
+ "framer-motion": "^11.1.7",
60
+ "remeda": "^1.61.0",
61
+ "zustand": "^4.5.2"
55
62
  },
56
63
  "peerDependencies": {
57
64
  "react": "^18.2.0",
@@ -59,30 +66,25 @@
59
66
  },
60
67
  "devDependencies": {
61
68
  "@lume/kiwi": "^0.4.3",
62
- "@mantine/vanilla-extract": "^7.7.0",
63
- "@react-hookz/deep-equal": "^2.0.2",
64
- "@react-hookz/web": "^24.0.4",
69
+ "@mantine/vanilla-extract": "^7.9.0",
65
70
  "@total-typescript/ts-reset": "^0.5.1",
66
71
  "@types/react": "^18.2.0",
67
72
  "@types/react-dom": "^18.2.0",
68
- "@vanilla-extract/css": "^1.14.1",
73
+ "@vanilla-extract/css": "^1.15.1",
69
74
  "@vanilla-extract/dynamic": "^2.1.0",
70
75
  "@vanilla-extract/esbuild-plugin": "^2.3.5",
71
- "@vanilla-extract/recipes": "^0.5.2",
72
76
  "@vitejs/plugin-react": "^4.2.1",
73
- "@xyflow/react": "^12.0.0-next.12",
74
- "clsx": "^2.1.0",
77
+ "@xyflow/react": "^12.0.0-next",
78
+ "clsx": "^2.1.1",
75
79
  "execa": "^8.0.1",
76
- "fast-equals": "^5.0.1",
77
80
  "khroma": "^2.1.0",
78
81
  "react": "^18.2.0",
79
82
  "react-dom": "^18.2.0",
80
- "terser": "^5.30.0",
81
83
  "tilg": "^0.1.1",
82
- "typescript": "^5.4.3",
84
+ "type-fest": "^4.18.2",
85
+ "typescript": "^5.4.5",
83
86
  "unbuild": "^2.0.0",
84
- "vite": "^5.2.6",
85
- "vite-plugin-dts": "^3.8.1",
86
- "vite-plugin-shadow-style": "^1.1.0"
87
+ "vite": "^5.2.11",
88
+ "vite-plugin-dts": "^3.8.1"
87
89
  }
88
90
  }
@@ -0,0 +1,31 @@
1
+ import { globalStyle, style } from '@vanilla-extract/css'
2
+ import { vars, xyvars } from './theme.css'
3
+
4
+ export const cssReactFlow = style({})
5
+
6
+ globalStyle(`.react-flow${cssReactFlow}`, {
7
+ vars: {
8
+ [xyvars.background.color]: vars.likec4.background.color,
9
+ [xyvars.background.pattern.color]: vars.likec4.background.pattern.color
10
+ }
11
+ })
12
+ globalStyle(`.react-flow${cssReactFlow} .react-flow__viewport`, {
13
+ willChange: 'transform'
14
+ })
15
+
16
+ export const cssDisablePan = style({})
17
+
18
+ export const cssTransparentBg = style({})
19
+
20
+ globalStyle(`.react-flow${cssReactFlow}${cssTransparentBg}`, {
21
+ backgroundColor: 'transparent !important',
22
+ vars: {
23
+ [vars.likec4.background.color]: 'transparent !important',
24
+ [xyvars.background.color]: 'transparent !important'
25
+ }
26
+ })
27
+
28
+ export const cssNoControls = style({})
29
+ globalStyle(`:where(${cssNoControls}, ${cssTransparentBg}) .react-flow__attribution`, {
30
+ display: 'none'
31
+ })
@@ -0,0 +1,154 @@
1
+ import type {
2
+ DiagramEdge,
3
+ DiagramNode,
4
+ DiagramView,
5
+ ElementShape,
6
+ Fqn,
7
+ NonEmptyArray,
8
+ ThemeColor,
9
+ ViewID
10
+ } from '@likec4/core'
11
+ import type { MouseEvent as ReactMouseEvent } from 'react'
12
+ import type { SetRequired, Simplify } from 'type-fest'
13
+ import type { XYFlowEdge, XYFlowNode } from './xyflow/types'
14
+ import type { XYBackgroundProps } from './xyflow/XYFlowBackground'
15
+
16
+ export type DiagramNodeWithNavigate = Simplify<SetRequired<DiagramNode, 'navigateTo'>>
17
+
18
+ export type OnNavigateTo = {
19
+ (
20
+ to: ViewID,
21
+ event: ReactMouseEvent,
22
+ element: DiagramNodeWithNavigate,
23
+ xynode: XYFlowNode
24
+ ): void
25
+ }
26
+ export type OnNodeClick = (
27
+ event: {
28
+ element: DiagramNode
29
+ xynode: XYFlowNode
30
+ event: ReactMouseEvent
31
+ }
32
+ ) => void
33
+ export type OnEdgeClick = (
34
+ event: {
35
+ relation: DiagramEdge
36
+ xyedge: XYFlowEdge
37
+ event: ReactMouseEvent
38
+ }
39
+ ) => void
40
+
41
+ /**
42
+ * On pane/canvas click (not on any node or edge)
43
+ */
44
+ export type OnCanvasClick = (event: ReactMouseEvent) => void
45
+
46
+ 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
56
+ targets: NonEmptyArray<Fqn>
57
+ }
58
+ }
59
+
60
+ export type Change =
61
+ | Changes.ChangeColor
62
+ | Changes.ChangeShape
63
+
64
+ export type ChangeEvent = {
65
+ changes: NonEmptyArray<Change>
66
+ }
67
+ export type OnChange = {
68
+ (event: ChangeEvent): void
69
+ }
70
+ export type LikeC4ColorScheme = 'light' | 'dark'
71
+
72
+ export interface LikeC4DiagramProperties {
73
+ view: DiagramView
74
+
75
+ className?: string | undefined
76
+
77
+ /**
78
+ * Controls color scheme used for styling the flow
79
+ * By default inherits from system or surrounding MantineProvider
80
+ *
81
+ * @example 'light' | 'dark'
82
+ */
83
+ // colorScheme?: LikeC4ColorScheme | undefined
84
+
85
+ /**
86
+ * Show/hide controls menu
87
+ * @default false
88
+ */
89
+ controls?: boolean | undefined
90
+ /**
91
+ * Enable/disable panning
92
+ * @default true
93
+ */
94
+ pannable?: boolean | undefined
95
+ /**
96
+ * Enable/disable zooming
97
+ * @default true
98
+ */
99
+ zoomable?: boolean | undefined
100
+ /**
101
+ * Disable any editing (dragging still can be enabled with `nodesDraggable`)
102
+ * @default true
103
+ */
104
+ readonly?: boolean | undefined
105
+ /**
106
+ * If set, initial viewport will show all nodes & edges
107
+ * @default true
108
+ */
109
+ fitView?: boolean | undefined
110
+ /**
111
+ * Seems like this is percentage of the view size
112
+ * @default 0
113
+ */
114
+ fitViewPadding?: number | undefined
115
+ nodesSelectable?: boolean | undefined
116
+
117
+ /**
118
+ * @default false
119
+ */
120
+ nodesDraggable?: boolean | undefined
121
+
122
+ initialWidth?: number | undefined
123
+ initialHeight?: number | undefined
124
+
125
+ /**
126
+ * Keep aspect ratio of the diagram
127
+ * @default false
128
+ */
129
+ keepAspectRatio?: boolean | undefined
130
+
131
+ /**
132
+ * Background pattern
133
+ * @default 'dots'
134
+ */
135
+ background?: 'transparent' | 'solid' | XYBackgroundProps | undefined
136
+
137
+ /**
138
+ * Display hovercards with element links
139
+ * @default true
140
+ */
141
+ showElementLinks?: boolean | undefined
142
+ }
143
+
144
+ export interface LikeC4DiagramEventHandlers {
145
+ onChange?: OnChange | null | undefined
146
+ onNavigateTo?: OnNavigateTo | null | undefined
147
+ onNodeClick?: OnNodeClick | null | undefined
148
+ onNodeContextMenu?: OnNodeClick | null | undefined
149
+ onCanvasContextMenu?: OnCanvasClick | null | undefined
150
+ onEdgeClick?: OnEdgeClick | null | undefined
151
+ onEdgeContextMenu?: OnEdgeClick | null | undefined
152
+ onCanvasClick?: OnCanvasClick | null | undefined
153
+ onCanvasDblClick?: OnCanvasClick | null | undefined
154
+ }
@@ -0,0 +1,119 @@
1
+ import { ReactFlowProvider as XYFlowProvider } from '@xyflow/react'
2
+ import clsx from 'clsx'
3
+ import { useRef } from 'react'
4
+ import { rootClassName } from './globals.css'
5
+ import { cssDisablePan, cssNoControls, cssReactFlow, cssTransparentBg } from './LikeC4Diagram.css'
6
+ import { type LikeC4DiagramEventHandlers, type LikeC4DiagramProperties } from './LikeC4Diagram.props'
7
+ import { EnsureMantine } from './mantine/EnsureMantine'
8
+ import { DiagramContextProvider } from './state/DiagramContext'
9
+ import { WhenInitialized } from './state/WhenInitialized'
10
+ import { KeepAspectRatio } from './ui/KeepAspectRatio'
11
+ import OptionsPanel from './ui/OptionsPanel'
12
+ import { diagramViewToXYFlowData } from './xyflow/diagram-to-xyflow'
13
+ import { FitViewOnDiagramChange } from './xyflow/FitviewOnDiagramChange'
14
+ import { SyncWithDiagram } from './xyflow/SyncWithDiagram'
15
+ import type { XYFlowData } from './xyflow/types'
16
+ import { XYFlow } from './xyflow/XYFlowWrapper'
17
+
18
+ export type LikeC4DiagramProps = LikeC4DiagramProperties & LikeC4DiagramEventHandlers
19
+ export function LikeC4Diagram({
20
+ view,
21
+ className,
22
+ fitView = true,
23
+ fitViewPadding = 0,
24
+ readonly = true,
25
+ pannable = true,
26
+ zoomable = true,
27
+ nodesSelectable = !readonly,
28
+ nodesDraggable = !readonly,
29
+ background = 'dots',
30
+ controls = false,
31
+ showElementLinks = true,
32
+ initialWidth,
33
+ initialHeight,
34
+ keepAspectRatio = false,
35
+ onCanvasClick,
36
+ onCanvasContextMenu,
37
+ onCanvasDblClick,
38
+ onEdgeClick,
39
+ onChange,
40
+ onEdgeContextMenu,
41
+ onNavigateTo,
42
+ onNodeClick,
43
+ onNodeContextMenu
44
+ }: LikeC4DiagramProps) {
45
+ const initialRef = useRef<{
46
+ defaultNodes: XYFlowData['nodes']
47
+ defaultEdges: XYFlowData['edges']
48
+ initialWidth: number
49
+ initialHeight: number
50
+ }>()
51
+ if (!initialRef.current) {
52
+ const initial = diagramViewToXYFlowData(view, {
53
+ selectable: nodesSelectable,
54
+ draggable: nodesDraggable
55
+ })
56
+ initialRef.current = {
57
+ defaultNodes: initial.nodes,
58
+ defaultEdges: initial.edges,
59
+ initialWidth: initialWidth ?? view.width,
60
+ initialHeight: initialHeight ?? view.height
61
+ }
62
+ }
63
+ return (
64
+ <EnsureMantine>
65
+ <XYFlowProvider
66
+ fitView={fitView}
67
+ {...initialRef.current}
68
+ >
69
+ <DiagramContextProvider
70
+ view={view}
71
+ readonly={readonly}
72
+ fitViewEnabled={fitView}
73
+ fitViewPadding={fitViewPadding}
74
+ showElementLinks={showElementLinks}
75
+ nodesDraggable={nodesDraggable}
76
+ nodesSelectable={nodesSelectable}
77
+ onCanvasClick={onCanvasClick}
78
+ onCanvasContextMenu={onCanvasContextMenu}
79
+ onEdgeClick={onEdgeClick}
80
+ onEdgeContextMenu={onEdgeContextMenu}
81
+ onNodeClick={onNodeClick}
82
+ onNodeContextMenu={onNodeContextMenu}
83
+ onChange={onChange}
84
+ onNavigateTo={onNavigateTo}
85
+ onCanvasDblClick={onCanvasDblClick}
86
+ >
87
+ <KeepAspectRatio
88
+ className={clsx(rootClassName, className)}
89
+ enabled={keepAspectRatio}
90
+ width={view.width}
91
+ height={view.height}
92
+ >
93
+ <XYFlow
94
+ className={clsx(
95
+ 'likec4-diagram',
96
+ cssReactFlow,
97
+ controls === false && cssNoControls,
98
+ pannable !== true && cssDisablePan,
99
+ background === 'transparent' && cssTransparentBg
100
+ )}
101
+ background={background}
102
+ controls={controls}
103
+ defaultNodes={initialRef.current.defaultNodes}
104
+ defaultEdges={initialRef.current.defaultEdges}
105
+ pannable={pannable}
106
+ zoomable={zoomable}
107
+ >
108
+ {readonly !== true && <OptionsPanel />}
109
+ </XYFlow>
110
+ </KeepAspectRatio>
111
+ <WhenInitialized>
112
+ <SyncWithDiagram />
113
+ <FitViewOnDiagramChange />
114
+ </WhenInitialized>
115
+ </DiagramContextProvider>
116
+ </XYFlowProvider>
117
+ </EnsureMantine>
118
+ )
119
+ }
@@ -0,0 +1,39 @@
1
+ import { LikeC4Diagram } from './LikeC4Diagram'
2
+ import type { LikeC4DiagramProperties } from './LikeC4Diagram.props'
3
+
4
+ export type StaticLikeC4DiagramProps = Pick<
5
+ LikeC4DiagramProperties,
6
+ | 'view'
7
+ | 'keepAspectRatio'
8
+ | 'className'
9
+ | 'fitView'
10
+ | 'fitViewPadding'
11
+ | 'background'
12
+ | 'initialWidth'
13
+ | 'initialHeight'
14
+ >
15
+
16
+ export function StaticLikeC4Diagram({
17
+ view,
18
+ fitView = true,
19
+ fitViewPadding = 0,
20
+ background = 'transparent',
21
+ ...rest
22
+ }: StaticLikeC4DiagramProps) {
23
+ return (
24
+ <LikeC4Diagram
25
+ view={view}
26
+ readonly
27
+ fitView={fitView}
28
+ fitViewPadding={fitViewPadding}
29
+ pannable={false}
30
+ zoomable={false}
31
+ controls={false}
32
+ background={background}
33
+ showElementLinks
34
+ nodesSelectable={false}
35
+ nodesDraggable={false}
36
+ {...rest}
37
+ />
38
+ )
39
+ }
@@ -0,0 +1,128 @@
1
+ import type { ThemeColor } from '@likec4/core'
2
+ import { defaultTheme } from '@likec4/core'
3
+ import { createGlobalTheme } from '@vanilla-extract/css'
4
+ import { omit } from 'remeda'
5
+ import { mantine } from './mantine.css'
6
+ import { vars } from './theme.css'
7
+
8
+ export const rootClassName = 'likec4-diagram-root'
9
+
10
+ createGlobalTheme(`.${rootClassName}`, {
11
+ ...omit(vars, ['optionsPanel', 'default'])
12
+ }, {
13
+ likec4: {
14
+ font:
15
+ `var(--likec4-default-font-family,'ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"')`,
16
+ background: {
17
+ color: mantine.colors.body,
18
+ pattern: {
19
+ color: mantine.colors.dimmed
20
+ }
21
+ }
22
+ },
23
+ compound: {
24
+ font: vars.likec4.font,
25
+ titleColor: vars.element.loContrast
26
+ },
27
+ element: {
28
+ font: vars.likec4.font,
29
+ ...defaultTheme.elements.primary
30
+ },
31
+ relation: {
32
+ ...defaultTheme.relationships.slate
33
+ }
34
+ // likec4: {
35
+ // font: `var(--likec4-font-family,'ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"')`,
36
+ // backgroundColor: fallbackVar(globalvars.likec4.backgroundColor, mantine.colors.body)
37
+ // },
38
+ // compound: {
39
+ // font: fallbackVar(vars.compound.font, vars.likec4.font),
40
+ // titleColor: fallbackVar(globalvars.compound.titleColor, globalvars.element.loContrast),
41
+ // },
42
+ // element: {
43
+ // font: fallbackVar(globalvars.element.font, vars.likec4.font),
44
+ // fill: fallbackVar(globalvars.element.fill, defaultTheme.elements.primary.fill),
45
+ // stroke: fallbackVar(globalvars.element.stroke, defaultTheme.elements.primary.stroke),
46
+ // hiContrast: fallbackVar(globalvars.element.hiContrast, defaultTheme.elements.primary.hiContrast),
47
+ // loContrast: fallbackVar(globalvars.element.loContrast, defaultTheme.elements.primary.loContrast),
48
+ // },
49
+ // relation: {
50
+ // lineColor: fallbackVar(globalvars.relation.lineColor, defaultTheme.relationships.slate.lineColor),
51
+ // labelColor: fallbackVar(globalvars.relation.labelColor, defaultTheme.relationships.slate.labelColor),
52
+ // labelBgColor: fallbackVar(globalvars.relation.labelBgColor, defaultTheme.relationships.slate.labelBgColor),
53
+ // },
54
+ // optionsPanel: {
55
+ // top: globalvars.optionsPanel.top,
56
+ // right: globalvars.optionsPanel.right
57
+ // }
58
+ })
59
+
60
+ createGlobalTheme(`:where([data-mantine-color-scheme='light']) .${rootClassName}`, {
61
+ likec4: {
62
+ background: {
63
+ pattern: {
64
+ color: vars.likec4.background.pattern.color
65
+ }
66
+ }
67
+ }
68
+ }, {
69
+ likec4: {
70
+ background: {
71
+ pattern: {
72
+ color: mantine.colors.dark[3]
73
+ }
74
+ }
75
+ }
76
+ })
77
+
78
+ // globalStyle(`${scope} *, ${scope} *::before, ${scope} *::after`, {
79
+ // boxSizing: 'border-box',
80
+ // outline: 'none',
81
+ // borderWidth: 0,
82
+ // borderStyle: 'solid',
83
+ // borderColor: 'transparent',
84
+ // })
85
+
86
+ // createGlobalTheme(':where(.likec4-diagram-root)', {
87
+ // ...omit(vars, ['optionsPanel', 'defaults']),
88
+ // }, {
89
+ // likec4: {
90
+ // font: `var(--likec4-default-font-family,'ui-sans-serif,system-ui,sans-serif,"Apple Color Emoji","Segoe UI Emoji","Segoe UI Symbol","Noto Color Emoji"')`,
91
+ // backgroundColor: mantine.colors.body
92
+ // },
93
+ // compound: {
94
+ // font: vars.likec4.font,
95
+ // titleColor: vars.element.loContrast
96
+ // },
97
+ // element: {
98
+ // font: vars.likec4.font,
99
+ // ...defaultTheme.elements.primary
100
+ // },
101
+ // relation: {
102
+ // ...defaultTheme.relationships.slate
103
+ // }
104
+ // })
105
+
106
+ for (const color of Object.keys(defaultTheme.elements)) {
107
+ if (!(color in defaultTheme.elements) || !(color in defaultTheme.relationships)) {
108
+ continue
109
+ }
110
+ createGlobalTheme(`:where([data-likec4-color='${color}'])`, {
111
+ element: {
112
+ fill: vars.element.fill,
113
+ stroke: vars.element.stroke,
114
+ hiContrast: vars.element.hiContrast,
115
+ loContrast: vars.element.loContrast
116
+ },
117
+ compound: {
118
+ titleColor: vars.compound.titleColor
119
+ },
120
+ relation: vars.relation
121
+ }, {
122
+ element: defaultTheme.elements[color as ThemeColor],
123
+ compound: {
124
+ titleColor: defaultTheme.elements[color as ThemeColor].loContrast
125
+ },
126
+ relation: defaultTheme.relationships[color as ThemeColor]
127
+ })
128
+ }
@@ -0,0 +1,2 @@
1
+ export * from './useSetState'
2
+ export * from './useUpdateEffect'
@@ -0,0 +1,19 @@
1
+ import { shallowEqual } from 'fast-equals'
2
+ import { useCallback, useState } from 'react'
3
+ import type { NonEmptyObject } from 'type-fest'
4
+
5
+ export function useSetState<T extends object>(initialState: T | (() => T)) {
6
+ const [state, _setState] = useState(initialState)
7
+ const setState = useCallback(
8
+ (statePartial: NonEmptyObject<Partial<T>> | ((current: T) => NonEmptyObject<Partial<T>>)) =>
9
+ _setState((current) => {
10
+ const next = {
11
+ ...current,
12
+ ...typeof statePartial === 'function' ? statePartial(current) : statePartial
13
+ }
14
+ return shallowEqual(current, next) ? current : next
15
+ }),
16
+ []
17
+ )
18
+ return [state, setState] as const
19
+ }