@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
package/src/icons/ZoomIn.tsx
DELETED
|
@@ -1,25 +0,0 @@
|
|
|
1
|
-
import clsx from 'clsx'
|
|
2
|
-
import { forwardRef, type SVGProps } from 'react'
|
|
3
|
-
|
|
4
|
-
export const ZoomIn = forwardRef<SVGSVGElement, SVGProps<SVGSVGElement>>(({ className, ...props }, ref) => (
|
|
5
|
-
<svg
|
|
6
|
-
ref={ref}
|
|
7
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
8
|
-
className={clsx('icon icon-tabler icon-tabler-zoom-in', className)}
|
|
9
|
-
width="24"
|
|
10
|
-
height="24"
|
|
11
|
-
viewBox="0 0 24 24"
|
|
12
|
-
strokeWidth="1.5"
|
|
13
|
-
stroke="currentColor"
|
|
14
|
-
fill="none"
|
|
15
|
-
strokeLinecap="round"
|
|
16
|
-
strokeLinejoin="round"
|
|
17
|
-
{...props}
|
|
18
|
-
>
|
|
19
|
-
<path stroke="none" d="M0 0h24v24H0z" fill="none" />
|
|
20
|
-
<path d="M10 10m-7 0a7 7 0 1 0 14 0a7 7 0 1 0 -14 0" />
|
|
21
|
-
<path d="M7 10l6 0" />
|
|
22
|
-
<path d="M10 7l0 6" />
|
|
23
|
-
<path d="M21 21l-6 -6" />
|
|
24
|
-
</svg>
|
|
25
|
-
))
|
package/src/icons/index.ts
DELETED
package/src/mantine/theme.ts
DELETED
|
@@ -1,20 +0,0 @@
|
|
|
1
|
-
import { createTheme, type MantineTheme } from '@mantine/core'
|
|
2
|
-
|
|
3
|
-
export const theme = createTheme({
|
|
4
|
-
primaryColor: 'indigo',
|
|
5
|
-
cursorType: 'pointer',
|
|
6
|
-
defaultRadius: 'sm',
|
|
7
|
-
respectReducedMotion: true,
|
|
8
|
-
headings: {
|
|
9
|
-
fontWeight: '500',
|
|
10
|
-
sizes: {
|
|
11
|
-
h1: {
|
|
12
|
-
// fontSize: '2rem',
|
|
13
|
-
fontWeight: '600'
|
|
14
|
-
},
|
|
15
|
-
h2: {
|
|
16
|
-
// fontSize: '1.85rem',
|
|
17
|
-
}
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
}) as MantineTheme
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { type PropsWithChildren, useEffect, useState } from 'react'
|
|
2
|
-
import { useDiagramStoreApi } from './useDiagramStore'
|
|
3
|
-
|
|
4
|
-
export function WhenInitialized({ children }: PropsWithChildren) {
|
|
5
|
-
const diagramApi = useDiagramStoreApi()
|
|
6
|
-
|
|
7
|
-
const [isInitialized, setIsInitialized] = useState(diagramApi.getState().initialized)
|
|
8
|
-
|
|
9
|
-
useEffect(() => {
|
|
10
|
-
if (isInitialized) {
|
|
11
|
-
return
|
|
12
|
-
}
|
|
13
|
-
return diagramApi.subscribe(
|
|
14
|
-
s => s.initialized,
|
|
15
|
-
setIsInitialized
|
|
16
|
-
)
|
|
17
|
-
}, [isInitialized])
|
|
18
|
-
|
|
19
|
-
if (!isInitialized) {
|
|
20
|
-
return null
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
return <>{children}</>
|
|
24
|
-
}
|
package/src/ui/Camera.tsx
DELETED
|
@@ -1,174 +0,0 @@
|
|
|
1
|
-
import { shallowEqual } from '@mantine/hooks'
|
|
2
|
-
import { useDebouncedEffect, useIsMounted } from '@react-hookz/web'
|
|
3
|
-
import {
|
|
4
|
-
type ReactFlowState,
|
|
5
|
-
useOnSelectionChange,
|
|
6
|
-
useOnViewportChange,
|
|
7
|
-
useStore,
|
|
8
|
-
useUpdateNodeInternals,
|
|
9
|
-
type Viewport
|
|
10
|
-
} from '@xyflow/react'
|
|
11
|
-
import { memo, useEffect, useRef, useState } from 'react'
|
|
12
|
-
import { uniq } from 'remeda'
|
|
13
|
-
import { useXYFlow } from '../xyflow/hooks'
|
|
14
|
-
import type { XYFlowNode } from '../xyflow/types'
|
|
15
|
-
import { distance } from '../xyflow/utils'
|
|
16
|
-
|
|
17
|
-
const selector = (state: ReactFlowState) => {
|
|
18
|
-
return {
|
|
19
|
-
isUserSelectionActive: state.userSelectionActive,
|
|
20
|
-
isDragging: state.paneDragging || state.nodes.some(n => n.dragging ?? false)
|
|
21
|
-
}
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const CameraMemo = /* @__PURE__ */ memo(function Camera() {
|
|
25
|
-
const isMounted = useIsMounted()
|
|
26
|
-
// const isUserSelectionActive = useStore(selectUserSelectionActive)
|
|
27
|
-
const {
|
|
28
|
-
isUserSelectionActive,
|
|
29
|
-
isDragging
|
|
30
|
-
} = useStore(selector, shallowEqual)
|
|
31
|
-
const reactflow = useXYFlow()
|
|
32
|
-
const updateNd = useUpdateNodeInternals()
|
|
33
|
-
|
|
34
|
-
const padding = 0 // editor.fitViewPadding
|
|
35
|
-
const viewId = '' // editor.viewId
|
|
36
|
-
const fitOnSelect: boolean = false // editor.fitOnSelect
|
|
37
|
-
|
|
38
|
-
const previousViewport = useRef<Viewport | null>(null)
|
|
39
|
-
const isZoomPendingRef = useRef(false)
|
|
40
|
-
|
|
41
|
-
const viewportChangeStart = useRef<Viewport | null>(null)
|
|
42
|
-
const prevViewId = useRef(viewId)
|
|
43
|
-
const isReady = reactflow.viewportInitialized
|
|
44
|
-
const selectedNodesRef = useRef([] as string[])
|
|
45
|
-
|
|
46
|
-
const [selectedNodes, setSelectedNodes] = useState([] as XYFlowNode[])
|
|
47
|
-
|
|
48
|
-
// WORKAROUND
|
|
49
|
-
|
|
50
|
-
useOnViewportChange({
|
|
51
|
-
onStart: (viewport) => {
|
|
52
|
-
viewportChangeStart.current = { ...viewport }
|
|
53
|
-
},
|
|
54
|
-
onEnd: (end) => {
|
|
55
|
-
if (!previousViewport.current) {
|
|
56
|
-
viewportChangeStart.current = null
|
|
57
|
-
}
|
|
58
|
-
if (!viewportChangeStart.current) {
|
|
59
|
-
return
|
|
60
|
-
}
|
|
61
|
-
const start = {
|
|
62
|
-
...viewportChangeStart.current
|
|
63
|
-
}
|
|
64
|
-
const d = distance(start, end)
|
|
65
|
-
if (d > 15) {
|
|
66
|
-
previousViewport.current = null
|
|
67
|
-
}
|
|
68
|
-
viewportChangeStart.current = null
|
|
69
|
-
}
|
|
70
|
-
})
|
|
71
|
-
|
|
72
|
-
const fixUseOnViewportChange = () => {
|
|
73
|
-
// WORKAROUND:
|
|
74
|
-
// react-flow triggers useOnViewportChange
|
|
75
|
-
// We reset the viewportChangeStart, before useOnViewportChange.onEnd called
|
|
76
|
-
setTimeout(() => {
|
|
77
|
-
viewportChangeStart.current = null
|
|
78
|
-
}, 50)
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
useOnSelectionChange({
|
|
82
|
-
onChange: ({ nodes, edges }) => {
|
|
83
|
-
if (!isMounted() || fitOnSelect === false) {
|
|
84
|
-
return
|
|
85
|
-
}
|
|
86
|
-
if (nodes.length === 0 && edges.length === 0) {
|
|
87
|
-
setSelectedNodes([])
|
|
88
|
-
return
|
|
89
|
-
}
|
|
90
|
-
const selected = new Set([
|
|
91
|
-
...nodes.map(({ id }) => reactflow.getNode(id)),
|
|
92
|
-
...edges.flatMap((edge) => [
|
|
93
|
-
reactflow.getNode(edge.source),
|
|
94
|
-
reactflow.getNode(edge.target)
|
|
95
|
-
])
|
|
96
|
-
].filter(Boolean))
|
|
97
|
-
setSelectedNodes([...selected])
|
|
98
|
-
}
|
|
99
|
-
})
|
|
100
|
-
|
|
101
|
-
const selectedNodesHash = selectedNodes.map((node) => node.id).sort().join('\n')
|
|
102
|
-
useEffect(() => {
|
|
103
|
-
isZoomPendingRef.current = selectedNodesHash !== ''
|
|
104
|
-
}, [selectedNodesHash])
|
|
105
|
-
|
|
106
|
-
useDebouncedEffect(
|
|
107
|
-
() => {
|
|
108
|
-
if (isUserSelectionActive || isDragging || !isReady) {
|
|
109
|
-
return
|
|
110
|
-
}
|
|
111
|
-
if (selectedNodes.length === 0) {
|
|
112
|
-
if (previousViewport.current) {
|
|
113
|
-
console.log(`Camera: revert viewport`)
|
|
114
|
-
reactflow.setViewport(previousViewport.current, {
|
|
115
|
-
duration: 300
|
|
116
|
-
})
|
|
117
|
-
previousViewport.current = null
|
|
118
|
-
}
|
|
119
|
-
return
|
|
120
|
-
}
|
|
121
|
-
if (!isZoomPendingRef.current) {
|
|
122
|
-
return
|
|
123
|
-
}
|
|
124
|
-
isZoomPendingRef.current = false
|
|
125
|
-
previousViewport.current ??= { ...reactflow.getViewport() }
|
|
126
|
-
const zoom = previousViewport.current.zoom
|
|
127
|
-
reactflow.fitView({
|
|
128
|
-
duration: 350,
|
|
129
|
-
maxZoom: Math.max(1, zoom),
|
|
130
|
-
padding,
|
|
131
|
-
nodes: selectedNodes
|
|
132
|
-
})
|
|
133
|
-
fixUseOnViewportChange()
|
|
134
|
-
},
|
|
135
|
-
[selectedNodesHash, isReady, isDragging, isUserSelectionActive],
|
|
136
|
-
previousViewport.current ? 100 : 1500
|
|
137
|
-
// previousViewport.current ? 200 : 2500
|
|
138
|
-
)
|
|
139
|
-
|
|
140
|
-
useEffect(() => {
|
|
141
|
-
const ids = selectedNodes.map((node) => node.id)
|
|
142
|
-
for (const id of uniq([...selectedNodesRef.current, ...ids])) {
|
|
143
|
-
try {
|
|
144
|
-
updateNd(id)
|
|
145
|
-
} catch (e) {
|
|
146
|
-
console.warn(`Camera: failed useUpdateNodeInternals`, e)
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
selectedNodesRef.current = ids
|
|
150
|
-
}, [selectedNodesHash, updateNd])
|
|
151
|
-
|
|
152
|
-
useDebouncedEffect(
|
|
153
|
-
() => {
|
|
154
|
-
if (!isReady || prevViewId.current === viewId) {
|
|
155
|
-
return
|
|
156
|
-
}
|
|
157
|
-
const zoom = previousViewport.current?.zoom ?? reactflow.getZoom()
|
|
158
|
-
reactflow.fitView({
|
|
159
|
-
duration: 400,
|
|
160
|
-
maxZoom: Math.max(1, zoom),
|
|
161
|
-
padding
|
|
162
|
-
})
|
|
163
|
-
previousViewport.current = null
|
|
164
|
-
prevViewId.current = viewId
|
|
165
|
-
},
|
|
166
|
-
[isReady, viewId],
|
|
167
|
-
50,
|
|
168
|
-
500
|
|
169
|
-
)
|
|
170
|
-
|
|
171
|
-
return null
|
|
172
|
-
})
|
|
173
|
-
|
|
174
|
-
export default CameraMemo
|