@likec4/diagram 1.3.0 → 1.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/LikeC4Diagram.css.d.ts +0 -1
- package/dist/LikeC4Diagram.d.ts +1 -1
- package/dist/LikeC4Diagram.props.d.ts +7 -2
- package/dist/index.d.ts +1 -1
- package/dist/index.mjs +1580 -1194
- package/dist/state/DiagramContext.d.ts +97 -4169
- package/dist/state/diagramStore.d.ts +98 -4172
- package/dist/state/hooks.d.ts +4 -0
- package/dist/state/index.d.ts +1 -3
- package/dist/state/useDiagramStore.d.ts +3 -4622
- package/dist/state/useNavigationHistory.d.ts +5 -0
- package/dist/style.css +217 -159
- package/dist/theme.css.d.ts +5 -0
- package/dist/ui/BackwardForwardPanel.css.d.ts +1 -0
- package/dist/ui/BackwardForwardPanel.d.ts +1 -0
- package/dist/ui/DiagramTitlePanel.css.d.ts +1 -1
- package/dist/ui/OptionsPanel.d.ts +1 -3
- package/dist/ui/options/EdgeOptions.d.ts +19 -0
- package/dist/ui/options/NodeOptions.d.ts +2 -2
- package/dist/xyflow/EdgeMarkers.d.ts +11 -0
- package/dist/xyflow/XYFlowEvents.d.ts +12 -9
- package/dist/xyflow/XYFlowInner.d.ts +1 -0
- package/dist/xyflow/const.d.ts +3 -3
- package/dist/xyflow/diagram-to-xyflow.d.ts +1 -1
- package/dist/xyflow/edges/RelationshipEdge.d.ts +4 -3
- package/dist/xyflow/edges/edges.css.d.ts +1 -0
- package/dist/xyflow/edges/utils.d.ts +1 -0
- package/dist/xyflow/hooks/index.d.ts +3 -2
- package/dist/xyflow/hooks/useXYFlow.d.ts +22 -21
- package/dist/xyflow/nodes/compound/CompoundNode.css.d.ts +1 -0
- package/dist/xyflow/nodes/element/ElementIcon.d.ts +1 -4
- package/dist/xyflow/nodes/element/element.css.d.ts +3 -1
- package/dist/xyflow/types.d.ts +2 -32
- package/package.json +21 -21
- package/src/LikeC4Diagram.css.ts +10 -8
- package/src/LikeC4Diagram.props.ts +12 -5
- package/src/LikeC4Diagram.tsx +43 -26
- package/src/globals.css.ts +11 -4
- package/src/index.ts +1 -1
- package/src/mantine.css.ts +2 -2
- package/src/state/DiagramContext.tsx +47 -16
- package/src/state/diagramStore.ts +89 -80
- package/src/state/hooks.ts +5 -0
- package/src/state/index.ts +1 -3
- package/src/state/useDiagramStore.ts +6 -13
- package/src/state/useNavigationHistory.ts +39 -0
- package/src/theme.css.ts +5 -0
- package/src/ui/BackwardForwardPanel.css.ts +22 -0
- package/src/ui/BackwardForwardPanel.tsx +59 -0
- package/src/ui/DiagramTitlePanel.css.ts +17 -6
- package/src/ui/DiagramTitlePanel.tsx +108 -94
- package/src/ui/DynamicViewWalkthrough.tsx +6 -4
- package/src/ui/OptionsPanel.tsx +37 -18
- package/src/ui/options/EdgeOptions.tsx +157 -0
- package/src/ui/options/NodeOptions.tsx +37 -29
- package/src/xyflow/EdgeMarkers.tsx +148 -0
- package/src/xyflow/FitviewOnDiagramChange.tsx +8 -4
- package/src/xyflow/SelectEdgesOnNodeFocus.tsx +59 -55
- package/src/xyflow/SyncWithDiagram.tsx +13 -20
- package/src/xyflow/XYFlow.tsx +2 -4
- package/src/xyflow/XYFlowEvents.tsx +48 -33
- package/src/xyflow/XYFlowInner.tsx +6 -3
- package/src/xyflow/const.ts +3 -3
- package/src/xyflow/diagram-to-xyflow.ts +18 -53
- package/src/xyflow/edges/RelationshipEdge.tsx +218 -126
- package/src/xyflow/edges/edges.css.ts +44 -26
- package/src/xyflow/edges/utils.ts +10 -0
- package/src/xyflow/hooks/index.ts +4 -2
- package/src/xyflow/hooks/useLayoutConstraints.ts +5 -5
- package/src/xyflow/hooks/useXYFlow.ts +28 -1
- package/src/xyflow/nodes/compound/CompoundNode.css.ts +41 -31
- package/src/xyflow/nodes/compound/CompoundNode.tsx +52 -53
- package/src/xyflow/nodes/element/ElementIcon.tsx +11 -22
- package/src/xyflow/nodes/element/ElementLink.tsx +11 -16
- package/src/xyflow/nodes/element/ElementNode.tsx +69 -114
- package/src/xyflow/nodes/element/element.css.ts +48 -15
- package/src/xyflow/nodes/shared/NavigateToBtn.tsx +1 -1
- package/src/xyflow/types.ts +2 -4
- package/src/xyflow/utils.ts +3 -6
- package/dist/KeepAspectRatioContainer.d.ts +0 -9
- package/dist/icons/Clipboard.d.ts +0 -3
- package/dist/icons/Link.d.ts +0 -3
- package/dist/icons/ZoomIn.d.ts +0 -3
- package/dist/icons/index.d.ts +0 -3
- package/dist/mantine/theme.d.ts +0 -3
- package/dist/state/WhenInitialized.d.ts +0 -3
- package/dist/ui/Camera.d.ts +0 -3
- package/src/KeepAspectRatioContainer.tsx +0 -36
- package/src/icons/Clipboard.tsx +0 -24
- package/src/icons/Link.tsx +0 -23
- package/src/icons/ZoomIn.tsx +0 -25
- package/src/icons/index.ts +0 -3
- package/src/mantine/theme.ts +0 -20
- package/src/state/WhenInitialized.tsx +0 -24
- package/src/ui/Camera.tsx +0 -174
|
@@ -14,16 +14,17 @@ import type { XYPosition } from '@xyflow/system'
|
|
|
14
14
|
import type { MouseEvent as ReactMouseEvent } from 'react'
|
|
15
15
|
import type { SetRequired, Simplify } from 'type-fest'
|
|
16
16
|
import type { XYFlowEdge, XYFlowNode } from './xyflow/types'
|
|
17
|
-
import type { XYBackground
|
|
17
|
+
import type { XYBackground } from './xyflow/XYFlowBackground'
|
|
18
18
|
|
|
19
19
|
export type DiagramNodeWithNavigate = Simplify<SetRequired<DiagramNode, 'navigateTo'>>
|
|
20
20
|
|
|
21
21
|
export type OnNavigateTo = {
|
|
22
22
|
(
|
|
23
23
|
to: ViewID,
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
24
|
+
// These fields present if navigateTo triggered by a node click
|
|
25
|
+
event?: ReactMouseEvent,
|
|
26
|
+
element?: DiagramNodeWithNavigate,
|
|
27
|
+
xynode?: XYFlowNode
|
|
27
28
|
): void
|
|
28
29
|
}
|
|
29
30
|
export type OnNodeClick = (
|
|
@@ -35,7 +36,7 @@ export type OnNodeClick = (
|
|
|
35
36
|
) => void
|
|
36
37
|
export type OnEdgeClick = (
|
|
37
38
|
event: {
|
|
38
|
-
|
|
39
|
+
edge: DiagramEdge
|
|
39
40
|
xyedge: XYFlowEdge
|
|
40
41
|
event: ReactMouseEvent
|
|
41
42
|
}
|
|
@@ -159,6 +160,12 @@ export interface LikeC4DiagramProperties {
|
|
|
159
160
|
*/
|
|
160
161
|
showDiagramTitle?: boolean | undefined
|
|
161
162
|
|
|
163
|
+
/**
|
|
164
|
+
* Show back/forward navigation buttons
|
|
165
|
+
* @default false
|
|
166
|
+
*/
|
|
167
|
+
showNavigationButtons?: undefined | boolean
|
|
168
|
+
|
|
162
169
|
/**
|
|
163
170
|
* If Walkthrough for dynamic views should be enabled
|
|
164
171
|
* @default false
|
package/src/LikeC4Diagram.tsx
CHANGED
|
@@ -4,15 +4,14 @@ import clsx from 'clsx'
|
|
|
4
4
|
import { DEV } from 'esm-env'
|
|
5
5
|
import { shallowEqual } from 'fast-equals'
|
|
6
6
|
import { domAnimation, LazyMotion } from 'framer-motion'
|
|
7
|
-
import { memo, useRef } from 'react'
|
|
7
|
+
import { memo, useEffect, useRef, useState } from 'react'
|
|
8
8
|
import useTilg from 'tilg'
|
|
9
9
|
import { rootClassName } from './globals.css'
|
|
10
|
-
import { KeepAspectRatioContainer } from './KeepAspectRatioContainer'
|
|
11
10
|
import { cssDisablePan, cssNoControls, cssReactFlow, cssTransparentBg } from './LikeC4Diagram.css'
|
|
12
11
|
import { type LikeC4DiagramEventHandlers, type LikeC4DiagramProperties } from './LikeC4Diagram.props'
|
|
13
12
|
import { EnsureMantine } from './mantine/EnsureMantine'
|
|
14
13
|
import { DiagramContextProvider } from './state/DiagramContext'
|
|
15
|
-
import {
|
|
14
|
+
import { useDiagramStoreApi } from './state/useDiagramStore'
|
|
16
15
|
import { diagramViewToXYFlowData } from './xyflow/diagram-to-xyflow'
|
|
17
16
|
import { FitViewOnDiagramChange } from './xyflow/FitviewOnDiagramChange'
|
|
18
17
|
import { SelectEdgesOnNodeFocus } from './xyflow/SelectEdgesOnNodeFocus'
|
|
@@ -36,6 +35,7 @@ export function LikeC4Diagram({
|
|
|
36
35
|
controls = false,
|
|
37
36
|
showElementLinks = true,
|
|
38
37
|
showDiagramTitle = true,
|
|
38
|
+
showNavigationButtons = false,
|
|
39
39
|
enableDynamicViewWalkthrough = true,
|
|
40
40
|
initialWidth,
|
|
41
41
|
initialHeight,
|
|
@@ -78,6 +78,8 @@ export function LikeC4Diagram({
|
|
|
78
78
|
>
|
|
79
79
|
<DiagramContextProvider
|
|
80
80
|
view={view}
|
|
81
|
+
keepAspectRatio={keepAspectRatio}
|
|
82
|
+
className={clsx(rootClassName, className)}
|
|
81
83
|
readonly={readonly}
|
|
82
84
|
pannable={pannable}
|
|
83
85
|
zoomable={zoomable}
|
|
@@ -98,24 +100,18 @@ export function LikeC4Diagram({
|
|
|
98
100
|
onCanvasDblClick={onCanvasDblClick}
|
|
99
101
|
>
|
|
100
102
|
<LazyMotion features={domAnimation} strict>
|
|
101
|
-
<
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
controls={controls}
|
|
114
|
-
pannable={pannable}
|
|
115
|
-
showDiagramTitle={showDiagramTitle}
|
|
116
|
-
enableDynamicViewWalkthrough={enableDynamicViewWalkthrough}
|
|
117
|
-
/>
|
|
118
|
-
</KeepAspectRatioContainer>
|
|
103
|
+
<LikeC4DiagramInnerMemo
|
|
104
|
+
defaultNodes={initialRef.current.defaultNodes}
|
|
105
|
+
defaultEdges={initialRef.current.defaultEdges}
|
|
106
|
+
fitView={fitView}
|
|
107
|
+
zoomable={zoomable}
|
|
108
|
+
background={background}
|
|
109
|
+
controls={controls}
|
|
110
|
+
pannable={pannable}
|
|
111
|
+
showDiagramTitle={showDiagramTitle}
|
|
112
|
+
showNavigationButtons={showNavigationButtons}
|
|
113
|
+
enableDynamicViewWalkthrough={enableDynamicViewWalkthrough}
|
|
114
|
+
/>
|
|
119
115
|
</LazyMotion>
|
|
120
116
|
</DiagramContextProvider>
|
|
121
117
|
</XYFlowProvider>
|
|
@@ -132,6 +128,7 @@ type LikeC4DiagramInnerProps = {
|
|
|
132
128
|
defaultNodes: XYFlowNode[]
|
|
133
129
|
defaultEdges: XYFlowEdge[]
|
|
134
130
|
showDiagramTitle: boolean
|
|
131
|
+
showNavigationButtons: boolean
|
|
135
132
|
enableDynamicViewWalkthrough: boolean
|
|
136
133
|
}
|
|
137
134
|
const LikeC4DiagramInnerMemo = memo<LikeC4DiagramInnerProps>(function LikeC4DiagramInner({
|
|
@@ -143,9 +140,26 @@ const LikeC4DiagramInnerMemo = memo<LikeC4DiagramInnerProps>(function LikeC4Diag
|
|
|
143
140
|
defaultNodes,
|
|
144
141
|
defaultEdges,
|
|
145
142
|
showDiagramTitle,
|
|
143
|
+
showNavigationButtons,
|
|
146
144
|
enableDynamicViewWalkthrough
|
|
147
145
|
}) {
|
|
148
146
|
DEV && useTilg()
|
|
147
|
+
const diagramApi = useDiagramStoreApi()
|
|
148
|
+
const [isInitialized, setIsInitialized] = useState(diagramApi.getState().initialized)
|
|
149
|
+
|
|
150
|
+
useEffect(() => {
|
|
151
|
+
if (isInitialized) {
|
|
152
|
+
return
|
|
153
|
+
}
|
|
154
|
+
return diagramApi.subscribe(
|
|
155
|
+
s => s.initialized,
|
|
156
|
+
setIsInitialized,
|
|
157
|
+
{
|
|
158
|
+
fireImmediately: true
|
|
159
|
+
}
|
|
160
|
+
)
|
|
161
|
+
}, [isInitialized])
|
|
162
|
+
|
|
149
163
|
return (
|
|
150
164
|
<>
|
|
151
165
|
<XYFlow
|
|
@@ -160,17 +174,20 @@ const LikeC4DiagramInnerMemo = memo<LikeC4DiagramInnerProps>(function LikeC4Diag
|
|
|
160
174
|
)}
|
|
161
175
|
>
|
|
162
176
|
<XYFlowInner
|
|
177
|
+
showNavigationButtons={showNavigationButtons}
|
|
163
178
|
showDiagramTitle={showDiagramTitle}
|
|
164
179
|
enableDynamicViewWalkthrough={enableDynamicViewWalkthrough}
|
|
165
180
|
background={background}
|
|
166
181
|
controls={controls}
|
|
167
182
|
/>
|
|
168
183
|
</XYFlow>
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
184
|
+
{isInitialized && (
|
|
185
|
+
<>
|
|
186
|
+
<SyncWithDiagram />
|
|
187
|
+
{fitView && <FitViewOnDiagramChange />}
|
|
188
|
+
{fitView && zoomable && <SelectEdgesOnNodeFocus />}
|
|
189
|
+
</>
|
|
190
|
+
)}
|
|
174
191
|
</>
|
|
175
192
|
)
|
|
176
193
|
}, shallowEqual)
|
package/src/globals.css.ts
CHANGED
|
@@ -8,12 +8,19 @@ import { vars } from './theme.css'
|
|
|
8
8
|
export const rootClassName = 'likec4-diagram-root'
|
|
9
9
|
|
|
10
10
|
globalStyle(`.${rootClassName}`, {
|
|
11
|
+
overflow: 'hidden',
|
|
12
|
+
position: 'relative',
|
|
13
|
+
width: '100%',
|
|
14
|
+
height: '100%',
|
|
15
|
+
padding: 0,
|
|
16
|
+
margin: 0,
|
|
17
|
+
boxSizing: 'border-box',
|
|
11
18
|
WebkitFontSmoothing: mantine.webkitFontSmoothing,
|
|
12
19
|
MozOsxFontSmoothing: mantine.mozFontSmoothing
|
|
13
20
|
})
|
|
14
21
|
|
|
15
22
|
createGlobalTheme(`.${rootClassName}`, {
|
|
16
|
-
...omit(vars, ['optionsPanel', 'default'])
|
|
23
|
+
...omit(vars, ['optionsPanel', 'navigationPanel', 'safariAnimationHook', 'default'])
|
|
17
24
|
}, {
|
|
18
25
|
likec4: {
|
|
19
26
|
font:
|
|
@@ -21,7 +28,7 @@ createGlobalTheme(`.${rootClassName}`, {
|
|
|
21
28
|
background: {
|
|
22
29
|
color: mantine.colors.body,
|
|
23
30
|
pattern: {
|
|
24
|
-
color: mantine.colors.
|
|
31
|
+
color: mantine.colors.dark[3]
|
|
25
32
|
}
|
|
26
33
|
}
|
|
27
34
|
},
|
|
@@ -74,13 +81,13 @@ createGlobalTheme(`:where([data-mantine-color-scheme='light']) .${rootClassName}
|
|
|
74
81
|
likec4: {
|
|
75
82
|
background: {
|
|
76
83
|
pattern: {
|
|
77
|
-
color: mantine.colors.
|
|
84
|
+
color: mantine.colors.gray[6]
|
|
78
85
|
}
|
|
79
86
|
}
|
|
80
87
|
}
|
|
81
88
|
})
|
|
82
89
|
|
|
83
|
-
for (const color of keys
|
|
90
|
+
for (const color of keys(defaultTheme.elements)) {
|
|
84
91
|
createGlobalTheme(`:where([data-likec4-color='${color}'])`, {
|
|
85
92
|
element: {
|
|
86
93
|
fill: vars.element.fill,
|
package/src/index.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
export { LikeC4Diagram } from './LikeC4Diagram'
|
|
2
2
|
export { StaticLikeC4Diagram } from './StaticLikeC4Diagram'
|
|
3
3
|
|
|
4
|
-
export
|
|
4
|
+
export { useSetState, useUpdateEffect } from './hooks'
|
|
5
5
|
export type * from './LikeC4Diagram'
|
|
6
6
|
export type * from './LikeC4Diagram.props'
|
|
7
7
|
export type * from './StaticLikeC4Diagram'
|
package/src/mantine.css.ts
CHANGED
|
@@ -1,31 +1,51 @@
|
|
|
1
|
+
import { shallowEqual } from 'fast-equals'
|
|
1
2
|
import { createContext, type PropsWithChildren, useEffect, useRef } from 'react'
|
|
2
|
-
import { hasSubObject,
|
|
3
|
+
import { hasSubObject, isNonNullish, pickBy } from 'remeda'
|
|
3
4
|
import { useUpdateEffect } from '../hooks'
|
|
4
|
-
import { useXYFlow } from '../xyflow/hooks'
|
|
5
|
+
import { useXYFlow, useXYStoreApi } from '../xyflow/hooks'
|
|
5
6
|
import { createDiagramStore, type DiagramInitialState } from './diagramStore'
|
|
6
7
|
|
|
7
|
-
type
|
|
8
|
-
export const DiagramContext = createContext<
|
|
8
|
+
export type DiagramZustandStore = ReturnType<typeof createDiagramStore>
|
|
9
|
+
export const DiagramContext = createContext<DiagramZustandStore | null>(null)
|
|
9
10
|
|
|
10
|
-
export
|
|
11
|
+
export type DiagramContextProviderProps = PropsWithChildren<
|
|
12
|
+
DiagramInitialState & {
|
|
13
|
+
className: string
|
|
14
|
+
keepAspectRatio: boolean
|
|
15
|
+
}
|
|
16
|
+
>
|
|
17
|
+
|
|
18
|
+
export function DiagramContextProvider({
|
|
19
|
+
children,
|
|
20
|
+
view,
|
|
21
|
+
className,
|
|
22
|
+
keepAspectRatio,
|
|
23
|
+
...props
|
|
24
|
+
}: DiagramContextProviderProps) {
|
|
25
|
+
const containerRef = useRef<HTMLDivElement>(null)
|
|
26
|
+
const xystore = useXYStoreApi()
|
|
11
27
|
const xyflow = useXYFlow()
|
|
12
|
-
const store = useRef<
|
|
28
|
+
const store = useRef<DiagramZustandStore>()
|
|
13
29
|
|
|
14
30
|
if (!store.current) {
|
|
15
31
|
store.current = createDiagramStore({
|
|
32
|
+
xystore,
|
|
16
33
|
xyflow,
|
|
17
34
|
view,
|
|
35
|
+
getContainer: () => containerRef.current,
|
|
18
36
|
...props
|
|
19
37
|
})
|
|
20
38
|
}
|
|
21
39
|
|
|
22
40
|
useEffect(
|
|
23
41
|
() => {
|
|
24
|
-
if (store.current
|
|
25
|
-
|
|
42
|
+
if (!store.current) return
|
|
43
|
+
const state = store.current.getState()
|
|
44
|
+
if (state.xyflow !== xyflow || state.xystore !== xystore) {
|
|
45
|
+
store.current.setState({ xyflow, xystore }, false, 'update xyflow and xystore')
|
|
26
46
|
}
|
|
27
47
|
},
|
|
28
|
-
[xyflow]
|
|
48
|
+
[xyflow, xystore]
|
|
29
49
|
)
|
|
30
50
|
|
|
31
51
|
useUpdateEffect(
|
|
@@ -35,16 +55,27 @@ export function DiagramContextProvider({ children, view, ...props }: PropsWithCh
|
|
|
35
55
|
if (state.view !== view) {
|
|
36
56
|
state.updateView(view)
|
|
37
57
|
}
|
|
38
|
-
|
|
39
|
-
|
|
58
|
+
const newProps = pickBy(props, isNonNullish)
|
|
59
|
+
if (!hasSubObject(state, newProps)) {
|
|
60
|
+
store.current.setState(newProps, false, 'update incoming props')
|
|
40
61
|
}
|
|
41
62
|
},
|
|
42
|
-
[view, props]
|
|
63
|
+
[view, props],
|
|
64
|
+
shallowEqual
|
|
43
65
|
)
|
|
44
|
-
|
|
45
66
|
return (
|
|
46
|
-
<
|
|
47
|
-
{
|
|
48
|
-
|
|
67
|
+
<div
|
|
68
|
+
ref={containerRef}
|
|
69
|
+
className={className}
|
|
70
|
+
{...(keepAspectRatio && {
|
|
71
|
+
style: {
|
|
72
|
+
aspectRatio: `${Math.ceil(view.width)}/${Math.ceil(view.height)}`,
|
|
73
|
+
maxHeight: Math.ceil(view.height)
|
|
74
|
+
}
|
|
75
|
+
})}>
|
|
76
|
+
<DiagramContext.Provider value={store.current}>
|
|
77
|
+
{children}
|
|
78
|
+
</DiagramContext.Provider>
|
|
79
|
+
</div>
|
|
49
80
|
)
|
|
50
81
|
}
|