likec4 0.48.0 → 0.50.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/README.md +12 -6
- package/dist/@likec4/diagrams/diagram/Diagram.js +55 -27
- package/dist/@likec4/diagrams/diagram/Edges.js +14 -11
- package/dist/@likec4/diagrams/diagram/Nodes.js +212 -23
- package/dist/@likec4/diagrams/diagram/icons/ZoomIn.js +2 -1
- package/dist/@likec4/diagrams/diagram/shapes/Compound.js +2 -1
- package/dist/@likec4/diagrams/diagram/shapes/Edge.js +1 -1
- package/dist/@likec4/diagrams/diagram/state/atoms.js +35 -60
- package/dist/@likec4/diagrams/diagram/utils.js +14 -0
- package/dist/@likec4/diagrams/hooks/useDiagramApi.js +4 -5
- package/dist/@likec4/diagrams/hooks/useImageLoader.js +1 -1
- package/dist/__app__/likec4.css +8 -5
- package/dist/__app__/src/App.jsx +9 -11
- package/dist/__app__/src/components/CopyToClipboard.jsx +29 -0
- package/dist/__app__/src/components/CopyToClipboard.module.css +16 -0
- package/dist/__app__/src/components/DiagramNotFound.jsx +2 -2
- package/dist/__app__/src/components/index.js +2 -1
- package/dist/__app__/src/components/sidebar/Sidebar.jsx +1 -1
- package/dist/__app__/src/components/sidebar/styles.module.css +4 -1
- package/dist/__app__/src/components/view-page/DisplayModeSelector.jsx +15 -9
- package/dist/__app__/src/components/view-page/Header.jsx +97 -0
- package/dist/__app__/src/components/view-page/Header.module.css +24 -0
- package/dist/__app__/src/components/view-page/ShareDialog.jsx +23 -15
- package/dist/__app__/src/components/view-page/ViewActions.jsx +69 -0
- package/dist/__app__/src/data/atoms.js +4 -22
- package/dist/__app__/src/data/hooks.js +5 -4
- package/dist/__app__/src/data/index-page.js +22 -0
- package/dist/__app__/src/likec4-views.js +1 -1
- package/dist/__app__/src/pages/index-page/index.jsx +99 -0
- package/dist/__app__/src/pages/index-page/index.module.css +20 -0
- package/dist/__app__/src/pages/index.js +1 -1
- package/dist/__app__/src/pages/useTransparentBackground.js +2 -2
- package/dist/__app__/src/pages/view-page/ViewAsReact.jsx +60 -0
- package/dist/__app__/src/pages/view-page/index.js +11 -0
- package/dist/__app__/src/pages/view-page/other-formats/ViewAsD2.jsx +18 -0
- package/dist/__app__/src/pages/view-page/other-formats/ViewAsDot.jsx +33 -0
- package/dist/__app__/src/pages/view-page/other-formats/ViewAsMmd.jsx +18 -0
- package/dist/__app__/src/pages/view-page/other-formats.jsx +43 -0
- package/dist/__app__/src/pages/view-page/view-page.module.css +81 -0
- package/dist/__app__/src/pages/view.page.jsx +12 -65
- package/dist/__app__/src/router.js +90 -20
- package/dist/__app__/src/utils/utils.js +1 -2
- package/dist/__app__/tsconfig.json +1 -0
- package/dist/cli/index.js +288 -207
- package/package.json +17 -17
- package/dist/__app__/postcss.config.cjs +0 -11
- package/dist/__app__/src/components/view-page/ViewActionsToolbar.jsx +0 -66
- package/dist/__app__/src/pages/index.module.css +0 -11
- package/dist/__app__/src/pages/index.page.jsx +0 -57
- package/dist/__app__/src/pages/view-page.module.css +0 -30
- package/dist/__app__/tailwind.config.cjs +0 -17
package/README.md
CHANGED
|
@@ -4,9 +4,9 @@
|
|
|
4
4
|
|
|
5
5
|
Features:
|
|
6
6
|
|
|
7
|
-
- Preview diagrams in a local web server (with lightning
|
|
7
|
+
- Preview diagrams in a local web server (with lightning-fast updates) ⚡️
|
|
8
8
|
- Build a static .website (deploy to github pages, netlify...) 🔗
|
|
9
|
-
- Export to PNG, Mermaid, Dot, D2 (if you something static) 🖼️
|
|
9
|
+
- Export to PNG, JSON, Mermaid, Dot, D2 (if you need something static) 🖼️
|
|
10
10
|
- Generate React components (for custom integrations ) 🛠️
|
|
11
11
|
|
|
12
12
|
## Install
|
|
@@ -76,7 +76,7 @@ likec4 start
|
|
|
76
76
|
likec4 dev
|
|
77
77
|
```
|
|
78
78
|
|
|
79
|
-
This recursively
|
|
79
|
+
This recursively searches for `*.c4`, `*.likec4` files in the current folder, parses and serves diagrams in a local web server.
|
|
80
80
|
Any changes in the sources trigger a super-fast hot update and you see changes in the browser immediately.
|
|
81
81
|
|
|
82
82
|
> **Tip:**
|
|
@@ -92,7 +92,7 @@ likec4 build -o ./dist
|
|
|
92
92
|
|
|
93
93
|
Example [https://template.likec4.dev](https://template.likec4.dev/view/cloud)
|
|
94
94
|
|
|
95
|
-
When you
|
|
95
|
+
When you deploy the website, you can use the "Share" button to get links.
|
|
96
96
|
|
|
97
97
|
> **Tip:**
|
|
98
98
|
> [likec4/template](https://github.com/likec4/template) repository demonstrates how to deploy to github pages.
|
|
@@ -111,9 +111,15 @@ For example, this command can be used on CI, to compare diagrams with ones from
|
|
|
111
111
|
likec4 export png -o ./assets
|
|
112
112
|
```
|
|
113
113
|
|
|
114
|
-
This command starts local web server and uses Playwright to take screenshots.
|
|
114
|
+
This command starts the local web server and uses Playwright to take screenshots.
|
|
115
115
|
If you plan to use it on CI, refer to [Playwright documentation](https://playwright.dev/docs/ci) for details.
|
|
116
116
|
|
|
117
|
+
### Export to JSON
|
|
118
|
+
|
|
119
|
+
```sh
|
|
120
|
+
likec4 export json -o dump.json
|
|
121
|
+
```
|
|
122
|
+
|
|
117
123
|
### Export to Mermaid, Dot, D2
|
|
118
124
|
|
|
119
125
|
Export to various formats via codegen:
|
|
@@ -165,4 +171,4 @@ yarn dev
|
|
|
165
171
|
|
|
166
172
|
## Support
|
|
167
173
|
|
|
168
|
-
If there's a problem you're encountering or something you need help with, don't hesitate to take advantage of my [_Priority Support_ service](https://github.com/sponsors/davydkov) where you can ask me questions in an exclusive forum. I'm well
|
|
174
|
+
If there's a problem you're encountering or something you need help with, don't hesitate to take advantage of my [_Priority Support_ service](https://github.com/sponsors/davydkov) where you can ask me questions in an exclusive forum. I'm well-equipped to assist you with this project and would be happy to help you out! 🙂
|
|
@@ -2,13 +2,14 @@ import { jsx, jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import { nonNullable, defaultTheme as theme } from "@likec4/core";
|
|
3
3
|
import { useHookableRef, useUpdateEffect } from "@react-hookz/web/esm";
|
|
4
4
|
import { useSpring } from "@react-spring/konva";
|
|
5
|
-
import { clamp } from "rambdax";
|
|
5
|
+
import { clamp, isNil } from "rambdax";
|
|
6
6
|
import { forwardRef, useEffect, useImperativeHandle, useRef } from "react";
|
|
7
7
|
import { AnimatedStage, Layer } from "../konva.js";
|
|
8
8
|
import { Edges } from "./Edges.js";
|
|
9
9
|
import { createUseGesture, dragAction, pinchAction } from "@use-gesture/react";
|
|
10
10
|
import { Nodes } from "./Nodes.js";
|
|
11
|
-
import { DiagramGesture, useResetHoveredStates } from "./state/index.js";
|
|
11
|
+
import { DiagramGesture, DiagramStateProvider, useResetHoveredStates } from "./state/index.js";
|
|
12
|
+
import { isNumber } from "./utils.js";
|
|
12
13
|
const useGesture = createUseGesture([dragAction, pinchAction]);
|
|
13
14
|
const useSyncedRef = (value) => {
|
|
14
15
|
const ref = useRef(value);
|
|
@@ -27,7 +28,7 @@ function diagramNodeId(konvaNode) {
|
|
|
27
28
|
}
|
|
28
29
|
return null;
|
|
29
30
|
}
|
|
30
|
-
|
|
31
|
+
const DiagramKonva = /* @__PURE__ */ forwardRef(
|
|
31
32
|
({
|
|
32
33
|
diagram,
|
|
33
34
|
padding = NoPadding,
|
|
@@ -56,15 +57,17 @@ export const Diagram = /* @__PURE__ */ forwardRef(
|
|
|
56
57
|
}
|
|
57
58
|
return value;
|
|
58
59
|
});
|
|
59
|
-
const [paddingTop, paddingRight, paddingBottom, paddingLeft] =
|
|
60
|
+
const [paddingTop, paddingRight, paddingBottom, paddingLeft] = isNumber(padding) ? [padding, padding, padding, padding] : padding;
|
|
60
61
|
const width = _width ?? diagram.width + paddingLeft + paddingRight;
|
|
61
62
|
const height = _height ?? diagram.height + paddingTop + paddingBottom;
|
|
62
|
-
const toCenterOnRect = (centerTo) => {
|
|
63
|
+
const toCenterOnRect = (centerTo, opts) => {
|
|
64
|
+
const keepZoom = opts?.keepZoom ?? false;
|
|
63
65
|
const container = containerRef.current;
|
|
66
|
+
const _maxZoom = keepZoom === true && !isNil(stageRef.current) ? stageRef.current.scaleX() : maxZoom;
|
|
64
67
|
const viewRect = {
|
|
65
68
|
width: Math.min(container?.clientWidth ?? width, width) - paddingLeft - paddingRight,
|
|
66
69
|
height: Math.min(container?.clientHeight ?? height, height) - paddingTop - paddingBottom
|
|
67
|
-
}, viewScale = Math.min(viewRect.width / centerTo.width, viewRect.height / centerTo.height), scale = clamp(minZoom,
|
|
70
|
+
}, viewScale = Math.min(viewRect.width / centerTo.width, viewRect.height / centerTo.height), scale = clamp(minZoom, _maxZoom, viewScale), centeringAjustment = {
|
|
68
71
|
x: ((width - centerTo.width) * scale + viewRect.width) / 2,
|
|
69
72
|
y: ((height - centerTo.height) * scale + viewRect.height) / 2
|
|
70
73
|
}, finalPosition = {
|
|
@@ -88,18 +91,21 @@ export const Diagram = /* @__PURE__ */ forwardRef(
|
|
|
88
91
|
},
|
|
89
92
|
[]
|
|
90
93
|
);
|
|
91
|
-
const centerOnRect = (centerTo) => {
|
|
94
|
+
const centerOnRect = (centerTo, opts) => {
|
|
92
95
|
stageSpringApi.start({
|
|
93
|
-
to: toCenterOnRect(centerTo
|
|
94
|
-
|
|
96
|
+
to: toCenterOnRect(centerTo, {
|
|
97
|
+
keepZoom: opts?.keepZoom ?? true
|
|
98
|
+
}),
|
|
99
|
+
delay: opts?.delay ?? 0,
|
|
100
|
+
immediate: immediate || (opts?.immediate ?? false)
|
|
95
101
|
});
|
|
96
102
|
return;
|
|
97
103
|
};
|
|
98
|
-
const centerAndFit = (
|
|
104
|
+
const centerAndFit = (opts) => {
|
|
99
105
|
stageSpringApi.start({
|
|
100
106
|
to: toFitDiagram(),
|
|
101
|
-
delay,
|
|
102
|
-
immediate
|
|
107
|
+
delay: opts?.delay ?? 0,
|
|
108
|
+
immediate: immediate || (opts?.immediate ?? false)
|
|
103
109
|
});
|
|
104
110
|
return;
|
|
105
111
|
};
|
|
@@ -137,25 +143,31 @@ export const Diagram = /* @__PURE__ */ forwardRef(
|
|
|
137
143
|
resetStageZoom: (_immediate) => {
|
|
138
144
|
refs.current.resetStageZoom(_immediate);
|
|
139
145
|
},
|
|
140
|
-
centerOnNode: (node) => refs.current.centerOnRect(
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
146
|
+
centerOnNode: (node, opts) => refs.current.centerOnRect(
|
|
147
|
+
{
|
|
148
|
+
x: node.position[0],
|
|
149
|
+
y: node.position[1],
|
|
150
|
+
width: node.size.width,
|
|
151
|
+
height: node.size.height
|
|
152
|
+
},
|
|
153
|
+
opts
|
|
154
|
+
),
|
|
155
|
+
centerOnRect: (rect, opts) => refs.current.centerOnRect(rect, opts),
|
|
156
|
+
centerAndFit: (opts) => refs.current.centerAndFit(opts)
|
|
147
157
|
}),
|
|
148
158
|
[refs, stageRef]
|
|
149
159
|
);
|
|
150
160
|
const resetHoveredStates = useResetHoveredStates();
|
|
151
161
|
useUpdateEffect(() => {
|
|
152
162
|
resetHoveredStates();
|
|
163
|
+
refs.current.centerAndFit({
|
|
164
|
+
delay: 200
|
|
165
|
+
});
|
|
153
166
|
}, [id]);
|
|
154
167
|
useUpdateEffect(() => {
|
|
155
|
-
refs.current.centerAndFit(
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
refs.current.centerAndFit(50);
|
|
168
|
+
refs.current.centerAndFit({
|
|
169
|
+
keepZoom: true
|
|
170
|
+
});
|
|
159
171
|
}, [height, width]);
|
|
160
172
|
useEffect(() => {
|
|
161
173
|
if (!zoomable) {
|
|
@@ -259,9 +271,12 @@ export const Diagram = /* @__PURE__ */ forwardRef(
|
|
|
259
271
|
theme,
|
|
260
272
|
diagram
|
|
261
273
|
};
|
|
274
|
+
const layerCenterX = diagram.width / 2;
|
|
275
|
+
const layerCenterY = diagram.height / 2;
|
|
262
276
|
return /* @__PURE__ */ jsxs(
|
|
263
277
|
AnimatedStage,
|
|
264
278
|
{
|
|
279
|
+
_useStrictMode: true,
|
|
265
280
|
ref: stageRef,
|
|
266
281
|
width,
|
|
267
282
|
height,
|
|
@@ -316,14 +331,27 @@ export const Diagram = /* @__PURE__ */ forwardRef(
|
|
|
316
331
|
},
|
|
317
332
|
...props,
|
|
318
333
|
children: [
|
|
319
|
-
/* @__PURE__ */ jsxs(
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
334
|
+
/* @__PURE__ */ jsxs(
|
|
335
|
+
Layer,
|
|
336
|
+
{
|
|
337
|
+
x: layerCenterX,
|
|
338
|
+
offsetX: layerCenterX,
|
|
339
|
+
y: layerCenterY,
|
|
340
|
+
offsetY: layerCenterY,
|
|
341
|
+
scaleX: 1,
|
|
342
|
+
scaleY: 1,
|
|
343
|
+
children: [
|
|
344
|
+
/* @__PURE__ */ jsx(Nodes, { ...sharedProps, onNodeClick }),
|
|
345
|
+
/* @__PURE__ */ jsx(Edges, { ...sharedProps, onEdgeClick })
|
|
346
|
+
]
|
|
347
|
+
}
|
|
348
|
+
),
|
|
323
349
|
/* @__PURE__ */ jsx(Layer, { name: "top" })
|
|
324
350
|
]
|
|
325
351
|
}
|
|
326
352
|
);
|
|
327
353
|
}
|
|
328
354
|
);
|
|
355
|
+
DiagramKonva.displayName = "DiagramKonva";
|
|
356
|
+
export const Diagram = /* @__PURE__ */ forwardRef((props, ref) => /* @__PURE__ */ jsx(DiagramStateProvider, { children: /* @__PURE__ */ jsx(DiagramKonva, { ...props, ref }) }));
|
|
329
357
|
Diagram.displayName = "Diagram";
|
|
@@ -102,23 +102,26 @@ const EdgeShape = memo(({ animate, edge, ctrl, theme, isHovered, onEdgeClick })
|
|
|
102
102
|
AnimatedGroup,
|
|
103
103
|
{
|
|
104
104
|
opacity: ctrl.springs.opacity,
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
105
|
+
...onEdgeClick && {
|
|
106
|
+
onPointerClick: (e) => {
|
|
107
|
+
if (DiagramGesture.isDragging || e.evt.button !== 0) {
|
|
108
|
+
return;
|
|
109
|
+
}
|
|
110
|
+
e.cancelBubble = true;
|
|
111
|
+
onEdgeClick(edge, e);
|
|
108
112
|
}
|
|
109
|
-
e.cancelBubble = true;
|
|
110
|
-
onEdgeClick(edge, e);
|
|
111
113
|
},
|
|
112
|
-
|
|
113
|
-
|
|
114
|
+
...animate && {
|
|
115
|
+
onPointerEnter: (e) => {
|
|
114
116
|
setHoveredEdge(edge);
|
|
115
117
|
mousePointer(e);
|
|
118
|
+
e.cancelBubble = true;
|
|
119
|
+
},
|
|
120
|
+
onPointerLeave: (e) => {
|
|
121
|
+
setHoveredEdge(null);
|
|
122
|
+
mouseDefault(e);
|
|
116
123
|
}
|
|
117
124
|
},
|
|
118
|
-
onPointerLeave: (e) => {
|
|
119
|
-
setHoveredEdge(null);
|
|
120
|
-
mouseDefault(e);
|
|
121
|
-
},
|
|
122
125
|
children: /* @__PURE__ */ jsx(
|
|
123
126
|
Edge,
|
|
124
127
|
{
|
|
@@ -1,9 +1,11 @@
|
|
|
1
1
|
import { Fragment, jsx, jsxs } from "react/jsx-runtime";
|
|
2
2
|
import { nonexhaustive } from "@likec4/core";
|
|
3
3
|
import { isEqualSimple } from "@react-hookz/deep-equal/esnext";
|
|
4
|
-
import {
|
|
4
|
+
import { useToggle } from "@react-hookz/web/esm";
|
|
5
|
+
import { useSpring, useTransition } from "@react-spring/konva";
|
|
6
|
+
import { mix, toHex, lighten } from "khroma";
|
|
5
7
|
import { memo, useRef } from "react";
|
|
6
|
-
import { AnimatedGroup } from "../konva.js";
|
|
8
|
+
import { AnimatedCircle, AnimatedGroup, Rect } from "../konva.js";
|
|
7
9
|
import { Portal } from "../konva-portal.js";
|
|
8
10
|
import { ZoomInIcon } from "./icons/index.js";
|
|
9
11
|
import { CylinderShape, MobileShape, PersonShape, QueueShape, RectangleShape } from "./shapes/index.js";
|
|
@@ -12,6 +14,7 @@ import { CompoundShape } from "./shapes/Compound.js";
|
|
|
12
14
|
import { mouseDefault, mousePointer } from "./shapes/utils.js";
|
|
13
15
|
import { isCompound, useNodeSpringsFn } from "./springs.js";
|
|
14
16
|
import { DiagramGesture, useHoveredEdge, useHoveredNodeId, useSetHoveredNode } from "./state/index.js";
|
|
17
|
+
import { Group } from "react-konva";
|
|
15
18
|
function nodeShape({ shape }) {
|
|
16
19
|
switch (shape) {
|
|
17
20
|
case "cylinder":
|
|
@@ -136,37 +139,29 @@ const NodeShape = memo(
|
|
|
136
139
|
const isNavigatable = animate && !!node.navigateTo && !!onNodeClick;
|
|
137
140
|
const Shape = nodeShape(node);
|
|
138
141
|
const springs = ctrl.springs;
|
|
139
|
-
let zoomInIconY;
|
|
140
|
-
switch (node.shape) {
|
|
141
|
-
case "browser":
|
|
142
|
-
case "mobile":
|
|
143
|
-
zoomInIconY = node.size.height - 20;
|
|
144
|
-
break;
|
|
145
|
-
default:
|
|
146
|
-
zoomInIconY = node.size.height - 16;
|
|
147
|
-
}
|
|
148
142
|
return /* @__PURE__ */ jsx(Portal, { selector: ".top", enabled: isHovered && !_isCompound, children: /* @__PURE__ */ jsxs(
|
|
149
143
|
AnimatedGroup,
|
|
150
144
|
{
|
|
151
145
|
name: node.id,
|
|
152
146
|
visible: expired !== true,
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
147
|
+
...animate && {
|
|
148
|
+
onPointerEnter: (_) => {
|
|
149
|
+
setHoveredNode(node);
|
|
150
|
+
},
|
|
151
|
+
onPointerLeave: (e) => {
|
|
152
|
+
setHoveredNode(null);
|
|
153
|
+
mouseDefault(e);
|
|
157
154
|
}
|
|
158
155
|
},
|
|
159
|
-
onPointerLeave: (e) => {
|
|
160
|
-
setHoveredNode(null);
|
|
161
|
-
mouseDefault(e);
|
|
162
|
-
},
|
|
163
156
|
...onNodeClick && {
|
|
164
157
|
onPointerClick: (e) => {
|
|
165
158
|
if (DiagramGesture.isDragging || e.evt.button !== 0) {
|
|
166
159
|
return;
|
|
167
160
|
}
|
|
168
161
|
e.cancelBubble = true;
|
|
169
|
-
|
|
162
|
+
if (!isNavigatable) {
|
|
163
|
+
onNodeClick(node, e);
|
|
164
|
+
}
|
|
170
165
|
}
|
|
171
166
|
},
|
|
172
167
|
x: springs.x,
|
|
@@ -186,14 +181,46 @@ const NodeShape = memo(
|
|
|
186
181
|
node,
|
|
187
182
|
theme,
|
|
188
183
|
springs,
|
|
189
|
-
labelOffsetX: isNavigatable ? -
|
|
184
|
+
labelOffsetX: isNavigatable ? -22 : 0
|
|
190
185
|
}
|
|
191
186
|
),
|
|
192
|
-
isNavigatable && /* @__PURE__ */
|
|
187
|
+
isNavigatable && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
188
|
+
/* @__PURE__ */ jsx(
|
|
189
|
+
Rect,
|
|
190
|
+
{
|
|
191
|
+
x: 0,
|
|
192
|
+
y: 0,
|
|
193
|
+
width: node.size.width,
|
|
194
|
+
height: Math.min(node.size.height, 150),
|
|
195
|
+
perfectDrawEnabled: false
|
|
196
|
+
}
|
|
197
|
+
),
|
|
198
|
+
/* @__PURE__ */ jsx(
|
|
199
|
+
CompoundZoomBtn,
|
|
200
|
+
{
|
|
201
|
+
animate,
|
|
202
|
+
node,
|
|
203
|
+
ctrl,
|
|
204
|
+
theme,
|
|
205
|
+
isHovered,
|
|
206
|
+
onNodeClick
|
|
207
|
+
}
|
|
208
|
+
)
|
|
209
|
+
] })
|
|
193
210
|
] }),
|
|
194
211
|
!_isCompound && /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
195
212
|
/* @__PURE__ */ jsx(Shape, { node, theme, springs, isHovered }),
|
|
196
|
-
isNavigatable && /* @__PURE__ */ jsx(
|
|
213
|
+
isNavigatable && /* @__PURE__ */ jsx(
|
|
214
|
+
NodeZoomBtn,
|
|
215
|
+
{
|
|
216
|
+
animate,
|
|
217
|
+
node,
|
|
218
|
+
ctrl,
|
|
219
|
+
theme,
|
|
220
|
+
isHovered,
|
|
221
|
+
onNodeClick
|
|
222
|
+
}
|
|
223
|
+
)
|
|
197
224
|
] })
|
|
198
225
|
]
|
|
199
226
|
}
|
|
@@ -202,3 +229,165 @@ const NodeShape = memo(
|
|
|
202
229
|
isEqualSimple
|
|
203
230
|
);
|
|
204
231
|
NodeShape.displayName = "NodeShape";
|
|
232
|
+
const NodeZoomBtn = ({ animate, node, theme, isHovered: _isHovered, onNodeClick }) => {
|
|
233
|
+
const size = 30;
|
|
234
|
+
const halfSize = size / 2;
|
|
235
|
+
const colors = theme.elements[node.color];
|
|
236
|
+
let zoomInIconY;
|
|
237
|
+
switch (node.shape) {
|
|
238
|
+
case "browser":
|
|
239
|
+
case "mobile":
|
|
240
|
+
zoomInIconY = node.size.height - 20;
|
|
241
|
+
break;
|
|
242
|
+
default:
|
|
243
|
+
zoomInIconY = node.size.height - 16;
|
|
244
|
+
}
|
|
245
|
+
const fill = toHex(mix(colors.fill, colors.stroke, 65));
|
|
246
|
+
const onOver = toHex(mix(colors.fill, colors.stroke, 75));
|
|
247
|
+
const [isOver, toggleOver] = useToggle(false);
|
|
248
|
+
const isHovered = _isHovered || isOver;
|
|
249
|
+
const props = useSpring({
|
|
250
|
+
to: {
|
|
251
|
+
fill: isOver ? onOver : fill,
|
|
252
|
+
opacity: isOver ? 1 : 0,
|
|
253
|
+
y: zoomInIconY + (isOver ? 2 : 0),
|
|
254
|
+
scale: isOver ? 1.38 : 1,
|
|
255
|
+
// shadowBlur: isOver ? 6 : 4,
|
|
256
|
+
shadowOpacity: isOver ? 0.3 : 0.15
|
|
257
|
+
// shadowOffsetY: isOver ? 8 : 6
|
|
258
|
+
},
|
|
259
|
+
delay: isHovered && !isOver ? 100 : 0,
|
|
260
|
+
immediate: !animate
|
|
261
|
+
});
|
|
262
|
+
return /* @__PURE__ */ jsxs(
|
|
263
|
+
AnimatedGroup,
|
|
264
|
+
{
|
|
265
|
+
x: node.size.width / 2,
|
|
266
|
+
y: props.y,
|
|
267
|
+
offsetX: halfSize,
|
|
268
|
+
offsetY: halfSize,
|
|
269
|
+
scaleX: props.scale,
|
|
270
|
+
scaleY: props.scale,
|
|
271
|
+
width: size,
|
|
272
|
+
height: size,
|
|
273
|
+
onPointerEnter: (e) => {
|
|
274
|
+
toggleOver(true);
|
|
275
|
+
mousePointer(e);
|
|
276
|
+
},
|
|
277
|
+
onPointerLeave: (e) => {
|
|
278
|
+
toggleOver(false);
|
|
279
|
+
mouseDefault(e);
|
|
280
|
+
},
|
|
281
|
+
onPointerClick: (e) => {
|
|
282
|
+
if (DiagramGesture.isDragging || e.evt.button !== 0) {
|
|
283
|
+
return;
|
|
284
|
+
}
|
|
285
|
+
e.cancelBubble = true;
|
|
286
|
+
onNodeClick(node, e);
|
|
287
|
+
},
|
|
288
|
+
children: [
|
|
289
|
+
/* @__PURE__ */ jsx(
|
|
290
|
+
AnimatedCircle,
|
|
291
|
+
{
|
|
292
|
+
x: halfSize,
|
|
293
|
+
y: halfSize,
|
|
294
|
+
radius: halfSize,
|
|
295
|
+
fill: props.fill,
|
|
296
|
+
shadowBlur: 4,
|
|
297
|
+
shadowOpacity: props.shadowOpacity,
|
|
298
|
+
shadowOffsetX: 2,
|
|
299
|
+
shadowOffsetY: 6,
|
|
300
|
+
shadowColor: theme.shadow,
|
|
301
|
+
shadowEnabled: isHovered,
|
|
302
|
+
perfectDrawEnabled: false,
|
|
303
|
+
opacity: props.opacity,
|
|
304
|
+
hitStrokeWidth: halfSize
|
|
305
|
+
}
|
|
306
|
+
),
|
|
307
|
+
/* @__PURE__ */ jsx(ZoomInIcon, { size: 16, x: halfSize, y: halfSize })
|
|
308
|
+
]
|
|
309
|
+
}
|
|
310
|
+
);
|
|
311
|
+
};
|
|
312
|
+
const CompoundZoomBtn = ({
|
|
313
|
+
animate,
|
|
314
|
+
node,
|
|
315
|
+
theme,
|
|
316
|
+
ctrl,
|
|
317
|
+
isHovered: _isHovered,
|
|
318
|
+
onNodeClick
|
|
319
|
+
}) => {
|
|
320
|
+
const size = 28;
|
|
321
|
+
const [isOver, toggleOver] = useToggle(false);
|
|
322
|
+
const halfSize = size / 2;
|
|
323
|
+
const fill = toHex(lighten(ctrl.springs.fill.get(), 10));
|
|
324
|
+
const isHovered = _isHovered || isOver;
|
|
325
|
+
const props = useSpring({
|
|
326
|
+
to: {
|
|
327
|
+
opacity: isOver ? 1 : 0,
|
|
328
|
+
x: halfSize + 4 - (isOver ? 4 : 0),
|
|
329
|
+
y: halfSize + 6 - (isOver ? 4 : 0),
|
|
330
|
+
scale: isOver ? 1.35 : 1,
|
|
331
|
+
// shadowBlur: isOver ? 6 : 4,
|
|
332
|
+
shadowOpacity: isOver ? 0.3 : 0.15
|
|
333
|
+
// shadowOffsetY: isOver ? 8 : 6
|
|
334
|
+
},
|
|
335
|
+
delay: isHovered && !isOver ? 100 : 0,
|
|
336
|
+
// delay: isOver ? 150 : (isHovered ? 70 : 0),
|
|
337
|
+
immediate: !animate
|
|
338
|
+
});
|
|
339
|
+
return /* @__PURE__ */ jsx(
|
|
340
|
+
Group,
|
|
341
|
+
{
|
|
342
|
+
onPointerEnter: (e) => {
|
|
343
|
+
toggleOver(true);
|
|
344
|
+
mousePointer(e);
|
|
345
|
+
},
|
|
346
|
+
onPointerLeave: (e) => {
|
|
347
|
+
toggleOver(false);
|
|
348
|
+
mouseDefault(e);
|
|
349
|
+
},
|
|
350
|
+
onPointerClick: (e) => {
|
|
351
|
+
if (DiagramGesture.isDragging || e.evt.button !== 0) {
|
|
352
|
+
return;
|
|
353
|
+
}
|
|
354
|
+
e.cancelBubble = true;
|
|
355
|
+
onNodeClick(node, e);
|
|
356
|
+
},
|
|
357
|
+
children: /* @__PURE__ */ jsxs(
|
|
358
|
+
AnimatedGroup,
|
|
359
|
+
{
|
|
360
|
+
x: props.x,
|
|
361
|
+
y: props.y,
|
|
362
|
+
offsetX: halfSize,
|
|
363
|
+
offsetY: halfSize,
|
|
364
|
+
scaleX: props.scale,
|
|
365
|
+
scaleY: props.scale,
|
|
366
|
+
width: size,
|
|
367
|
+
height: size,
|
|
368
|
+
children: [
|
|
369
|
+
/* @__PURE__ */ jsx(
|
|
370
|
+
AnimatedCircle,
|
|
371
|
+
{
|
|
372
|
+
x: halfSize,
|
|
373
|
+
y: halfSize,
|
|
374
|
+
radius: halfSize,
|
|
375
|
+
fill,
|
|
376
|
+
shadowBlur: 4,
|
|
377
|
+
shadowOpacity: props.shadowOpacity,
|
|
378
|
+
shadowOffsetX: 2,
|
|
379
|
+
shadowOffsetY: 6,
|
|
380
|
+
shadowColor: theme.shadow,
|
|
381
|
+
shadowEnabled: isHovered,
|
|
382
|
+
perfectDrawEnabled: false,
|
|
383
|
+
opacity: props.opacity,
|
|
384
|
+
hitStrokeWidth: halfSize
|
|
385
|
+
}
|
|
386
|
+
),
|
|
387
|
+
/* @__PURE__ */ jsx(ZoomInIcon, { size: 16, x: halfSize, y: halfSize })
|
|
388
|
+
]
|
|
389
|
+
}
|
|
390
|
+
)
|
|
391
|
+
}
|
|
392
|
+
);
|
|
393
|
+
};
|
|
@@ -21,7 +21,8 @@ export const ZoomInIcon = ({ fill = "#BABABA", opacity = 1, size = 20, x, y }) =
|
|
|
21
21
|
height: originalSize,
|
|
22
22
|
opacity,
|
|
23
23
|
perfectDrawEnabled: false,
|
|
24
|
-
globalCompositeOperation: "luminosity"
|
|
24
|
+
globalCompositeOperation: "luminosity",
|
|
25
|
+
listening: false
|
|
25
26
|
}
|
|
26
27
|
);
|
|
27
28
|
};
|
|
@@ -36,7 +36,8 @@ export function CompoundShape({ node, theme, springs, labelOffsetX = 0 }) {
|
|
|
36
36
|
wrap: "none",
|
|
37
37
|
ellipsis: true,
|
|
38
38
|
perfectDrawEnabled: false,
|
|
39
|
-
globalCompositeOperation: "luminosity"
|
|
39
|
+
globalCompositeOperation: "luminosity",
|
|
40
|
+
listening: false
|
|
40
41
|
},
|
|
41
42
|
i
|
|
42
43
|
))
|