@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
|
@@ -7,14 +7,16 @@ import {
|
|
|
7
7
|
Group,
|
|
8
8
|
HoverCard,
|
|
9
9
|
HoverCardDropdown,
|
|
10
|
+
type HoverCardProps,
|
|
10
11
|
HoverCardTarget,
|
|
11
12
|
Stack,
|
|
12
13
|
UnstyledButton
|
|
13
14
|
} from '@mantine/core'
|
|
15
|
+
import { IconLink } from '@tabler/icons-react'
|
|
14
16
|
import clsx from 'clsx'
|
|
15
17
|
import { useId } from 'react'
|
|
16
18
|
import { clamp } from 'remeda'
|
|
17
|
-
import {
|
|
19
|
+
import { type DiagramState, useDiagramState } from '../../../state/hooks'
|
|
18
20
|
import type { XYFlowNode } from '../../types'
|
|
19
21
|
import { elementLink, trigger } from './ElementLink.css'
|
|
20
22
|
|
|
@@ -22,23 +24,17 @@ type ElementLinkProps = {
|
|
|
22
24
|
element: XYFlowNode['data']['element']
|
|
23
25
|
}
|
|
24
26
|
|
|
27
|
+
const selector = (s: DiagramState) => {
|
|
28
|
+
const target = s.getContainer()
|
|
29
|
+
return target ? { target } : null
|
|
30
|
+
}
|
|
31
|
+
|
|
25
32
|
export function ElementLink({
|
|
26
33
|
element
|
|
27
34
|
}: ElementLinkProps) {
|
|
28
35
|
invariant(element.links, 'ElementLink: links are required')
|
|
29
36
|
const id = useId()
|
|
30
|
-
|
|
31
|
-
// const root = mantineCtx.getRootElement()
|
|
32
|
-
|
|
33
|
-
// const targetSelector = `.react-flow:has([data-likec4-linkid="${id}"])`
|
|
34
|
-
// // const target = root?.querySelector<HTMLDivElement>(targetSelector) ?? targetSelector
|
|
35
|
-
|
|
36
|
-
// const portalProps = useMemo(() => ({
|
|
37
|
-
// get target(): HTMLElement | string {
|
|
38
|
-
// const root = mantineCtx.getRootElement()
|
|
39
|
-
// return root?.querySelector<HTMLDivElement>(targetSelector) ?? targetSelector
|
|
40
|
-
// }
|
|
41
|
-
// }), [targetSelector])
|
|
37
|
+
const portalProps = useDiagramState(selector)
|
|
42
38
|
return (
|
|
43
39
|
<div className={elementLink} data-likec4-linkid={id}>
|
|
44
40
|
<HoverCard
|
|
@@ -51,8 +47,7 @@ export function ElementLink({
|
|
|
51
47
|
transitionProps={{
|
|
52
48
|
transition: 'pop'
|
|
53
49
|
}}
|
|
54
|
-
|
|
55
|
-
withinPortal={false}
|
|
50
|
+
{...(portalProps ? { portalProps } : { withinPortal: false })}
|
|
56
51
|
floatingStrategy={'fixed'}
|
|
57
52
|
openDelay={350}
|
|
58
53
|
closeDelay={800}
|
|
@@ -64,7 +59,7 @@ export function ElementLink({
|
|
|
64
59
|
<UnstyledButton
|
|
65
60
|
className={clsx('nodrag nopan', trigger)}
|
|
66
61
|
autoFocus={false}>
|
|
67
|
-
<
|
|
62
|
+
<IconLink size={12} />
|
|
68
63
|
<span>links</span>
|
|
69
64
|
</UnstyledButton>
|
|
70
65
|
</HoverCardTarget>
|
|
@@ -1,13 +1,11 @@
|
|
|
1
1
|
import { Text } from '@mantine/core'
|
|
2
2
|
import { Handle, type NodeProps, Position } from '@xyflow/react'
|
|
3
3
|
import clsx from 'clsx'
|
|
4
|
-
import { DEV } from 'esm-env'
|
|
5
4
|
import { deepEqual as eq } from 'fast-equals'
|
|
6
5
|
import { m, type Variants } from 'framer-motion'
|
|
7
6
|
import { memo } from 'react'
|
|
8
7
|
import { isNumber } from 'remeda'
|
|
9
|
-
import
|
|
10
|
-
import { useDiagramState } from '../../../state'
|
|
8
|
+
import { useDiagramState } from '../../../state/hooks'
|
|
11
9
|
import type { ElementXYFlowNode } from '../../types'
|
|
12
10
|
import { toDomPrecision } from '../../utils'
|
|
13
11
|
import { NavigateToBtn } from '../shared/NavigateToBtn'
|
|
@@ -24,13 +22,13 @@ const variants = {
|
|
|
24
22
|
idle: (_, { scale }) => ({
|
|
25
23
|
scale: 1,
|
|
26
24
|
transition: {
|
|
27
|
-
delay: isNumber(scale) && scale > selectedScale ? 0.
|
|
25
|
+
delay: isNumber(scale) && scale > selectedScale ? 0.09 : 0
|
|
28
26
|
}
|
|
29
27
|
}),
|
|
30
28
|
selected: (_, { scale }) => ({
|
|
31
29
|
scale: selectedScale,
|
|
32
30
|
transition: {
|
|
33
|
-
delay: isNumber(scale) && scale > selectedScale ? 0.
|
|
31
|
+
delay: isNumber(scale) && scale > selectedScale ? 0.09 : 0
|
|
34
32
|
}
|
|
35
33
|
}),
|
|
36
34
|
// dimmed: {
|
|
@@ -54,12 +52,9 @@ const variants = {
|
|
|
54
52
|
// delay: 1
|
|
55
53
|
// }
|
|
56
54
|
// }),
|
|
57
|
-
hovered:
|
|
58
|
-
scale: 1.06
|
|
59
|
-
|
|
60
|
-
delay: isNumber(scale) && scale !== 1 && scale !== selectedScale ? 0 : 0.15
|
|
61
|
-
}
|
|
62
|
-
}),
|
|
55
|
+
hovered: {
|
|
56
|
+
scale: 1.06
|
|
57
|
+
},
|
|
63
58
|
tap: {
|
|
64
59
|
scale: 0.975
|
|
65
60
|
}
|
|
@@ -72,6 +67,7 @@ const isEqualProps = (prev: ElementNodeProps, next: ElementNodeProps) => (
|
|
|
72
67
|
prev.id === next.id
|
|
73
68
|
&& eq(prev.selected ?? false, next.selected ?? false)
|
|
74
69
|
&& eq(prev.dragging ?? false, next.dragging ?? false)
|
|
70
|
+
&& eq(prev.draggable ?? false, next.draggable ?? false)
|
|
75
71
|
&& eq(prev.width ?? 0, next.width ?? 0)
|
|
76
72
|
&& eq(prev.height ?? 0, next.height ?? 0)
|
|
77
73
|
&& eq(prev.data.element, next.data.element)
|
|
@@ -83,11 +79,11 @@ export const ElementNodeMemo = memo<ElementNodeProps>(function ElementNode({
|
|
|
83
79
|
element
|
|
84
80
|
},
|
|
85
81
|
dragging,
|
|
82
|
+
// draggable = false,
|
|
86
83
|
selected = false,
|
|
87
84
|
width,
|
|
88
85
|
height
|
|
89
86
|
}) {
|
|
90
|
-
DEV && useTilg()
|
|
91
87
|
const { isHovered, isDimmed, hasOnNavigateTo, isHovercards, isInteractive } = useDiagramState(s => ({
|
|
92
88
|
isHovered: s.hoveredNodeId === id,
|
|
93
89
|
isDimmed: s.dimmed.has(id),
|
|
@@ -123,122 +119,81 @@ export const ElementNodeMemo = memo<ElementNodeProps>(function ElementNode({
|
|
|
123
119
|
// useTilg(animate, isHovered, isInteractive)
|
|
124
120
|
|
|
125
121
|
return (
|
|
126
|
-
|
|
127
|
-
id={id}
|
|
128
|
-
className={clsx([
|
|
129
|
-
css.container,
|
|
130
|
-
isDimmed && css.dimmed,
|
|
131
|
-
'likec4-element-node'
|
|
132
|
-
])}
|
|
133
|
-
data-likec4-color={element.color}
|
|
134
|
-
data-likec4-shape={element.shape}
|
|
135
|
-
variants={variants}
|
|
136
|
-
initial={false}
|
|
137
|
-
animate={animate}
|
|
138
|
-
{...(isInteractive && {
|
|
139
|
-
whileTap: dragging ? animate : 'tap'
|
|
140
|
-
})}
|
|
141
|
-
>
|
|
142
|
-
{
|
|
143
|
-
/* <NodeToolbar
|
|
144
|
-
position={Position.Bottom}
|
|
145
|
-
align={'start'}
|
|
146
|
-
offset={-10}
|
|
147
|
-
isVisible={selected || isHovered}>
|
|
148
|
-
<Button>editggg</Button>
|
|
149
|
-
</NodeToolbar> */
|
|
150
|
-
}
|
|
151
|
-
{
|
|
152
|
-
/* <NodeResizer minWidth={100} minHeight={30} />
|
|
153
|
-
<NodeToolbar
|
|
154
|
-
position={Position.Right}
|
|
155
|
-
align={'start'}
|
|
156
|
-
style={{
|
|
157
|
-
background: 'blue'
|
|
158
|
-
}}>
|
|
159
|
-
<Stack>
|
|
160
|
-
<Button>edit</Button>
|
|
161
|
-
|
|
162
|
-
</Stack>
|
|
163
|
-
</NodeToolbar>*/
|
|
164
|
-
}
|
|
165
|
-
{
|
|
166
|
-
/* {element.inEdges.map((edge) => (
|
|
167
|
-
<Handle
|
|
168
|
-
key={edge}
|
|
169
|
-
id={edge}
|
|
170
|
-
type="target"
|
|
171
|
-
position={Position.Top}
|
|
172
|
-
style={{ visibility: 'hidden' }}
|
|
173
|
-
/>
|
|
174
|
-
))} */
|
|
175
|
-
}
|
|
122
|
+
<>
|
|
176
123
|
<Handle
|
|
177
124
|
type="target"
|
|
178
125
|
position={Position.Top}
|
|
179
|
-
|
|
126
|
+
className={css.handleCenter}
|
|
180
127
|
/>
|
|
181
|
-
<
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
128
|
+
<m.div
|
|
129
|
+
id={id}
|
|
130
|
+
className={clsx([
|
|
131
|
+
css.container,
|
|
132
|
+
isDimmed && css.dimmed,
|
|
133
|
+
animate !== 'idle' && css.containerAnimated,
|
|
134
|
+
'likec4-element-node'
|
|
135
|
+
])}
|
|
136
|
+
data-hovered={!dragging && isHovered}
|
|
137
|
+
data-likec4-color={element.color}
|
|
138
|
+
data-likec4-shape={element.shape}
|
|
139
|
+
variants={variants}
|
|
140
|
+
initial={false}
|
|
141
|
+
animate={animate}
|
|
142
|
+
{...(isInteractive && {
|
|
143
|
+
whileTap: dragging ? animate : 'tap'
|
|
144
|
+
})}
|
|
188
145
|
>
|
|
189
|
-
<
|
|
190
|
-
|
|
146
|
+
<svg
|
|
147
|
+
className={clsx(
|
|
148
|
+
css.cssShapeSvg
|
|
149
|
+
)}
|
|
150
|
+
viewBox={`0 0 ${w} ${h}`}
|
|
151
|
+
width={w}
|
|
152
|
+
height={h}
|
|
153
|
+
>
|
|
154
|
+
<g className={css.indicator}>
|
|
155
|
+
<SelectedIndicator
|
|
156
|
+
shape={element.shape}
|
|
157
|
+
w={w}
|
|
158
|
+
h={h}
|
|
159
|
+
/>
|
|
160
|
+
</g>
|
|
161
|
+
<ElementShapeSvg
|
|
191
162
|
shape={element.shape}
|
|
192
163
|
w={w}
|
|
193
164
|
h={h}
|
|
194
165
|
/>
|
|
195
|
-
</
|
|
196
|
-
<
|
|
197
|
-
|
|
198
|
-
w={w}
|
|
199
|
-
h={h}
|
|
200
|
-
/>
|
|
201
|
-
</svg>
|
|
202
|
-
<div className={clsx(css.element, 'likec4-element')}>
|
|
203
|
-
{element.icon && <ElementIcon node={element} />}
|
|
204
|
-
<Text
|
|
205
|
-
component="div"
|
|
206
|
-
className={clsx(css.title, 'likec4-element-title')}>
|
|
207
|
-
{element.title}
|
|
208
|
-
</Text>
|
|
209
|
-
{element.technology && (
|
|
166
|
+
</svg>
|
|
167
|
+
<div className={clsx(css.element, 'likec4-element')}>
|
|
168
|
+
<ElementIcon node={element} />
|
|
210
169
|
<Text
|
|
211
170
|
component="div"
|
|
212
|
-
className={clsx(css.
|
|
213
|
-
{element.
|
|
171
|
+
className={clsx(css.title, 'likec4-element-title')}>
|
|
172
|
+
{element.title}
|
|
214
173
|
</Text>
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
174
|
+
{element.technology && (
|
|
175
|
+
<Text
|
|
176
|
+
component="div"
|
|
177
|
+
className={clsx(css.technology, 'likec4-element-technology')}>
|
|
178
|
+
{element.technology}
|
|
179
|
+
</Text>
|
|
180
|
+
)}
|
|
181
|
+
{element.description && (
|
|
182
|
+
<Text
|
|
183
|
+
component="div"
|
|
184
|
+
className={clsx(css.description, 'likec4-element-description')}>
|
|
185
|
+
{element.description}
|
|
186
|
+
</Text>
|
|
187
|
+
)}
|
|
188
|
+
</div>
|
|
189
|
+
{isHovercards && element.links && <ElementLink element={element} />}
|
|
190
|
+
{isNavigable && <NavigateToBtn xynodeId={id} className={css.cssNavigateBtn} />}
|
|
191
|
+
</m.div>
|
|
224
192
|
<Handle
|
|
225
193
|
type="source"
|
|
226
|
-
position={Position.
|
|
227
|
-
|
|
194
|
+
position={Position.Top}
|
|
195
|
+
className={css.handleCenter}
|
|
228
196
|
/>
|
|
229
|
-
|
|
230
|
-
/* {element.outEdges.map((edge) => (
|
|
231
|
-
<Handle
|
|
232
|
-
key={edge}
|
|
233
|
-
id={edge}
|
|
234
|
-
type="source"
|
|
235
|
-
position={Position.Bottom}
|
|
236
|
-
style={{ visibility: 'hidden' }}
|
|
237
|
-
/>
|
|
238
|
-
))} */
|
|
239
|
-
}
|
|
240
|
-
{isHovercards && element.links && <ElementLink element={element} />}
|
|
241
|
-
{isNavigable && <NavigateToBtn xynodeId={id} className={css.cssNavigateBtn} />}
|
|
242
|
-
</m.div>
|
|
197
|
+
</>
|
|
243
198
|
)
|
|
244
199
|
}, isEqualProps)
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { rem } from '@mantine/core'
|
|
2
2
|
import { createVar, fallbackVar, globalStyle, keyframes, style } from '@vanilla-extract/css'
|
|
3
|
+
import { calc } from '@vanilla-extract/css-utils'
|
|
3
4
|
import { mantine } from '../../../mantine.css'
|
|
4
5
|
import { vars } from '../../../theme.css'
|
|
5
6
|
|
|
@@ -16,16 +17,34 @@ export const container = style({
|
|
|
16
17
|
alignItems: 'stretch',
|
|
17
18
|
vars: {
|
|
18
19
|
[stokeFillMix]: `color-mix(in srgb, ${vars.element.stroke} 90%, ${vars.element.fill})`
|
|
20
|
+
},
|
|
21
|
+
selectors: {
|
|
22
|
+
':where(.react-flow__node.selected) &': {
|
|
23
|
+
willChange: 'transform'
|
|
24
|
+
},
|
|
25
|
+
'&[data-hovered="true"]': {
|
|
26
|
+
willChange: 'transform'
|
|
27
|
+
}
|
|
19
28
|
}
|
|
20
29
|
})
|
|
21
30
|
|
|
31
|
+
export const handleCenter = style({
|
|
32
|
+
top: '50%',
|
|
33
|
+
left: '50%',
|
|
34
|
+
visibility: 'hidden'
|
|
35
|
+
})
|
|
36
|
+
|
|
37
|
+
export const containerAnimated = style({
|
|
38
|
+
willChange: 'transform'
|
|
39
|
+
})
|
|
40
|
+
|
|
22
41
|
export const dimmed = style({})
|
|
23
42
|
|
|
24
43
|
globalStyle(`.react-flow__node-element:has(${dimmed})`, {
|
|
25
44
|
opacity: 0.25,
|
|
26
45
|
transition: 'opacity 600ms ease-in-out, filter 600ms ease-in-out',
|
|
27
46
|
transitionDelay: '200ms',
|
|
28
|
-
filter:
|
|
47
|
+
filter: `grayscale(0.85) ${fallbackVar(vars.safariAnimationHook, 'blur(2px)')}`,
|
|
29
48
|
willChange: 'opacity, filter'
|
|
30
49
|
})
|
|
31
50
|
|
|
@@ -44,21 +63,27 @@ const outlineColor = fallbackVar(
|
|
|
44
63
|
vars.element.stroke
|
|
45
64
|
)
|
|
46
65
|
|
|
66
|
+
const indicatorStroke = createVar('indicator-stroke')
|
|
67
|
+
|
|
47
68
|
export const indicator = style({
|
|
48
|
-
stroke:
|
|
69
|
+
stroke: indicatorStroke,
|
|
70
|
+
fill: 'none',
|
|
49
71
|
transformOrigin: 'center center',
|
|
50
72
|
strokeWidth: 6,
|
|
51
73
|
animationDuration: '800ms',
|
|
52
|
-
animationName: indicatorKeyframes,
|
|
53
74
|
animationIterationCount: 'infinite',
|
|
54
75
|
animationDirection: 'alternate',
|
|
76
|
+
opacity: 0.6,
|
|
55
77
|
visibility: 'hidden',
|
|
78
|
+
vars: {
|
|
79
|
+
[indicatorStroke]: vars.element.loContrast
|
|
80
|
+
},
|
|
56
81
|
selectors: {
|
|
57
82
|
':where(.react-flow__node.selected) &': {
|
|
58
|
-
visibility: 'visible'
|
|
83
|
+
visibility: 'visible',
|
|
84
|
+
animationName: fallbackVar(vars.safariAnimationHook, indicatorKeyframes)
|
|
59
85
|
},
|
|
60
86
|
[`:where(.react-flow__node:focus-visible, ${container}:focus-visible) &`]: {
|
|
61
|
-
animationName: 'none',
|
|
62
87
|
strokeWidth: 10,
|
|
63
88
|
stroke: outlineColor,
|
|
64
89
|
visibility: 'visible'
|
|
@@ -66,8 +91,14 @@ export const indicator = style({
|
|
|
66
91
|
':where([data-likec4-shape="queue"], [data-likec4-shape="cylinder"], [data-likec4-shape="storage"]) &': {
|
|
67
92
|
strokeWidth: 10
|
|
68
93
|
},
|
|
94
|
+
[`:where([data-mantine-color-scheme='light']) &`]: {
|
|
95
|
+
vars: {
|
|
96
|
+
[indicatorStroke]: `color-mix(in srgb, ${vars.element.fill} 60%, ${vars.element.loContrast})`
|
|
97
|
+
}
|
|
98
|
+
},
|
|
69
99
|
[`${dimmed} &`]: {
|
|
70
|
-
visibility: 'hidden'
|
|
100
|
+
visibility: 'hidden',
|
|
101
|
+
display: 'none'
|
|
71
102
|
}
|
|
72
103
|
}
|
|
73
104
|
})
|
|
@@ -91,7 +122,7 @@ export const title = style({
|
|
|
91
122
|
fontStyle: 'normal',
|
|
92
123
|
textAlign: 'center',
|
|
93
124
|
fontWeight: 500,
|
|
94
|
-
fontSize: rem(19),
|
|
125
|
+
fontSize: rem(19.5),
|
|
95
126
|
lineHeight: 1.2,
|
|
96
127
|
textWrap: 'balance',
|
|
97
128
|
color: vars.element.hiContrast
|
|
@@ -162,34 +193,34 @@ export const element = style({
|
|
|
162
193
|
}
|
|
163
194
|
})
|
|
164
195
|
|
|
165
|
-
export const
|
|
196
|
+
export const iconOffsetY = createVar('offset-y')
|
|
197
|
+
|
|
198
|
+
const iconMaxH = createVar('max-h')
|
|
166
199
|
|
|
167
200
|
export const elementIcon = style({
|
|
168
201
|
flex: `0 1 ${iconMaxH}`,
|
|
169
202
|
maxHeight: iconMaxH,
|
|
170
|
-
marginTop: -8,
|
|
171
203
|
position: 'relative',
|
|
172
204
|
userSelect: 'none',
|
|
173
205
|
pointerEvents: 'none',
|
|
174
206
|
overflow: 'visible',
|
|
175
207
|
mixBlendMode: 'hard-light',
|
|
176
208
|
'vars': {
|
|
177
|
-
[iconMaxH]: '
|
|
209
|
+
[iconMaxH]: calc(iconOffsetY).subtract('12px').toString()
|
|
178
210
|
}
|
|
179
211
|
})
|
|
180
212
|
|
|
181
213
|
globalStyle(`${elementIcon} img`, {
|
|
182
214
|
position: 'absolute',
|
|
183
215
|
left: 0,
|
|
184
|
-
bottom:
|
|
216
|
+
bottom: 4,
|
|
185
217
|
width: '100%',
|
|
186
218
|
height: 'auto',
|
|
187
219
|
objectFit: 'contain',
|
|
188
|
-
maxHeight:
|
|
220
|
+
maxHeight: iconOffsetY
|
|
189
221
|
})
|
|
190
222
|
|
|
191
223
|
const filterShadow = createVar('filter-shadow')
|
|
192
|
-
const filterShadowHovered = createVar('filter-shadow-hovered')
|
|
193
224
|
|
|
194
225
|
export const cssShapeSvg = style({
|
|
195
226
|
top: '0px',
|
|
@@ -199,7 +230,7 @@ export const cssShapeSvg = style({
|
|
|
199
230
|
fill: vars.element.fill,
|
|
200
231
|
stroke: vars.element.stroke,
|
|
201
232
|
overflow: 'visible',
|
|
202
|
-
filter:
|
|
233
|
+
filter: filterShadow,
|
|
203
234
|
transition: 'filter 300ms ease-out',
|
|
204
235
|
transitionDelay: '0ms',
|
|
205
236
|
zIndex: -1,
|
|
@@ -212,7 +243,9 @@ export const cssShapeSvg = style({
|
|
|
212
243
|
},
|
|
213
244
|
selectors: {
|
|
214
245
|
[`:where(.react-flow__node.selected, .react-flow__node:focus-visible, ${container}:focus-visible) &`]: {
|
|
215
|
-
|
|
246
|
+
vars: {
|
|
247
|
+
[filterShadow]: `none`
|
|
248
|
+
}
|
|
216
249
|
}
|
|
217
250
|
}
|
|
218
251
|
})
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { ActionIcon } from '@mantine/core'
|
|
2
2
|
import { IconZoomScan } from '@tabler/icons-react'
|
|
3
3
|
import clsx from 'clsx'
|
|
4
|
-
import { useDiagramStoreApi } from '../../../state'
|
|
4
|
+
import { useDiagramStoreApi } from '../../../state/hooks'
|
|
5
5
|
|
|
6
6
|
export type NavigateToBtnProps = {
|
|
7
7
|
xynodeId: string
|
package/src/xyflow/types.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { BBox, DiagramEdge, DiagramNode, Fqn,
|
|
1
|
+
import type { BBox, DiagramEdge, DiagramNode, Fqn, XYPosition } from '@likec4/core'
|
|
2
2
|
import type {
|
|
3
3
|
Edge,
|
|
4
4
|
EdgeMouseHandler,
|
|
@@ -13,7 +13,7 @@ import type {
|
|
|
13
13
|
import { isNode } from '@xyflow/react'
|
|
14
14
|
import type { MouseEvent as ReactMouseEvent } from 'react'
|
|
15
15
|
import { isTruthy } from 'remeda'
|
|
16
|
-
import type { SetReadonly, SetRequired
|
|
16
|
+
import type { SetReadonly, SetRequired } from 'type-fest'
|
|
17
17
|
|
|
18
18
|
export type ElementNodeData = {
|
|
19
19
|
fqn: Fqn
|
|
@@ -61,8 +61,6 @@ export type RelationshipData = {
|
|
|
61
61
|
// viewId: ViewID
|
|
62
62
|
// if set - edge was changed by user
|
|
63
63
|
controlPoints: XYPosition[] | null
|
|
64
|
-
headPoint: Point | null
|
|
65
|
-
tailPoint: Point | null
|
|
66
64
|
type: 'bezier' | 'poly'
|
|
67
65
|
// if dynamic view
|
|
68
66
|
stepNum: number | null
|
package/src/xyflow/utils.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { hasAtLeast, invariant } from '@likec4/core'
|
|
2
|
-
import type { DiagramEdge,
|
|
2
|
+
import type { DiagramEdge, Point } from '@likec4/core/types'
|
|
3
3
|
import type { XYPosition } from '@xyflow/react'
|
|
4
4
|
import { Bezier } from 'bezier-js'
|
|
5
5
|
import { isArray } from 'remeda'
|
|
@@ -33,17 +33,14 @@ export function bezierControlPoints(diagramEdge: DiagramEdge) {
|
|
|
33
33
|
inflections.forEach(t => {
|
|
34
34
|
const { x, y } = bezier.get(t)
|
|
35
35
|
handles.push({
|
|
36
|
-
x:
|
|
37
|
-
y:
|
|
36
|
+
x: Math.round(x),
|
|
37
|
+
y: Math.round(y)
|
|
38
38
|
})
|
|
39
39
|
})
|
|
40
40
|
bezierPoints = rest
|
|
41
41
|
start = end
|
|
42
42
|
}
|
|
43
43
|
invariant(bezierPoints.length === 0, 'all points should be consumed')
|
|
44
|
-
if (diagramEdge.dir === 'back' && handles.length > 0) {
|
|
45
|
-
handles.reverse()
|
|
46
|
-
}
|
|
47
44
|
|
|
48
45
|
return handles
|
|
49
46
|
}
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
import { HTMLAttributes } from 'react';
|
|
2
|
-
|
|
3
|
-
type KeepAspectRatioContainerProps = HTMLAttributes<HTMLDivElement> & {
|
|
4
|
-
enabled: boolean;
|
|
5
|
-
width: number;
|
|
6
|
-
height: number;
|
|
7
|
-
};
|
|
8
|
-
export declare function KeepAspectRatioContainer({ children, width, height, enabled, className, style, ...rest }: KeepAspectRatioContainerProps): import("react/jsx-runtime").JSX.Element;
|
|
9
|
-
export {};
|
package/dist/icons/Link.d.ts
DELETED
package/dist/icons/ZoomIn.d.ts
DELETED
package/dist/icons/index.d.ts
DELETED
package/dist/mantine/theme.d.ts
DELETED
package/dist/ui/Camera.d.ts
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { Box } from '@mantine/core'
|
|
2
|
-
import clsx from 'clsx'
|
|
3
|
-
import { type HTMLAttributes, useId } from 'react'
|
|
4
|
-
import * as css from './LikeC4Diagram.css'
|
|
5
|
-
|
|
6
|
-
type KeepAspectRatioContainerProps = HTMLAttributes<HTMLDivElement> & {
|
|
7
|
-
// Whether to keep the aspect ratio
|
|
8
|
-
enabled: boolean
|
|
9
|
-
width: number
|
|
10
|
-
height: number
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
export function KeepAspectRatioContainer({
|
|
14
|
-
children,
|
|
15
|
-
width,
|
|
16
|
-
height,
|
|
17
|
-
enabled,
|
|
18
|
-
className,
|
|
19
|
-
style,
|
|
20
|
-
...rest
|
|
21
|
-
}: KeepAspectRatioContainerProps) {
|
|
22
|
-
return (
|
|
23
|
-
<Box
|
|
24
|
-
{...rest}
|
|
25
|
-
className={clsx(css.keepAspectRatioContainer, className)}
|
|
26
|
-
style={enabled
|
|
27
|
-
? {
|
|
28
|
-
...style,
|
|
29
|
-
aspectRatio: `${Math.ceil(width)}/${Math.ceil(height)}`,
|
|
30
|
-
maxHeight: `var(--likec4-view-max-height, ${Math.ceil(height)}px)`
|
|
31
|
-
}
|
|
32
|
-
: style}>
|
|
33
|
-
{children}
|
|
34
|
-
</Box>
|
|
35
|
-
)
|
|
36
|
-
}
|
package/src/icons/Clipboard.tsx
DELETED
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import clsx from 'clsx'
|
|
2
|
-
import { forwardRef, type SVGProps } from 'react'
|
|
3
|
-
|
|
4
|
-
export const ClipboardCopy = 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="M9 5h-2a2 2 0 0 0 -2 2v12a2 2 0 0 0 2 2h3m9 -9v-5a2 2 0 0 0 -2 -2h-2" />
|
|
21
|
-
<path d="M13 17v-1a1 1 0 0 1 1 -1h1m3 0h1a1 1 0 0 1 1 1v1m0 3v1a1 1 0 0 1 -1 1h-1m-3 0h-1a1 1 0 0 1 -1 -1v-1" />
|
|
22
|
-
<path d="M9 3m0 2a2 2 0 0 1 2 -2h2a2 2 0 0 1 2 2v0a2 2 0 0 1 -2 2h-2a2 2 0 0 1 -2 -2z" />
|
|
23
|
-
</svg>
|
|
24
|
-
))
|
package/src/icons/Link.tsx
DELETED
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
import clsx from 'clsx'
|
|
2
|
-
import { forwardRef, type SVGProps } from 'react'
|
|
3
|
-
|
|
4
|
-
export const Link = forwardRef<SVGSVGElement, SVGProps<SVGSVGElement>>(({ className, ...props }, ref) => (
|
|
5
|
-
<svg
|
|
6
|
-
ref={ref}
|
|
7
|
-
className={clsx('icon icon-tabler', className)}
|
|
8
|
-
stroke="currentColor"
|
|
9
|
-
fill="currentColor"
|
|
10
|
-
strokeWidth="0"
|
|
11
|
-
viewBox="0 0 20 20"
|
|
12
|
-
height="20"
|
|
13
|
-
width="20"
|
|
14
|
-
xmlns="http://www.w3.org/2000/svg"
|
|
15
|
-
{...props}
|
|
16
|
-
>
|
|
17
|
-
<path
|
|
18
|
-
fillRule="evenodd"
|
|
19
|
-
d="M12.586 4.586a2 2 0 112.828 2.828l-3 3a2 2 0 01-2.828 0 1 1 0 00-1.414 1.414 4 4 0 005.656 0l3-3a4 4 0 00-5.656-5.656l-1.5 1.5a1 1 0 101.414 1.414l1.5-1.5zm-5 5a2 2 0 012.828 0 1 1 0 101.414-1.414 4 4 0 00-5.656 0l-3 3a4 4 0 105.656 5.656l1.5-1.5a1 1 0 10-1.414-1.414l-1.5 1.5a2 2 0 11-2.828-2.828l3-3z"
|
|
20
|
-
clipRule="evenodd">
|
|
21
|
-
</path>
|
|
22
|
-
</svg>
|
|
23
|
-
))
|