@likec4/diagram 1.9.0 → 1.12.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 (113) hide show
  1. package/package.json +20 -43
  2. package/src/LikeC4CustomColors.tsx +5 -2
  3. package/src/LikeC4Diagram.css.ts +1 -1
  4. package/src/LikeC4Diagram.props.ts +40 -94
  5. package/src/LikeC4Diagram.tsx +14 -4
  6. package/src/LikeC4ModelProvider.tsx +21 -0
  7. package/src/StaticLikeC4Diagram.tsx +1 -0
  8. package/src/globals.css.ts +2 -3
  9. package/src/hooks/index.ts +1 -0
  10. package/src/hooks/useMantinePortalProps.ts +8 -0
  11. package/src/hooks/useXYFlow.ts +1 -2
  12. package/src/index.ts +9 -0
  13. package/src/likec4model/LikeC4ModelContext.ts +4 -0
  14. package/src/likec4model/index.ts +1 -0
  15. package/src/likec4model/useLikeC4Model.ts +58 -0
  16. package/src/state/diagram-to-xyflow.ts +1 -2
  17. package/src/state/diagramStore.ts +185 -66
  18. package/src/{theme.css.ts → theme-vars.ts} +11 -4
  19. package/src/ui/DiagramTitlePanel.css.ts +2 -3
  20. package/src/ui/DiagramTitlePanel.tsx +25 -3
  21. package/src/ui/DynamicViewWalkthrough.css.ts +28 -2
  22. package/src/ui/DynamicViewWalkthrough.tsx +97 -52
  23. package/src/ui/OptionsPanel.css.ts +1 -2
  24. package/src/ui/OptionsPanel.tsx +5 -2
  25. package/src/ui/notation/NotationPanel.css.ts +2 -3
  26. package/src/ui/notation/NotationPanel.tsx +10 -11
  27. package/src/ui/options/NodeOptions.tsx +4 -1
  28. package/src/ui/top-left/ChangeAutoLayoutButton.tsx +122 -71
  29. package/src/ui/top-left/TopLeftPanel.tsx +128 -117
  30. package/src/ui/top-left/_shared.ts +7 -6
  31. package/src/ui/top-left/styles.css.ts +48 -8
  32. package/src/utils/vector.ts +57 -0
  33. package/src/xyflow/FitviewOnDiagramChange.tsx +5 -4
  34. package/src/xyflow/SelectEdgesOnNodeFocus.tsx +7 -5
  35. package/src/xyflow/XYFlow.tsx +13 -17
  36. package/src/xyflow/XYFlowEvents.tsx +58 -58
  37. package/src/xyflow/XYFlowInner.tsx +4 -8
  38. package/src/xyflow/edges/EdgeLabel.tsx +185 -0
  39. package/src/xyflow/edges/RelationshipEdge.tsx +170 -137
  40. package/src/xyflow/edges/RelationshipsDropdownMenu.css.ts +60 -0
  41. package/src/xyflow/edges/RelationshipsDropdownMenu.tsx +214 -0
  42. package/src/xyflow/edges/edges.css.ts +75 -7
  43. package/src/xyflow/nodes/compound/CompoundNode.css.ts +1 -2
  44. package/src/xyflow/nodes/compound/CompoundNode.tsx +25 -8
  45. package/src/xyflow/nodes/element/ElementLink.css.ts +1 -1
  46. package/src/xyflow/nodes/element/ElementLink.tsx +4 -8
  47. package/src/xyflow/nodes/element/ElementNode.tsx +47 -8
  48. package/src/xyflow/nodes/element/element.css.ts +1 -2
  49. package/src/xyflow/nodes/shared/Toolbar.tsx +426 -0
  50. package/src/xyflow/types.ts +1 -24
  51. package/src/xyflow/useLayoutConstraints.ts +10 -6
  52. package/dist/LikeC4CustomColors.d.ts +0 -3
  53. package/dist/LikeC4CustomColors.props.d.ts +0 -5
  54. package/dist/LikeC4Diagram.css.d.ts +0 -4
  55. package/dist/LikeC4Diagram.d.ts +0 -7
  56. package/dist/LikeC4Diagram.props.d.ts +0 -154
  57. package/dist/StaticLikeC4Diagram.d.ts +0 -4
  58. package/dist/globals.css.d.ts +0 -1
  59. package/dist/hooks/index.d.ts +0 -4
  60. package/dist/hooks/useDiagramState.d.ts +0 -6
  61. package/dist/hooks/useSetState.d.ts +0 -3
  62. package/dist/hooks/useUpdateEffect.d.ts +0 -5
  63. package/dist/hooks/useXYFlow.d.ts +0 -267
  64. package/dist/index.d.ts +0 -9
  65. package/dist/index.mjs +0 -3684
  66. package/dist/mantine/EnsureMantine.d.ts +0 -8
  67. package/dist/mantine.css.d.ts +0 -3
  68. package/dist/state/DiagramContext.d.ts +0 -1192
  69. package/dist/state/diagram-to-xyflow.d.ts +0 -12
  70. package/dist/state/diagramStore.d.ts +0 -1268
  71. package/dist/style.css +0 -2139
  72. package/dist/theme.css.d.ts +0 -63
  73. package/dist/ui/DiagramTitlePanel.css.d.ts +0 -4
  74. package/dist/ui/DiagramTitlePanel.d.ts +0 -1
  75. package/dist/ui/DynamicViewWalkthrough.css.d.ts +0 -3
  76. package/dist/ui/DynamicViewWalkthrough.d.ts +0 -1
  77. package/dist/ui/OptionsPanel.css.d.ts +0 -1
  78. package/dist/ui/OptionsPanel.d.ts +0 -1
  79. package/dist/ui/notation/NotationPanel.css.d.ts +0 -6
  80. package/dist/ui/notation/NotationPanel.d.ts +0 -1
  81. package/dist/ui/notation/index.d.ts +0 -1
  82. package/dist/ui/options/EdgeOptions.d.ts +0 -19
  83. package/dist/ui/options/NodeOptions.d.ts +0 -19
  84. package/dist/ui/top-left/ChangeAutoLayoutButton.d.ts +0 -3
  85. package/dist/ui/top-left/TopLeftPanel.d.ts +0 -4
  86. package/dist/ui/top-left/_shared.d.ts +0 -5
  87. package/dist/ui/top-left/styles.css.d.ts +0 -3
  88. package/dist/xyflow/EdgeMarkers.d.ts +0 -12
  89. package/dist/xyflow/FitviewOnDiagramChange.d.ts +0 -4
  90. package/dist/xyflow/SelectEdgesOnNodeFocus.d.ts +0 -1
  91. package/dist/xyflow/XYFlow.d.ts +0 -12
  92. package/dist/xyflow/XYFlowBackground.d.ts +0 -11
  93. package/dist/xyflow/XYFlowEvents.d.ts +0 -161
  94. package/dist/xyflow/XYFlowInner.d.ts +0 -10
  95. package/dist/xyflow/const.d.ts +0 -7
  96. package/dist/xyflow/edges/RelationshipEdge.d.ts +0 -32
  97. package/dist/xyflow/edges/edges.css.d.ts +0 -12
  98. package/dist/xyflow/edges/utils.d.ts +0 -17
  99. package/dist/xyflow/nodes/compound/CompoundNode.css.d.ts +0 -11
  100. package/dist/xyflow/nodes/compound/CompoundNode.d.ts +0 -6
  101. package/dist/xyflow/nodes/compound/index.d.ts +0 -1
  102. package/dist/xyflow/nodes/element/ElementLink.css.d.ts +0 -3
  103. package/dist/xyflow/nodes/element/ElementLink.d.ts +0 -7
  104. package/dist/xyflow/nodes/element/ElementNode.d.ts +0 -6
  105. package/dist/xyflow/nodes/element/ElementShapeSvg.d.ts +0 -18
  106. package/dist/xyflow/nodes/element/element.css.d.ts +0 -19
  107. package/dist/xyflow/nodes/element/index.d.ts +0 -1
  108. package/dist/xyflow/nodes/shared/NavigateToBtn.d.ts +0 -5
  109. package/dist/xyflow/types.d.ts +0 -50
  110. package/dist/xyflow/useLayoutConstraints.d.ts +0 -9
  111. package/dist/xyflow/utils.d.ts +0 -18
  112. package/src/mantine.css.ts +0 -7
  113. package/src/reset.d.ts +0 -2
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@likec4/diagram",
3
- "version": "1.9.0",
3
+ "version": "1.12.1",
4
4
  "license": "MIT",
5
5
  "bugs": "https://github.com/likec4/likec4/issues",
6
6
  "homepage": "https://likec4.dev",
@@ -14,83 +14,60 @@
14
14
  "package.json",
15
15
  "LICENSE",
16
16
  "README.md",
17
- "dist",
18
17
  "src",
19
- "!dist/src",
20
18
  "!**/*.spec.*",
21
19
  "!**/*.d.ts.map"
22
20
  ],
23
21
  "sideEffects": false,
24
22
  "type": "module",
25
23
  "exports": {
26
- ".": {
27
- "types": "./dist/index.d.ts",
28
- "default": "./dist/index.mjs"
29
- },
30
- "./style.css": "./dist/style.css"
24
+ ".": "./src/index.ts"
31
25
  },
32
- "publishConfig": {
33
- "registry": "https://registry.npmjs.org",
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
- }
42
- },
43
- "packageManager": "yarn@4.3.1",
26
+ "packageManager": "yarn@4.5.0",
44
27
  "scripts": {
45
28
  "typecheck": "tsc --noEmit",
46
- "prepack": "vite build --mode production",
47
29
  "lint": "run -T eslint src/ --fix",
48
- "clean": "run -T rimraf -v -g 'dist/*' .tsbuildinfo"
30
+ "clean": "rm -r -f -g 'dist/*' .tsbuildinfo"
49
31
  },
50
32
  "dependencies": {
51
- "@likec4/core": "1.9.0",
52
- "@lume/kiwi": "^0.4.3",
33
+ "@likec4/core": "1.12.1",
34
+ "@lume/kiwi": "^0.4.4",
35
+ "@mantine/vanilla-extract": "7.13.2",
53
36
  "@react-hookz/web": "^24.0.4",
54
- "@tabler/icons-react": "^3.14.0",
55
- "@vanilla-extract/css": "^1.15.5",
37
+ "@tabler/icons-react": "^3.19.0",
38
+ "@vanilla-extract/css": "^1.16.0",
56
39
  "@vanilla-extract/css-utils": "^0.1.4",
57
40
  "@vanilla-extract/dynamic": "^2.1.2",
58
- "@xyflow/react": "12.1.1",
59
- "@xyflow/system": "0.0.39",
41
+ "@xyflow/react": "12.3.1",
42
+ "@xyflow/system": "0.0.43",
60
43
  "bezier-js": "^6.1.4",
61
44
  "clsx": "^2.1.1",
62
45
  "d3-shape": "^3.2.0",
63
46
  "esm-env": "^1.0.0",
64
47
  "fast-equals": "^5.0.1",
65
- "framer-motion": "^11.3.30",
48
+ "framer-motion": "^11.11.1",
66
49
  "khroma": "^2.1.0",
67
- "remeda": "^2.11.0",
68
- "type-fest": "^4.26.0",
50
+ "remeda": "^2.14.0",
51
+ "type-fest": "4.26.1",
69
52
  "zustand": "^4.5.5"
70
53
  },
71
54
  "peerDependencies": {
72
- "@mantine/core": "^7.11.2",
73
- "@mantine/hooks": "^7.11.2",
55
+ "@mantine/core": "^7.13.2",
56
+ "@mantine/hooks": "^7.13.2",
74
57
  "react": "^18.3.1",
75
58
  "react-dom": "^18.3.1"
76
59
  },
77
60
  "devDependencies": {
78
- "@likec4/tsconfig": "1.9.0",
79
- "@mantine/core": "7.12.2",
80
- "@mantine/hooks": "7.12.2",
81
- "@mantine/vanilla-extract": "7.12.2",
82
- "@total-typescript/ts-reset": "^0.5.1",
61
+ "@likec4/tsconfig": "1.12.1",
62
+ "@mantine/core": "7.13.2",
63
+ "@mantine/hooks": "7.13.2",
83
64
  "@types/bezier-js": "^4.1.3",
84
65
  "@types/d3-shape": "^3.1.6",
85
66
  "@types/react": "^18.3.4",
86
67
  "@types/react-dom": "^18.3.0",
87
- "@vanilla-extract/esbuild-plugin": "^2.3.10",
88
- "@vitejs/plugin-react": "^4.3.1",
89
68
  "execa": "^9.3.1",
90
69
  "react": "^18.3.1",
91
70
  "react-dom": "^18.3.1",
92
- "typescript": "^5.5.4",
93
- "vite": "5.3.4",
94
- "vite-plugin-dts": "^3.9.1"
71
+ "typescript": "^5.6.2"
95
72
  }
96
73
  }
@@ -1,7 +1,8 @@
1
1
  import { type ThemeColorValues } from '@likec4/core'
2
2
  import { entries } from 'remeda'
3
3
  import type { LikeC4CustomColorsProperties } from './LikeC4CustomColors.props'
4
- import { vars } from './theme.css'
4
+ import { vars } from './theme-vars'
5
+ import { useMantineStyleNonce } from '@mantine/core'
5
6
 
6
7
  type CSSVarFunction = `var(--${string})` | `var(--${string}, ${string | number} )`
7
8
 
@@ -28,10 +29,12 @@ export function LikeC4CustomColors({ customColors }: LikeC4CustomColorsPropertie
28
29
  const styles = entries(customColors)
29
30
  .map(([name, color]) => toStyle(name, color))
30
31
  .join('\n')
32
+
33
+ const nonce = useMantineStyleNonce()?.()
31
34
 
32
35
  return (
33
36
  <>
34
- <style type="text/css" dangerouslySetInnerHTML={{ __html: styles }} />
37
+ <style type="text/css" dangerouslySetInnerHTML={{ __html: styles }} {...(nonce && { nonce })} />
35
38
  </>
36
39
  )
37
40
  }
@@ -1,5 +1,5 @@
1
1
  import { globalStyle, style } from '@vanilla-extract/css'
2
- import { vars, xyvars } from './theme.css'
2
+ import { vars, xyvars } from './theme-vars'
3
3
 
4
4
  export const cssReactFlow = style({
5
5
  '@supports': {
@@ -9,69 +9,12 @@ import type {
9
9
  WhereOperator
10
10
  } from '@likec4/core'
11
11
  import type { MouseEvent as ReactMouseEvent, ReactNode } from 'react'
12
- import type { XYFlowEdge, XYFlowNode } from './xyflow/types'
13
12
  import type { XYBackground } from './xyflow/XYFlowBackground'
14
13
 
15
- // type EqualOperator<V> = {
16
- // eq: V
17
- // neq?: never
18
- // } | {
19
- // eq?: never
20
- // neq: V
21
- // }
22
-
23
- // type AllNever = {
24
- // not?: never
25
- // and?: never
26
- // or?: never
27
- // tag?: never
28
- // kind?: never
29
- // }
30
-
31
- // type TagKindOperator<Tag, Kind> =
32
- // & Omit<AllNever, 'tag' | 'kind'>
33
- // & ({
34
- // tag: EqualOperator<Tag>
35
- // kind?: never
36
- // } | {
37
- // tag?: never
38
- // kind: EqualOperator<Kind>
39
- // })
40
-
41
- // type NotOperator<Tag, Kind> = Omit<AllNever, 'not'> & {
42
- // not: TagKindOperator<Tag, Kind> | AndOperator<Tag, Kind> | OrOperator<Tag, Kind>
43
- // }
44
-
45
- // type AndOperator<Tag, Kind> = Omit<AllNever, 'and'> & {
46
- // and: NonEmptyArray<
47
- // | TagKindOperator<Tag, Kind>
48
- // | OrOperator<Tag, Kind>
49
- // | NotOperator<Tag, Kind>
50
- // >
51
- // }
52
-
53
- // type OrOperator<Tag, Kind> = Omit<AllNever, 'or'> & {
54
- // or: NonEmptyArray<
55
- // | TagKindOperator<Tag, Kind>
56
- // | AndOperator<Tag, Kind>
57
- // | NotOperator<Tag, Kind>
58
- // >
59
- // }
60
-
61
- // // export const isOrOperator = (operator: WhereOperator): operator is OrOperator<WhereOperator> => {
62
- // // return 'or' in operator
63
- // // }
64
-
65
- // export type WhereOperator<Tag extends string, Kind extends string> =
66
- // | TagKindOperator<Tag, Kind>
67
- // | NotOperator<Tag, Kind>
68
- // | AndOperator<Tag, Kind>
69
- // | OrOperator<Tag, Kind>
70
-
71
14
  export type { WhereOperator }
72
15
 
73
- export type DiagramNodeWithNavigate = Omit<DiagramNode, 'navigateTo'> & {
74
- navigateTo: ViewID
16
+ export type DiagramNodeWithNavigate<ID extends string = ViewID> = Omit<DiagramNode, 'navigateTo'> & {
17
+ navigateTo: ID
75
18
  }
76
19
 
77
20
  type ElementIconNodeProps = {
@@ -84,28 +27,21 @@ export type ElementIconRenderer = (props: {
84
27
  node: ElementIconNodeProps
85
28
  }) => ReactNode
86
29
 
87
- export type OnNavigateTo = {
88
- (
89
- to: ViewID,
90
- // These fields present if navigateTo triggered by a node click
91
- event?: ReactMouseEvent,
92
- element?: DiagramNodeWithNavigate,
93
- xynode?: XYFlowNode
94
- ): void
95
- }
30
+ export type OnNavigateTo<ID extends string = ViewID> = (
31
+ to: ID,
32
+ // These fields present if navigateTo triggered by a node click
33
+ event?: ReactMouseEvent,
34
+ element?: DiagramNodeWithNavigate<ID>
35
+ ) => void
36
+
96
37
  export type OnNodeClick = (
97
- event: {
98
- element: DiagramNode
99
- xynode: XYFlowNode
100
- event: ReactMouseEvent
101
- }
38
+ node: DiagramNode,
39
+ event: ReactMouseEvent
102
40
  ) => void
41
+
103
42
  export type OnEdgeClick = (
104
- event: {
105
- edge: DiagramEdge
106
- xyedge: XYFlowEdge
107
- event: ReactMouseEvent
108
- }
43
+ edge: DiagramEdge,
44
+ event: ReactMouseEvent
109
45
  ) => void
110
46
 
111
47
  /**
@@ -116,9 +52,8 @@ export type OnCanvasClick = (event: ReactMouseEvent) => void
116
52
  export type ChangeEvent = {
117
53
  change: ViewChange
118
54
  }
119
- export type OnChange = {
120
- (event: ChangeEvent): void
121
- }
55
+ export type OnChange = (event: ChangeEvent) => void
56
+
122
57
  export type LikeC4ColorScheme = 'light' | 'dark'
123
58
 
124
59
  export interface LikeC4DiagramProperties {
@@ -127,15 +62,7 @@ export interface LikeC4DiagramProperties {
127
62
  className?: string | undefined
128
63
 
129
64
  /**
130
- * Controls color scheme used for styling the flow
131
- * By default inherits from system or surrounding MantineProvider
132
- *
133
- * @example 'light' | 'dark'
134
- */
135
- // colorScheme?: LikeC4ColorScheme | undefined
136
-
137
- /**
138
- * Show/hide controls menu
65
+ * Show/hide ReactFlow controls menu
139
66
  * @default false
140
67
  */
141
68
  controls?: boolean | undefined
@@ -165,10 +92,13 @@ export interface LikeC4DiagramProperties {
165
92
  */
166
93
  fitViewPadding?: number | undefined
167
94
 
95
+ /**
96
+ * @default false if readonly
97
+ */
168
98
  nodesSelectable?: boolean | undefined
169
99
 
170
100
  /**
171
- * @default false
101
+ * @default false if readonly
172
102
  */
173
103
  nodesDraggable?: boolean | undefined
174
104
 
@@ -194,14 +124,14 @@ export interface LikeC4DiagramProperties {
194
124
  showElementLinks?: boolean | undefined
195
125
 
196
126
  /**
197
- * Display panel with diagram title / description
127
+ * Display webview with diagram title / description
198
128
  * @default true
199
129
  */
200
130
  showDiagramTitle?: boolean | undefined
201
131
 
202
132
  /**
203
133
  * Show back/forward navigation buttons
204
- * @default false
134
+ * @default true if `onNavigateTo` is set
205
135
  */
206
136
  showNavigationButtons?: undefined | boolean
207
137
 
@@ -211,6 +141,12 @@ export interface LikeC4DiagramProperties {
211
141
  */
212
142
  showNotations?: boolean | undefined
213
143
 
144
+ /**
145
+ * Display dropdown with details on relationship's label click
146
+ * @default true
147
+ */
148
+ showRelationshipDetails?: boolean | undefined
149
+
214
150
  /**
215
151
  * If double click on a node should enable focus mode, i.e. highlight incoming/outgoing edges
216
152
  * @default true
@@ -230,11 +166,14 @@ export interface LikeC4DiagramProperties {
230
166
  experimentalEdgeEditing?: boolean | undefined
231
167
 
232
168
  /**
233
- * Render custom icon for a node
169
+ * Render icon for an element, bundled or remote
234
170
  * By default, if icon is http:// or https://, it will be rendered as an image
235
171
  */
236
172
  renderIcon?: ElementIconRenderer | undefined
237
173
 
174
+ /**
175
+ * Dynamic filter, applies both to nodes and edges
176
+ */
238
177
  where?: WhereOperator<string, string> | undefined
239
178
  }
240
179
 
@@ -249,8 +188,15 @@ export interface LikeC4DiagramEventHandlers {
249
188
  onCanvasClick?: OnCanvasClick | null | undefined
250
189
  onCanvasDblClick?: OnCanvasClick | null | undefined
251
190
 
191
+ // if set, will render a burger menu icon in the top left corner
252
192
  onBurgerMenuClick?: null | undefined | (() => void)
193
+
194
+ // if set, will render a source code icon in the top left corner
253
195
  onOpenSourceView?: null | undefined | (() => void)
196
+
197
+ // if set, will render an icon in properties webview for each element
254
198
  onOpenSourceElement?: null | undefined | ((fqn: Fqn) => void)
199
+
200
+ // if set, will be called on edge click
255
201
  onOpenSourceRelation?: null | undefined | ((id: RelationID) => void)
256
202
  }
@@ -2,13 +2,14 @@ import type { DiagramView } from '@likec4/core'
2
2
  import { ReactFlowProvider as XYFlowProvider } from '@xyflow/react'
3
3
  import clsx from 'clsx'
4
4
  import { shallowEqual } from 'fast-equals'
5
- import { domAnimation, LazyMotion } from 'framer-motion'
6
- import { memo, useRef } from 'react'
5
+ import { domMax, LazyMotion } from 'framer-motion'
6
+ import { memo, useEffect, useRef } from 'react'
7
7
  import { rootClassName } from './globals.css'
8
8
  import { useDiagramState } from './hooks/useDiagramState'
9
9
  import { LikeC4CustomColors } from './LikeC4CustomColors'
10
10
  import * as css from './LikeC4Diagram.css'
11
11
  import { type LikeC4DiagramEventHandlers, type LikeC4DiagramProperties } from './LikeC4Diagram.props'
12
+ import { useLikeC4Model } from './likec4model'
12
13
  import { EnsureMantine } from './mantine/EnsureMantine'
13
14
  import { DiagramContextProvider } from './state/DiagramContext'
14
15
  import { FitViewOnDiagramChange } from './xyflow/FitviewOnDiagramChange'
@@ -33,6 +34,7 @@ export function LikeC4Diagram({
33
34
  showElementLinks = true,
34
35
  showDiagramTitle = true,
35
36
  showNotations = true,
37
+ showRelationshipDetails = true,
36
38
  enableDynamicViewWalkthrough = false,
37
39
  enableFocusMode = false,
38
40
  initialWidth,
@@ -56,6 +58,7 @@ export function LikeC4Diagram({
56
58
  where,
57
59
  showNavigationButtons = !!onNavigateTo
58
60
  }: LikeC4DiagramProps) {
61
+ const hasLikec4model = !!useLikeC4Model()
59
62
  const initialRef = useRef({
60
63
  defaultNodes: [] as XYFlowNode[],
61
64
  defaultEdges: [] as XYFlowEdge[],
@@ -65,9 +68,15 @@ export function LikeC4Diagram({
65
68
  if (readonly !== true && !!where) {
66
69
  console.warn('where filter is only supported in readonly mode')
67
70
  }
71
+ useEffect(() => {
72
+ if (showRelationshipDetails && !hasLikec4model) {
73
+ console.warn('Relationship details require LikeC4ModelProvider')
74
+ }
75
+ }, [showRelationshipDetails, hasLikec4model])
76
+
68
77
  return (
69
78
  <EnsureMantine>
70
- <LazyMotion features={domAnimation} strict>
79
+ <LazyMotion features={domMax} strict>
71
80
  <XYFlowProvider
72
81
  fitView={fitView}
73
82
  {...initialRef.current}
@@ -85,6 +94,7 @@ export function LikeC4Diagram({
85
94
  showElementLinks={showElementLinks}
86
95
  showNavigationButtons={showNavigationButtons}
87
96
  showNotations={showNotations}
97
+ showRelationshipDetails={showRelationshipDetails && hasLikec4model}
88
98
  nodesDraggable={nodesDraggable}
89
99
  nodesSelectable={nodesSelectable}
90
100
  experimentalEdgeEditing={experimentalEdgeEditing}
@@ -124,7 +134,7 @@ type LikeC4DiagramInnerProps = {
124
134
  controls: boolean
125
135
  showDiagramTitle: boolean
126
136
  }
127
- const LikeC4DiagramInnerMemo = memo<LikeC4DiagramInnerProps>(function LikeC4DiagramInner({
137
+ const LikeC4DiagramInnerMemo = /* @__PURE__ */ memo<LikeC4DiagramInnerProps>(function LikeC4DiagramInner({
128
138
  background,
129
139
  controls,
130
140
  showDiagramTitle
@@ -0,0 +1,21 @@
1
+ import type { LikeC4Model } from '@likec4/core'
2
+ import { type PropsWithChildren } from 'react'
3
+ import { LikeC4ModelContext } from './likec4model/LikeC4ModelContext'
4
+
5
+ export type LikeC4ModelProviderProps = PropsWithChildren<{
6
+ likec4model: LikeC4Model
7
+ }>
8
+
9
+ /**
10
+ * Ensures LikeC4Model context
11
+ */
12
+ export function LikeC4ModelProvider({
13
+ children,
14
+ likec4model
15
+ }: LikeC4ModelProviderProps) {
16
+ return (
17
+ <LikeC4ModelContext.Provider value={likec4model}>
18
+ {children}
19
+ </LikeC4ModelContext.Provider>
20
+ )
21
+ }
@@ -35,6 +35,7 @@ export function StaticLikeC4Diagram({
35
35
  showElementLinks
36
36
  showDiagramTitle={false}
37
37
  showNotations={false}
38
+ showRelationshipDetails={false}
38
39
  enableDynamicViewWalkthrough={false}
39
40
  enableFocusMode={false}
40
41
  nodesSelectable={false}
@@ -2,8 +2,7 @@ import { defaultTheme } from '@likec4/core'
2
2
  import { createGlobalTheme, globalStyle } from '@vanilla-extract/css'
3
3
  import { scale, toHex } from 'khroma'
4
4
  import { keys, omit } from 'remeda'
5
- import { mantine, whereDark } from './mantine.css'
6
- import { vars } from './theme.css'
5
+ import { mantine, vars, whereDark } from './theme-vars'
7
6
 
8
7
  export const rootClassName = 'likec4-diagram-root'
9
8
 
@@ -18,7 +17,7 @@ globalStyle(`.${rootClassName}`, {
18
17
  WebkitFontSmoothing: mantine.webkitFontSmoothing,
19
18
  MozOsxFontSmoothing: mantine.mozFontSmoothing
20
19
  })
21
- globalStyle(`.${rootClassName} .mantine-ActionIcon-icon .tabler-icon`, {
20
+ globalStyle(`:where(.${rootClassName}) .mantine-ActionIcon-icon .tabler-icon`, {
22
21
  width: '75%',
23
22
  height: '75%'
24
23
  })
@@ -1,4 +1,5 @@
1
1
  export * from './useDiagramState'
2
+ export * from './useMantinePortalProps'
2
3
  export * from './useSetState'
3
4
  export * from './useUpdateEffect'
4
5
  export * from './useXYFlow'
@@ -0,0 +1,8 @@
1
+ import { useMemo } from 'react'
2
+
3
+ import { useDiagramState } from './useDiagramState'
4
+
5
+ export function useMantinePortalProps() {
6
+ const target = useDiagramState(s => s.getContainer())
7
+ return useMemo(() => target ? { portalProps: { target }, withinPortal: true } : { withinPortal: false }, [target])
8
+ }
@@ -12,8 +12,7 @@ export function useXYStore<StateSlice = unknown>(
12
12
  equalityFn?: (a: StateSlice, b: StateSlice) => boolean
13
13
  ): StateSlice {
14
14
  return useStore(
15
- // @ts-expect-error - types are not correct
16
- selector,
15
+ selector as any,
17
16
  equalityFn ?? shallowEqual
18
17
  )
19
18
  }
package/src/index.ts CHANGED
@@ -1,11 +1,20 @@
1
1
  import '@xyflow/react/dist/style.css'
2
2
 
3
3
  export { LikeC4Diagram } from './LikeC4Diagram'
4
+ export {
5
+ useLikeC4DiagramView,
6
+ useLikeC4Model,
7
+ useLikeC4View,
8
+ useLikeC4ViewModel,
9
+ useLikeC4Views
10
+ } from './likec4model/useLikeC4Model'
11
+ export { LikeC4ModelProvider } from './LikeC4ModelProvider'
4
12
  export { StaticLikeC4Diagram } from './StaticLikeC4Diagram'
5
13
 
6
14
  export { useSetState } from './hooks/useSetState'
7
15
  export { useUpdateEffect } from './hooks/useUpdateEffect'
8
16
  export type * from './LikeC4Diagram'
9
17
  export type * from './LikeC4Diagram.props'
18
+ export type * from './LikeC4ModelProvider'
10
19
  export type * from './StaticLikeC4Diagram'
11
20
  export type * from './xyflow/types'
@@ -0,0 +1,4 @@
1
+ import type { LikeC4Model } from '@likec4/core'
2
+ import { createContext } from 'react'
3
+
4
+ export const LikeC4ModelContext = createContext<LikeC4Model | null>(null)
@@ -0,0 +1 @@
1
+ export * from './useLikeC4Model'
@@ -0,0 +1,58 @@
1
+ import { type ComputedView, type DiagramView, type LikeC4Model, type ViewID } from '@likec4/core'
2
+ import { useContext } from 'react'
3
+ import { isDefined, isNonNullish, isString } from 'remeda'
4
+ import type { LiteralUnion } from 'type-fest'
5
+ import { LikeC4ModelContext } from './LikeC4ModelContext'
6
+
7
+ export function useLikeC4Model(): LikeC4Model | null
8
+ export function useLikeC4Model(strict: true): LikeC4Model
9
+ export function useLikeC4Model(strict: boolean): LikeC4Model | null
10
+ export function useLikeC4Model(strict: true, type: 'layouted'): LikeC4Model.Layouted
11
+ export function useLikeC4Model(strict: true, type: 'computed'): LikeC4Model.Computed
12
+ export function useLikeC4Model(strict: true, type: LikeC4Model['type'] | undefined): LikeC4Model
13
+ export function useLikeC4Model(strict: boolean, type: 'layouted'): LikeC4Model.Layouted | null
14
+ export function useLikeC4Model(strict: boolean, type: 'computed'): LikeC4Model.Computed | null
15
+ export function useLikeC4Model(strict: boolean, type: LikeC4Model['type'] | undefined): LikeC4Model | null
16
+ export function useLikeC4Model(strict?: boolean, type?: LikeC4Model['type']) {
17
+ const model = useContext(LikeC4ModelContext)
18
+
19
+ if (isString(type) && isNonNullish(model) && model.type !== type) {
20
+ throw new Error(`Invalid LikeC4ModelContext, expected "${type}" but got "${model.type}" in context`)
21
+ }
22
+
23
+ if (isDefined(strict) && strict === true && !model) {
24
+ throw new Error('No LikeC4Model found in context')
25
+ }
26
+ return model
27
+ }
28
+
29
+ export function useLikeC4Views(): LikeC4Model.SourceModel['views'] {
30
+ return useLikeC4Model(true).sourcemodel.views
31
+ }
32
+
33
+ export function useLikeC4ViewModel(viewId: LiteralUnion<ViewID, string>): LikeC4Model.ViewModel {
34
+ return useLikeC4Model(true).view(viewId)
35
+ }
36
+
37
+ /**
38
+ * Parsed view, computed or layouted
39
+ */
40
+ export function useLikeC4View(viewId: LiteralUnion<ViewID, string>): ComputedView | DiagramView | null {
41
+ const model = useLikeC4Model(true)
42
+ try {
43
+ return model.view(viewId).view
44
+ } catch (error) {
45
+ console.warn(error)
46
+ return null
47
+ }
48
+ }
49
+
50
+ export function useLikeC4DiagramView(viewId: LiteralUnion<ViewID, string>): DiagramView | null {
51
+ const model = useLikeC4Model(true, 'layouted')
52
+ try {
53
+ return model.view(viewId).view
54
+ } catch (error) {
55
+ console.warn(error)
56
+ return null
57
+ }
58
+ }
@@ -1,5 +1,5 @@
1
- import { extractStep, invariant, nonNullable, whereOperatorAsPredicate } from '@likec4/core'
2
1
  import type { DiagramEdge, DiagramNode, DiagramView, Fqn } from '@likec4/core'
2
+ import { nonNullable, whereOperatorAsPredicate } from '@likec4/core'
3
3
  import { hasAtLeast } from 'remeda'
4
4
  import type { WhereOperator } from '../LikeC4Diagram.props'
5
5
  import { ZIndexes } from '../xyflow/const'
@@ -122,7 +122,6 @@ export function diagramViewToXYFlowData(
122
122
  data: {
123
123
  edge,
124
124
  controlPoints: edge.controlPoints || null,
125
- stepNum: isDynamicView ? extractStep(edge.id) : null,
126
125
  label: !!edge.labelBBox
127
126
  ? {
128
127
  bbox: edge.labelBBox,