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.
Files changed (51) hide show
  1. package/README.md +12 -6
  2. package/dist/@likec4/diagrams/diagram/Diagram.js +55 -27
  3. package/dist/@likec4/diagrams/diagram/Edges.js +14 -11
  4. package/dist/@likec4/diagrams/diagram/Nodes.js +212 -23
  5. package/dist/@likec4/diagrams/diagram/icons/ZoomIn.js +2 -1
  6. package/dist/@likec4/diagrams/diagram/shapes/Compound.js +2 -1
  7. package/dist/@likec4/diagrams/diagram/shapes/Edge.js +1 -1
  8. package/dist/@likec4/diagrams/diagram/state/atoms.js +35 -60
  9. package/dist/@likec4/diagrams/diagram/utils.js +14 -0
  10. package/dist/@likec4/diagrams/hooks/useDiagramApi.js +4 -5
  11. package/dist/@likec4/diagrams/hooks/useImageLoader.js +1 -1
  12. package/dist/__app__/likec4.css +8 -5
  13. package/dist/__app__/src/App.jsx +9 -11
  14. package/dist/__app__/src/components/CopyToClipboard.jsx +29 -0
  15. package/dist/__app__/src/components/CopyToClipboard.module.css +16 -0
  16. package/dist/__app__/src/components/DiagramNotFound.jsx +2 -2
  17. package/dist/__app__/src/components/index.js +2 -1
  18. package/dist/__app__/src/components/sidebar/Sidebar.jsx +1 -1
  19. package/dist/__app__/src/components/sidebar/styles.module.css +4 -1
  20. package/dist/__app__/src/components/view-page/DisplayModeSelector.jsx +15 -9
  21. package/dist/__app__/src/components/view-page/Header.jsx +97 -0
  22. package/dist/__app__/src/components/view-page/Header.module.css +24 -0
  23. package/dist/__app__/src/components/view-page/ShareDialog.jsx +23 -15
  24. package/dist/__app__/src/components/view-page/ViewActions.jsx +69 -0
  25. package/dist/__app__/src/data/atoms.js +4 -22
  26. package/dist/__app__/src/data/hooks.js +5 -4
  27. package/dist/__app__/src/data/index-page.js +22 -0
  28. package/dist/__app__/src/likec4-views.js +1 -1
  29. package/dist/__app__/src/pages/index-page/index.jsx +99 -0
  30. package/dist/__app__/src/pages/index-page/index.module.css +20 -0
  31. package/dist/__app__/src/pages/index.js +1 -1
  32. package/dist/__app__/src/pages/useTransparentBackground.js +2 -2
  33. package/dist/__app__/src/pages/view-page/ViewAsReact.jsx +60 -0
  34. package/dist/__app__/src/pages/view-page/index.js +11 -0
  35. package/dist/__app__/src/pages/view-page/other-formats/ViewAsD2.jsx +18 -0
  36. package/dist/__app__/src/pages/view-page/other-formats/ViewAsDot.jsx +33 -0
  37. package/dist/__app__/src/pages/view-page/other-formats/ViewAsMmd.jsx +18 -0
  38. package/dist/__app__/src/pages/view-page/other-formats.jsx +43 -0
  39. package/dist/__app__/src/pages/view-page/view-page.module.css +81 -0
  40. package/dist/__app__/src/pages/view.page.jsx +12 -65
  41. package/dist/__app__/src/router.js +90 -20
  42. package/dist/__app__/src/utils/utils.js +1 -2
  43. package/dist/__app__/tsconfig.json +1 -0
  44. package/dist/cli/index.js +288 -207
  45. package/package.json +17 -17
  46. package/dist/__app__/postcss.config.cjs +0 -11
  47. package/dist/__app__/src/components/view-page/ViewActionsToolbar.jsx +0 -66
  48. package/dist/__app__/src/pages/index.module.css +0 -11
  49. package/dist/__app__/src/pages/index.page.jsx +0 -57
  50. package/dist/__app__/src/pages/view-page.module.css +0 -30
  51. 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 fast updates) ⚡️
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 searchs for `*.c4`, `*.likec4` files in current folder, parses and serves diagrams in a local web server.
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 deployed the website, you can use "Share" button to get a link to a specific diagram.
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 equppied to assist you with this project and would be happy to help you out! 🙂
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
- export const Diagram = /* @__PURE__ */ forwardRef(
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] = Array.isArray(padding) ? padding : [padding, padding, padding, padding];
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, maxZoom, viewScale), centeringAjustment = {
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
- immediate
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 = (delay = 0) => {
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
- x: node.position[0],
142
- y: node.position[1],
143
- width: node.size.width,
144
- height: node.size.height
145
- }),
146
- centerAndFit: () => refs.current.centerAndFit()
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(200);
156
- }, [id]);
157
- useUpdateEffect(() => {
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(Layer, { children: [
320
- /* @__PURE__ */ jsx(Nodes, { ...sharedProps, onNodeClick }),
321
- /* @__PURE__ */ jsx(Edges, { ...sharedProps, onEdgeClick })
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
- onPointerClick: (e) => {
106
- if (!onEdgeClick || DiagramGesture.isDragging || e.evt.button !== 0) {
107
- return;
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
- onPointerEnter: (e) => {
113
- if (animate) {
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 { useTransition } from "@react-spring/konva";
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
- onPointerEnter: (e) => {
154
- setHoveredNode(node);
155
- if (isNavigatable) {
156
- mousePointer(e);
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
- onNodeClick(node, e);
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 ? -20 : 0
184
+ labelOffsetX: isNavigatable ? -22 : 0
190
185
  }
191
186
  ),
192
- isNavigatable && /* @__PURE__ */ jsx(ZoomInIcon, { opacity: 0.9, size: 20, x: 18, y: 21 })
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(ZoomInIcon, { size: 16, x: node.size.width / 2, y: zoomInIconY })
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
  ))
@@ -54,7 +54,7 @@ function EdgeLabelBg({
54
54
  fill: springs.labelBgColor,
55
55
  cornerRadius: 2,
56
56
  globalCompositeOperation: "lighten",
57
- hitStrokeWidth: 5
57
+ hitStrokeWidth: 20
58
58
  }
59
59
  );
60
60
  }