@likec4/diagram 1.8.1 → 1.12.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/package.json +21 -45
- package/src/LikeC4CustomColors.props.ts +5 -0
- package/src/LikeC4CustomColors.tsx +37 -0
- package/src/LikeC4Diagram.css.ts +1 -1
- package/src/LikeC4Diagram.props.ts +43 -95
- package/src/LikeC4Diagram.tsx +21 -2
- package/src/LikeC4ModelProvider.tsx +49 -0
- package/src/StaticLikeC4Diagram.tsx +1 -0
- package/src/globals.css.ts +2 -3
- package/src/hooks/index.ts +1 -0
- package/src/hooks/useMantinePortalProps.ts +8 -0
- package/src/hooks/useXYFlow.ts +1 -2
- package/src/index.ts +3 -0
- package/src/likec4model/LikeC4ModelContext.ts +4 -0
- package/src/likec4model/index.ts +1 -0
- package/src/likec4model/useLikeC4Model.ts +55 -0
- package/src/mantine/EnsureMantine.tsx +1 -0
- package/src/state/DiagramContext.tsx +1 -0
- package/src/state/diagram-to-xyflow.ts +2 -3
- package/src/state/diagramStore.ts +185 -66
- package/src/{theme.css.ts → theme-vars.ts} +11 -4
- package/src/ui/DiagramTitlePanel.css.ts +2 -3
- package/src/ui/DiagramTitlePanel.tsx +17 -1
- package/src/ui/DynamicViewWalkthrough.css.ts +28 -2
- package/src/ui/DynamicViewWalkthrough.tsx +97 -52
- package/src/ui/OptionsPanel.css.ts +1 -2
- package/src/ui/OptionsPanel.tsx +1 -1
- package/src/ui/notation/NotationPanel.css.ts +2 -3
- package/src/ui/notation/NotationPanel.tsx +11 -12
- package/src/ui/options/NodeOptions.tsx +1 -1
- package/src/ui/top-left/ChangeAutoLayoutButton.tsx +20 -32
- package/src/ui/top-left/TopLeftPanel.tsx +128 -117
- package/src/ui/top-left/_shared.ts +7 -6
- package/src/ui/top-left/styles.css.ts +17 -8
- package/src/utils/vector.ts +57 -0
- package/src/xyflow/FitviewOnDiagramChange.tsx +5 -4
- package/src/xyflow/SelectEdgesOnNodeFocus.tsx +7 -5
- package/src/xyflow/XYFlow.tsx +10 -11
- package/src/xyflow/XYFlowEvents.tsx +59 -60
- package/src/xyflow/XYFlowInner.tsx +5 -5
- package/src/xyflow/edges/EdgeLabel.tsx +185 -0
- package/src/xyflow/edges/RelationshipEdge.tsx +170 -137
- package/src/xyflow/edges/RelationshipsDropdownMenu.css.ts +60 -0
- package/src/xyflow/edges/RelationshipsDropdownMenu.tsx +214 -0
- package/src/xyflow/edges/edges.css.ts +75 -7
- package/src/xyflow/nodes/compound/CompoundNode.css.ts +1 -2
- package/src/xyflow/nodes/compound/CompoundNode.tsx +4 -4
- package/src/xyflow/nodes/element/ElementLink.css.ts +1 -1
- package/src/xyflow/nodes/element/ElementLink.tsx +3 -8
- package/src/xyflow/nodes/element/ElementNode.tsx +47 -4
- package/src/xyflow/nodes/element/element.css.ts +1 -2
- package/src/xyflow/types.ts +1 -24
- package/src/xyflow/useLayoutConstraints.ts +10 -6
- package/src/xyflow/utils.ts +1 -1
- package/dist/LikeC4Diagram.css.d.ts +0 -4
- package/dist/LikeC4Diagram.d.ts +0 -4
- package/dist/LikeC4Diagram.props.d.ts +0 -185
- package/dist/StaticLikeC4Diagram.d.ts +0 -4
- package/dist/globals.css.d.ts +0 -1
- package/dist/hooks/index.d.ts +0 -4
- package/dist/hooks/useDiagramState.d.ts +0 -6
- package/dist/hooks/useSetState.d.ts +0 -3
- package/dist/hooks/useUpdateEffect.d.ts +0 -5
- package/dist/hooks/useXYFlow.d.ts +0 -267
- package/dist/index.d.ts +0 -9
- package/dist/index.mjs +0 -3651
- package/dist/mantine/EnsureMantine.d.ts +0 -5
- package/dist/mantine.css.d.ts +0 -3
- package/dist/state/DiagramContext.d.ts +0 -1189
- package/dist/state/diagram-to-xyflow.d.ts +0 -12
- package/dist/state/diagramStore.d.ts +0 -1268
- package/dist/style.css +0 -2139
- package/dist/theme.css.d.ts +0 -63
- package/dist/ui/DiagramTitlePanel.css.d.ts +0 -4
- package/dist/ui/DiagramTitlePanel.d.ts +0 -1
- package/dist/ui/DynamicViewWalkthrough.css.d.ts +0 -3
- package/dist/ui/DynamicViewWalkthrough.d.ts +0 -1
- package/dist/ui/OptionsPanel.css.d.ts +0 -1
- package/dist/ui/OptionsPanel.d.ts +0 -1
- package/dist/ui/notation/NotationPanel.css.d.ts +0 -6
- package/dist/ui/notation/NotationPanel.d.ts +0 -1
- package/dist/ui/notation/index.d.ts +0 -1
- package/dist/ui/options/EdgeOptions.d.ts +0 -19
- package/dist/ui/options/NodeOptions.d.ts +0 -19
- package/dist/ui/top-left/ChangeAutoLayoutButton.d.ts +0 -3
- package/dist/ui/top-left/TopLeftPanel.d.ts +0 -4
- package/dist/ui/top-left/_shared.d.ts +0 -5
- package/dist/ui/top-left/styles.css.d.ts +0 -3
- package/dist/xyflow/EdgeMarkers.d.ts +0 -12
- package/dist/xyflow/FitviewOnDiagramChange.d.ts +0 -4
- package/dist/xyflow/SelectEdgesOnNodeFocus.d.ts +0 -1
- package/dist/xyflow/XYFlow.d.ts +0 -9
- package/dist/xyflow/XYFlowBackground.d.ts +0 -11
- package/dist/xyflow/XYFlowEvents.d.ts +0 -161
- package/dist/xyflow/XYFlowInner.d.ts +0 -10
- package/dist/xyflow/const.d.ts +0 -7
- package/dist/xyflow/edges/RelationshipEdge.d.ts +0 -32
- package/dist/xyflow/edges/edges.css.d.ts +0 -12
- package/dist/xyflow/edges/utils.d.ts +0 -17
- package/dist/xyflow/nodes/compound/CompoundNode.css.d.ts +0 -11
- package/dist/xyflow/nodes/compound/CompoundNode.d.ts +0 -6
- package/dist/xyflow/nodes/compound/index.d.ts +0 -1
- package/dist/xyflow/nodes/element/ElementLink.css.d.ts +0 -3
- package/dist/xyflow/nodes/element/ElementLink.d.ts +0 -7
- package/dist/xyflow/nodes/element/ElementNode.d.ts +0 -6
- package/dist/xyflow/nodes/element/ElementShapeSvg.d.ts +0 -18
- package/dist/xyflow/nodes/element/element.css.d.ts +0 -19
- package/dist/xyflow/nodes/element/index.d.ts +0 -1
- package/dist/xyflow/nodes/shared/NavigateToBtn.d.ts +0 -5
- package/dist/xyflow/types.d.ts +0 -50
- package/dist/xyflow/useLayoutConstraints.d.ts +0 -9
- package/dist/xyflow/utils.d.ts +0 -18
- package/src/mantine.css.ts +0 -7
- 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.
|
|
3
|
+
"version": "1.12.0",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"bugs": "https://github.com/likec4/likec4/issues",
|
|
6
6
|
"homepage": "https://likec4.dev",
|
|
@@ -14,84 +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
|
-
"
|
|
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": "
|
|
30
|
+
"clean": "rm -r -f -g 'dist/*' .tsbuildinfo"
|
|
49
31
|
},
|
|
50
32
|
"dependencies": {
|
|
51
|
-
"@
|
|
33
|
+
"@likec4/core": "1.12.0",
|
|
34
|
+
"@lume/kiwi": "^0.4.4",
|
|
35
|
+
"@mantine/vanilla-extract": "7.12.2",
|
|
52
36
|
"@react-hookz/web": "^24.0.4",
|
|
53
|
-
"@tabler/icons-react": "^3.
|
|
54
|
-
"@vanilla-extract/css": "^1.
|
|
37
|
+
"@tabler/icons-react": "^3.19.0",
|
|
38
|
+
"@vanilla-extract/css": "^1.16.0",
|
|
55
39
|
"@vanilla-extract/css-utils": "^0.1.4",
|
|
56
40
|
"@vanilla-extract/dynamic": "^2.1.2",
|
|
57
|
-
"@xyflow/react": "12.
|
|
58
|
-
"@xyflow/system": "0.0.
|
|
41
|
+
"@xyflow/react": "12.3.1",
|
|
42
|
+
"@xyflow/system": "0.0.43",
|
|
59
43
|
"bezier-js": "^6.1.4",
|
|
60
44
|
"clsx": "^2.1.1",
|
|
61
45
|
"d3-shape": "^3.2.0",
|
|
62
46
|
"esm-env": "^1.0.0",
|
|
63
47
|
"fast-equals": "^5.0.1",
|
|
64
|
-
"framer-motion": "^11.
|
|
65
|
-
"
|
|
48
|
+
"framer-motion": "^11.5.6",
|
|
49
|
+
"khroma": "^2.1.0",
|
|
50
|
+
"remeda": "^2.14.0",
|
|
51
|
+
"type-fest": "4.26.1",
|
|
66
52
|
"zustand": "^4.5.5"
|
|
67
53
|
},
|
|
68
54
|
"peerDependencies": {
|
|
69
|
-
"@
|
|
70
|
-
"@mantine/
|
|
71
|
-
"@mantine/hooks": "^7.11.2",
|
|
55
|
+
"@mantine/core": "^7.12.2",
|
|
56
|
+
"@mantine/hooks": "^7.12.2",
|
|
72
57
|
"react": "^18.3.1",
|
|
73
58
|
"react-dom": "^18.3.1"
|
|
74
59
|
},
|
|
75
60
|
"devDependencies": {
|
|
76
|
-
"@likec4/
|
|
77
|
-
"@
|
|
78
|
-
"@mantine/
|
|
79
|
-
"@mantine/hooks": "7.11.2",
|
|
80
|
-
"@mantine/vanilla-extract": "7.11.2",
|
|
81
|
-
"@total-typescript/ts-reset": "^0.5.1",
|
|
61
|
+
"@likec4/tsconfig": "1.12.0",
|
|
62
|
+
"@mantine/core": "7.12.2",
|
|
63
|
+
"@mantine/hooks": "7.12.2",
|
|
82
64
|
"@types/bezier-js": "^4.1.3",
|
|
83
65
|
"@types/d3-shape": "^3.1.6",
|
|
84
66
|
"@types/react": "^18.3.4",
|
|
85
67
|
"@types/react-dom": "^18.3.0",
|
|
86
|
-
"@vanilla-extract/esbuild-plugin": "^2.3.10",
|
|
87
|
-
"@vitejs/plugin-react": "^4.3.1",
|
|
88
68
|
"execa": "^9.3.1",
|
|
89
|
-
"khroma": "^2.1.0",
|
|
90
69
|
"react": "^18.3.1",
|
|
91
70
|
"react-dom": "^18.3.1",
|
|
92
|
-
"
|
|
93
|
-
"typescript": "^5.5.4",
|
|
94
|
-
"vite": "5.3.4",
|
|
95
|
-
"vite-plugin-dts": "^3.9.1"
|
|
71
|
+
"typescript": "^5.6.2"
|
|
96
72
|
}
|
|
97
73
|
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import { type ThemeColorValues } from '@likec4/core'
|
|
2
|
+
import { entries } from 'remeda'
|
|
3
|
+
import type { LikeC4CustomColorsProperties } from './LikeC4CustomColors.props'
|
|
4
|
+
import { vars } from './theme-vars'
|
|
5
|
+
|
|
6
|
+
type CSSVarFunction = `var(--${string})` | `var(--${string}, ${string | number} )`
|
|
7
|
+
|
|
8
|
+
export function LikeC4CustomColors({ customColors }: LikeC4CustomColorsProperties) {
|
|
9
|
+
function toStyle(name: String, colorValues: ThemeColorValues): String {
|
|
10
|
+
const rules = new Array<String>(
|
|
11
|
+
...entries(colorValues.elements).map(([key, value]) => `${stripCssVarReference(vars.element[key])}: ${value};`),
|
|
12
|
+
...entries(colorValues.relationships).map(([key, value]) =>
|
|
13
|
+
`${stripCssVarReference(vars.relation[key])}: ${value};`
|
|
14
|
+
)
|
|
15
|
+
)
|
|
16
|
+
.join('\n')
|
|
17
|
+
|
|
18
|
+
return `:where([data-likec4-color=${name}]) {
|
|
19
|
+
${rules}
|
|
20
|
+
}`
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function stripCssVarReference(ref: CSSVarFunction): String {
|
|
24
|
+
const end = ref.indexOf(',')
|
|
25
|
+
return ref.substring(4, end == -1 ? ref.length - 1 : end)
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
const styles = entries(customColors)
|
|
29
|
+
.map(([name, color]) => toStyle(name, color))
|
|
30
|
+
.join('\n')
|
|
31
|
+
|
|
32
|
+
return (
|
|
33
|
+
<>
|
|
34
|
+
<style type="text/css" dangerouslySetInnerHTML={{ __html: styles }} />
|
|
35
|
+
</>
|
|
36
|
+
)
|
|
37
|
+
}
|
package/src/LikeC4Diagram.css.ts
CHANGED
|
@@ -3,73 +3,18 @@ import type {
|
|
|
3
3
|
DiagramNode,
|
|
4
4
|
DiagramView,
|
|
5
5
|
Fqn,
|
|
6
|
-
NonEmptyArray,
|
|
7
6
|
RelationID,
|
|
8
7
|
ViewChange,
|
|
9
|
-
ViewID
|
|
8
|
+
ViewID,
|
|
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
|
|
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
|
-
}
|
|
14
|
+
export type { WhereOperator }
|
|
44
15
|
|
|
45
|
-
type
|
|
46
|
-
|
|
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
|
-
export type DiagramNodeWithNavigate = Omit<DiagramNode, 'navigateTo'> & {
|
|
72
|
-
navigateTo: ViewID
|
|
16
|
+
export type DiagramNodeWithNavigate<ID extends string = ViewID> = Omit<DiagramNode, 'navigateTo'> & {
|
|
17
|
+
navigateTo: ID
|
|
73
18
|
}
|
|
74
19
|
|
|
75
20
|
type ElementIconNodeProps = {
|
|
@@ -82,28 +27,21 @@ export type ElementIconRenderer = (props: {
|
|
|
82
27
|
node: ElementIconNodeProps
|
|
83
28
|
}) => ReactNode
|
|
84
29
|
|
|
85
|
-
export type OnNavigateTo =
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
): void
|
|
93
|
-
}
|
|
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
|
+
|
|
94
37
|
export type OnNodeClick = (
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
xynode: XYFlowNode
|
|
98
|
-
event: ReactMouseEvent
|
|
99
|
-
}
|
|
38
|
+
node: DiagramNode,
|
|
39
|
+
event: ReactMouseEvent
|
|
100
40
|
) => void
|
|
41
|
+
|
|
101
42
|
export type OnEdgeClick = (
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
xyedge: XYFlowEdge
|
|
105
|
-
event: ReactMouseEvent
|
|
106
|
-
}
|
|
43
|
+
edge: DiagramEdge,
|
|
44
|
+
event: ReactMouseEvent
|
|
107
45
|
) => void
|
|
108
46
|
|
|
109
47
|
/**
|
|
@@ -114,9 +52,8 @@ export type OnCanvasClick = (event: ReactMouseEvent) => void
|
|
|
114
52
|
export type ChangeEvent = {
|
|
115
53
|
change: ViewChange
|
|
116
54
|
}
|
|
117
|
-
export type OnChange =
|
|
118
|
-
|
|
119
|
-
}
|
|
55
|
+
export type OnChange = (event: ChangeEvent) => void
|
|
56
|
+
|
|
120
57
|
export type LikeC4ColorScheme = 'light' | 'dark'
|
|
121
58
|
|
|
122
59
|
export interface LikeC4DiagramProperties {
|
|
@@ -125,15 +62,7 @@ export interface LikeC4DiagramProperties {
|
|
|
125
62
|
className?: string | undefined
|
|
126
63
|
|
|
127
64
|
/**
|
|
128
|
-
*
|
|
129
|
-
* By default inherits from system or surrounding MantineProvider
|
|
130
|
-
*
|
|
131
|
-
* @example 'light' | 'dark'
|
|
132
|
-
*/
|
|
133
|
-
// colorScheme?: LikeC4ColorScheme | undefined
|
|
134
|
-
|
|
135
|
-
/**
|
|
136
|
-
* Show/hide controls menu
|
|
65
|
+
* Show/hide ReactFlow controls menu
|
|
137
66
|
* @default false
|
|
138
67
|
*/
|
|
139
68
|
controls?: boolean | undefined
|
|
@@ -163,10 +92,13 @@ export interface LikeC4DiagramProperties {
|
|
|
163
92
|
*/
|
|
164
93
|
fitViewPadding?: number | undefined
|
|
165
94
|
|
|
95
|
+
/**
|
|
96
|
+
* @default false if readonly
|
|
97
|
+
*/
|
|
166
98
|
nodesSelectable?: boolean | undefined
|
|
167
99
|
|
|
168
100
|
/**
|
|
169
|
-
* @default false
|
|
101
|
+
* @default false if readonly
|
|
170
102
|
*/
|
|
171
103
|
nodesDraggable?: boolean | undefined
|
|
172
104
|
|
|
@@ -192,14 +124,14 @@ export interface LikeC4DiagramProperties {
|
|
|
192
124
|
showElementLinks?: boolean | undefined
|
|
193
125
|
|
|
194
126
|
/**
|
|
195
|
-
* Display
|
|
127
|
+
* Display webview with diagram title / description
|
|
196
128
|
* @default true
|
|
197
129
|
*/
|
|
198
130
|
showDiagramTitle?: boolean | undefined
|
|
199
131
|
|
|
200
132
|
/**
|
|
201
133
|
* Show back/forward navigation buttons
|
|
202
|
-
* @default
|
|
134
|
+
* @default true if `onNavigateTo` is set
|
|
203
135
|
*/
|
|
204
136
|
showNavigationButtons?: undefined | boolean
|
|
205
137
|
|
|
@@ -209,6 +141,12 @@ export interface LikeC4DiagramProperties {
|
|
|
209
141
|
*/
|
|
210
142
|
showNotations?: boolean | undefined
|
|
211
143
|
|
|
144
|
+
/**
|
|
145
|
+
* Display dropdown with details on relationship's label click
|
|
146
|
+
* @default true
|
|
147
|
+
*/
|
|
148
|
+
showRelationshipDetails?: boolean | undefined
|
|
149
|
+
|
|
212
150
|
/**
|
|
213
151
|
* If double click on a node should enable focus mode, i.e. highlight incoming/outgoing edges
|
|
214
152
|
* @default true
|
|
@@ -228,11 +166,14 @@ export interface LikeC4DiagramProperties {
|
|
|
228
166
|
experimentalEdgeEditing?: boolean | undefined
|
|
229
167
|
|
|
230
168
|
/**
|
|
231
|
-
* Render
|
|
169
|
+
* Render icon for an element, bundled or remote
|
|
232
170
|
* By default, if icon is http:// or https://, it will be rendered as an image
|
|
233
171
|
*/
|
|
234
172
|
renderIcon?: ElementIconRenderer | undefined
|
|
235
173
|
|
|
174
|
+
/**
|
|
175
|
+
* Dynamic filter, applies both to nodes and edges
|
|
176
|
+
*/
|
|
236
177
|
where?: WhereOperator<string, string> | undefined
|
|
237
178
|
}
|
|
238
179
|
|
|
@@ -247,8 +188,15 @@ export interface LikeC4DiagramEventHandlers {
|
|
|
247
188
|
onCanvasClick?: OnCanvasClick | null | undefined
|
|
248
189
|
onCanvasDblClick?: OnCanvasClick | null | undefined
|
|
249
190
|
|
|
191
|
+
// if set, will render a burger menu icon in the top left corner
|
|
250
192
|
onBurgerMenuClick?: null | undefined | (() => void)
|
|
193
|
+
|
|
194
|
+
// if set, will render a source code icon in the top left corner
|
|
251
195
|
onOpenSourceView?: null | undefined | (() => void)
|
|
196
|
+
|
|
197
|
+
// if set, will render an icon in properties webview for each element
|
|
252
198
|
onOpenSourceElement?: null | undefined | ((fqn: Fqn) => void)
|
|
199
|
+
|
|
200
|
+
// if set, will be called on edge click
|
|
253
201
|
onOpenSourceRelation?: null | undefined | ((id: RelationID) => void)
|
|
254
202
|
}
|
package/src/LikeC4Diagram.tsx
CHANGED
|
@@ -1,12 +1,15 @@
|
|
|
1
|
+
import type { DiagramView } from '@likec4/core'
|
|
1
2
|
import { ReactFlowProvider as XYFlowProvider } from '@xyflow/react'
|
|
2
3
|
import clsx from 'clsx'
|
|
3
4
|
import { shallowEqual } from 'fast-equals'
|
|
4
5
|
import { domAnimation, LazyMotion } from 'framer-motion'
|
|
5
|
-
import { memo, useRef } from 'react'
|
|
6
|
+
import { memo, useEffect, useRef } from 'react'
|
|
6
7
|
import { rootClassName } from './globals.css'
|
|
7
8
|
import { useDiagramState } from './hooks/useDiagramState'
|
|
9
|
+
import { LikeC4CustomColors } from './LikeC4CustomColors'
|
|
8
10
|
import * as css from './LikeC4Diagram.css'
|
|
9
11
|
import { type LikeC4DiagramEventHandlers, type LikeC4DiagramProperties } from './LikeC4Diagram.props'
|
|
12
|
+
import { useLikeC4Model } from './likec4model'
|
|
10
13
|
import { EnsureMantine } from './mantine/EnsureMantine'
|
|
11
14
|
import { DiagramContextProvider } from './state/DiagramContext'
|
|
12
15
|
import { FitViewOnDiagramChange } from './xyflow/FitviewOnDiagramChange'
|
|
@@ -31,6 +34,7 @@ export function LikeC4Diagram({
|
|
|
31
34
|
showElementLinks = true,
|
|
32
35
|
showDiagramTitle = true,
|
|
33
36
|
showNotations = true,
|
|
37
|
+
showRelationshipDetails = true,
|
|
34
38
|
enableDynamicViewWalkthrough = false,
|
|
35
39
|
enableFocusMode = false,
|
|
36
40
|
initialWidth,
|
|
@@ -54,6 +58,7 @@ export function LikeC4Diagram({
|
|
|
54
58
|
where,
|
|
55
59
|
showNavigationButtons = !!onNavigateTo
|
|
56
60
|
}: LikeC4DiagramProps) {
|
|
61
|
+
const hasLikec4model = !!useLikeC4Model()
|
|
57
62
|
const initialRef = useRef({
|
|
58
63
|
defaultNodes: [] as XYFlowNode[],
|
|
59
64
|
defaultEdges: [] as XYFlowEdge[],
|
|
@@ -63,6 +68,12 @@ export function LikeC4Diagram({
|
|
|
63
68
|
if (readonly !== true && !!where) {
|
|
64
69
|
console.warn('where filter is only supported in readonly mode')
|
|
65
70
|
}
|
|
71
|
+
useEffect(() => {
|
|
72
|
+
if (showRelationshipDetails && !hasLikec4model) {
|
|
73
|
+
console.warn('Relationship details require LikeC4ModelProvider')
|
|
74
|
+
}
|
|
75
|
+
}, [showRelationshipDetails, hasLikec4model])
|
|
76
|
+
|
|
66
77
|
return (
|
|
67
78
|
<EnsureMantine>
|
|
68
79
|
<LazyMotion features={domAnimation} strict>
|
|
@@ -70,6 +81,7 @@ export function LikeC4Diagram({
|
|
|
70
81
|
fitView={fitView}
|
|
71
82
|
{...initialRef.current}
|
|
72
83
|
>
|
|
84
|
+
{customColorsDefined(view) && <LikeC4CustomColors customColors={view.customColorDefinitions} />}
|
|
73
85
|
<DiagramContextProvider
|
|
74
86
|
view={view}
|
|
75
87
|
keepAspectRatio={keepAspectRatio}
|
|
@@ -82,6 +94,7 @@ export function LikeC4Diagram({
|
|
|
82
94
|
showElementLinks={showElementLinks}
|
|
83
95
|
showNavigationButtons={showNavigationButtons}
|
|
84
96
|
showNotations={showNotations}
|
|
97
|
+
showRelationshipDetails={showRelationshipDetails && hasLikec4model}
|
|
85
98
|
nodesDraggable={nodesDraggable}
|
|
86
99
|
nodesSelectable={nodesSelectable}
|
|
87
100
|
experimentalEdgeEditing={experimentalEdgeEditing}
|
|
@@ -114,13 +127,14 @@ export function LikeC4Diagram({
|
|
|
114
127
|
</EnsureMantine>
|
|
115
128
|
)
|
|
116
129
|
}
|
|
130
|
+
LikeC4Diagram.displayName = 'LikeC4Diagram'
|
|
117
131
|
|
|
118
132
|
type LikeC4DiagramInnerProps = {
|
|
119
133
|
background: NonNullable<LikeC4DiagramProperties['background']>
|
|
120
134
|
controls: boolean
|
|
121
135
|
showDiagramTitle: boolean
|
|
122
136
|
}
|
|
123
|
-
const LikeC4DiagramInnerMemo = memo<LikeC4DiagramInnerProps>(function LikeC4DiagramInner({
|
|
137
|
+
const LikeC4DiagramInnerMemo = /* @__PURE__ */ memo<LikeC4DiagramInnerProps>(function LikeC4DiagramInner({
|
|
124
138
|
background,
|
|
125
139
|
controls,
|
|
126
140
|
showDiagramTitle
|
|
@@ -164,3 +178,8 @@ const LikeC4DiagramInnerMemo = memo<LikeC4DiagramInnerProps>(function LikeC4Diag
|
|
|
164
178
|
</>
|
|
165
179
|
)
|
|
166
180
|
}, shallowEqual)
|
|
181
|
+
LikeC4DiagramInnerMemo.displayName = 'LikeC4DiagramInnerMemo'
|
|
182
|
+
|
|
183
|
+
function customColorsDefined(view: DiagramView) {
|
|
184
|
+
return Object.keys(view.customColorDefinitions).length > 0
|
|
185
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
import { LikeC4Model } from '@likec4/core'
|
|
2
|
+
import { useCustomCompareMemo } from '@react-hookz/web'
|
|
3
|
+
import { type PropsWithChildren } from 'react'
|
|
4
|
+
import type { RequireExactlyOne } from 'type-fest'
|
|
5
|
+
import { depsShallowEqual } from './hooks/useUpdateEffect'
|
|
6
|
+
import { LikeC4ModelContext } from './likec4model/LikeC4ModelContext'
|
|
7
|
+
import { useLikeC4Model } from './likec4model/useLikeC4Model'
|
|
8
|
+
|
|
9
|
+
export type LikeC4ModelProviderProps = PropsWithChildren<
|
|
10
|
+
RequireExactlyOne<{
|
|
11
|
+
likec4model: LikeC4Model
|
|
12
|
+
layouted: LikeC4Model.Layouted.SourceModel
|
|
13
|
+
computed: LikeC4Model.Computed.SourceModel
|
|
14
|
+
}>
|
|
15
|
+
>
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Ensures LikeC4Model context
|
|
19
|
+
*/
|
|
20
|
+
export function LikeC4ModelProvider({
|
|
21
|
+
children,
|
|
22
|
+
...props
|
|
23
|
+
}: LikeC4ModelProviderProps) {
|
|
24
|
+
const model = useLikeC4Model()
|
|
25
|
+
|
|
26
|
+
if (model) {
|
|
27
|
+
return <>{children}</>
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const value = useCustomCompareMemo(
|
|
31
|
+
() => {
|
|
32
|
+
if (props.likec4model) {
|
|
33
|
+
return props.likec4model
|
|
34
|
+
}
|
|
35
|
+
if (props.layouted) {
|
|
36
|
+
return LikeC4Model.layouted(props.layouted)
|
|
37
|
+
}
|
|
38
|
+
return LikeC4Model.computed(props.computed)
|
|
39
|
+
},
|
|
40
|
+
[props.likec4model ?? props.layouted ?? props.computed],
|
|
41
|
+
depsShallowEqual
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
return (
|
|
45
|
+
<LikeC4ModelContext.Provider value={value}>
|
|
46
|
+
{children}
|
|
47
|
+
</LikeC4ModelContext.Provider>
|
|
48
|
+
)
|
|
49
|
+
}
|
package/src/globals.css.ts
CHANGED
|
@@ -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 './
|
|
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(
|
|
20
|
+
globalStyle(`:where(.${rootClassName}) .mantine-ActionIcon-icon .tabler-icon`, {
|
|
22
21
|
width: '75%',
|
|
23
22
|
height: '75%'
|
|
24
23
|
})
|
package/src/hooks/index.ts
CHANGED
|
@@ -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
|
+
}
|
package/src/hooks/useXYFlow.ts
CHANGED
|
@@ -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
|
-
|
|
16
|
-
selector,
|
|
15
|
+
selector as any,
|
|
17
16
|
equalityFn ?? shallowEqual
|
|
18
17
|
)
|
|
19
18
|
}
|
package/src/index.ts
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import '@xyflow/react/dist/style.css'
|
|
2
2
|
|
|
3
3
|
export { LikeC4Diagram } from './LikeC4Diagram'
|
|
4
|
+
export * from './likec4model/useLikeC4Model'
|
|
5
|
+
export { LikeC4ModelProvider } from './LikeC4ModelProvider'
|
|
4
6
|
export { StaticLikeC4Diagram } from './StaticLikeC4Diagram'
|
|
5
7
|
|
|
6
8
|
export { useSetState } from './hooks/useSetState'
|
|
7
9
|
export { useUpdateEffect } from './hooks/useUpdateEffect'
|
|
8
10
|
export type * from './LikeC4Diagram'
|
|
9
11
|
export type * from './LikeC4Diagram.props'
|
|
12
|
+
export type * from './LikeC4ModelProvider'
|
|
10
13
|
export type * from './StaticLikeC4Diagram'
|
|
11
14
|
export type * from './xyflow/types'
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export * from './useLikeC4Model'
|
|
@@ -0,0 +1,55 @@
|
|
|
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
|
+
export function useLikeC4View(viewId: LiteralUnion<ViewID, string>): ComputedView | DiagramView | null {
|
|
38
|
+
const model = useLikeC4Model(true)
|
|
39
|
+
try {
|
|
40
|
+
return model.view(viewId).view
|
|
41
|
+
} catch (error) {
|
|
42
|
+
console.error(error)
|
|
43
|
+
return null
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export function useLikeC4DiagramView(viewId: LiteralUnion<ViewID, string>): DiagramView | null {
|
|
48
|
+
const model = useLikeC4Model(true, 'layouted')
|
|
49
|
+
try {
|
|
50
|
+
return model.view(viewId).view
|
|
51
|
+
} catch (error) {
|
|
52
|
+
console.error(error)
|
|
53
|
+
return null
|
|
54
|
+
}
|
|
55
|
+
}
|