@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.
Files changed (95) hide show
  1. package/dist/LikeC4Diagram.css.d.ts +0 -1
  2. package/dist/LikeC4Diagram.d.ts +1 -1
  3. package/dist/LikeC4Diagram.props.d.ts +7 -2
  4. package/dist/index.d.ts +1 -1
  5. package/dist/index.mjs +1580 -1194
  6. package/dist/state/DiagramContext.d.ts +97 -4169
  7. package/dist/state/diagramStore.d.ts +98 -4172
  8. package/dist/state/hooks.d.ts +4 -0
  9. package/dist/state/index.d.ts +1 -3
  10. package/dist/state/useDiagramStore.d.ts +3 -4622
  11. package/dist/state/useNavigationHistory.d.ts +5 -0
  12. package/dist/style.css +217 -159
  13. package/dist/theme.css.d.ts +5 -0
  14. package/dist/ui/BackwardForwardPanel.css.d.ts +1 -0
  15. package/dist/ui/BackwardForwardPanel.d.ts +1 -0
  16. package/dist/ui/DiagramTitlePanel.css.d.ts +1 -1
  17. package/dist/ui/OptionsPanel.d.ts +1 -3
  18. package/dist/ui/options/EdgeOptions.d.ts +19 -0
  19. package/dist/ui/options/NodeOptions.d.ts +2 -2
  20. package/dist/xyflow/EdgeMarkers.d.ts +11 -0
  21. package/dist/xyflow/XYFlowEvents.d.ts +12 -9
  22. package/dist/xyflow/XYFlowInner.d.ts +1 -0
  23. package/dist/xyflow/const.d.ts +3 -3
  24. package/dist/xyflow/diagram-to-xyflow.d.ts +1 -1
  25. package/dist/xyflow/edges/RelationshipEdge.d.ts +4 -3
  26. package/dist/xyflow/edges/edges.css.d.ts +1 -0
  27. package/dist/xyflow/edges/utils.d.ts +1 -0
  28. package/dist/xyflow/hooks/index.d.ts +3 -2
  29. package/dist/xyflow/hooks/useXYFlow.d.ts +22 -21
  30. package/dist/xyflow/nodes/compound/CompoundNode.css.d.ts +1 -0
  31. package/dist/xyflow/nodes/element/ElementIcon.d.ts +1 -4
  32. package/dist/xyflow/nodes/element/element.css.d.ts +3 -1
  33. package/dist/xyflow/types.d.ts +2 -32
  34. package/package.json +21 -21
  35. package/src/LikeC4Diagram.css.ts +10 -8
  36. package/src/LikeC4Diagram.props.ts +12 -5
  37. package/src/LikeC4Diagram.tsx +43 -26
  38. package/src/globals.css.ts +11 -4
  39. package/src/index.ts +1 -1
  40. package/src/mantine.css.ts +2 -2
  41. package/src/state/DiagramContext.tsx +47 -16
  42. package/src/state/diagramStore.ts +89 -80
  43. package/src/state/hooks.ts +5 -0
  44. package/src/state/index.ts +1 -3
  45. package/src/state/useDiagramStore.ts +6 -13
  46. package/src/state/useNavigationHistory.ts +39 -0
  47. package/src/theme.css.ts +5 -0
  48. package/src/ui/BackwardForwardPanel.css.ts +22 -0
  49. package/src/ui/BackwardForwardPanel.tsx +59 -0
  50. package/src/ui/DiagramTitlePanel.css.ts +17 -6
  51. package/src/ui/DiagramTitlePanel.tsx +108 -94
  52. package/src/ui/DynamicViewWalkthrough.tsx +6 -4
  53. package/src/ui/OptionsPanel.tsx +37 -18
  54. package/src/ui/options/EdgeOptions.tsx +157 -0
  55. package/src/ui/options/NodeOptions.tsx +37 -29
  56. package/src/xyflow/EdgeMarkers.tsx +148 -0
  57. package/src/xyflow/FitviewOnDiagramChange.tsx +8 -4
  58. package/src/xyflow/SelectEdgesOnNodeFocus.tsx +59 -55
  59. package/src/xyflow/SyncWithDiagram.tsx +13 -20
  60. package/src/xyflow/XYFlow.tsx +2 -4
  61. package/src/xyflow/XYFlowEvents.tsx +48 -33
  62. package/src/xyflow/XYFlowInner.tsx +6 -3
  63. package/src/xyflow/const.ts +3 -3
  64. package/src/xyflow/diagram-to-xyflow.ts +18 -53
  65. package/src/xyflow/edges/RelationshipEdge.tsx +218 -126
  66. package/src/xyflow/edges/edges.css.ts +44 -26
  67. package/src/xyflow/edges/utils.ts +10 -0
  68. package/src/xyflow/hooks/index.ts +4 -2
  69. package/src/xyflow/hooks/useLayoutConstraints.ts +5 -5
  70. package/src/xyflow/hooks/useXYFlow.ts +28 -1
  71. package/src/xyflow/nodes/compound/CompoundNode.css.ts +41 -31
  72. package/src/xyflow/nodes/compound/CompoundNode.tsx +52 -53
  73. package/src/xyflow/nodes/element/ElementIcon.tsx +11 -22
  74. package/src/xyflow/nodes/element/ElementLink.tsx +11 -16
  75. package/src/xyflow/nodes/element/ElementNode.tsx +69 -114
  76. package/src/xyflow/nodes/element/element.css.ts +48 -15
  77. package/src/xyflow/nodes/shared/NavigateToBtn.tsx +1 -1
  78. package/src/xyflow/types.ts +2 -4
  79. package/src/xyflow/utils.ts +3 -6
  80. package/dist/KeepAspectRatioContainer.d.ts +0 -9
  81. package/dist/icons/Clipboard.d.ts +0 -3
  82. package/dist/icons/Link.d.ts +0 -3
  83. package/dist/icons/ZoomIn.d.ts +0 -3
  84. package/dist/icons/index.d.ts +0 -3
  85. package/dist/mantine/theme.d.ts +0 -3
  86. package/dist/state/WhenInitialized.d.ts +0 -3
  87. package/dist/ui/Camera.d.ts +0 -3
  88. package/src/KeepAspectRatioContainer.tsx +0 -36
  89. package/src/icons/Clipboard.tsx +0 -24
  90. package/src/icons/Link.tsx +0 -23
  91. package/src/icons/ZoomIn.tsx +0 -25
  92. package/src/icons/index.ts +0 -3
  93. package/src/mantine/theme.ts +0 -20
  94. package/src/state/WhenInitialized.tsx +0 -24
  95. package/src/ui/Camera.tsx +0 -174
@@ -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
- ))
@@ -1,3 +0,0 @@
1
- export * from './Clipboard'
2
- export * from './Link'
3
- export * from './ZoomIn'
@@ -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