@likec4/diagram 1.4.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 (83) hide show
  1. package/dist/LikeC4Diagram.css.d.ts +0 -1
  2. package/dist/LikeC4Diagram.props.d.ts +1 -1
  3. package/dist/index.d.ts +1 -1
  4. package/dist/index.mjs +1398 -1114
  5. package/dist/state/DiagramContext.d.ts +86 -4159
  6. package/dist/state/diagramStore.d.ts +88 -4162
  7. package/dist/state/hooks.d.ts +4 -0
  8. package/dist/state/index.d.ts +1 -2
  9. package/dist/style.css +182 -156
  10. package/dist/ui/options/EdgeOptions.d.ts +19 -0
  11. package/dist/ui/options/NodeOptions.d.ts +2 -2
  12. package/dist/xyflow/EdgeMarkers.d.ts +11 -0
  13. package/dist/xyflow/XYFlowEvents.d.ts +8 -5
  14. package/dist/xyflow/const.d.ts +3 -3
  15. package/dist/xyflow/diagram-to-xyflow.d.ts +1 -1
  16. package/dist/xyflow/edges/RelationshipEdge.d.ts +3 -2
  17. package/dist/xyflow/edges/edges.css.d.ts +1 -0
  18. package/dist/xyflow/edges/utils.d.ts +1 -0
  19. package/dist/xyflow/hooks/index.d.ts +3 -2
  20. package/dist/xyflow/hooks/useXYFlow.d.ts +13 -12
  21. package/dist/xyflow/nodes/compound/CompoundNode.css.d.ts +1 -0
  22. package/dist/xyflow/nodes/element/ElementIcon.d.ts +1 -4
  23. package/dist/xyflow/nodes/element/element.css.d.ts +2 -1
  24. package/dist/xyflow/types.d.ts +2 -32
  25. package/package.json +19 -19
  26. package/src/LikeC4Diagram.css.ts +0 -8
  27. package/src/LikeC4Diagram.props.ts +2 -2
  28. package/src/LikeC4Diagram.tsx +14 -20
  29. package/src/globals.css.ts +10 -3
  30. package/src/index.ts +1 -1
  31. package/src/mantine.css.ts +2 -2
  32. package/src/state/DiagramContext.tsx +44 -13
  33. package/src/state/diagramStore.ts +64 -52
  34. package/src/state/hooks.ts +5 -0
  35. package/src/state/index.ts +1 -2
  36. package/src/ui/BackwardForwardPanel.css.ts +9 -9
  37. package/src/ui/BackwardForwardPanel.tsx +1 -1
  38. package/src/ui/DiagramTitlePanel.css.ts +7 -2
  39. package/src/ui/DiagramTitlePanel.tsx +5 -3
  40. package/src/ui/DynamicViewWalkthrough.tsx +6 -4
  41. package/src/ui/OptionsPanel.tsx +37 -27
  42. package/src/ui/options/EdgeOptions.tsx +157 -0
  43. package/src/ui/options/NodeOptions.tsx +37 -29
  44. package/src/xyflow/EdgeMarkers.tsx +148 -0
  45. package/src/xyflow/FitviewOnDiagramChange.tsx +8 -4
  46. package/src/xyflow/SelectEdgesOnNodeFocus.tsx +59 -55
  47. package/src/xyflow/SyncWithDiagram.tsx +13 -20
  48. package/src/xyflow/XYFlow.tsx +2 -4
  49. package/src/xyflow/XYFlowEvents.tsx +48 -33
  50. package/src/xyflow/XYFlowInner.tsx +1 -1
  51. package/src/xyflow/const.ts +3 -3
  52. package/src/xyflow/diagram-to-xyflow.ts +17 -41
  53. package/src/xyflow/edges/RelationshipEdge.tsx +207 -118
  54. package/src/xyflow/edges/edges.css.ts +36 -22
  55. package/src/xyflow/edges/utils.ts +10 -0
  56. package/src/xyflow/hooks/index.ts +4 -2
  57. package/src/xyflow/hooks/useLayoutConstraints.ts +3 -4
  58. package/src/xyflow/hooks/useXYFlow.ts +28 -1
  59. package/src/xyflow/nodes/compound/CompoundNode.css.ts +34 -24
  60. package/src/xyflow/nodes/compound/CompoundNode.tsx +52 -53
  61. package/src/xyflow/nodes/element/ElementIcon.tsx +11 -22
  62. package/src/xyflow/nodes/element/ElementLink.tsx +11 -16
  63. package/src/xyflow/nodes/element/ElementNode.tsx +64 -108
  64. package/src/xyflow/nodes/element/element.css.ts +30 -10
  65. package/src/xyflow/nodes/shared/NavigateToBtn.tsx +1 -1
  66. package/src/xyflow/types.ts +2 -4
  67. package/src/xyflow/utils.ts +3 -6
  68. package/dist/KeepAspectRatioContainer.d.ts +0 -9
  69. package/dist/icons/Clipboard.d.ts +0 -3
  70. package/dist/icons/Link.d.ts +0 -3
  71. package/dist/icons/ZoomIn.d.ts +0 -3
  72. package/dist/icons/index.d.ts +0 -3
  73. package/dist/mantine/theme.d.ts +0 -3
  74. package/dist/state/WhenInitialized.d.ts +0 -3
  75. package/dist/ui/Camera.d.ts +0 -3
  76. package/src/KeepAspectRatioContainer.tsx +0 -36
  77. package/src/icons/Clipboard.tsx +0 -24
  78. package/src/icons/Link.tsx +0 -23
  79. package/src/icons/ZoomIn.tsx +0 -25
  80. package/src/icons/index.ts +0 -3
  81. package/src/mantine/theme.ts +0 -20
  82. package/src/state/WhenInitialized.tsx +0 -24
  83. package/src/ui/Camera.tsx +0 -174
package/dist/index.mjs CHANGED
@@ -9,14 +9,14 @@ import { createPortal } from "react-dom";
9
9
  import { DEV } from "esm-env";
10
10
  import { shallowEqual, deepEqual } from "fast-equals";
11
11
  import { m, AnimatePresence, LazyMotion, domAnimation } from "framer-motion";
12
- import { Box, MantineContext, ActionIcon, Text, HoverCard, HoverCardTarget, UnstyledButton, HoverCardDropdown, Stack, Group, Anchor, CopyButton, Button, Card, CardSection, Spoiler, Divider, TooltipGroup, Flex, Tooltip, ColorSwatch, CheckIcon, rem, Select, Slider, SegmentedControl } from "@mantine/core";
13
- import { isArray, isNullish, entries, reduce, isEmpty, hasSubObject, hasAtLeast as hasAtLeast$1, isTruthy, first, last, clamp as clamp$1, isNumber, keys, takeWhile, isNonNull } from "remeda";
12
+ import { MantineContext, Box, ActionIcon, Text, HoverCard, HoverCardTarget, UnstyledButton, HoverCardDropdown, Stack, Group, Anchor, CopyButton, Button, Card, CardSection, Spoiler, ButtonGroup, rem, Divider, Space, TooltipGroup, Flex, Tooltip, ColorSwatch, CheckIcon, Select, Slider, SegmentedControl } from "@mantine/core";
13
+ import { isArray, isNullish, entries, reduce, isEmpty, pickBy, isNonNullish, hasSubObject, hasAtLeast as hasAtLeast$1, omit, isTruthy, first, last, clamp as clamp$1, isNumber, keys, takeWhile, isNonNull } from "remeda";
14
14
  import { invariant, hasAtLeast, isAncestor, nonNullable, StepEdgeId, nonexhaustive, extractStep, defaultTheme, ElementShapes } from "@likec4/core";
15
15
  import { subscribeWithSelector, devtools } from "zustand/middleware";
16
16
  import { useFirstMountState, useCustomCompareEffect, useDebouncedEffect, useIsomorphicLayoutEffect as useIsomorphicLayoutEffect$1 } from "@react-hookz/web";
17
17
  import { assignInlineVars } from "@vanilla-extract/dynamic";
18
18
  import { line, curveCatmullRomOpen } from "d3-shape";
19
- import { IconZoomScan, IconChevronLeft, IconChevronRight, IconMenu, IconPlayerPlayFilled, IconPlayerSkipBackFilled, IconPlayerStopFilled, IconPlayerSkipForwardFilled } from "@tabler/icons-react";
19
+ import { IconZoomScan, IconLink, IconChevronLeft, IconChevronRight, IconMenu, IconPlayerPlayFilled, IconPlayerSkipBackFilled, IconPlayerStopFilled, IconPlayerSkipForwardFilled } from "@tabler/icons-react";
20
20
  import { useStateHistory, useLocalStorage, useHotkeys } from "@mantine/hooks";
21
21
  function cc(names) {
22
22
  if (typeof names == "string" || typeof names == "number") return "" + names;
@@ -119,13 +119,13 @@ function creator(name) {
119
119
  }
120
120
  function none() {
121
121
  }
122
- function selector$5(selector2) {
122
+ function selector$4(selector2) {
123
123
  return selector2 == null ? none : function() {
124
124
  return this.querySelector(selector2);
125
125
  };
126
126
  }
127
127
  function selection_select(select2) {
128
- typeof select2 != "function" && (select2 = selector$5(select2));
128
+ typeof select2 != "function" && (select2 = selector$4(select2));
129
129
  for (var groups = this._groups, m2 = groups.length, subgroups = new Array(m2), j = 0; j < m2; ++j)
130
130
  for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i)
131
131
  (node = group[i]) && (subnode = select2.call(node, node.__data__, i, group)) && ("__data__" in node && (subnode.__data__ = node.__data__), subgroup[i] = subnode);
@@ -516,7 +516,7 @@ function constantNull() {
516
516
  return null;
517
517
  }
518
518
  function selection_insert(name, before) {
519
- var create2 = typeof name == "function" ? name : creator(name), select2 = before == null ? constantNull : typeof before == "function" ? before : selector$5(before);
519
+ var create2 = typeof name == "function" ? name : creator(name), select2 = before == null ? constantNull : typeof before == "function" ? before : selector$4(before);
520
520
  return this.select(function() {
521
521
  return this.insertBefore(create2.apply(this, arguments), select2.apply(this, arguments) || null);
522
522
  });
@@ -1669,7 +1669,7 @@ function transition_remove() {
1669
1669
  }
1670
1670
  function transition_select(select2) {
1671
1671
  var name = this._name, id2 = this._id;
1672
- typeof select2 != "function" && (select2 = selector$5(select2));
1672
+ typeof select2 != "function" && (select2 = selector$4(select2));
1673
1673
  for (var groups = this._groups, m2 = groups.length, subgroups = new Array(m2), j = 0; j < m2; ++j)
1674
1674
  for (var group = groups[j], n = group.length, subgroup = subgroups[j] = new Array(n), node, subnode, i = 0; i < n; ++i)
1675
1675
  (node = group[i]) && (subnode = select2.call(node, node.__data__, i, group)) && ("__data__" in node && (subnode.__data__ = node.__data__), subgroup[i] = subnode, schedule(subgroup[i], name, id2, i, subgroup, get(node, id2)));
@@ -2190,6 +2190,18 @@ var SelectionMode;
2190
2190
  (function(SelectionMode2) {
2191
2191
  SelectionMode2.Partial = "partial", SelectionMode2.Full = "full";
2192
2192
  })(SelectionMode || (SelectionMode = {}));
2193
+ const initialConnection = {
2194
+ inProgress: !1,
2195
+ isValid: null,
2196
+ from: null,
2197
+ fromHandle: null,
2198
+ fromPosition: null,
2199
+ fromNode: null,
2200
+ to: null,
2201
+ toHandle: null,
2202
+ toPosition: null,
2203
+ toNode: null
2204
+ };
2193
2205
  var ConnectionLineType;
2194
2206
  (function(ConnectionLineType2) {
2195
2207
  ConnectionLineType2.Bezier = "default", ConnectionLineType2.Straight = "straight", ConnectionLineType2.Step = "step", ConnectionLineType2.SmoothStep = "smoothstep", ConnectionLineType2.SimpleBezier = "simplebezier";
@@ -2202,39 +2214,32 @@ var Position;
2202
2214
  (function(Position2) {
2203
2215
  Position2.Left = "left", Position2.Top = "top", Position2.Right = "right", Position2.Bottom = "bottom";
2204
2216
  })(Position || (Position = {}));
2205
- const isEdgeBase = (element2) => "id" in element2 && "source" in element2 && "target" in element2, isNodeBase = (element2) => "id" in element2 && "position" in element2 && !("source" in element2) && !("target" in element2), getNodePositionWithOrigin = (node, nodeOrigin = [0, 0]) => {
2206
- const { width, height } = getNodeDimensions(node), positionAbsolute = "internals" in node ? node.internals.positionAbsolute : node.position, origin = node.origin || nodeOrigin, offsetX = width * origin[0], offsetY = height * origin[1];
2217
+ const oppositePosition = {
2218
+ [Position.Left]: Position.Right,
2219
+ [Position.Right]: Position.Left,
2220
+ [Position.Top]: Position.Bottom,
2221
+ [Position.Bottom]: Position.Top
2222
+ };
2223
+ function getConnectionStatus(isValid) {
2224
+ return isValid === null ? null : isValid ? "valid" : "invalid";
2225
+ }
2226
+ const isEdgeBase = (element2) => "id" in element2 && "source" in element2 && "target" in element2, isNodeBase = (element2) => "id" in element2 && "position" in element2 && !("source" in element2) && !("target" in element2), isInternalNodeBase = (element2) => "id" in element2 && "internals" in element2 && !("source" in element2) && !("target" in element2), getNodePositionWithOrigin = (node, nodeOrigin = [0, 0]) => {
2227
+ const { width, height } = getNodeDimensions(node), origin = node.origin ?? nodeOrigin, offsetX = width * origin[0], offsetY = height * origin[1];
2207
2228
  return {
2208
- position: {
2209
- x: node.position.x - offsetX,
2210
- y: node.position.y - offsetY
2211
- },
2212
- positionAbsolute: {
2213
- x: positionAbsolute.x - offsetX,
2214
- y: positionAbsolute.y - offsetY
2215
- }
2229
+ x: node.position.x - offsetX,
2230
+ y: node.position.y - offsetY
2216
2231
  };
2217
- }, getNodesBounds = (nodes, params = { nodeOrigin: [0, 0] }) => {
2218
- if (nodes.length === 0)
2219
- return { x: 0, y: 0, width: 0, height: 0 };
2220
- const box = nodes.reduce((currBox, node) => {
2221
- const nodeBox = nodeToBox(node, params.nodeOrigin);
2222
- return getBoundsOfBoxes(currBox, nodeBox);
2223
- }, { x: 1 / 0, y: 1 / 0, x2: -1 / 0, y2: -1 / 0 });
2224
- return boxToRect(box);
2225
- }, getInternalNodesBounds = (nodeLookup, params = {
2226
- nodeOrigin: [0, 0]
2227
- }) => {
2232
+ }, getInternalNodesBounds = (nodeLookup, params = {}) => {
2228
2233
  if (nodeLookup.size === 0)
2229
2234
  return { x: 0, y: 0, width: 0, height: 0 };
2230
2235
  let box = { x: 1 / 0, y: 1 / 0, x2: -1 / 0, y2: -1 / 0 };
2231
2236
  return nodeLookup.forEach((node) => {
2232
- if (params.filter == null || params.filter(node)) {
2233
- const nodeBox = nodeToBox(node, params.nodeOrigin);
2237
+ if (params.filter === void 0 || params.filter(node)) {
2238
+ const nodeBox = nodeToBox(node);
2234
2239
  box = getBoundsOfBoxes(box, nodeBox);
2235
2240
  }
2236
2241
  }), boxToRect(box);
2237
- }, getNodesInside = (nodes, rect, [tx, ty, tScale] = [0, 0, 1], partially = !1, excludeNonSelectableNodes = !1, nodeOrigin = [0, 0]) => {
2242
+ }, getNodesInside = (nodes, rect, [tx, ty, tScale] = [0, 0, 1], partially = !1, excludeNonSelectableNodes = !1) => {
2238
2243
  const paneRect = {
2239
2244
  ...pointToRendererPoint(rect, [tx, ty, tScale]),
2240
2245
  width: rect.width / tScale,
@@ -2244,7 +2249,7 @@ const isEdgeBase = (element2) => "id" in element2 && "source" in element2 && "ta
2244
2249
  const { measured, selectable = !0, hidden = !1 } = node, width = measured.width ?? node.width ?? node.initialWidth ?? null, height = measured.height ?? node.height ?? node.initialHeight ?? null;
2245
2250
  if (excludeNonSelectableNodes && !selectable || hidden)
2246
2251
  continue;
2247
- const overlappingArea = getOverlappingArea(paneRect, nodeToRect(node, nodeOrigin)), notInitialized = width === null || height === null, partiallyVisible = partially && overlappingArea > 0, area = (width ?? 0) * (height ?? 0);
2252
+ const overlappingArea = getOverlappingArea(paneRect, nodeToRect(node)), notInitialized = width === null || height === null, partiallyVisible = partially && overlappingArea > 0, area = (width ?? 0) * (height ?? 0);
2248
2253
  (notInitialized || partiallyVisible || overlappingArea >= area || node.dragging) && visibleNodes.push(node);
2249
2254
  }
2250
2255
  return visibleNodes;
@@ -2254,35 +2259,34 @@ const isEdgeBase = (element2) => "id" in element2 && "source" in element2 && "ta
2254
2259
  nodeIds.add(node.id);
2255
2260
  }), edges.filter((edge) => nodeIds.has(edge.source) || nodeIds.has(edge.target));
2256
2261
  };
2257
- function fitView({ nodeLookup, width, height, panZoom, minZoom, maxZoom, nodeOrigin = [0, 0] }, options) {
2258
- const filteredNodes = [], optionNodeIds = options != null && options.nodes ? new Set(options.nodes.map((node) => node.id)) : null;
2259
- if (nodeLookup.forEach((n) => {
2260
- n.measured.width && n.measured.height && ((options == null ? void 0 : options.includeHiddenNodes) || !n.hidden) && (!optionNodeIds || optionNodeIds.has(n.id)) && filteredNodes.push(n);
2261
- }), filteredNodes.length > 0) {
2262
- const bounds = getNodesBounds(filteredNodes, { nodeOrigin }), viewport = getViewportForBounds(bounds, width, height, (options == null ? void 0 : options.minZoom) ?? minZoom, (options == null ? void 0 : options.maxZoom) ?? maxZoom, (options == null ? void 0 : options.padding) ?? 0.1);
2263
- return panZoom.setViewport(viewport, { duration: options == null ? void 0 : options.duration }), !0;
2264
- }
2265
- return !1;
2262
+ function getFitViewNodes(nodeLookup, options) {
2263
+ const fitViewNodes = /* @__PURE__ */ new Map(), optionNodeIds = options != null && options.nodes ? new Set(options.nodes.map((node) => node.id)) : null;
2264
+ return nodeLookup.forEach((n) => {
2265
+ n.measured.width && n.measured.height && ((options == null ? void 0 : options.includeHiddenNodes) || !n.hidden) && (!optionNodeIds || optionNodeIds.has(n.id)) && fitViewNodes.set(n.id, n);
2266
+ }), fitViewNodes;
2267
+ }
2268
+ async function fitView({ nodes, width, height, panZoom, minZoom, maxZoom }, options) {
2269
+ if (nodes.size === 0)
2270
+ return Promise.resolve(!1);
2271
+ const bounds = getInternalNodesBounds(nodes), viewport = getViewportForBounds(bounds, width, height, (options == null ? void 0 : options.minZoom) ?? minZoom, (options == null ? void 0 : options.maxZoom) ?? maxZoom, (options == null ? void 0 : options.padding) ?? 0.1);
2272
+ return await panZoom.setViewport(viewport, { duration: options == null ? void 0 : options.duration }), Promise.resolve(!0);
2266
2273
  }
2267
2274
  function clampNodeExtent(node, extent) {
2268
2275
  var _a, _b;
2269
2276
  return !extent || extent === "parent" ? extent : [extent[0], [extent[1][0] - (((_a = node.measured) == null ? void 0 : _a.width) ?? 0), extent[1][1] - (((_b = node.measured) == null ? void 0 : _b.height) ?? 0)]];
2270
2277
  }
2271
2278
  function calculateNodePosition({ nodeId, nextPosition, nodeLookup, nodeOrigin = [0, 0], nodeExtent, onError }) {
2272
- const node = nodeLookup.get(nodeId), parentNode = node.parentId ? nodeLookup.get(node.parentId) : void 0, { x: parentX, y: parentY } = parentNode ? getNodePositionWithOrigin(parentNode, parentNode.origin || nodeOrigin).positionAbsolute : { x: 0, y: 0 };
2279
+ const node = nodeLookup.get(nodeId), parentNode = node.parentId ? nodeLookup.get(node.parentId) : void 0, { x: parentX, y: parentY } = parentNode ? parentNode.internals.positionAbsolute : { x: 0, y: 0 }, origin = node.origin ?? nodeOrigin;
2273
2280
  let currentExtent = clampNodeExtent(node, node.extent || nodeExtent);
2274
2281
  if (node.extent === "parent" && !node.expandParent)
2275
2282
  if (!parentNode)
2276
2283
  onError == null || onError("005", errorMessages.error005());
2277
2284
  else {
2278
2285
  const nodeWidth = node.measured.width, nodeHeight = node.measured.height, parentWidth = parentNode.measured.width, parentHeight = parentNode.measured.height;
2279
- if (nodeWidth && nodeHeight && parentWidth && parentHeight) {
2280
- const currNodeOrigin = node.origin || nodeOrigin, extentX = parentX + nodeWidth * currNodeOrigin[0], extentY = parentY + nodeHeight * currNodeOrigin[1];
2281
- currentExtent = [
2282
- [extentX, extentY],
2283
- [extentX + parentWidth - nodeWidth, extentY + parentHeight - nodeHeight]
2284
- ];
2285
- }
2286
+ nodeWidth && nodeHeight && parentWidth && parentHeight && (currentExtent = [
2287
+ [parentX, parentY],
2288
+ [parentX + parentWidth - nodeWidth, parentY + parentHeight - nodeHeight]
2289
+ ]);
2286
2290
  }
2287
2291
  else parentNode && isCoordinateExtent(node.extent) && (currentExtent = [
2288
2292
  [node.extent[0][0] + parentX, node.extent[0][1] + parentY],
@@ -2291,8 +2295,9 @@ function calculateNodePosition({ nodeId, nextPosition, nodeLookup, nodeOrigin =
2291
2295
  const positionAbsolute = isCoordinateExtent(currentExtent) ? clampPosition(nextPosition, currentExtent) : nextPosition;
2292
2296
  return {
2293
2297
  position: {
2294
- x: positionAbsolute.x - parentX,
2295
- y: positionAbsolute.y - parentY
2298
+ // TODO: is there a better way to do this?
2299
+ x: positionAbsolute.x - parentX + node.measured.width * origin[0],
2300
+ y: positionAbsolute.y - parentY + node.measured.height * origin[1]
2296
2301
  },
2297
2302
  positionAbsolute
2298
2303
  };
@@ -2322,8 +2327,8 @@ async function getElementsToRemove({ nodesToRemove = [], edgesToRemove = [], nod
2322
2327
  const clamp = (val, min2 = 0, max2 = 1) => Math.min(Math.max(val, min2), max2), clampPosition = (position = { x: 0, y: 0 }, extent) => ({
2323
2328
  x: clamp(position.x, extent[0][0], extent[1][0]),
2324
2329
  y: clamp(position.y, extent[0][1], extent[1][1])
2325
- }), calcAutoPanVelocity = (value, min2, max2) => value < min2 ? clamp(Math.abs(value - min2), 1, 50) / 50 : value > max2 ? -clamp(Math.abs(value - max2), 1, 50) / 50 : 0, calcAutoPan = (pos, bounds) => {
2326
- const xMovement = calcAutoPanVelocity(pos.x, 35, bounds.width - 35) * 20, yMovement = calcAutoPanVelocity(pos.y, 35, bounds.height - 35) * 20;
2330
+ }), calcAutoPanVelocity = (value, min2, max2) => value < min2 ? clamp(Math.abs(value - min2), 1, min2) / min2 : value > max2 ? -clamp(Math.abs(value - max2), 1, min2) / min2 : 0, calcAutoPan = (pos, bounds, speed = 15, distance2 = 40) => {
2331
+ const xMovement = calcAutoPanVelocity(pos.x, distance2, bounds.width - distance2) * speed, yMovement = calcAutoPanVelocity(pos.y, distance2, bounds.height - distance2) * speed;
2327
2332
  return [xMovement, yMovement];
2328
2333
  }, getBoundsOfBoxes = (box1, box2) => ({
2329
2334
  x: Math.min(box1.x, box2.x),
@@ -2342,29 +2347,26 @@ const clamp = (val, min2 = 0, max2 = 1) => Math.min(Math.max(val, min2), max2),
2342
2347
  height: y2 - y
2343
2348
  }), nodeToRect = (node, nodeOrigin = [0, 0]) => {
2344
2349
  var _a, _b;
2345
- const { x, y } = getNodePositionWithOrigin(node, nodeOrigin).positionAbsolute;
2350
+ const { x, y } = isInternalNodeBase(node) ? node.internals.positionAbsolute : getNodePositionWithOrigin(node, nodeOrigin);
2346
2351
  return {
2347
2352
  x,
2348
2353
  y,
2349
- width: ((_a = node.measured) == null ? void 0 : _a.width) ?? node.width ?? 0,
2350
- height: ((_b = node.measured) == null ? void 0 : _b.height) ?? node.height ?? 0
2354
+ width: ((_a = node.measured) == null ? void 0 : _a.width) ?? node.width ?? node.initialWidth ?? 0,
2355
+ height: ((_b = node.measured) == null ? void 0 : _b.height) ?? node.height ?? node.initialHeight ?? 0
2351
2356
  };
2352
2357
  }, nodeToBox = (node, nodeOrigin = [0, 0]) => {
2353
2358
  var _a, _b;
2354
- const { x, y } = getNodePositionWithOrigin(node, nodeOrigin).positionAbsolute;
2359
+ const { x, y } = isInternalNodeBase(node) ? node.internals.positionAbsolute : getNodePositionWithOrigin(node, nodeOrigin);
2355
2360
  return {
2356
2361
  x,
2357
2362
  y,
2358
- x2: x + (((_a = node.measured) == null ? void 0 : _a.width) ?? node.width ?? 0),
2359
- y2: y + (((_b = node.measured) == null ? void 0 : _b.height) ?? node.height ?? 0)
2363
+ x2: x + (((_a = node.measured) == null ? void 0 : _a.width) ?? node.width ?? node.initialWidth ?? 0),
2364
+ y2: y + (((_b = node.measured) == null ? void 0 : _b.height) ?? node.height ?? node.initialHeight ?? 0)
2360
2365
  };
2361
2366
  }, getBoundsOfRects = (rect1, rect2) => boxToRect(getBoundsOfBoxes(rectToBox(rect1), rectToBox(rect2))), getOverlappingArea = (rectA, rectB) => {
2362
2367
  const xOverlap = Math.max(0, Math.min(rectA.x + rectA.width, rectB.x + rectB.width) - Math.max(rectA.x, rectB.x)), yOverlap = Math.max(0, Math.min(rectA.y + rectA.height, rectB.y + rectB.height) - Math.max(rectA.y, rectB.y));
2363
2368
  return Math.ceil(xOverlap * yOverlap);
2364
2369
  }, isRectObject = (obj) => isNumeric(obj.width) && isNumeric(obj.height) && isNumeric(obj.x) && isNumeric(obj.y), isNumeric = (n) => !isNaN(n) && isFinite(n), devWarn = (id2, message) => {
2365
- }, getPositionWithOrigin = ({ x, y, width, height, origin = [0, 0] }) => !width || !height || origin[0] < 0 || origin[1] < 0 || origin[0] > 1 || origin[1] > 1 ? { x, y } : {
2366
- x: x - width * origin[0],
2367
- y: y - height * origin[1]
2368
2370
  }, snapPosition = (position, snapGrid = [1, 1]) => ({
2369
2371
  x: snapGrid[0] * Math.round(position.x / snapGrid[0]),
2370
2372
  y: snapGrid[1] * Math.round(position.y / snapGrid[1])
@@ -2398,14 +2400,14 @@ function nodeHasDimensions(node) {
2398
2400
  var _a, _b;
2399
2401
  return (((_a = node.measured) == null ? void 0 : _a.width) ?? node.width ?? node.initialWidth) !== void 0 && (((_b = node.measured) == null ? void 0 : _b.height) ?? node.height ?? node.initialHeight) !== void 0;
2400
2402
  }
2401
- function evaluateAbsolutePosition(position, parentId, nodeLookup, nodeOrigin = [0, 0]) {
2403
+ function evaluateAbsolutePosition(position, dimensions = { width: 0, height: 0 }, parentId, nodeLookup, nodeOrigin) {
2402
2404
  let nextParentId = parentId;
2403
2405
  const positionAbsolute = { ...position };
2404
2406
  for (; nextParentId; ) {
2405
2407
  const parent = nodeLookup.get(nextParentId);
2406
2408
  if (nextParentId = parent == null ? void 0 : parent.parentId, parent) {
2407
- const origin = parent.origin || nodeOrigin, xOffset = (parent.measured.width ?? 0) * origin[0], yOffset = (parent.measured.height ?? 0) * origin[1];
2408
- positionAbsolute.x += parent.position.x - xOffset, positionAbsolute.y += parent.position.y - yOffset;
2409
+ const origin = parent.origin || nodeOrigin;
2410
+ positionAbsolute.x += parent.internals.positionAbsolute.x - (dimensions.width ?? 0) * origin[0], positionAbsolute.y += parent.internals.positionAbsolute.y - (dimensions.height ?? 0) * origin[1];
2409
2411
  }
2410
2412
  }
2411
2413
  return positionAbsolute;
@@ -2437,21 +2439,17 @@ const isMouseEvent = (event) => "clientX" in event, getEventPosition = (event, b
2437
2439
  x: evtX - ((bounds == null ? void 0 : bounds.left) ?? 0),
2438
2440
  y: evtY - ((bounds == null ? void 0 : bounds.top) ?? 0)
2439
2441
  };
2440
- }, getHandleBounds = (selector2, nodeElement, nodeBounds, zoom2, nodeOrigin = [0, 0]) => {
2441
- const handles = nodeElement.querySelectorAll(selector2);
2442
- if (!handles || !handles.length)
2443
- return null;
2444
- const handlesArray = Array.from(handles), nodeOffset = {
2445
- x: nodeBounds.left + nodeBounds.width * nodeOrigin[0],
2446
- y: nodeBounds.top + nodeBounds.height * nodeOrigin[1]
2447
- };
2448
- return handlesArray.map((handle) => {
2442
+ }, getHandleBounds = (type, nodeElement, nodeBounds, zoom2, nodeId) => {
2443
+ const handles = nodeElement.querySelectorAll(`.${type}`);
2444
+ return !handles || !handles.length ? null : Array.from(handles).map((handle) => {
2449
2445
  const handleBounds = handle.getBoundingClientRect();
2450
2446
  return {
2451
2447
  id: handle.getAttribute("data-handleid"),
2448
+ type,
2449
+ nodeId,
2452
2450
  position: handle.getAttribute("data-handlepos"),
2453
- x: (handleBounds.left - nodeOffset.x) / zoom2,
2454
- y: (handleBounds.top - nodeOffset.y) / zoom2,
2451
+ x: (handleBounds.left - nodeBounds.left) / zoom2,
2452
+ y: (handleBounds.top - nodeBounds.top) / zoom2,
2455
2453
  ...getDimensions(handle)
2456
2454
  };
2457
2455
  });
@@ -2645,12 +2643,12 @@ function getEdgePosition(params) {
2645
2643
  sourceHandle: params.sourceHandle,
2646
2644
  targetHandle: params.targetHandle
2647
2645
  })), null;
2648
- const sourcePosition = (sourceHandle == null ? void 0 : sourceHandle.position) || Position.Bottom, targetPosition = (targetHandle == null ? void 0 : targetHandle.position) || Position.Top, [sourceX, sourceY] = getHandlePosition(sourceNode, sourceHandle, sourcePosition), [targetX, targetY] = getHandlePosition(targetNode, targetHandle, targetPosition);
2646
+ const sourcePosition = (sourceHandle == null ? void 0 : sourceHandle.position) || Position.Bottom, targetPosition = (targetHandle == null ? void 0 : targetHandle.position) || Position.Top, source = getHandlePosition(sourceNode, sourceHandle, sourcePosition), target = getHandlePosition(targetNode, targetHandle, targetPosition);
2649
2647
  return {
2650
- sourceX,
2651
- sourceY,
2652
- targetX,
2653
- targetY,
2648
+ sourceX: source.x,
2649
+ sourceY: source.y,
2650
+ targetX: target.x,
2651
+ targetY: target.y,
2654
2652
  sourcePosition,
2655
2653
  targetPosition
2656
2654
  };
@@ -2666,17 +2664,19 @@ function toHandleBounds(handles) {
2666
2664
  target
2667
2665
  };
2668
2666
  }
2669
- function getHandlePosition(node, handle, fallbackPosition = Position.Left) {
2667
+ function getHandlePosition(node, handle, fallbackPosition = Position.Left, center = !1) {
2670
2668
  const x = ((handle == null ? void 0 : handle.x) ?? 0) + node.internals.positionAbsolute.x, y = ((handle == null ? void 0 : handle.y) ?? 0) + node.internals.positionAbsolute.y, { width, height } = handle ?? getNodeDimensions(node);
2669
+ if (center)
2670
+ return { x: x + width / 2, y: y + height / 2 };
2671
2671
  switch ((handle == null ? void 0 : handle.position) ?? fallbackPosition) {
2672
2672
  case Position.Top:
2673
- return [x + width / 2, y];
2673
+ return { x: x + width / 2, y };
2674
2674
  case Position.Right:
2675
- return [x + width, y + height / 2];
2675
+ return { x: x + width, y: y + height / 2 };
2676
2676
  case Position.Bottom:
2677
- return [x + width / 2, y + height];
2677
+ return { x: x + width / 2, y: y + height };
2678
2678
  case Position.Left:
2679
- return [x, y + height / 2];
2679
+ return { x, y: y + height / 2 };
2680
2680
  }
2681
2681
  }
2682
2682
  function getHandle(bounds, handleId) {
@@ -2694,110 +2694,102 @@ function createMarkerIds(edges, { id: id2, defaultColor, defaultMarkerStart, def
2694
2694
  }
2695
2695
  }), markers), []).sort((a, b) => a.id.localeCompare(b.id));
2696
2696
  }
2697
- function updateAbsolutePositions(nodeLookup, options = {
2697
+ const defaultOptions = {
2698
2698
  nodeOrigin: [0, 0],
2699
2699
  elevateNodesOnSelect: !0,
2700
2700
  defaults: {}
2701
- }) {
2702
- const selectedNodeZ = options != null && options.elevateNodesOnSelect ? 1e3 : 0;
2703
- for (const [, node] of nodeLookup) {
2704
- const parentId = node.parentId;
2705
- if (!parentId)
2706
- continue;
2707
- if (!nodeLookup.has(parentId))
2708
- throw new Error(`Parent node ${parentId} not found`);
2709
- const parentNode = nodeLookup.get(parentId), { x, y, z } = calculateXYZPosition(node, nodeLookup, {
2710
- ...node.position,
2711
- z: (isNumeric(node.zIndex) ? node.zIndex : 0) + (node.selected ? selectedNodeZ : 0)
2712
- }, (parentNode == null ? void 0 : parentNode.origin) ?? options.nodeOrigin), currPosition = node.internals.positionAbsolute, positionChanged = x !== currPosition.x || y !== currPosition.y;
2713
- (positionChanged || z !== node.internals.z) && (node.internals = {
2714
- ...node.internals,
2715
- positionAbsolute: positionChanged ? { x, y } : currPosition,
2716
- z
2717
- });
2718
- }
2719
- }
2720
- function adoptUserNodes(nodes, nodeLookup, parentLookup, options = {
2721
- nodeOrigin: [0, 0],
2722
- elevateNodesOnSelect: !0,
2723
- defaults: {},
2701
+ }, adoptUserNodesDefaultOptions = {
2702
+ ...defaultOptions,
2724
2703
  checkEquality: !0
2725
- }) {
2726
- const tmpLookup = new Map(nodeLookup);
2704
+ };
2705
+ function updateAbsolutePositions(nodeLookup, parentLookup, options) {
2706
+ const _options = { ...defaultOptions, ...options };
2707
+ for (const node of nodeLookup.values())
2708
+ node.parentId && updateChildPosition(node, nodeLookup, parentLookup, _options);
2709
+ }
2710
+ function adoptUserNodes(nodes, nodeLookup, parentLookup, options) {
2711
+ var _a, _b;
2712
+ const _options = { ...adoptUserNodesDefaultOptions, ...options }, tmpLookup = new Map(nodeLookup);
2727
2713
  nodeLookup.clear(), parentLookup.clear();
2728
2714
  const selectedNodeZ = options != null && options.elevateNodesOnSelect ? 1e3 : 0;
2729
- nodes.forEach((userNode) => {
2730
- var _a, _b;
2715
+ for (const userNode of nodes) {
2731
2716
  let internalNode = tmpLookup.get(userNode.id);
2732
- if (options.checkEquality && userNode === (internalNode == null ? void 0 : internalNode.internals.userNode) || (internalNode = {
2733
- ...options.defaults,
2717
+ _options.checkEquality && userNode === (internalNode == null ? void 0 : internalNode.internals.userNode) || (internalNode = {
2718
+ ..._options.defaults,
2734
2719
  ...userNode,
2735
2720
  measured: {
2736
2721
  width: (_a = userNode.measured) == null ? void 0 : _a.width,
2737
2722
  height: (_b = userNode.measured) == null ? void 0 : _b.height
2738
2723
  },
2739
2724
  internals: {
2740
- positionAbsolute: userNode.position,
2725
+ positionAbsolute: getNodePositionWithOrigin(userNode, _options.nodeOrigin),
2741
2726
  handleBounds: internalNode == null ? void 0 : internalNode.internals.handleBounds,
2742
- z: (isNumeric(userNode.zIndex) ? userNode.zIndex : 0) + (userNode.selected ? selectedNodeZ : 0),
2727
+ z: calculateZ(userNode, selectedNodeZ),
2743
2728
  userNode
2744
2729
  }
2745
- }), nodeLookup.set(userNode.id, internalNode), userNode.parentId) {
2746
- const childNodes = parentLookup.get(userNode.parentId);
2747
- childNodes ? childNodes.push(internalNode) : parentLookup.set(userNode.parentId, [internalNode]);
2748
- }
2749
- }), parentLookup.size > 0 && updateAbsolutePositions(nodeLookup, options);
2730
+ }), nodeLookup.set(userNode.id, internalNode), userNode.parentId && updateChildPosition(internalNode, nodeLookup, parentLookup, options);
2731
+ }
2732
+ }
2733
+ function updateChildPosition(node, nodeLookup, parentLookup, options) {
2734
+ const _options = { ...defaultOptions, ...options }, parentId = node.parentId, parentNode = nodeLookup.get(parentId);
2735
+ if (!parentNode)
2736
+ throw new Error(`Parent node ${parentId} not found`);
2737
+ const childNodes = parentLookup.get(parentId);
2738
+ childNodes ? childNodes.set(node.id, node) : parentLookup.set(parentId, /* @__PURE__ */ new Map([[node.id, node]]));
2739
+ const selectedNodeZ = options != null && options.elevateNodesOnSelect ? 1e3 : 0, { x, y, z } = calculateChildXYZ(node, parentNode, _options.nodeOrigin, selectedNodeZ), currPosition = node.internals.positionAbsolute, positionChanged = x !== currPosition.x || y !== currPosition.y;
2740
+ (positionChanged || z !== node.internals.z) && (node.internals = {
2741
+ ...node.internals,
2742
+ positionAbsolute: positionChanged ? { x, y } : currPosition,
2743
+ z
2744
+ });
2750
2745
  }
2751
- function calculateXYZPosition(node, nodeLookup, result, nodeOrigin = [0, 0]) {
2752
- if (!node.parentId)
2753
- return result;
2754
- const parent = nodeLookup.get(node.parentId), parentPosition = getNodePositionWithOrigin(parent, nodeOrigin).position;
2755
- return calculateXYZPosition(parent, nodeLookup, {
2756
- x: (result.x ?? 0) + parentPosition.x,
2757
- y: (result.y ?? 0) + parentPosition.y,
2758
- z: (parent.internals.z ?? 0) > (result.z ?? 0) ? parent.internals.z ?? 0 : result.z ?? 0
2759
- }, parent.origin || nodeOrigin);
2760
- }
2761
- function handleExpandParent(children2, nodeLookup, parentLookup, nodeOrigin) {
2746
+ function calculateZ(node, selectedNodeZ) {
2747
+ return (isNumeric(node.zIndex) ? node.zIndex : 0) + (node.selected ? selectedNodeZ : 0);
2748
+ }
2749
+ function calculateChildXYZ(childNode, parentNode, nodeOrigin, selectedNodeZ) {
2750
+ const position = getNodePositionWithOrigin(childNode, nodeOrigin), childZ = calculateZ(childNode, selectedNodeZ), parentZ = parentNode.internals.z ?? 0;
2751
+ return {
2752
+ x: parentNode.internals.positionAbsolute.x + position.x,
2753
+ y: parentNode.internals.positionAbsolute.y + position.y,
2754
+ z: parentZ > childZ ? parentZ : childZ
2755
+ };
2756
+ }
2757
+ function handleExpandParent(children2, nodeLookup, parentLookup, nodeOrigin = [0, 0]) {
2762
2758
  var _a;
2763
2759
  const changes = [], parentExpansions = /* @__PURE__ */ new Map();
2764
2760
  for (const child of children2) {
2765
2761
  const parent = nodeLookup.get(child.parentId);
2766
2762
  if (!parent)
2767
2763
  continue;
2768
- const parentRect = ((_a = parentExpansions.get(child.parentId)) == null ? void 0 : _a.expandedRect) ?? nodeToRect(parent, parent.origin ?? nodeOrigin), expandedRect = getBoundsOfRects(parentRect, child.rect);
2764
+ const parentRect = ((_a = parentExpansions.get(child.parentId)) == null ? void 0 : _a.expandedRect) ?? nodeToRect(parent), expandedRect = getBoundsOfRects(parentRect, child.rect);
2769
2765
  parentExpansions.set(child.parentId, { expandedRect, parent });
2770
2766
  }
2771
2767
  return parentExpansions.size > 0 && parentExpansions.forEach(({ expandedRect, parent }, parentId) => {
2772
- const { position } = getNodePositionWithOrigin(parent, parent.origin), dimensions = getNodeDimensions(parent), xChange = expandedRect.x < position.x ? Math.round(Math.abs(position.x - expandedRect.x)) : 0, yChange = expandedRect.y < position.y ? Math.round(Math.abs(position.y - expandedRect.y)) : 0;
2773
- if (xChange > 0 || yChange > 0) {
2774
- changes.push({
2775
- id: parentId,
2768
+ var _a2;
2769
+ const positionAbsolute = parent.internals.positionAbsolute, dimensions = getNodeDimensions(parent), origin = parent.origin ?? nodeOrigin, xChange = expandedRect.x < positionAbsolute.x ? Math.round(Math.abs(positionAbsolute.x - expandedRect.x)) : 0, yChange = expandedRect.y < positionAbsolute.y ? Math.round(Math.abs(positionAbsolute.y - expandedRect.y)) : 0, newWidth = Math.max(dimensions.width, Math.round(expandedRect.width)), newHeight = Math.max(dimensions.height, Math.round(expandedRect.height)), widthChange = (newWidth - dimensions.width) * origin[0], heightChange = (newHeight - dimensions.height) * origin[1];
2770
+ (xChange > 0 || yChange > 0 || widthChange || heightChange) && (changes.push({
2771
+ id: parentId,
2772
+ type: "position",
2773
+ position: {
2774
+ x: parent.position.x - xChange + widthChange,
2775
+ y: parent.position.y - yChange + heightChange
2776
+ }
2777
+ }), (_a2 = parentLookup.get(parentId)) == null || _a2.forEach((childNode) => {
2778
+ children2.some((child) => child.id === childNode.id) || changes.push({
2779
+ id: childNode.id,
2776
2780
  type: "position",
2777
2781
  position: {
2778
- x: position.x - xChange,
2779
- y: position.y - yChange
2782
+ x: childNode.position.x + xChange,
2783
+ y: childNode.position.y + yChange
2780
2784
  }
2781
2785
  });
2782
- const childNodes = parentLookup.get(parentId);
2783
- childNodes == null || childNodes.forEach((childNode) => {
2784
- children2.some((child) => child.id === childNode.id) || changes.push({
2785
- id: childNode.id,
2786
- type: "position",
2787
- position: {
2788
- x: childNode.position.x + xChange,
2789
- y: childNode.position.y + yChange
2790
- }
2791
- });
2792
- });
2793
- }
2794
- (dimensions.width < expandedRect.width || dimensions.height < expandedRect.height) && changes.push({
2786
+ })), (dimensions.width < expandedRect.width || dimensions.height < expandedRect.height || xChange || yChange) && changes.push({
2795
2787
  id: parentId,
2796
2788
  type: "dimensions",
2797
2789
  setAttributes: !0,
2798
2790
  dimensions: {
2799
- width: Math.max(dimensions.width, Math.round(expandedRect.width)),
2800
- height: Math.max(dimensions.height, Math.round(expandedRect.height))
2791
+ width: newWidth + (xChange ? origin[0] * xChange - widthChange : 0),
2792
+ height: newHeight + (yChange ? origin[1] * yChange - heightChange : 0)
2801
2793
  }
2802
2794
  });
2803
2795
  }), changes;
@@ -2808,52 +2800,55 @@ function updateNodeInternals(updates, nodeLookup, parentLookup, domNode, nodeOri
2808
2800
  if (!viewportNode)
2809
2801
  return { changes: [], updatedInternals };
2810
2802
  const changes = [], style2 = window.getComputedStyle(viewportNode), { m22: zoom2 } = new window.DOMMatrixReadOnly(style2.transform), parentExpandChildren = [];
2811
- if (updates.forEach((update) => {
2803
+ for (const update of updates.values()) {
2812
2804
  const node = nodeLookup.get(update.id);
2813
- if (node != null && node.hidden)
2814
- node.internals = {
2815
- ...node.internals,
2816
- handleBounds: void 0
2817
- }, updatedInternals = !0;
2818
- else if (node) {
2819
- const dimensions = getDimensions(update.nodeElement), dimensionChanged = node.measured.width !== dimensions.width || node.measured.height !== dimensions.height;
2820
- if (!!(dimensions.width && dimensions.height && (dimensionChanged || !node.internals.handleBounds || update.force))) {
2821
- const nodeBounds = update.nodeElement.getBoundingClientRect();
2822
- node.measured = dimensions, node.internals = {
2805
+ if (node)
2806
+ if (node.hidden)
2807
+ node.internals = {
2823
2808
  ...node.internals,
2824
- handleBounds: {
2825
- source: getHandleBounds(".source", update.nodeElement, nodeBounds, zoom2, node.origin || nodeOrigin),
2826
- target: getHandleBounds(".target", update.nodeElement, nodeBounds, zoom2, node.origin || nodeOrigin)
2827
- }
2828
- }, updatedInternals = !0, dimensionChanged && (changes.push({
2829
- id: node.id,
2830
- type: "dimensions",
2831
- dimensions
2832
- }), node.expandParent && node.parentId && parentExpandChildren.push({
2833
- id: node.id,
2834
- parentId: node.parentId,
2835
- rect: nodeToRect(node, nodeOrigin)
2836
- }));
2809
+ handleBounds: void 0
2810
+ }, updatedInternals = !0;
2811
+ else {
2812
+ const dimensions = getDimensions(update.nodeElement), dimensionChanged = node.measured.width !== dimensions.width || node.measured.height !== dimensions.height;
2813
+ if (!!(dimensions.width && dimensions.height && (dimensionChanged || !node.internals.handleBounds || update.force))) {
2814
+ const nodeBounds = update.nodeElement.getBoundingClientRect();
2815
+ node.measured = dimensions, node.internals = {
2816
+ ...node.internals,
2817
+ positionAbsolute: getNodePositionWithOrigin(node, nodeOrigin),
2818
+ handleBounds: {
2819
+ source: getHandleBounds("source", update.nodeElement, nodeBounds, zoom2, node.id),
2820
+ target: getHandleBounds("target", update.nodeElement, nodeBounds, zoom2, node.id)
2821
+ }
2822
+ }, node.parentId && updateChildPosition(node, nodeLookup, parentLookup, { nodeOrigin }), updatedInternals = !0, dimensionChanged && (changes.push({
2823
+ id: node.id,
2824
+ type: "dimensions",
2825
+ dimensions
2826
+ }), node.expandParent && node.parentId && parentExpandChildren.push({
2827
+ id: node.id,
2828
+ parentId: node.parentId,
2829
+ rect: nodeToRect(node, nodeOrigin)
2830
+ }));
2831
+ }
2837
2832
  }
2838
- }
2839
- }), parentExpandChildren.length > 0) {
2833
+ }
2834
+ if (parentExpandChildren.length > 0) {
2840
2835
  const parentExpandChanges = handleExpandParent(parentExpandChildren, nodeLookup, parentLookup, nodeOrigin);
2841
2836
  changes.push(...parentExpandChanges);
2842
2837
  }
2843
2838
  return { changes, updatedInternals };
2844
2839
  }
2845
- function panBy({ delta, panZoom, transform: transform2, translateExtent, width, height }) {
2840
+ async function panBy({ delta, panZoom, transform: transform2, translateExtent, width, height }) {
2846
2841
  if (!panZoom || !delta.x && !delta.y)
2847
- return !1;
2848
- const nextViewport = panZoom.setViewportConstrained({
2842
+ return Promise.resolve(!1);
2843
+ const nextViewport = await panZoom.setViewportConstrained({
2849
2844
  x: transform2[0] + delta.x,
2850
2845
  y: transform2[1] + delta.y,
2851
2846
  zoom: transform2[2]
2852
2847
  }, [
2853
2848
  [0, 0],
2854
2849
  [width, height]
2855
- ], translateExtent);
2856
- return !!nextViewport && (nextViewport.x !== transform2[0] || nextViewport.y !== transform2[1] || nextViewport.k !== transform2[2]);
2850
+ ], translateExtent), transformChanged = !!nextViewport && (nextViewport.x !== transform2[0] || nextViewport.y !== transform2[1] || nextViewport.k !== transform2[2]);
2851
+ return Promise.resolve(transformChanged);
2857
2852
  }
2858
2853
  function updateConnectionLookup(connectionLookup, edgeLookup, edges) {
2859
2854
  connectionLookup.clear(), edgeLookup.clear();
@@ -2917,14 +2912,15 @@ function getDragItems(nodeLookup, nodesDraggable, mousePos, nodeId) {
2917
2912
  }
2918
2913
  return dragItems;
2919
2914
  }
2920
- function getEventHandlerParams({ nodeId, dragItems, nodeLookup }) {
2915
+ function getEventHandlerParams({ nodeId, dragItems, nodeLookup, dragging = !0 }) {
2921
2916
  var _a, _b;
2922
2917
  const nodesFromDragItems = [];
2923
2918
  for (const [id2, dragItem] of dragItems) {
2924
2919
  const node2 = (_a = nodeLookup.get(id2)) == null ? void 0 : _a.internals.userNode;
2925
2920
  node2 && nodesFromDragItems.push({
2926
2921
  ...node2,
2927
- position: dragItem.position
2922
+ position: dragItem.position,
2923
+ dragging
2928
2924
  });
2929
2925
  }
2930
2926
  if (!nodeId)
@@ -2933,7 +2929,8 @@ function getEventHandlerParams({ nodeId, dragItems, nodeLookup }) {
2933
2929
  return [
2934
2930
  {
2935
2931
  ...node,
2936
- position: ((_b = dragItems.get(nodeId)) == null ? void 0 : _b.position) || node.position
2932
+ position: ((_b = dragItems.get(nodeId)) == null ? void 0 : _b.position) || node.position,
2933
+ dragging
2937
2934
  },
2938
2935
  nodesFromDragItems
2939
2936
  ];
@@ -2947,7 +2944,7 @@ function XYDrag({ onNodeMouseDown, getStoreItems, onDragStart, onDrag, onDragSto
2947
2944
  lastPos = { x, y };
2948
2945
  let hasChange = !1, nodesBox = { x: 0, y: 0, x2: 0, y2: 0 };
2949
2946
  if (dragItems.size > 1 && nodeExtent) {
2950
- const rect = getInternalNodesBounds(dragItems, { nodeOrigin });
2947
+ const rect = getInternalNodesBounds(dragItems);
2951
2948
  nodesBox = rectToBox(rect);
2952
2949
  }
2953
2950
  for (const [id2, dragItem] of dragItems) {
@@ -2983,15 +2980,11 @@ function XYDrag({ onNodeMouseDown, getStoreItems, onDragStart, onDrag, onDragSto
2983
2980
  onDrag == null || onDrag(dragEvent, dragItems, currentNode, currentNodes), onNodeDrag == null || onNodeDrag(dragEvent, currentNode, currentNodes), nodeId || onSelectionDrag == null || onSelectionDrag(dragEvent, currentNodes);
2984
2981
  }
2985
2982
  }
2986
- function autoPan() {
2983
+ async function autoPan() {
2987
2984
  if (!containerBounds)
2988
2985
  return;
2989
- const [xMovement, yMovement] = calcAutoPan(mousePosition, containerBounds);
2990
- if (xMovement !== 0 || yMovement !== 0) {
2991
- const { transform: transform2, panBy: panBy2 } = getStoreItems();
2992
- lastPos.x = (lastPos.x ?? 0) - xMovement / transform2[2], lastPos.y = (lastPos.y ?? 0) - yMovement / transform2[2], panBy2({ x: xMovement, y: yMovement }) && updateNodes(lastPos, null);
2993
- }
2994
- autoPanId = requestAnimationFrame(autoPan);
2986
+ const { transform: transform2, panBy: panBy2, autoPanSpeed } = getStoreItems(), [xMovement, yMovement] = calcAutoPan(mousePosition, containerBounds, autoPanSpeed);
2987
+ (xMovement !== 0 || yMovement !== 0) && (lastPos.x = (lastPos.x ?? 0) - xMovement / transform2[2], lastPos.y = (lastPos.y ?? 0) - yMovement / transform2[2], await panBy2({ x: xMovement, y: yMovement }) && updateNodes(lastPos, null)), autoPanId = requestAnimationFrame(autoPan);
2995
2988
  }
2996
2989
  function startDrag(event) {
2997
2990
  var _a;
@@ -3026,7 +3019,8 @@ function XYDrag({ onNodeMouseDown, getStoreItems, onDragStart, onDrag, onDragSto
3026
3019
  const [currentNode, currentNodes] = getEventHandlerParams({
3027
3020
  nodeId,
3028
3021
  dragItems,
3029
- nodeLookup
3022
+ nodeLookup,
3023
+ dragging: !1
3030
3024
  });
3031
3025
  onDragStop == null || onDragStop(event.sourceEvent, dragItems, currentNode, currentNodes), onNodeDragStop == null || onNodeDragStop(event.sourceEvent, currentNode, currentNodes), nodeId || onSelectionDragStop == null || onSelectionDragStop(event.sourceEvent, currentNodes);
3032
3026
  }
@@ -3046,19 +3040,16 @@ function XYDrag({ onNodeMouseDown, getStoreItems, onDragStart, onDrag, onDragSto
3046
3040
  };
3047
3041
  }
3048
3042
  function getHandles(node, handleBounds, type, currentHandle) {
3049
- return (handleBounds[type] || []).reduce((res, handle) => {
3050
- if (`${node.id}-${handle.id}-${type}` !== currentHandle) {
3051
- const [x, y] = getHandlePosition(node, handle);
3052
- res.push({
3053
- id: handle.id || null,
3054
- type,
3055
- nodeId: node.id,
3056
- x,
3057
- y
3058
- });
3043
+ let excludedHandle = null;
3044
+ return [(handleBounds[type] || []).reduce((res, handle) => {
3045
+ if (node.id === currentHandle.nodeId && type === currentHandle.handleType && handle.id === currentHandle.handleId)
3046
+ excludedHandle = handle;
3047
+ else {
3048
+ const handleXY = getHandlePosition(node, handle, handle.position, !0);
3049
+ res.push({ ...handle, ...handleXY });
3059
3050
  }
3060
3051
  return res;
3061
- }, []);
3052
+ }, []), excludedHandle];
3062
3053
  }
3063
3054
  function getClosestHandle(pos, connectionRadius, handles) {
3064
3055
  let closestHandles = [], minDistance = 1 / 0;
@@ -3072,31 +3063,31 @@ function getClosestHandle(pos, connectionRadius, handles) {
3072
3063
  ) : null;
3073
3064
  }
3074
3065
  function getHandleLookup({ nodeLookup, nodeId, handleId, handleType }) {
3075
- const connectionHandles = [];
3076
- for (const [, node] of nodeLookup)
3066
+ const connectionHandles = [], currentHandle = { nodeId, handleId, handleType };
3067
+ let excludedHandle = null;
3068
+ for (const node of nodeLookup.values())
3077
3069
  if (node.internals.handleBounds) {
3078
- const id2 = `${nodeId}-${handleId}-${handleType}`, sourceHandles = getHandles(node, node.internals.handleBounds, "source", id2), targetHandles = getHandles(node, node.internals.handleBounds, "target", id2);
3079
- connectionHandles.push(...sourceHandles, ...targetHandles);
3070
+ const [sourceHandles, excludedSource] = getHandles(node, node.internals.handleBounds, "source", currentHandle), [targetHandles, excludedTarget] = getHandles(node, node.internals.handleBounds, "target", currentHandle);
3071
+ excludedHandle = excludedHandle || (excludedSource ?? excludedTarget), connectionHandles.push(...sourceHandles, ...targetHandles);
3080
3072
  }
3081
- return connectionHandles;
3073
+ return [connectionHandles, excludedHandle];
3082
3074
  }
3083
3075
  function getHandleType(edgeUpdaterType, handleDomNode) {
3084
3076
  return edgeUpdaterType || (handleDomNode != null && handleDomNode.classList.contains("target") ? "target" : handleDomNode != null && handleDomNode.classList.contains("source") ? "source" : null);
3085
3077
  }
3086
- function getConnectionStatus(isInsideConnectionRadius, isHandleValid) {
3087
- let connectionStatus = null;
3088
- return isHandleValid ? connectionStatus = "valid" : isInsideConnectionRadius && !isHandleValid && (connectionStatus = "invalid"), connectionStatus;
3078
+ function isConnectionValid(isInsideConnectionRadius, isHandleValid) {
3079
+ let isValid = null;
3080
+ return isHandleValid ? isValid = !0 : isInsideConnectionRadius && !isHandleValid && (isValid = !1), isValid;
3089
3081
  }
3090
3082
  const alwaysValid = () => !0;
3091
- let connectionStartHandle = null;
3092
- function onPointerDown(event, { connectionMode, connectionRadius, handleId, nodeId, edgeUpdaterType, isTarget, domNode, nodeLookup, lib, autoPanOnConnect, flowId, panBy: panBy2, cancelConnection, onConnectStart, onConnect, onConnectEnd, isValidConnection = alwaysValid, onReconnectEnd, updateConnection, getTransform, getConnectionStartHandle }) {
3083
+ function onPointerDown(event, { connectionMode, connectionRadius, handleId, nodeId, edgeUpdaterType, isTarget, domNode, nodeLookup, lib, autoPanOnConnect, flowId, panBy: panBy2, cancelConnection, onConnectStart, onConnect, onConnectEnd, isValidConnection = alwaysValid, onReconnectEnd, updateConnection, getTransform, getFromHandle, autoPanSpeed }) {
3093
3084
  const doc = getHostForElement(event.target);
3094
3085
  let autoPanId = 0, closestHandle;
3095
3086
  const { x, y } = getEventPosition(event), clickedHandle = doc == null ? void 0 : doc.elementFromPoint(x, y), handleType = getHandleType(edgeUpdaterType, clickedHandle), containerBounds = domNode == null ? void 0 : domNode.getBoundingClientRect();
3096
3087
  if (!containerBounds || !handleType)
3097
3088
  return;
3098
- let connectionPosition = getEventPosition(event, containerBounds), autoPanStarted = !1, connection = null, isValid = !1, handleDomNode = null;
3099
- const handleLookup = getHandleLookup({
3089
+ let position = getEventPosition(event, containerBounds), autoPanStarted = !1, connection = null, isValid = !1, handleDomNode = null;
3090
+ const [handleLookup, fromHandleInternal] = getHandleLookup({
3100
3091
  nodeLookup,
3101
3092
  nodeId,
3102
3093
  handleId,
@@ -3105,24 +3096,36 @@ function onPointerDown(event, { connectionMode, connectionRadius, handleId, node
3105
3096
  function autoPan() {
3106
3097
  if (!autoPanOnConnect || !containerBounds)
3107
3098
  return;
3108
- const [x2, y2] = calcAutoPan(connectionPosition, containerBounds);
3099
+ const [x2, y2] = calcAutoPan(position, containerBounds, autoPanSpeed);
3109
3100
  panBy2({ x: x2, y: y2 }), autoPanId = requestAnimationFrame(autoPan);
3110
3101
  }
3111
- connectionStartHandle = {
3102
+ const fromHandle = {
3103
+ ...fromHandleInternal,
3112
3104
  nodeId,
3113
- handleId,
3114
3105
  type: handleType,
3115
- position: (clickedHandle == null ? void 0 : clickedHandle.getAttribute("data-handlepos")) || Position.Top
3116
- }, updateConnection({
3117
- connectionPosition,
3118
- connectionStatus: null,
3119
- connectionStartHandle,
3120
- connectionEndHandle: null
3121
- }), onConnectStart == null || onConnectStart(event, { nodeId, handleId, handleType });
3106
+ position: fromHandleInternal.position
3107
+ }, fromNodeInternal = nodeLookup.get(nodeId), newConnection = {
3108
+ inProgress: !0,
3109
+ isValid: null,
3110
+ from: getHandlePosition(fromNodeInternal, fromHandle, Position.Left, !0),
3111
+ fromHandle,
3112
+ fromPosition: fromHandle.position,
3113
+ fromNode: fromNodeInternal,
3114
+ to: position,
3115
+ toHandle: null,
3116
+ toPosition: oppositePosition[fromHandle.position],
3117
+ toNode: null
3118
+ };
3119
+ updateConnection(newConnection);
3120
+ let previousConnection = newConnection;
3121
+ onConnectStart == null || onConnectStart(event, { nodeId, handleId, handleType });
3122
3122
  function onPointerMove(event2) {
3123
- getConnectionStartHandle() || onPointerUp(event2);
3123
+ if (!getFromHandle() || !fromHandle) {
3124
+ onPointerUp(event2);
3125
+ return;
3126
+ }
3124
3127
  const transform2 = getTransform();
3125
- connectionPosition = getEventPosition(event2, containerBounds), closestHandle = getClosestHandle(pointToRendererPoint(connectionPosition, transform2, !1, [1, 1]), connectionRadius, handleLookup), autoPanStarted || (autoPan(), autoPanStarted = !0);
3128
+ position = getEventPosition(event2, containerBounds), closestHandle = getClosestHandle(pointToRendererPoint(position, transform2, !1, [1, 1]), connectionRadius, handleLookup), autoPanStarted || (autoPan(), autoPanStarted = !0);
3126
3129
  const result = isValidHandle(event2, {
3127
3130
  handle: closestHandle,
3128
3131
  connectionMode,
@@ -3132,29 +3135,32 @@ function onPointerDown(event, { connectionMode, connectionRadius, handleId, node
3132
3135
  isValidConnection,
3133
3136
  doc,
3134
3137
  lib,
3135
- flowId
3136
- });
3137
- handleDomNode = result.handleDomNode, connection = result.connection, isValid = result.isValid, updateConnection({
3138
- connectionStartHandle,
3139
- connectionPosition: closestHandle && isValid ? rendererPointToPoint({
3140
- x: closestHandle.x,
3141
- y: closestHandle.y
3142
- }, transform2) : connectionPosition,
3143
- connectionStatus: getConnectionStatus(!!closestHandle, isValid),
3144
- connectionEndHandle: result.endHandle
3138
+ flowId,
3139
+ handleLookup
3145
3140
  });
3141
+ handleDomNode = result.handleDomNode, connection = result.connection, isValid = isConnectionValid(!!closestHandle, result.isValid);
3142
+ const newConnection2 = {
3143
+ // from stays the same
3144
+ ...previousConnection,
3145
+ isValid,
3146
+ to: closestHandle && isValid ? rendererPointToPoint({ x: closestHandle.x, y: closestHandle.y }, transform2) : position,
3147
+ toHandle: result.toHandle,
3148
+ toPosition: isValid && result.toHandle ? result.toHandle.position : oppositePosition[fromHandle.position],
3149
+ toNode: result.toHandle ? nodeLookup.get(result.toHandle.nodeId) : null
3150
+ };
3151
+ isValid && closestHandle && previousConnection.toHandle && newConnection2.toHandle && previousConnection.toHandle.type === newConnection2.toHandle.type && previousConnection.toHandle.nodeId === newConnection2.toHandle.nodeId && previousConnection.toHandle.id === newConnection2.toHandle.id || (updateConnection(newConnection2), previousConnection = newConnection2);
3146
3152
  }
3147
3153
  function onPointerUp(event2) {
3148
- (closestHandle || handleDomNode) && connection && isValid && (onConnect == null || onConnect(connection)), onConnectEnd == null || onConnectEnd(event2), edgeUpdaterType && (onReconnectEnd == null || onReconnectEnd(event2)), cancelConnection(), cancelAnimationFrame(autoPanId), autoPanStarted = !1, isValid = !1, connection = null, handleDomNode = null, connectionStartHandle = null, doc.removeEventListener("mousemove", onPointerMove), doc.removeEventListener("mouseup", onPointerUp), doc.removeEventListener("touchmove", onPointerMove), doc.removeEventListener("touchend", onPointerUp);
3154
+ (closestHandle || handleDomNode) && connection && isValid && (onConnect == null || onConnect(connection)), onConnectEnd == null || onConnectEnd(event2), edgeUpdaterType && (onReconnectEnd == null || onReconnectEnd(event2)), cancelConnection(), cancelAnimationFrame(autoPanId), autoPanStarted = !1, isValid = !1, connection = null, handleDomNode = null, doc.removeEventListener("mousemove", onPointerMove), doc.removeEventListener("mouseup", onPointerUp), doc.removeEventListener("touchmove", onPointerMove), doc.removeEventListener("touchend", onPointerUp);
3149
3155
  }
3150
3156
  doc.addEventListener("mousemove", onPointerMove), doc.addEventListener("mouseup", onPointerUp), doc.addEventListener("touchmove", onPointerMove), doc.addEventListener("touchend", onPointerUp);
3151
3157
  }
3152
- function isValidHandle(event, { handle, connectionMode, fromNodeId, fromHandleId, fromType, doc, lib, flowId, isValidConnection = alwaysValid }) {
3158
+ function isValidHandle(event, { handle, connectionMode, fromNodeId, fromHandleId, fromType, doc, lib, flowId, isValidConnection = alwaysValid, handleLookup }) {
3153
3159
  const isTarget = fromType === "target", handleDomNode = handle ? doc.querySelector(`.${lib}-flow__handle[data-id="${flowId}-${handle == null ? void 0 : handle.nodeId}-${handle == null ? void 0 : handle.id}-${handle == null ? void 0 : handle.type}"]`) : null, { x, y } = getEventPosition(event), handleBelow = doc.elementFromPoint(x, y), handleToCheck = handleBelow != null && handleBelow.classList.contains(`${lib}-flow__handle`) ? handleBelow : handleDomNode, result = {
3154
3160
  handleDomNode: handleToCheck,
3155
3161
  isValid: !1,
3156
3162
  connection: null,
3157
- endHandle: null
3163
+ toHandle: null
3158
3164
  };
3159
3165
  if (handleToCheck) {
3160
3166
  const handleType = getHandleType(void 0, handleToCheck), handleNodeId = handleToCheck.getAttribute("data-nodeid"), handleId = handleToCheck.getAttribute("data-handleid"), connectable = handleToCheck.classList.contains("connectable"), connectableEnd = handleToCheck.classList.contains("connectableend");
@@ -3168,12 +3174,12 @@ function isValidHandle(event, { handle, connectionMode, fromNodeId, fromHandleId
3168
3174
  };
3169
3175
  result.connection = connection;
3170
3176
  const isValid = connectable && connectableEnd && (connectionMode === ConnectionMode.Strict ? isTarget && handleType === "source" || !isTarget && handleType === "target" : handleNodeId !== fromNodeId || handleId !== fromHandleId);
3171
- result.isValid = isValid && isValidConnection(connection), result.endHandle = {
3172
- nodeId: handleNodeId,
3173
- handleId,
3174
- type: handleType,
3175
- position: handleToCheck.getAttribute("data-handlepos")
3176
- };
3177
+ if (result.isValid = isValid && isValidConnection(connection), handleLookup) {
3178
+ const toHandle = handleLookup.find((h) => h.id === handleId && h.nodeId === handleNodeId && h.type === handleType);
3179
+ toHandle && (result.toHandle = {
3180
+ ...toHandle
3181
+ });
3182
+ }
3177
3183
  }
3178
3184
  return result;
3179
3185
  }
@@ -3234,7 +3240,11 @@ const viewChanged = (prevViewport, eventViewport) => prevViewport.x !== eventVie
3234
3240
  x: transform2.x,
3235
3241
  y: transform2.y,
3236
3242
  zoom: transform2.k
3237
- }), viewportToTransform = ({ x, y, zoom: zoom2 }) => identity.translate(x, y).scale(zoom2), isWrappedWithClass = (event, className) => event.target.closest(`.${className}`), isRightClickPan = (panOnDrag, usedButton) => usedButton === 2 && Array.isArray(panOnDrag) && panOnDrag.includes(2), getD3Transition = (selection2, duration = 0) => typeof duration == "number" && duration > 0 ? selection2.transition().duration(duration) : selection2, wheelDelta = (event) => {
3243
+ }), viewportToTransform = ({ x, y, zoom: zoom2 }) => identity.translate(x, y).scale(zoom2), isWrappedWithClass = (event, className) => event.target.closest(`.${className}`), isRightClickPan = (panOnDrag, usedButton) => usedButton === 2 && Array.isArray(panOnDrag) && panOnDrag.includes(2), getD3Transition = (selection2, duration = 0, onEnd = () => {
3244
+ }) => {
3245
+ const hasDuration = typeof duration == "number" && duration > 0;
3246
+ return hasDuration || onEnd(), hasDuration ? selection2.transition().duration(duration).on("end", onEnd) : selection2;
3247
+ }, wheelDelta = (event) => {
3238
3248
  const factor = event.ctrlKey && isMacOs() ? 10 : 1;
3239
3249
  return -event.deltaY * (event.deltaMode === 1 ? 0.05 : event.deltaMode ? 1 : 2e-3) * factor;
3240
3250
  };
@@ -3317,7 +3327,7 @@ function createFilter({ zoomActivationKeyPressed, zoomOnScroll, zoomOnPinch, pan
3317
3327
  return (!event.ctrlKey || event.type === "wheel") && buttonAllowed;
3318
3328
  };
3319
3329
  }
3320
- function XYPanZoom({ domNode, minZoom, maxZoom, translateExtent, viewport, onPanZoom, onPanZoomStart, onPanZoomEnd, onTransformChange, onDraggingChange }) {
3330
+ function XYPanZoom({ domNode, minZoom, maxZoom, paneClickDistance, translateExtent, viewport, onPanZoom, onPanZoomStart, onPanZoomEnd, onTransformChange, onDraggingChange }) {
3321
3331
  const zoomPanValues = {
3322
3332
  isZoomingOrPanning: !1,
3323
3333
  usedRightMouseButton: !1,
@@ -3326,7 +3336,7 @@ function XYPanZoom({ domNode, minZoom, maxZoom, translateExtent, viewport, onPan
3326
3336
  timerId: void 0,
3327
3337
  panScrollTimeout: void 0,
3328
3338
  isPanScrolling: !1
3329
- }, bbox = domNode.getBoundingClientRect(), d3ZoomInstance = zoom().scaleExtent([minZoom, maxZoom]).translateExtent(translateExtent), d3Selection = select(domNode).call(d3ZoomInstance);
3339
+ }, bbox = domNode.getBoundingClientRect(), d3ZoomInstance = zoom().clickDistance(!isNumeric(paneClickDistance) || paneClickDistance < 0 ? 0 : paneClickDistance).scaleExtent([minZoom, maxZoom]).translateExtent(translateExtent), d3Selection = select(domNode).call(d3ZoomInstance);
3330
3340
  setViewportConstrained({
3331
3341
  x: viewport.x,
3332
3342
  y: viewport.y,
@@ -3338,7 +3348,9 @@ function XYPanZoom({ domNode, minZoom, maxZoom, translateExtent, viewport, onPan
3338
3348
  const d3ZoomHandler = d3Selection.on("wheel.zoom"), d3DblClickZoomHandler = d3Selection.on("dblclick.zoom");
3339
3349
  d3ZoomInstance.wheelDelta(wheelDelta);
3340
3350
  function setTransform(transform2, options) {
3341
- d3Selection && (d3ZoomInstance == null || d3ZoomInstance.transform(getD3Transition(d3Selection, options == null ? void 0 : options.duration), transform2));
3351
+ return d3Selection ? new Promise((resolve) => {
3352
+ d3ZoomInstance == null || d3ZoomInstance.transform(getD3Transition(d3Selection, options == null ? void 0 : options.duration, () => resolve(!0)), transform2);
3353
+ }) : Promise.resolve(!1);
3342
3354
  }
3343
3355
  function update({ noWheelClassName, noPanClassName, onPaneContextMenu, userSelectionActive, panOnScroll, panOnDrag, panOnScrollMode, panOnScrollSpeed, preventScrolling, zoomOnPinch, zoomOnScroll, zoomOnDoubleClick, zoomActivationKeyPressed, lib }) {
3344
3356
  userSelectionActive && !zoomPanValues.isZoomingOrPanning && destroy();
@@ -3400,13 +3412,13 @@ function XYPanZoom({ domNode, minZoom, maxZoom, translateExtent, viewport, onPan
3400
3412
  function destroy() {
3401
3413
  d3ZoomInstance.on("zoom", null);
3402
3414
  }
3403
- function setViewportConstrained(viewport2, extent, translateExtent2) {
3415
+ async function setViewportConstrained(viewport2, extent, translateExtent2) {
3404
3416
  const nextTransform = viewportToTransform(viewport2), contrainedTransform = d3ZoomInstance == null ? void 0 : d3ZoomInstance.constrain()(nextTransform, extent, translateExtent2);
3405
- return contrainedTransform && setTransform(contrainedTransform), contrainedTransform;
3417
+ return contrainedTransform && await setTransform(contrainedTransform), new Promise((resolve) => resolve(contrainedTransform));
3406
3418
  }
3407
- function setViewport(viewport2, options) {
3419
+ async function setViewport(viewport2, options) {
3408
3420
  const nextTransform = viewportToTransform(viewport2);
3409
- return setTransform(nextTransform, options), nextTransform;
3421
+ return await setTransform(nextTransform, options), new Promise((resolve) => resolve(nextTransform));
3410
3422
  }
3411
3423
  function syncViewport(viewport2) {
3412
3424
  if (d3Selection) {
@@ -3419,10 +3431,14 @@ function XYPanZoom({ domNode, minZoom, maxZoom, translateExtent, viewport, onPan
3419
3431
  return { x: transform$1.x, y: transform$1.y, zoom: transform$1.k };
3420
3432
  }
3421
3433
  function scaleTo(zoom2, options) {
3422
- d3Selection && (d3ZoomInstance == null || d3ZoomInstance.scaleTo(getD3Transition(d3Selection, options == null ? void 0 : options.duration), zoom2));
3434
+ return d3Selection ? new Promise((resolve) => {
3435
+ d3ZoomInstance == null || d3ZoomInstance.scaleTo(getD3Transition(d3Selection, options == null ? void 0 : options.duration, () => resolve(!0)), zoom2);
3436
+ }) : Promise.resolve(!1);
3423
3437
  }
3424
3438
  function scaleBy(factor, options) {
3425
- d3Selection && (d3ZoomInstance == null || d3ZoomInstance.scaleBy(getD3Transition(d3Selection, options == null ? void 0 : options.duration), factor));
3439
+ return d3Selection ? new Promise((resolve) => {
3440
+ d3ZoomInstance == null || d3ZoomInstance.scaleBy(getD3Transition(d3Selection, options == null ? void 0 : options.duration, () => resolve(!0)), factor);
3441
+ }) : Promise.resolve(!1);
3426
3442
  }
3427
3443
  function setScaleExtent(scaleExtent) {
3428
3444
  d3ZoomInstance == null || d3ZoomInstance.scaleExtent(scaleExtent);
@@ -3430,6 +3446,10 @@ function XYPanZoom({ domNode, minZoom, maxZoom, translateExtent, viewport, onPan
3430
3446
  function setTranslateExtent(translateExtent2) {
3431
3447
  d3ZoomInstance == null || d3ZoomInstance.translateExtent(translateExtent2);
3432
3448
  }
3449
+ function setClickDistance(distance2) {
3450
+ const validDistance = !isNumeric(distance2) || distance2 < 0 ? 0 : distance2;
3451
+ d3ZoomInstance == null || d3ZoomInstance.clickDistance(validDistance);
3452
+ }
3433
3453
  return {
3434
3454
  update,
3435
3455
  destroy,
@@ -3440,7 +3460,8 @@ function XYPanZoom({ domNode, minZoom, maxZoom, translateExtent, viewport, onPan
3440
3460
  scaleBy,
3441
3461
  setScaleExtent,
3442
3462
  setTranslateExtent,
3443
- syncViewport
3463
+ syncViewport,
3464
+ setClickDistance
3444
3465
  };
3445
3466
  }
3446
3467
  var ResizeControlVariant;
@@ -3545,14 +3566,13 @@ function XYResizer({ domNode, nodeId, getStoreItems, onChange, onEnd }) {
3545
3566
  const controlDirection = getControlDirection(controlPosition);
3546
3567
  let node, childNodes = [], parentNode, parentExtent, childExtent;
3547
3568
  const dragHandler = drag().on("start", (event) => {
3548
- var _a, _b;
3549
3569
  const { nodeLookup, transform: transform2, snapGrid, snapToGrid, nodeOrigin } = getStoreItems();
3550
3570
  if (node = nodeLookup.get(nodeId), !node)
3551
3571
  return;
3552
3572
  const { xSnapped, ySnapped } = getPointerPosition(event.sourceEvent, { transform: transform2, snapGrid, snapToGrid });
3553
3573
  prevValues = {
3554
- width: ((_a = node.measured) == null ? void 0 : _a.width) ?? 0,
3555
- height: ((_b = node.measured) == null ? void 0 : _b.height) ?? 0,
3574
+ width: node.measured.width ?? 0,
3575
+ height: node.measured.height ?? 0,
3556
3576
  x: node.position.x ?? 0,
3557
3577
  y: node.position.y ?? 0
3558
3578
  }, startValues = {
@@ -3560,7 +3580,7 @@ function XYResizer({ domNode, nodeId, getStoreItems, onChange, onEnd }) {
3560
3580
  pointerX: xSnapped,
3561
3581
  pointerY: ySnapped,
3562
3582
  aspectRatio: prevValues.width / prevValues.height
3563
- }, parentNode = void 0, (node.extent === "parent" || node.expandParent) && (parentNode = nodeLookup.get(node.parentId), parentNode && node.extent === "parent" && (parentExtent = nodeToParentExtent(parentNode))), childNodes = [], childExtent = void 0;
3583
+ }, parentNode = void 0, node.parentId && (node.extent === "parent" || node.expandParent) && (parentNode = nodeLookup.get(node.parentId), parentExtent = parentNode && node.extent === "parent" ? nodeToParentExtent(parentNode) : void 0), childNodes = [], childExtent = void 0;
3564
3584
  for (const [childId, child] of nodeLookup)
3565
3585
  if (child.parentId === nodeId && (childNodes.push({
3566
3586
  id: childId,
@@ -3581,7 +3601,7 @@ function XYResizer({ domNode, nodeId, getStoreItems, onChange, onEnd }) {
3581
3601
  const { x: prevX, y: prevY, width: prevWidth, height: prevHeight } = prevValues, change = {}, nodeOrigin = node.origin ?? storeNodeOrigin, { width, height, x, y } = getDimensionsAfterResize(startValues, controlDirection, pointerPosition, boundaries, keepAspectRatio, nodeOrigin, parentExtent, childExtent), isWidthChange = width !== prevWidth, isHeightChange = height !== prevHeight, isXPosChange = x !== prevX && isWidthChange, isYPosChange = y !== prevY && isHeightChange;
3582
3602
  if (!isXPosChange && !isYPosChange && !isWidthChange && !isHeightChange)
3583
3603
  return;
3584
- if ((isXPosChange || isYPosChange || nodeOrigin[0] === 1 || nodeOrigin[1] == 1) && (change.x = isXPosChange ? x : prevValues.x, change.y = isYPosChange ? y : prevValues.y, prevValues.x = change.x, prevValues.y = change.y, parentNode && node.expandParent && (change.x && change.x < 0 && (prevValues.x = 0, startValues.x = startValues.x - change.x), change.y && change.y < 0 && (prevValues.y = 0, startValues.y = startValues.y - change.y)), childNodes.length > 0)) {
3604
+ if ((isXPosChange || isYPosChange || nodeOrigin[0] === 1 || nodeOrigin[1] === 1) && (change.x = isXPosChange ? x : prevValues.x, change.y = isYPosChange ? y : prevValues.y, prevValues.x = change.x, prevValues.y = change.y, childNodes.length > 0)) {
3585
3605
  const xChange = x - prevX, yChange = y - prevY;
3586
3606
  for (const childNode of childNodes)
3587
3607
  childNode.position = {
@@ -3589,7 +3609,12 @@ function XYResizer({ domNode, nodeId, getStoreItems, onChange, onEnd }) {
3589
3609
  y: childNode.position.y - yChange + nodeOrigin[1] * (height - prevHeight)
3590
3610
  }, childChanges.push(childNode);
3591
3611
  }
3592
- (isWidthChange || isHeightChange) && (change.width = isWidthChange ? width : prevValues.width, change.height = isHeightChange ? height : prevValues.height, prevValues.width = change.width, prevValues.height = change.height);
3612
+ if ((isWidthChange || isHeightChange) && (change.width = isWidthChange ? width : prevValues.width, change.height = isHeightChange ? height : prevValues.height, prevValues.width = change.width, prevValues.height = change.height), parentNode && node.expandParent) {
3613
+ const xLimit = nodeOrigin[0] * (change.width ?? 0);
3614
+ change.x && change.x < xLimit && (prevValues.x = xLimit, startValues.x = startValues.x - (change.x - xLimit));
3615
+ const yLimit = nodeOrigin[1] * (change.height ?? 0);
3616
+ change.y && change.y < yLimit && (prevValues.y = yLimit, startValues.y = startValues.y - (change.y - yLimit));
3617
+ }
3593
3618
  const direction = getResizeDirection({
3594
3619
  width: prevValues.width,
3595
3620
  prevWidth,
@@ -3639,23 +3664,23 @@ const style = { display: "none" }, ariaLiveStyle = {
3639
3664
  overflow: "hidden",
3640
3665
  clip: "rect(0px, 0px, 0px, 0px)",
3641
3666
  clipPath: "inset(100%)"
3642
- }, ARIA_NODE_DESC_KEY = "react-flow__node-desc", ARIA_EDGE_DESC_KEY = "react-flow__edge-desc", ARIA_LIVE_MESSAGE = "react-flow__aria-live", selector$q = (s) => s.ariaLiveMessage;
3667
+ }, ARIA_NODE_DESC_KEY = "react-flow__node-desc", ARIA_EDGE_DESC_KEY = "react-flow__edge-desc", ARIA_LIVE_MESSAGE = "react-flow__aria-live", selector$p = (s) => s.ariaLiveMessage;
3643
3668
  function AriaLiveMessage({ rfId }) {
3644
- const ariaLiveMessage = useStore(selector$q);
3669
+ const ariaLiveMessage = useStore(selector$p);
3645
3670
  return jsx("div", { id: `${ARIA_LIVE_MESSAGE}-${rfId}`, "aria-live": "assertive", "aria-atomic": "true", style: ariaLiveStyle, children: ariaLiveMessage });
3646
3671
  }
3647
3672
  function A11yDescriptions({ rfId, disableKeyboardA11y }) {
3648
3673
  return jsxs(Fragment, { children: [jsxs("div", { id: `${ARIA_NODE_DESC_KEY}-${rfId}`, style, children: ["Press enter or space to select a node.", !disableKeyboardA11y && "You can then use the arrow keys to move the node around.", " Press delete to remove it and escape to cancel.", " "] }), jsx("div", { id: `${ARIA_EDGE_DESC_KEY}-${rfId}`, style, children: "Press enter or space to select an edge. You can then press delete to remove it or escape to cancel." }), !disableKeyboardA11y && jsx(AriaLiveMessage, { rfId })] });
3649
3674
  }
3650
- const selector$p = (s) => s.userSelectionActive ? "none" : "all";
3675
+ const selector$o = (s) => s.userSelectionActive ? "none" : "all";
3651
3676
  function Panel({ position = "top-left", children: children2, className, style: style2, ...rest }) {
3652
- const pointerEvents = useStore(selector$p), positionClasses = `${position}`.split("-");
3677
+ const pointerEvents = useStore(selector$o), positionClasses = `${position}`.split("-");
3653
3678
  return jsx("div", { className: cc(["react-flow__panel", className, ...positionClasses]), style: { ...style2, pointerEvents }, ...rest, children: children2 });
3654
3679
  }
3655
3680
  function Attribution({ proOptions, position = "bottom-right" }) {
3656
3681
  return proOptions != null && proOptions.hideAttribution ? null : jsx(Panel, { position, className: "react-flow__attribution", "data-message": "Please only hide this attribution when you are subscribed to React Flow Pro: https://pro.reactflow.dev", children: jsx("a", { href: "https://reactflow.dev", target: "_blank", rel: "noopener noreferrer", "aria-label": "React Flow attribution", children: "React Flow" }) });
3657
3682
  }
3658
- const selector$o = (s) => {
3683
+ const selector$n = (s) => {
3659
3684
  const selectedNodes = [], selectedEdges = [];
3660
3685
  for (const [, node] of s.nodeLookup)
3661
3686
  node.selected && selectedNodes.push(node.internals.userNode);
@@ -3667,7 +3692,7 @@ function areEqual(a, b) {
3667
3692
  return shallow(a.selectedNodes.map(selectId), b.selectedNodes.map(selectId)) && shallow(a.selectedEdges.map(selectId), b.selectedEdges.map(selectId));
3668
3693
  }
3669
3694
  function SelectionListenerInner({ onSelectionChange }) {
3670
- const store = useStoreApi(), { selectedNodes, selectedEdges } = useStore(selector$o, areEqual);
3695
+ const store = useStoreApi(), { selectedNodes, selectedEdges } = useStore(selector$n, areEqual);
3671
3696
  return useEffect(() => {
3672
3697
  const params = { nodes: selectedNodes, edges: selectedEdges };
3673
3698
  onSelectionChange == null || onSelectionChange(params), store.getState().onSelectionChangeHandlers.forEach((fn) => fn(params));
@@ -3731,8 +3756,10 @@ const defaultNodeOrigin = [0, 0], defaultViewport = { x: 0, y: 0, zoom: 1 }, rea
3731
3756
  "selectNodesOnDrag",
3732
3757
  "nodeDragThreshold",
3733
3758
  "onBeforeDelete",
3734
- "debug"
3735
- ], fieldsToTrack = [...reactFlowFieldsToTrack, "rfId"], selector$n = (s) => ({
3759
+ "debug",
3760
+ "autoPanSpeed",
3761
+ "paneClickDistance"
3762
+ ], fieldsToTrack = [...reactFlowFieldsToTrack, "rfId"], selector$m = (s) => ({
3736
3763
  setNodes: s.setNodes,
3737
3764
  setEdges: s.setEdges,
3738
3765
  setMinZoom: s.setMinZoom,
@@ -3740,7 +3767,8 @@ const defaultNodeOrigin = [0, 0], defaultViewport = { x: 0, y: 0, zoom: 1 }, rea
3740
3767
  setTranslateExtent: s.setTranslateExtent,
3741
3768
  setNodeExtent: s.setNodeExtent,
3742
3769
  reset: s.reset,
3743
- setDefaultNodesAndEdges: s.setDefaultNodesAndEdges
3770
+ setDefaultNodesAndEdges: s.setDefaultNodesAndEdges,
3771
+ setPaneClickDistance: s.setPaneClickDistance
3744
3772
  }), initPrevValues = {
3745
3773
  // these are values that are also passed directly to other components
3746
3774
  // than the StoreUpdater. We can reduce the number of setStore calls
@@ -3751,10 +3779,11 @@ const defaultNodeOrigin = [0, 0], defaultViewport = { x: 0, y: 0, zoom: 1 }, rea
3751
3779
  maxZoom: 2,
3752
3780
  elementsSelectable: !0,
3753
3781
  noPanClassName: "nopan",
3754
- rfId: "1"
3782
+ rfId: "1",
3783
+ paneClickDistance: 0
3755
3784
  };
3756
3785
  function StoreUpdater(props) {
3757
- const { setNodes, setEdges, setMinZoom, setMaxZoom, setTranslateExtent, setNodeExtent, reset, setDefaultNodesAndEdges } = useStore(selector$n, shallow), store = useStoreApi();
3786
+ const { setNodes, setEdges, setMinZoom, setMaxZoom, setTranslateExtent, setNodeExtent, reset, setDefaultNodesAndEdges, setPaneClickDistance } = useStore(selector$m, shallow), store = useStoreApi();
3758
3787
  useEffect(() => (setDefaultNodesAndEdges(props.defaultNodes, props.defaultEdges), () => {
3759
3788
  previousFields.current = initPrevValues, reset();
3760
3789
  }), []);
@@ -3763,7 +3792,7 @@ function StoreUpdater(props) {
3763
3792
  () => {
3764
3793
  for (const fieldName of fieldsToTrack) {
3765
3794
  const fieldValue = props[fieldName], previousFieldValue = previousFields.current[fieldName];
3766
- fieldValue !== previousFieldValue && (typeof props[fieldName] > "u" || (fieldName === "nodes" ? setNodes(fieldValue) : fieldName === "edges" ? setEdges(fieldValue) : fieldName === "minZoom" ? setMinZoom(fieldValue) : fieldName === "maxZoom" ? setMaxZoom(fieldValue) : fieldName === "translateExtent" ? setTranslateExtent(fieldValue) : fieldName === "nodeExtent" ? setNodeExtent(fieldValue) : fieldName === "fitView" ? store.setState({ fitViewOnInit: fieldValue }) : fieldName === "fitViewOptions" ? store.setState({ fitViewOnInitOptions: fieldValue }) : store.setState({ [fieldName]: fieldValue })));
3795
+ fieldValue !== previousFieldValue && (typeof props[fieldName] > "u" || (fieldName === "nodes" ? setNodes(fieldValue) : fieldName === "edges" ? setEdges(fieldValue) : fieldName === "minZoom" ? setMinZoom(fieldValue) : fieldName === "maxZoom" ? setMaxZoom(fieldValue) : fieldName === "translateExtent" ? setTranslateExtent(fieldValue) : fieldName === "nodeExtent" ? setNodeExtent(fieldValue) : fieldName === "paneClickDistance" ? setPaneClickDistance(fieldValue) : fieldName === "fitView" ? store.setState({ fitViewOnInit: fieldValue }) : fieldName === "fitViewOptions" ? store.setState({ fitViewOnInitOptions: fieldValue }) : store.setState({ [fieldName]: fieldValue })));
3767
3796
  }
3768
3797
  previousFields.current = props;
3769
3798
  },
@@ -3829,53 +3858,52 @@ const useViewportHelper = () => {
3829
3858
  const store = useStoreApi();
3830
3859
  return useMemo(() => ({
3831
3860
  zoomIn: (options) => {
3832
- var _a;
3833
- return (_a = store.getState().panZoom) == null ? void 0 : _a.scaleBy(1.2, { duration: options == null ? void 0 : options.duration });
3861
+ const { panZoom } = store.getState();
3862
+ return panZoom ? panZoom.scaleBy(1.2, { duration: options == null ? void 0 : options.duration }) : Promise.resolve(!1);
3834
3863
  },
3835
3864
  zoomOut: (options) => {
3836
- var _a;
3837
- return (_a = store.getState().panZoom) == null ? void 0 : _a.scaleBy(1 / 1.2, { duration: options == null ? void 0 : options.duration });
3865
+ const { panZoom } = store.getState();
3866
+ return panZoom ? panZoom.scaleBy(1 / 1.2, { duration: options == null ? void 0 : options.duration }) : Promise.resolve(!1);
3838
3867
  },
3839
3868
  zoomTo: (zoomLevel, options) => {
3840
- var _a;
3841
- return (_a = store.getState().panZoom) == null ? void 0 : _a.scaleTo(zoomLevel, { duration: options == null ? void 0 : options.duration });
3869
+ const { panZoom } = store.getState();
3870
+ return panZoom ? panZoom.scaleTo(zoomLevel, { duration: options == null ? void 0 : options.duration }) : Promise.resolve(!1);
3842
3871
  },
3843
3872
  getZoom: () => store.getState().transform[2],
3844
- setViewport: (viewport, options) => {
3873
+ setViewport: async (viewport, options) => {
3845
3874
  const { transform: [tX, tY, tZoom], panZoom } = store.getState();
3846
- panZoom == null || panZoom.setViewport({
3875
+ return panZoom ? (await panZoom.setViewport({
3847
3876
  x: viewport.x ?? tX,
3848
3877
  y: viewport.y ?? tY,
3849
3878
  zoom: viewport.zoom ?? tZoom
3850
- }, { duration: options == null ? void 0 : options.duration });
3879
+ }, { duration: options == null ? void 0 : options.duration }), Promise.resolve(!0)) : Promise.resolve(!1);
3851
3880
  },
3852
3881
  getViewport: () => {
3853
3882
  const [x, y, zoom2] = store.getState().transform;
3854
3883
  return { x, y, zoom: zoom2 };
3855
3884
  },
3856
3885
  fitView: (options) => {
3857
- const { nodeLookup, width, height, nodeOrigin, minZoom, maxZoom, panZoom } = store.getState();
3886
+ const { nodeLookup, width, height, minZoom, maxZoom, panZoom } = store.getState(), fitViewNodes = getFitViewNodes(nodeLookup, options);
3858
3887
  return panZoom ? fitView({
3859
- nodeLookup,
3888
+ nodes: fitViewNodes,
3860
3889
  width,
3861
3890
  height,
3862
- nodeOrigin,
3863
3891
  minZoom,
3864
3892
  maxZoom,
3865
3893
  panZoom
3866
- }, options) : !1;
3894
+ }, options) : Promise.resolve(!1);
3867
3895
  },
3868
- setCenter: (x, y, options) => {
3896
+ setCenter: async (x, y, options) => {
3869
3897
  const { width, height, maxZoom, panZoom } = store.getState(), nextZoom = typeof (options == null ? void 0 : options.zoom) < "u" ? options.zoom : maxZoom, centerX = width / 2 - x * nextZoom, centerY = height / 2 - y * nextZoom;
3870
- panZoom == null || panZoom.setViewport({
3898
+ return panZoom ? (await panZoom.setViewport({
3871
3899
  x: centerX,
3872
3900
  y: centerY,
3873
3901
  zoom: nextZoom
3874
- }, { duration: options == null ? void 0 : options.duration });
3902
+ }, { duration: options == null ? void 0 : options.duration }), Promise.resolve(!0)) : Promise.resolve(!1);
3875
3903
  },
3876
- fitBounds: (bounds, options) => {
3904
+ fitBounds: async (bounds, options) => {
3877
3905
  const { width, height, minZoom, maxZoom, panZoom } = store.getState(), viewport = getViewportForBounds(bounds, width, height, minZoom, maxZoom, (options == null ? void 0 : options.padding) ?? 0.1);
3878
- panZoom == null || panZoom.setViewport(viewport, { duration: options == null ? void 0 : options.duration });
3906
+ return panZoom ? (await panZoom.setViewport(viewport, { duration: options == null ? void 0 : options.duration }), Promise.resolve(!0)) : Promise.resolve(!1);
3879
3907
  },
3880
3908
  screenToFlowPosition: (clientPosition, options = { snapToGrid: !0 }) => {
3881
3909
  const { transform: transform2, snapGrid, domNode } = store.getState();
@@ -4041,16 +4069,16 @@ function useBatchContext() {
4041
4069
  throw new Error("useBatchContext must be used within a BatchProvider");
4042
4070
  return batchContext;
4043
4071
  }
4044
- const selector$m = (s) => !!s.panZoom;
4072
+ const selector$l = (s) => !!s.panZoom;
4045
4073
  function useReactFlow() {
4046
- const viewportHelper = useViewportHelper(), store = useStoreApi(), batchContext = useBatchContext(), viewportInitialized = useStore(selector$m), generalHelper = useMemo(() => {
4074
+ const viewportHelper = useViewportHelper(), store = useStoreApi(), batchContext = useBatchContext(), viewportInitialized = useStore(selector$l), generalHelper = useMemo(() => {
4047
4075
  const getInternalNode = (id2) => store.getState().nodeLookup.get(id2), setNodes = (payload) => {
4048
4076
  batchContext.nodeQueue.push(payload);
4049
4077
  }, setEdges = (payload) => {
4050
4078
  batchContext.edgeQueue.push(payload);
4051
4079
  }, getNodeRect = (node) => {
4052
4080
  var _a, _b;
4053
- const { nodeLookup, nodeOrigin } = store.getState(), nodeToUse = isNode(node) ? node : nodeLookup.get(node.id), position = nodeToUse.parentId ? evaluateAbsolutePosition(nodeToUse.position, nodeToUse.parentId, nodeLookup, nodeOrigin) : nodeToUse.position, nodeWithPosition = {
4081
+ const { nodeLookup, nodeOrigin } = store.getState(), nodeToUse = isNode(node) ? node : nodeLookup.get(node.id), position = nodeToUse.parentId ? evaluateAbsolutePosition(nodeToUse.position, nodeToUse.measured, nodeToUse.parentId, nodeLookup, nodeOrigin) : nodeToUse.position, nodeWithPosition = {
4054
4082
  id: nodeToUse.id,
4055
4083
  position,
4056
4084
  width: ((_a = nodeToUse.measured) == null ? void 0 : _a.width) ?? nodeToUse.width,
@@ -4203,12 +4231,12 @@ const containerStyle = {
4203
4231
  height: "100%",
4204
4232
  top: 0,
4205
4233
  left: 0
4206
- }, selector$l = (s) => ({
4234
+ }, selector$k = (s) => ({
4207
4235
  userSelectionActive: s.userSelectionActive,
4208
4236
  lib: s.lib
4209
4237
  });
4210
- function ZoomPane({ onPaneContextMenu, zoomOnScroll = !0, zoomOnPinch = !0, panOnScroll = !1, panOnScrollSpeed = 0.5, panOnScrollMode = PanOnScrollMode.Free, zoomOnDoubleClick = !0, panOnDrag = !0, defaultViewport: defaultViewport2, translateExtent, minZoom, maxZoom, zoomActivationKeyCode, preventScrolling = !0, children: children2, noWheelClassName, noPanClassName, onViewportChange, isControlledViewport }) {
4211
- const store = useStoreApi(), zoomPane = useRef(null), { userSelectionActive, lib } = useStore(selector$l, shallow), zoomActivationKeyPressed = useKeyPress(zoomActivationKeyCode), panZoom = useRef();
4238
+ function ZoomPane({ onPaneContextMenu, zoomOnScroll = !0, zoomOnPinch = !0, panOnScroll = !1, panOnScrollSpeed = 0.5, panOnScrollMode = PanOnScrollMode.Free, zoomOnDoubleClick = !0, panOnDrag = !0, defaultViewport: defaultViewport2, translateExtent, minZoom, maxZoom, zoomActivationKeyCode, preventScrolling = !0, children: children2, noWheelClassName, noPanClassName, onViewportChange, isControlledViewport, paneClickDistance }) {
4239
+ const store = useStoreApi(), zoomPane = useRef(null), { userSelectionActive, lib } = useStore(selector$k, shallow), zoomActivationKeyPressed = useKeyPress(zoomActivationKeyCode), panZoom = useRef();
4212
4240
  return useResizeHandler(zoomPane), useEffect(() => {
4213
4241
  if (zoomPane.current) {
4214
4242
  panZoom.current = XYPanZoom({
@@ -4217,6 +4245,7 @@ function ZoomPane({ onPaneContextMenu, zoomOnScroll = !0, zoomOnPinch = !0, panO
4217
4245
  maxZoom,
4218
4246
  translateExtent,
4219
4247
  viewport: defaultViewport2,
4248
+ paneClickDistance,
4220
4249
  onTransformChange: (transform2) => {
4221
4250
  onViewportChange == null || onViewportChange({ x: transform2[0], y: transform2[1], zoom: transform2[2] }), isControlledViewport || store.setState({ transform: transform2 });
4222
4251
  },
@@ -4279,12 +4308,12 @@ function ZoomPane({ onPaneContextMenu, zoomOnScroll = !0, zoomOnPinch = !0, panO
4279
4308
  lib
4280
4309
  ]), jsx("div", { className: "react-flow__renderer", ref: zoomPane, style: containerStyle, children: children2 });
4281
4310
  }
4282
- const selector$k = (s) => ({
4311
+ const selector$j = (s) => ({
4283
4312
  userSelectionActive: s.userSelectionActive,
4284
4313
  userSelectionRect: s.userSelectionRect
4285
4314
  });
4286
4315
  function UserSelection() {
4287
- const { userSelectionActive, userSelectionRect } = useStore(selector$k, shallow);
4316
+ const { userSelectionActive, userSelectionRect } = useStore(selector$j, shallow);
4288
4317
  return userSelectionActive && userSelectionRect ? jsx("div", { className: "react-flow__selection react-flow__container", style: {
4289
4318
  width: userSelectionRect.width,
4290
4319
  height: userSelectionRect.height,
@@ -4293,13 +4322,13 @@ function UserSelection() {
4293
4322
  }
4294
4323
  const wrapHandler = (handler, containerRef) => (event) => {
4295
4324
  event.target === containerRef.current && (handler == null || handler(event));
4296
- }, selector$j = (s) => ({
4325
+ }, selector$i = (s) => ({
4297
4326
  userSelectionActive: s.userSelectionActive,
4298
4327
  elementsSelectable: s.elementsSelectable,
4299
4328
  dragging: s.paneDragging
4300
4329
  });
4301
4330
  function Pane({ isSelecting, selectionKeyPressed, selectionMode = SelectionMode.Full, panOnDrag, onSelectionStart, onSelectionEnd, onPaneClick, onPaneContextMenu, onPaneScroll, onPaneMouseEnter, onPaneMouseMove, onPaneMouseLeave, children: children2 }) {
4302
- const container2 = useRef(null), store = useStoreApi(), prevSelectedNodesCount = useRef(0), prevSelectedEdgesCount = useRef(0), containerBounds = useRef(), edgeIdLookup = useRef(/* @__PURE__ */ new Map()), { userSelectionActive, elementsSelectable, dragging } = useStore(selector$j, shallow), hasActiveSelection = elementsSelectable && (isSelecting || userSelectionActive), selectionInProgress = useRef(!1), resetUserSelection = () => {
4331
+ const container2 = useRef(null), store = useStoreApi(), prevSelectedNodesCount = useRef(0), prevSelectedEdgesCount = useRef(0), containerBounds = useRef(), edgeIdLookup = useRef(/* @__PURE__ */ new Map()), { userSelectionActive, elementsSelectable, dragging } = useStore(selector$i, shallow), hasActiveSelection = elementsSelectable && (isSelecting || userSelectionActive), selectionInProgress = useRef(!1), resetUserSelection = () => {
4303
4332
  store.setState({ userSelectionActive: !1, userSelectionRect: null }), prevSelectedNodesCount.current = 0, prevSelectedEdgesCount.current = 0;
4304
4333
  }, onClick = (event) => {
4305
4334
  if (selectionInProgress.current) {
@@ -4314,13 +4343,13 @@ function Pane({ isSelecting, selectionKeyPressed, selectionMode = SelectionMode.
4314
4343
  }
4315
4344
  onPaneContextMenu == null || onPaneContextMenu(event);
4316
4345
  }, onWheel = onPaneScroll ? (event) => onPaneScroll(event) : void 0, onPointerDown2 = (event) => {
4317
- var _a, _b, _c;
4346
+ var _a, _b, _c, _d;
4318
4347
  const { resetSelectedElements, domNode, edgeLookup } = store.getState();
4319
- if (containerBounds.current = domNode == null ? void 0 : domNode.getBoundingClientRect(), (_a = container2.current) == null || _a.setPointerCapture(event.pointerId), !elementsSelectable || !isSelecting || event.button !== 0 || event.target !== container2.current || !containerBounds.current)
4348
+ if (containerBounds.current = domNode == null ? void 0 : domNode.getBoundingClientRect(), (_b = (_a = event.target) == null ? void 0 : _a.setPointerCapture) == null || _b.call(_a, event.pointerId), !elementsSelectable || !isSelecting || event.button !== 0 || event.target !== container2.current || !containerBounds.current)
4320
4349
  return;
4321
4350
  edgeIdLookup.current = /* @__PURE__ */ new Map();
4322
4351
  for (const [id2, edge] of edgeLookup)
4323
- edgeIdLookup.current.set(edge.source, ((_b = edgeIdLookup.current.get(edge.source)) == null ? void 0 : _b.add(id2)) || /* @__PURE__ */ new Set([id2])), edgeIdLookup.current.set(edge.target, ((_c = edgeIdLookup.current.get(edge.target)) == null ? void 0 : _c.add(id2)) || /* @__PURE__ */ new Set([id2]));
4352
+ edgeIdLookup.current.set(edge.source, ((_c = edgeIdLookup.current.get(edge.source)) == null ? void 0 : _c.add(id2)) || /* @__PURE__ */ new Set([id2])), edgeIdLookup.current.set(edge.target, ((_d = edgeIdLookup.current.get(edge.target)) == null ? void 0 : _d.add(id2)) || /* @__PURE__ */ new Set([id2]));
4324
4353
  const { x, y } = getEventPosition(event.nativeEvent, containerBounds.current);
4325
4354
  resetSelectedElements(), store.setState({
4326
4355
  userSelectionRect: {
@@ -4333,7 +4362,7 @@ function Pane({ isSelecting, selectionKeyPressed, selectionMode = SelectionMode.
4333
4362
  }
4334
4363
  }), onSelectionStart == null || onSelectionStart(event);
4335
4364
  }, onPointerMove = (event) => {
4336
- const { userSelectionRect, edgeLookup, transform: transform2, nodeOrigin, nodeLookup, triggerNodeChanges, triggerEdgeChanges } = store.getState();
4365
+ const { userSelectionRect, edgeLookup, transform: transform2, nodeLookup, triggerNodeChanges, triggerEdgeChanges } = store.getState();
4337
4366
  if (!containerBounds.current || !userSelectionRect)
4338
4367
  return;
4339
4368
  selectionInProgress.current = !0;
@@ -4344,7 +4373,7 @@ function Pane({ isSelecting, selectionKeyPressed, selectionMode = SelectionMode.
4344
4373
  y: mouseY < startY ? mouseY : startY,
4345
4374
  width: Math.abs(mouseX - startX),
4346
4375
  height: Math.abs(mouseY - startY)
4347
- }, selectedNodes = getNodesInside(nodeLookup, nextUserSelectRect, transform2, selectionMode === SelectionMode.Partial, !0, nodeOrigin), selectedEdgeIds = /* @__PURE__ */ new Set(), selectedNodeIds = /* @__PURE__ */ new Set();
4376
+ }, selectedNodes = getNodesInside(nodeLookup, nextUserSelectRect, transform2, selectionMode === SelectionMode.Partial, !0), selectedEdgeIds = /* @__PURE__ */ new Set(), selectedNodeIds = /* @__PURE__ */ new Set();
4348
4377
  for (const selectedNode of selectedNodes) {
4349
4378
  selectedNodeIds.add(selectedNode.id);
4350
4379
  const edgeIds = edgeIdLookup.current.get(selectedNode.id);
@@ -4368,12 +4397,12 @@ function Pane({ isSelecting, selectionKeyPressed, selectionMode = SelectionMode.
4368
4397
  nodesSelectionActive: !1
4369
4398
  });
4370
4399
  }, onPointerUp = (event) => {
4371
- var _a;
4400
+ var _a, _b;
4372
4401
  if (event.button !== 0)
4373
4402
  return;
4374
- (_a = container2.current) == null || _a.releasePointerCapture(event.pointerId);
4403
+ (_b = (_a = event.target) == null ? void 0 : _a.releasePointerCapture) == null || _b.call(_a, event.pointerId);
4375
4404
  const { userSelectionRect } = store.getState();
4376
- !userSelectionActive && userSelectionRect && event.target === container2.current && (onClick == null || onClick(event)), store.setState({ nodesSelectionActive: prevSelectedNodesCount.current > 0 }), resetUserSelection(), onSelectionEnd == null || onSelectionEnd(event), selectionKeyPressed && (selectionInProgress.current = !1);
4405
+ !userSelectionActive && userSelectionRect && event.target === container2.current && (onClick == null || onClick(event)), prevSelectedNodesCount.current > 0 && store.setState({ nodesSelectionActive: !0 }), resetUserSelection(), onSelectionEnd == null || onSelectionEnd(event), selectionKeyPressed && (selectionInProgress.current = !1);
4377
4406
  };
4378
4407
  return jsxs("div", { className: cc(["react-flow__pane", { draggable: panOnDrag, dragging, selection: isSelecting }]), onClick: hasActiveSelection ? void 0 : wrapHandler(onClick, container2), onContextMenu: wrapHandler(onContextMenu, container2), onWheel: wrapHandler(onWheel, container2), onPointerEnter: hasActiveSelection ? void 0 : onPaneMouseEnter, onPointerDown: hasActiveSelection ? onPointerDown2 : onPaneMouseMove, onPointerMove: hasActiveSelection ? onPointerMove : onPaneMouseMove, onPointerUp: hasActiveSelection ? onPointerUp : void 0, onPointerLeave: onPaneMouseLeave, ref: container2, style: containerStyle, children: [children2, jsx(UserSelection, {})] });
4379
4408
  }
@@ -4452,24 +4481,24 @@ function useMoveSelectedNodes() {
4452
4481
  }
4453
4482
  const NodeIdContext = createContext(null), Provider = NodeIdContext.Provider;
4454
4483
  NodeIdContext.Consumer;
4455
- const useNodeId = () => useContext(NodeIdContext), selector$i = (s) => ({
4484
+ const useNodeId = () => useContext(NodeIdContext), selector$h = (s) => ({
4456
4485
  connectOnClick: s.connectOnClick,
4457
4486
  noPanClassName: s.noPanClassName,
4458
4487
  rfId: s.rfId
4459
4488
  }), connectingSelector = (nodeId, handleId, type) => (state) => {
4460
- const { connectionStartHandle: startHandle, connectionEndHandle: endHandle, connectionClickStartHandle: clickHandle, connectionMode, connectionStatus } = state, connectingTo = (endHandle == null ? void 0 : endHandle.nodeId) === nodeId && (endHandle == null ? void 0 : endHandle.handleId) === handleId && (endHandle == null ? void 0 : endHandle.type) === type;
4489
+ const { connectionClickStartHandle: clickHandle, connectionMode, connection } = state, { fromHandle, toHandle, isValid } = connection, connectingTo = (toHandle == null ? void 0 : toHandle.nodeId) === nodeId && (toHandle == null ? void 0 : toHandle.id) === handleId && (toHandle == null ? void 0 : toHandle.type) === type;
4461
4490
  return {
4462
- connectingFrom: (startHandle == null ? void 0 : startHandle.nodeId) === nodeId && (startHandle == null ? void 0 : startHandle.handleId) === handleId && (startHandle == null ? void 0 : startHandle.type) === type,
4491
+ connectingFrom: (fromHandle == null ? void 0 : fromHandle.nodeId) === nodeId && (fromHandle == null ? void 0 : fromHandle.id) === handleId && (fromHandle == null ? void 0 : fromHandle.type) === type,
4463
4492
  connectingTo,
4464
- clickConnecting: (clickHandle == null ? void 0 : clickHandle.nodeId) === nodeId && (clickHandle == null ? void 0 : clickHandle.handleId) === handleId && (clickHandle == null ? void 0 : clickHandle.type) === type,
4465
- isPossibleEndHandle: connectionMode === ConnectionMode.Strict ? (startHandle == null ? void 0 : startHandle.type) !== type : nodeId !== (startHandle == null ? void 0 : startHandle.nodeId) || handleId !== (startHandle == null ? void 0 : startHandle.handleId),
4466
- connectionInProcess: !!startHandle,
4467
- valid: connectingTo && connectionStatus === "valid"
4493
+ clickConnecting: (clickHandle == null ? void 0 : clickHandle.nodeId) === nodeId && (clickHandle == null ? void 0 : clickHandle.id) === handleId && (clickHandle == null ? void 0 : clickHandle.type) === type,
4494
+ isPossibleEndHandle: connectionMode === ConnectionMode.Strict ? (fromHandle == null ? void 0 : fromHandle.type) !== type : nodeId !== (fromHandle == null ? void 0 : fromHandle.nodeId) || handleId !== (fromHandle == null ? void 0 : fromHandle.id),
4495
+ connectionInProcess: !!fromHandle,
4496
+ valid: connectingTo && isValid
4468
4497
  };
4469
4498
  };
4470
4499
  function HandleComponent({ type = "source", position = Position.Top, isValidConnection, isConnectable = !0, isConnectableStart = !0, isConnectableEnd = !0, id: id2, onConnect, children: children2, className, onMouseDown, onTouchStart, ...rest }, ref) {
4471
4500
  var _a, _b;
4472
- const handleId = id2 || null, isTarget = type === "target", store = useStoreApi(), nodeId = useNodeId(), { connectOnClick, noPanClassName, rfId } = useStore(selector$i, shallow), { connectingFrom, connectingTo, clickConnecting, isPossibleEndHandle, connectionInProcess, valid } = useStore(connectingSelector(nodeId, handleId, type), shallow);
4501
+ const handleId = id2 || null, isTarget = type === "target", store = useStoreApi(), nodeId = useNodeId(), { connectOnClick, noPanClassName, rfId } = useStore(selector$h, shallow), { connectingFrom, connectingTo, clickConnecting, isPossibleEndHandle, connectionInProcess, valid } = useStore(connectingSelector(nodeId, handleId, type), shallow);
4473
4502
  nodeId || (_b = (_a = store.getState()).onError) == null || _b.call(_a, "010", errorMessages.error010());
4474
4503
  const onConnectExtended = (params) => {
4475
4504
  const { defaultEdgeOptions, onConnect: onConnectAction, hasDefaultEdges } = store.getState(), edgeParams = {
@@ -4506,7 +4535,8 @@ function HandleComponent({ type = "source", position = Position.Top, isValidConn
4506
4535
  onConnect: onConnectExtended,
4507
4536
  isValidConnection: isValidConnection || currentStore.isValidConnection,
4508
4537
  getTransform: () => store.getState().transform,
4509
- getConnectionStartHandle: () => store.getState().connectionStartHandle
4538
+ getFromHandle: () => store.getState().connection.fromHandle,
4539
+ autoPanSpeed: currentStore.autoPanSpeed
4510
4540
  });
4511
4541
  }
4512
4542
  isMouseTriggered ? onMouseDown == null || onMouseDown(event) : onTouchStart == null || onTouchStart(event);
@@ -4515,7 +4545,7 @@ function HandleComponent({ type = "source", position = Position.Top, isValidConn
4515
4545
  if (!nodeId || !connectionClickStartHandle && !isConnectableStart)
4516
4546
  return;
4517
4547
  if (!connectionClickStartHandle) {
4518
- onClickConnectStart == null || onClickConnectStart(event.nativeEvent, { nodeId, handleId, handleType: type }), store.setState({ connectionClickStartHandle: { nodeId, type, handleId } });
4548
+ onClickConnectStart == null || onClickConnectStart(event.nativeEvent, { nodeId, handleId, handleType: type }), store.setState({ connectionClickStartHandle: { nodeId, type, id: handleId } });
4519
4549
  return;
4520
4550
  }
4521
4551
  const doc = getHostForElement(event.target), isValidConnectionHandler = isValidConnection || isValidConnectionStore, { connection, isValid } = XYHandle.isValid(event.nativeEvent, {
@@ -4526,7 +4556,7 @@ function HandleComponent({ type = "source", position = Position.Top, isValidConn
4526
4556
  },
4527
4557
  connectionMode,
4528
4558
  fromNodeId: connectionClickStartHandle.nodeId,
4529
- fromHandleId: connectionClickStartHandle.handleId || null,
4559
+ fromHandleId: connectionClickStartHandle.id || null,
4530
4560
  fromType: connectionClickStartHandle.type,
4531
4561
  isValidConnection: isValidConnectionHandler,
4532
4562
  flowId,
@@ -4591,9 +4621,8 @@ function getNodeInlineStyleDimensions(node) {
4591
4621
  height: node.height ?? ((_d = node.style) == null ? void 0 : _d.height)
4592
4622
  };
4593
4623
  }
4594
- const selector$h = (s) => {
4624
+ const selector$g = (s) => {
4595
4625
  const { width, height, x, y } = getInternalNodesBounds(s.nodeLookup, {
4596
- nodeOrigin: s.nodeOrigin,
4597
4626
  filter: (node) => !!node.selected
4598
4627
  });
4599
4628
  return {
@@ -4604,7 +4633,7 @@ const selector$h = (s) => {
4604
4633
  };
4605
4634
  };
4606
4635
  function NodesSelection({ onSelectionContextMenu, noPanClassName, disableKeyboardA11y }) {
4607
- const store = useStoreApi(), { width, height, transformString, userSelectionActive } = useStore(selector$h, shallow), moveSelectedNodes = useMoveSelectedNodes(), nodeRef = useRef(null);
4636
+ const store = useStoreApi(), { width, height, transformString, userSelectionActive } = useStore(selector$g, shallow), moveSelectedNodes = useMoveSelectedNodes(), nodeRef = useRef(null);
4608
4637
  if (useEffect(() => {
4609
4638
  var _a;
4610
4639
  disableKeyboardA11y || (_a = nodeRef.current) == null || _a.focus({
@@ -4630,19 +4659,19 @@ function NodesSelection({ onSelectionContextMenu, noPanClassName, disableKeyboar
4630
4659
  height
4631
4660
  } }) });
4632
4661
  }
4633
- const win = typeof window < "u" ? window : void 0, selector$g = (s) => ({ nodesSelectionActive: s.nodesSelectionActive, userSelectionActive: s.userSelectionActive });
4634
- function FlowRendererComponent({ children: children2, onPaneClick, onPaneMouseEnter, onPaneMouseMove, onPaneMouseLeave, onPaneContextMenu, onPaneScroll, deleteKeyCode, selectionKeyCode, selectionOnDrag, selectionMode, onSelectionStart, onSelectionEnd, multiSelectionKeyCode, panActivationKeyCode, zoomActivationKeyCode, elementsSelectable, zoomOnScroll, zoomOnPinch, panOnScroll: _panOnScroll, panOnScrollSpeed, panOnScrollMode, zoomOnDoubleClick, panOnDrag: _panOnDrag, defaultViewport: defaultViewport2, translateExtent, minZoom, maxZoom, preventScrolling, onSelectionContextMenu, noWheelClassName, noPanClassName, disableKeyboardA11y, onViewportChange, isControlledViewport }) {
4635
- const { nodesSelectionActive, userSelectionActive } = useStore(selector$g), selectionKeyPressed = useKeyPress(selectionKeyCode, { target: win }), panActivationKeyPressed = useKeyPress(panActivationKeyCode, { target: win }), panOnDrag = panActivationKeyPressed || _panOnDrag, panOnScroll = panActivationKeyPressed || _panOnScroll, isSelecting = selectionKeyPressed || userSelectionActive || selectionOnDrag && panOnDrag !== !0;
4636
- return useGlobalKeyHandler({ deleteKeyCode, multiSelectionKeyCode }), jsx(ZoomPane, { onPaneContextMenu, elementsSelectable, zoomOnScroll, zoomOnPinch, panOnScroll, panOnScrollSpeed, panOnScrollMode, zoomOnDoubleClick, panOnDrag: !selectionKeyPressed && panOnDrag, defaultViewport: defaultViewport2, translateExtent, minZoom, maxZoom, zoomActivationKeyCode, preventScrolling, noWheelClassName, noPanClassName, onViewportChange, isControlledViewport, children: jsxs(Pane, { onSelectionStart, onSelectionEnd, onPaneClick, onPaneMouseEnter, onPaneMouseMove, onPaneMouseLeave, onPaneContextMenu, onPaneScroll, panOnDrag, isSelecting: !!isSelecting, selectionMode, selectionKeyPressed, children: [children2, nodesSelectionActive && jsx(NodesSelection, { onSelectionContextMenu, noPanClassName, disableKeyboardA11y })] }) });
4662
+ const win = typeof window < "u" ? window : void 0, selector$f = (s) => ({ nodesSelectionActive: s.nodesSelectionActive, userSelectionActive: s.userSelectionActive });
4663
+ function FlowRendererComponent({ children: children2, onPaneClick, onPaneMouseEnter, onPaneMouseMove, onPaneMouseLeave, onPaneContextMenu, onPaneScroll, paneClickDistance, deleteKeyCode, selectionKeyCode, selectionOnDrag, selectionMode, onSelectionStart, onSelectionEnd, multiSelectionKeyCode, panActivationKeyCode, zoomActivationKeyCode, elementsSelectable, zoomOnScroll, zoomOnPinch, panOnScroll: _panOnScroll, panOnScrollSpeed, panOnScrollMode, zoomOnDoubleClick, panOnDrag: _panOnDrag, defaultViewport: defaultViewport2, translateExtent, minZoom, maxZoom, preventScrolling, onSelectionContextMenu, noWheelClassName, noPanClassName, disableKeyboardA11y, onViewportChange, isControlledViewport }) {
4664
+ const { nodesSelectionActive, userSelectionActive } = useStore(selector$f), selectionKeyPressed = useKeyPress(selectionKeyCode, { target: win }), panActivationKeyPressed = useKeyPress(panActivationKeyCode, { target: win }), panOnDrag = panActivationKeyPressed || _panOnDrag, panOnScroll = panActivationKeyPressed || _panOnScroll, isSelecting = selectionKeyPressed || userSelectionActive || selectionOnDrag && panOnDrag !== !0;
4665
+ return useGlobalKeyHandler({ deleteKeyCode, multiSelectionKeyCode }), jsx(ZoomPane, { onPaneContextMenu, elementsSelectable, zoomOnScroll, zoomOnPinch, panOnScroll, panOnScrollSpeed, panOnScrollMode, zoomOnDoubleClick, panOnDrag: !selectionKeyPressed && panOnDrag, defaultViewport: defaultViewport2, translateExtent, minZoom, maxZoom, zoomActivationKeyCode, preventScrolling, noWheelClassName, noPanClassName, onViewportChange, isControlledViewport, paneClickDistance, children: jsxs(Pane, { onSelectionStart, onSelectionEnd, onPaneClick, onPaneMouseEnter, onPaneMouseMove, onPaneMouseLeave, onPaneContextMenu, onPaneScroll, panOnDrag, isSelecting: !!isSelecting, selectionMode, selectionKeyPressed, children: [children2, nodesSelectionActive && jsx(NodesSelection, { onSelectionContextMenu, noPanClassName, disableKeyboardA11y })] }) });
4637
4666
  }
4638
4667
  FlowRendererComponent.displayName = "FlowRenderer";
4639
- const FlowRenderer = memo(FlowRendererComponent), selector$f = (onlyRenderVisible) => (s) => onlyRenderVisible ? getNodesInside(s.nodeLookup, { x: 0, y: 0, width: s.width, height: s.height }, s.transform, !0).map((node) => node.id) : Array.from(s.nodeLookup.keys());
4668
+ const FlowRenderer = memo(FlowRendererComponent), selector$e = (onlyRenderVisible) => (s) => onlyRenderVisible ? getNodesInside(s.nodeLookup, { x: 0, y: 0, width: s.width, height: s.height }, s.transform, !0).map((node) => node.id) : Array.from(s.nodeLookup.keys());
4640
4669
  function useVisibleNodeIds(onlyRenderVisible) {
4641
- return useStore(useCallback(selector$f(onlyRenderVisible), [onlyRenderVisible]), shallow);
4670
+ return useStore(useCallback(selector$e(onlyRenderVisible), [onlyRenderVisible]), shallow);
4642
4671
  }
4643
- const selector$e = (s) => s.updateNodeInternals;
4672
+ const selector$d = (s) => s.updateNodeInternals;
4644
4673
  function useResizeObserver() {
4645
- const updateNodeInternals2 = useStore(selector$e), [resizeObserver] = useState(() => typeof ResizeObserver > "u" ? null : new ResizeObserver((entries2) => {
4674
+ const updateNodeInternals2 = useStore(selector$d), [resizeObserver] = useState(() => typeof ResizeObserver > "u" ? null : new ResizeObserver((entries2) => {
4646
4675
  const updates = /* @__PURE__ */ new Map();
4647
4676
  entries2.forEach((entry) => {
4648
4677
  const id2 = entry.target.getAttribute("data-id");
@@ -4670,7 +4699,7 @@ function useNodeObserver({ node, nodeType, hasDimensions, resizeObserver }) {
4670
4699
  }
4671
4700
  }, [node.id, nodeType, node.sourcePosition, node.targetPosition]), nodeRef;
4672
4701
  }
4673
- function NodeWrapper({ id: id2, onClick, onMouseEnter, onMouseMove, onMouseLeave, onContextMenu, onDoubleClick, nodesDraggable, elementsSelectable, nodesConnectable, nodesFocusable, resizeObserver, noDragClassName, noPanClassName, disableKeyboardA11y, rfId, nodeTypes: nodeTypes2, nodeExtent, nodeOrigin, onError }) {
4702
+ function NodeWrapper({ id: id2, onClick, onMouseEnter, onMouseMove, onMouseLeave, onContextMenu, onDoubleClick, nodesDraggable, elementsSelectable, nodesConnectable, nodesFocusable, resizeObserver, noDragClassName, noPanClassName, disableKeyboardA11y, rfId, nodeTypes: nodeTypes2, nodeExtent, onError }) {
4674
4703
  const { node, internals, isParent } = useStore((s) => {
4675
4704
  const node2 = s.nodeLookup.get(id2), isParent2 = s.parentLookup.has(id2);
4676
4705
  return {
@@ -4691,11 +4720,7 @@ function NodeWrapper({ id: id2, onClick, onMouseEnter, onMouseMove, onMouseLeave
4691
4720
  }), moveSelectedNodes = useMoveSelectedNodes();
4692
4721
  if (node.hidden)
4693
4722
  return null;
4694
- const nodeDimensions = getNodeDimensions(node), inlineDimensions = getNodeInlineStyleDimensions(node), clampedPosition = nodeExtent ? clampPosition(internals.positionAbsolute, nodeExtent) : internals.positionAbsolute, positionWithOrigin = getPositionWithOrigin({
4695
- ...clampedPosition,
4696
- ...nodeDimensions,
4697
- origin: node.origin || nodeOrigin
4698
- }), hasPointerEvents = isSelectable || isDraggable || onClick || onMouseEnter || onMouseMove || onMouseLeave, onMouseEnterHandler = onMouseEnter ? (event) => onMouseEnter(event, { ...internals.userNode }) : void 0, onMouseMoveHandler = onMouseMove ? (event) => onMouseMove(event, { ...internals.userNode }) : void 0, onMouseLeaveHandler = onMouseLeave ? (event) => onMouseLeave(event, { ...internals.userNode }) : void 0, onContextMenuHandler = onContextMenu ? (event) => onContextMenu(event, { ...internals.userNode }) : void 0, onDoubleClickHandler = onDoubleClick ? (event) => onDoubleClick(event, { ...internals.userNode }) : void 0, onSelectNodeHandler = (event) => {
4723
+ const nodeDimensions = getNodeDimensions(node), inlineDimensions = getNodeInlineStyleDimensions(node), clampedPosition = nodeExtent ? clampPosition(internals.positionAbsolute, nodeExtent) : internals.positionAbsolute, hasPointerEvents = isSelectable || isDraggable || onClick || onMouseEnter || onMouseMove || onMouseLeave, onMouseEnterHandler = onMouseEnter ? (event) => onMouseEnter(event, { ...internals.userNode }) : void 0, onMouseMoveHandler = onMouseMove ? (event) => onMouseMove(event, { ...internals.userNode }) : void 0, onMouseLeaveHandler = onMouseLeave ? (event) => onMouseLeave(event, { ...internals.userNode }) : void 0, onContextMenuHandler = onContextMenu ? (event) => onContextMenu(event, { ...internals.userNode }) : void 0, onDoubleClickHandler = onDoubleClick ? (event) => onDoubleClick(event, { ...internals.userNode }) : void 0, onSelectNodeHandler = (event) => {
4699
4724
  const { selectNodesOnDrag, nodeDragThreshold } = store.getState();
4700
4725
  isSelectable && (!selectNodesOnDrag || !isDraggable || nodeDragThreshold > 0) && handleNodeClick({
4701
4726
  id: id2,
@@ -4736,14 +4761,14 @@ function NodeWrapper({ id: id2, onClick, onMouseEnter, onMouseMove, onMouseLeave
4736
4761
  }
4737
4762
  ]), ref: nodeRef, style: {
4738
4763
  zIndex: internals.z,
4739
- transform: `translate(${positionWithOrigin.x}px,${positionWithOrigin.y}px)`,
4764
+ transform: `translate(${clampedPosition.x}px,${clampedPosition.y}px)`,
4740
4765
  pointerEvents: hasPointerEvents ? "all" : "none",
4741
4766
  visibility: hasDimensions ? "visible" : "hidden",
4742
4767
  ...node.style,
4743
4768
  ...inlineDimensions
4744
4769
  }, "data-id": id2, "data-testid": `rf__node-${id2}`, onMouseEnter: onMouseEnterHandler, onMouseMove: onMouseMoveHandler, onMouseLeave: onMouseLeaveHandler, onContextMenu: onContextMenuHandler, onClick: onSelectNodeHandler, onDoubleClick: onDoubleClickHandler, onKeyDown: isFocusable ? onKeyDown : void 0, tabIndex: isFocusable ? 0 : void 0, role: isFocusable ? "button" : void 0, "aria-describedby": disableKeyboardA11y ? void 0 : `${ARIA_NODE_DESC_KEY}-${rfId}`, "aria-label": node.ariaLabel, children: jsx(Provider, { value: id2, children: jsx(NodeComponent, { id: id2, data: node.data, type: nodeType, positionAbsoluteX: clampedPosition.x, positionAbsoluteY: clampedPosition.y, selected: node.selected, selectable: isSelectable, draggable: isDraggable, deletable: node.deletable ?? !0, isConnectable, sourcePosition: node.sourcePosition, targetPosition: node.targetPosition, dragging, dragHandle: node.dragHandle, zIndex: internals.z, parentId: node.parentId, ...nodeDimensions }) }) });
4745
4770
  }
4746
- const selector$d = (s) => ({
4771
+ const selector$c = (s) => ({
4747
4772
  nodesDraggable: s.nodesDraggable,
4748
4773
  nodesConnectable: s.nodesConnectable,
4749
4774
  nodesFocusable: s.nodesFocusable,
@@ -4751,7 +4776,7 @@ const selector$d = (s) => ({
4751
4776
  onError: s.onError
4752
4777
  });
4753
4778
  function NodeRendererComponent(props) {
4754
- const { nodesDraggable, nodesConnectable, nodesFocusable, elementsSelectable, onError } = useStore(selector$d, shallow), nodeIds = useVisibleNodeIds(props.onlyRenderVisibleElements), resizeObserver = useResizeObserver();
4779
+ const { nodesDraggable, nodesConnectable, nodesFocusable, elementsSelectable, onError } = useStore(selector$c, shallow), nodeIds = useVisibleNodeIds(props.onlyRenderVisibleElements), resizeObserver = useResizeObserver();
4755
4780
  return jsx("div", { className: "react-flow__nodes", style: containerStyle, children: nodeIds.map((nodeId) => (
4756
4781
  // The split of responsibilities between NodeRenderer and
4757
4782
  // NodeComponentWrapper may appear weird. However, it’s designed to
@@ -4776,7 +4801,7 @@ function NodeRendererComponent(props) {
4776
4801
  // moved into `NodeComponentWrapper`. This ensures they are
4777
4802
  // memorized – so if `NodeRenderer` *has* to rerender, it only
4778
4803
  // needs to regenerate the list of nodes, nothing else.
4779
- jsx(NodeWrapper, { id: nodeId, nodeTypes: props.nodeTypes, nodeExtent: props.nodeExtent, nodeOrigin: props.nodeOrigin, onClick: props.onNodeClick, onMouseEnter: props.onNodeMouseEnter, onMouseMove: props.onNodeMouseMove, onMouseLeave: props.onNodeMouseLeave, onContextMenu: props.onNodeContextMenu, onDoubleClick: props.onNodeDoubleClick, noDragClassName: props.noDragClassName, noPanClassName: props.noPanClassName, rfId: props.rfId, disableKeyboardA11y: props.disableKeyboardA11y, resizeObserver, nodesDraggable, nodesConnectable, nodesFocusable, elementsSelectable, onError }, nodeId)
4804
+ jsx(NodeWrapper, { id: nodeId, nodeTypes: props.nodeTypes, nodeExtent: props.nodeExtent, onClick: props.onNodeClick, onMouseEnter: props.onNodeMouseEnter, onMouseMove: props.onNodeMouseMove, onMouseLeave: props.onNodeMouseLeave, onContextMenu: props.onNodeContextMenu, onDoubleClick: props.onNodeDoubleClick, noDragClassName: props.noDragClassName, noPanClassName: props.noPanClassName, rfId: props.rfId, disableKeyboardA11y: props.disableKeyboardA11y, resizeObserver, nodesDraggable, nodesConnectable, nodesFocusable, elementsSelectable, onError }, nodeId)
4780
4805
  )) });
4781
4806
  }
4782
4807
  NodeRendererComponent.displayName = "NodeRenderer";
@@ -5005,7 +5030,7 @@ function EdgeUpdateAnchors({ isReconnectable, reconnectRadius, edge, targetHandl
5005
5030
  onReconnectEnd: _onReconnectEnd,
5006
5031
  updateConnection,
5007
5032
  getTransform: () => store.getState().transform,
5008
- getConnectionStartHandle: () => store.getState().connectionStartHandle
5033
+ getFromHandle: () => store.getState().connection.fromHandle
5009
5034
  });
5010
5035
  }, onReconnectSourceMouseDown = (event) => handleEdgeUpdater(event, !0), onReconnectTargetMouseDown = (event) => handleEdgeUpdater(event, !1), onReconnectMouseEnter = () => setUpdateHover(!0), onReconnectMouseOut = () => setUpdateHover(!1);
5011
5036
  return jsxs(Fragment, { children: [(isReconnectable === "source" || isReconnectable === !0) && jsx(EdgeAnchor, { position: sourcePosition, centerX: sourceX, centerY: sourceY, radius: reconnectRadius, onMouseDown: onReconnectSourceMouseDown, onMouseEnter: onReconnectMouseEnter, onMouseOut: onReconnectMouseOut, type: "source" }), (isReconnectable === "target" || isReconnectable === !0) && jsx(EdgeAnchor, { position: targetPosition, centerX: targetX, centerY: targetY, radius: reconnectRadius, onMouseDown: onReconnectTargetMouseDown, onMouseEnter: onReconnectMouseEnter, onMouseOut: onReconnectMouseOut, type: "target" })] });
@@ -5080,7 +5105,7 @@ function EdgeWrapper({ id: id2, edgesFocusable, edgesReconnectable, elementsSele
5080
5105
  }
5081
5106
  ]), onClick: onEdgeClick, onDoubleClick: onEdgeDoubleClick, onContextMenu: onEdgeContextMenu, onMouseEnter: onEdgeMouseEnter, onMouseMove: onEdgeMouseMove, onMouseLeave: onEdgeMouseLeave, onKeyDown: isFocusable ? onKeyDown : void 0, tabIndex: isFocusable ? 0 : void 0, role: isFocusable ? "button" : "img", "data-id": id2, "data-testid": `rf__edge-${id2}`, "aria-label": edge.ariaLabel === null ? void 0 : edge.ariaLabel || `Edge from ${edge.source} to ${edge.target}`, "aria-describedby": isFocusable ? `${ARIA_EDGE_DESC_KEY}-${rfId}` : void 0, ref: edgeRef, children: [!reconnecting && jsx(EdgeComponent, { id: id2, source: edge.source, target: edge.target, type: edge.type, selected: edge.selected, animated: edge.animated, selectable: isSelectable, deletable: edge.deletable ?? !0, label: edge.label, labelStyle: edge.labelStyle, labelShowBg: edge.labelShowBg, labelBgStyle: edge.labelBgStyle, labelBgPadding: edge.labelBgPadding, labelBgBorderRadius: edge.labelBgBorderRadius, sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, data: edge.data, style: edge.style, sourceHandleId: edge.sourceHandle, targetHandleId: edge.targetHandle, markerStart: markerStartUrl, markerEnd: markerEndUrl, pathOptions: "pathOptions" in edge ? edge.pathOptions : void 0, interactionWidth: edge.interactionWidth }), isReconnectable && jsx(EdgeUpdateAnchors, { edge, isReconnectable, reconnectRadius, onReconnect, onReconnectStart, onReconnectEnd, sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, setUpdateHover, setReconnecting, sourceHandleId: edge.sourceHandle, targetHandleId: edge.targetHandle })] }) });
5082
5107
  }
5083
- const selector$c = (s) => ({
5108
+ const selector$b = (s) => ({
5084
5109
  width: s.width,
5085
5110
  height: s.height,
5086
5111
  edgesFocusable: s.edgesFocusable,
@@ -5090,13 +5115,13 @@ const selector$c = (s) => ({
5090
5115
  onError: s.onError
5091
5116
  });
5092
5117
  function EdgeRendererComponent({ defaultMarkerColor, onlyRenderVisibleElements, rfId, edgeTypes: edgeTypes2, noPanClassName, onReconnect, onEdgeContextMenu, onEdgeMouseEnter, onEdgeMouseMove, onEdgeMouseLeave, onEdgeClick, reconnectRadius, onEdgeDoubleClick, onReconnectStart, onReconnectEnd, disableKeyboardA11y }) {
5093
- const { edgesFocusable, edgesReconnectable, elementsSelectable, onError } = useStore(selector$c, shallow), edgeIds = useVisibleEdgeIds(onlyRenderVisibleElements);
5118
+ const { edgesFocusable, edgesReconnectable, elementsSelectable, onError } = useStore(selector$b, shallow), edgeIds = useVisibleEdgeIds(onlyRenderVisibleElements);
5094
5119
  return jsxs("div", { className: "react-flow__edges", children: [jsx(MarkerDefinitions$1, { defaultColor: defaultMarkerColor, rfId }), edgeIds.map((id2) => jsx(EdgeWrapper, { id: id2, edgesFocusable, edgesReconnectable, elementsSelectable, noPanClassName, onReconnect, onContextMenu: onEdgeContextMenu, onMouseEnter: onEdgeMouseEnter, onMouseMove: onEdgeMouseMove, onMouseLeave: onEdgeMouseLeave, onClick: onEdgeClick, reconnectRadius, onDoubleClick: onEdgeDoubleClick, onReconnectStart, onReconnectEnd, rfId, onError, edgeTypes: edgeTypes2, disableKeyboardA11y }, id2))] });
5095
5120
  }
5096
5121
  EdgeRendererComponent.displayName = "EdgeRenderer";
5097
- const EdgeRenderer = memo(EdgeRendererComponent), selector$b = (s) => `translate(${s.transform[0]}px,${s.transform[1]}px) scale(${s.transform[2]})`;
5122
+ const EdgeRenderer = memo(EdgeRendererComponent), selector$a = (s) => `translate(${s.transform[0]}px,${s.transform[1]}px) scale(${s.transform[2]})`;
5098
5123
  function Viewport({ children: children2 }) {
5099
- const transform2 = useStore(selector$b);
5124
+ const transform2 = useStore(selector$a);
5100
5125
  return jsx("div", { className: "react-flow__viewport xyflow__viewport react-flow__container", style: { transform: transform2 }, children: children2 });
5101
5126
  }
5102
5127
  function useOnInitHandler(onInit) {
@@ -5105,72 +5130,68 @@ function useOnInitHandler(onInit) {
5105
5130
  !isInitialized.current && rfInstance.viewportInitialized && onInit && (setTimeout(() => onInit(rfInstance), 1), isInitialized.current = !0);
5106
5131
  }, [onInit, rfInstance.viewportInitialized]);
5107
5132
  }
5108
- const selector$a = (state) => {
5133
+ const selector$9 = (state) => {
5109
5134
  var _a;
5110
5135
  return (_a = state.panZoom) == null ? void 0 : _a.syncViewport;
5111
5136
  };
5112
5137
  function useViewportSync(viewport) {
5113
- const syncViewport = useStore(selector$a), store = useStoreApi();
5138
+ const syncViewport = useStore(selector$9), store = useStoreApi();
5114
5139
  return useEffect(() => {
5115
5140
  viewport && (syncViewport == null || syncViewport(viewport), store.setState({ transform: [viewport.x, viewport.y, viewport.zoom] }));
5116
5141
  }, [viewport, syncViewport]), null;
5117
5142
  }
5118
- const oppositePosition = {
5119
- [Position.Left]: Position.Right,
5120
- [Position.Right]: Position.Left,
5121
- [Position.Top]: Position.Bottom,
5122
- [Position.Bottom]: Position.Top
5123
- }, ConnectionLine = ({ nodeId, handleType, style: style2, type = ConnectionLineType.Bezier, CustomComponent, connectionStatus }) => {
5124
- const { fromNode, handleId, toX, toY, connectionMode, endPosition, isValid } = useStore(useCallback((s) => {
5125
- var _a, _b;
5126
- return {
5127
- fromNode: s.nodeLookup.get(nodeId),
5128
- handleId: (_a = s.connectionStartHandle) == null ? void 0 : _a.handleId,
5129
- toX: (s.connectionPosition.x - s.transform[0]) / s.transform[2],
5130
- toY: (s.connectionPosition.y - s.transform[1]) / s.transform[2],
5131
- connectionMode: s.connectionMode,
5132
- endPosition: (_b = s.connectionEndHandle) == null ? void 0 : _b.position,
5133
- isValid: s.connectionStatus === "valid"
5134
- };
5135
- }, [nodeId]), shallow), fromHandleBounds = fromNode == null ? void 0 : fromNode.internals.handleBounds;
5136
- let handleBounds = fromHandleBounds == null ? void 0 : fromHandleBounds[handleType];
5137
- if (connectionMode === ConnectionMode.Loose && (handleBounds = handleBounds || (fromHandleBounds == null ? void 0 : fromHandleBounds[handleType === "source" ? "target" : "source"])), !fromNode || !handleBounds)
5138
- return null;
5139
- const fromHandle = handleId ? handleBounds.find((d) => d.id === handleId) : handleBounds[0], fromHandleX = fromHandle ? fromHandle.x + fromHandle.width / 2 : (fromNode.measured.width ?? 0) / 2, fromHandleY = fromHandle ? fromHandle.y + fromHandle.height / 2 : fromNode.measured.height ?? 0, fromX = fromNode.internals.positionAbsolute.x + fromHandleX, fromY = fromNode.internals.positionAbsolute.y + fromHandleY, fromPosition = fromHandle == null ? void 0 : fromHandle.position, toPosition = isValid && endPosition ? endPosition : fromPosition ? oppositePosition[fromPosition] : null;
5140
- if (!fromPosition || !toPosition)
5141
- return null;
5143
+ const selector$8 = (s) => s.connection.inProgress ? { ...s.connection, to: pointToRendererPoint(s.connection.to, s.transform) } : { ...s.connection };
5144
+ function useConnection() {
5145
+ return useStore(selector$8, shallow);
5146
+ }
5147
+ const selector$7 = (s) => ({
5148
+ nodesConnectable: s.nodesConnectable,
5149
+ isValid: s.connection.isValid,
5150
+ inProgress: s.connection.inProgress,
5151
+ width: s.width,
5152
+ height: s.height
5153
+ });
5154
+ function ConnectionLineWrapper({ containerStyle: containerStyle2, style: style2, type, component }) {
5155
+ const { nodesConnectable, width, height, isValid, inProgress } = useStore(selector$7, shallow);
5156
+ return !(width && nodesConnectable && inProgress) ? null : jsx("svg", { style: containerStyle2, width, height, className: "react-flow__connectionline react-flow__container", children: jsx("g", { className: cc(["react-flow__connection", getConnectionStatus(isValid)]), children: jsx(ConnectionLine, { style: style2, type, CustomComponent: component, isValid }) }) });
5157
+ }
5158
+ const ConnectionLine = ({ style: style2, type = ConnectionLineType.Bezier, CustomComponent, isValid }) => {
5159
+ const { inProgress, from, fromNode, fromHandle, fromPosition, to, toNode, toHandle, toPosition } = useConnection();
5160
+ if (!inProgress)
5161
+ return;
5142
5162
  if (CustomComponent)
5143
- return jsx(CustomComponent, { connectionLineType: type, connectionLineStyle: style2, fromNode, fromHandle, fromX, fromY, toX, toY, fromPosition, toPosition, connectionStatus });
5144
- let dAttr = "";
5163
+ return jsx(CustomComponent, { connectionLineType: type, connectionLineStyle: style2, fromNode, fromHandle, fromX: from.x, fromY: from.y, toX: to.x, toY: to.y, fromPosition, toPosition, connectionStatus: getConnectionStatus(isValid), toNode, toHandle });
5164
+ let path = "";
5145
5165
  const pathParams = {
5146
- sourceX: fromX,
5147
- sourceY: fromY,
5166
+ sourceX: from.x,
5167
+ sourceY: from.y,
5148
5168
  sourcePosition: fromPosition,
5149
- targetX: toX,
5150
- targetY: toY,
5169
+ targetX: to.x,
5170
+ targetY: to.y,
5151
5171
  targetPosition: toPosition
5152
5172
  };
5153
- return type === ConnectionLineType.Bezier ? [dAttr] = getBezierPath(pathParams) : type === ConnectionLineType.Step ? [dAttr] = getSmoothStepPath({
5154
- ...pathParams,
5155
- borderRadius: 0
5156
- }) : type === ConnectionLineType.SmoothStep ? [dAttr] = getSmoothStepPath(pathParams) : type === ConnectionLineType.SimpleBezier ? [dAttr] = getSimpleBezierPath(pathParams) : dAttr = `M${fromX},${fromY} ${toX},${toY}`, jsx("path", { d: dAttr, fill: "none", className: "react-flow__connection-path", style: style2 });
5173
+ switch (type) {
5174
+ case ConnectionLineType.Bezier:
5175
+ [path] = getBezierPath(pathParams);
5176
+ break;
5177
+ case ConnectionLineType.SimpleBezier:
5178
+ [path] = getSimpleBezierPath(pathParams);
5179
+ break;
5180
+ case ConnectionLineType.Step:
5181
+ [path] = getSmoothStepPath({
5182
+ ...pathParams,
5183
+ borderRadius: 0
5184
+ });
5185
+ break;
5186
+ case ConnectionLineType.SmoothStep:
5187
+ [path] = getSmoothStepPath(pathParams);
5188
+ break;
5189
+ default:
5190
+ [path] = getStraightPath(pathParams);
5191
+ }
5192
+ return jsx("path", { d: path, fill: "none", className: "react-flow__connection-path", style: style2 });
5157
5193
  };
5158
5194
  ConnectionLine.displayName = "ConnectionLine";
5159
- const selector$9 = (s) => {
5160
- var _a, _b;
5161
- return {
5162
- nodeId: (_a = s.connectionStartHandle) == null ? void 0 : _a.nodeId,
5163
- handleType: (_b = s.connectionStartHandle) == null ? void 0 : _b.type,
5164
- nodesConnectable: s.nodesConnectable,
5165
- connectionStatus: s.connectionStatus,
5166
- width: s.width,
5167
- height: s.height
5168
- };
5169
- };
5170
- function ConnectionLineWrapper({ containerStyle: containerStyle2, style: style2, type, component }) {
5171
- const { nodeId, handleType, nodesConnectable, width, height, connectionStatus } = useStore(selector$9, shallow);
5172
- return !(nodeId && handleType && width && nodesConnectable) ? null : jsx("svg", { style: containerStyle2, width, height, className: "react-flow__connectionline react-flow__container", children: jsx("g", { className: cc(["react-flow__connection", connectionStatus]), children: jsx(ConnectionLine, { nodeId, handleType, style: style2, type, CustomComponent: component, connectionStatus }) }) });
5173
- }
5174
5195
  const emptyTypes = {};
5175
5196
  function useNodeOrEdgeTypesWarning(nodeOrEdgeTypes = emptyTypes) {
5176
5197
  useRef(nodeOrEdgeTypes), useStoreApi(), useEffect(() => {
@@ -5180,20 +5201,19 @@ function useStylesLoadedWarning() {
5180
5201
  useStoreApi(), useRef(!1), useEffect(() => {
5181
5202
  }, []);
5182
5203
  }
5183
- function GraphViewComponent({ nodeTypes: nodeTypes2, edgeTypes: edgeTypes2, onInit, onNodeClick, onEdgeClick, onNodeDoubleClick, onEdgeDoubleClick, onNodeMouseEnter, onNodeMouseMove, onNodeMouseLeave, onNodeContextMenu, onSelectionContextMenu, onSelectionStart, onSelectionEnd, connectionLineType, connectionLineStyle, connectionLineComponent, connectionLineContainerStyle, selectionKeyCode, selectionOnDrag, selectionMode, multiSelectionKeyCode, panActivationKeyCode, zoomActivationKeyCode, deleteKeyCode, onlyRenderVisibleElements, elementsSelectable, defaultViewport: defaultViewport2, translateExtent, minZoom, maxZoom, preventScrolling, defaultMarkerColor, zoomOnScroll, zoomOnPinch, panOnScroll, panOnScrollSpeed, panOnScrollMode, zoomOnDoubleClick, panOnDrag, onPaneClick, onPaneMouseEnter, onPaneMouseMove, onPaneMouseLeave, onPaneScroll, onPaneContextMenu, onEdgeContextMenu, onEdgeMouseEnter, onEdgeMouseMove, onEdgeMouseLeave, reconnectRadius, onReconnect, onReconnectStart, onReconnectEnd, noDragClassName, noWheelClassName, noPanClassName, disableKeyboardA11y, nodeOrigin, nodeExtent, rfId, viewport, onViewportChange }) {
5184
- return useNodeOrEdgeTypesWarning(nodeTypes2), useNodeOrEdgeTypesWarning(edgeTypes2), useStylesLoadedWarning(), useOnInitHandler(onInit), useViewportSync(viewport), jsx(FlowRenderer, { onPaneClick, onPaneMouseEnter, onPaneMouseMove, onPaneMouseLeave, onPaneContextMenu, onPaneScroll, deleteKeyCode, selectionKeyCode, selectionOnDrag, selectionMode, onSelectionStart, onSelectionEnd, multiSelectionKeyCode, panActivationKeyCode, zoomActivationKeyCode, elementsSelectable, zoomOnScroll, zoomOnPinch, zoomOnDoubleClick, panOnScroll, panOnScrollSpeed, panOnScrollMode, panOnDrag, defaultViewport: defaultViewport2, translateExtent, minZoom, maxZoom, onSelectionContextMenu, preventScrolling, noDragClassName, noWheelClassName, noPanClassName, disableKeyboardA11y, onViewportChange, isControlledViewport: !!viewport, children: jsxs(Viewport, { children: [jsx(EdgeRenderer, { edgeTypes: edgeTypes2, onEdgeClick, onEdgeDoubleClick, onReconnect, onReconnectStart, onReconnectEnd, onlyRenderVisibleElements, onEdgeContextMenu, onEdgeMouseEnter, onEdgeMouseMove, onEdgeMouseLeave, reconnectRadius, defaultMarkerColor, noPanClassName, disableKeyboardA11y, rfId }), jsx(ConnectionLineWrapper, { style: connectionLineStyle, type: connectionLineType, component: connectionLineComponent, containerStyle: connectionLineContainerStyle }), jsx("div", { className: "react-flow__edgelabel-renderer" }), jsx(NodeRenderer, { nodeTypes: nodeTypes2, onNodeClick, onNodeDoubleClick, onNodeMouseEnter, onNodeMouseMove, onNodeMouseLeave, onNodeContextMenu, onlyRenderVisibleElements, noPanClassName, noDragClassName, disableKeyboardA11y, nodeOrigin, nodeExtent, rfId }), jsx("div", { className: "react-flow__viewport-portal" })] }) });
5204
+ function GraphViewComponent({ nodeTypes: nodeTypes2, edgeTypes: edgeTypes2, onInit, onNodeClick, onEdgeClick, onNodeDoubleClick, onEdgeDoubleClick, onNodeMouseEnter, onNodeMouseMove, onNodeMouseLeave, onNodeContextMenu, onSelectionContextMenu, onSelectionStart, onSelectionEnd, connectionLineType, connectionLineStyle, connectionLineComponent, connectionLineContainerStyle, selectionKeyCode, selectionOnDrag, selectionMode, multiSelectionKeyCode, panActivationKeyCode, zoomActivationKeyCode, deleteKeyCode, onlyRenderVisibleElements, elementsSelectable, defaultViewport: defaultViewport2, translateExtent, minZoom, maxZoom, preventScrolling, defaultMarkerColor, zoomOnScroll, zoomOnPinch, panOnScroll, panOnScrollSpeed, panOnScrollMode, zoomOnDoubleClick, panOnDrag, onPaneClick, onPaneMouseEnter, onPaneMouseMove, onPaneMouseLeave, onPaneScroll, onPaneContextMenu, paneClickDistance, onEdgeContextMenu, onEdgeMouseEnter, onEdgeMouseMove, onEdgeMouseLeave, reconnectRadius, onReconnect, onReconnectStart, onReconnectEnd, noDragClassName, noWheelClassName, noPanClassName, disableKeyboardA11y, nodeExtent, rfId, viewport, onViewportChange }) {
5205
+ return useNodeOrEdgeTypesWarning(nodeTypes2), useNodeOrEdgeTypesWarning(edgeTypes2), useStylesLoadedWarning(), useOnInitHandler(onInit), useViewportSync(viewport), jsx(FlowRenderer, { onPaneClick, onPaneMouseEnter, onPaneMouseMove, onPaneMouseLeave, onPaneContextMenu, onPaneScroll, paneClickDistance, deleteKeyCode, selectionKeyCode, selectionOnDrag, selectionMode, onSelectionStart, onSelectionEnd, multiSelectionKeyCode, panActivationKeyCode, zoomActivationKeyCode, elementsSelectable, zoomOnScroll, zoomOnPinch, zoomOnDoubleClick, panOnScroll, panOnScrollSpeed, panOnScrollMode, panOnDrag, defaultViewport: defaultViewport2, translateExtent, minZoom, maxZoom, onSelectionContextMenu, preventScrolling, noDragClassName, noWheelClassName, noPanClassName, disableKeyboardA11y, onViewportChange, isControlledViewport: !!viewport, children: jsxs(Viewport, { children: [jsx(EdgeRenderer, { edgeTypes: edgeTypes2, onEdgeClick, onEdgeDoubleClick, onReconnect, onReconnectStart, onReconnectEnd, onlyRenderVisibleElements, onEdgeContextMenu, onEdgeMouseEnter, onEdgeMouseMove, onEdgeMouseLeave, reconnectRadius, defaultMarkerColor, noPanClassName, disableKeyboardA11y, rfId }), jsx(ConnectionLineWrapper, { style: connectionLineStyle, type: connectionLineType, component: connectionLineComponent, containerStyle: connectionLineContainerStyle }), jsx("div", { className: "react-flow__edgelabel-renderer" }), jsx(NodeRenderer, { nodeTypes: nodeTypes2, onNodeClick, onNodeDoubleClick, onNodeMouseEnter, onNodeMouseMove, onNodeMouseLeave, onNodeContextMenu, onlyRenderVisibleElements, noPanClassName, noDragClassName, disableKeyboardA11y, nodeExtent, rfId }), jsx("div", { className: "react-flow__viewport-portal" })] }) });
5185
5206
  }
5186
5207
  GraphViewComponent.displayName = "GraphView";
5187
- const GraphView = memo(GraphViewComponent), getInitialState = ({ nodes, edges, defaultNodes, defaultEdges, width, height, fitView: fitView2 } = {}) => {
5188
- const nodeLookup = /* @__PURE__ */ new Map(), parentLookup = /* @__PURE__ */ new Map(), connectionLookup = /* @__PURE__ */ new Map(), edgeLookup = /* @__PURE__ */ new Map(), storeEdges = defaultEdges ?? edges ?? [], storeNodes = defaultNodes ?? nodes ?? [];
5208
+ const GraphView = memo(GraphViewComponent), getInitialState = ({ nodes, edges, defaultNodes, defaultEdges, width, height, fitView: fitView2, nodeOrigin } = {}) => {
5209
+ const nodeLookup = /* @__PURE__ */ new Map(), parentLookup = /* @__PURE__ */ new Map(), connectionLookup = /* @__PURE__ */ new Map(), edgeLookup = /* @__PURE__ */ new Map(), storeEdges = defaultEdges ?? edges ?? [], storeNodes = defaultNodes ?? nodes ?? [], storeNodeOrigin = nodeOrigin ?? [0, 0];
5189
5210
  updateConnectionLookup(connectionLookup, edgeLookup, storeEdges), adoptUserNodes(storeNodes, nodeLookup, parentLookup, {
5190
- nodeOrigin: [0, 0],
5211
+ nodeOrigin: storeNodeOrigin,
5191
5212
  elevateNodesOnSelect: !1
5192
5213
  });
5193
5214
  let transform2 = [0, 0, 1];
5194
5215
  if (fitView2 && width && height) {
5195
5216
  const bounds = getInternalNodesBounds(nodeLookup, {
5196
- nodeOrigin: [0, 0],
5197
5217
  filter: (node) => !!((node.width || node.initialWidth) && (node.height || node.initialHeight))
5198
5218
  }), { x, y, zoom: zoom2 } = getViewportForBounds(bounds, width, height, 0.5, 2, 0.1);
5199
5219
  transform2 = [x, y, zoom2];
@@ -5221,13 +5241,11 @@ const GraphView = memo(GraphViewComponent), getInitialState = ({ nodes, edges, d
5221
5241
  nodesSelectionActive: !1,
5222
5242
  userSelectionActive: !1,
5223
5243
  userSelectionRect: null,
5224
- connectionPosition: { x: 0, y: 0 },
5225
- connectionStatus: null,
5226
5244
  connectionMode: ConnectionMode.Strict,
5227
5245
  domNode: null,
5228
5246
  paneDragging: !1,
5229
5247
  noPanClassName: "nopan",
5230
- nodeOrigin: [0, 0],
5248
+ nodeOrigin: storeNodeOrigin,
5231
5249
  nodeDragThreshold: 1,
5232
5250
  snapGrid: [15, 15],
5233
5251
  snapToGrid: !1,
@@ -5244,13 +5262,13 @@ const GraphView = memo(GraphViewComponent), getInitialState = ({ nodes, edges, d
5244
5262
  fitViewOnInitOptions: void 0,
5245
5263
  selectNodesOnDrag: !0,
5246
5264
  multiSelectionActive: !1,
5247
- connectionStartHandle: null,
5248
- connectionEndHandle: null,
5265
+ connection: { ...initialConnection },
5249
5266
  connectionClickStartHandle: null,
5250
5267
  connectOnClick: !0,
5251
5268
  ariaLiveMessage: "",
5252
5269
  autoPanOnConnect: !0,
5253
5270
  autoPanOnNodeDrag: !0,
5271
+ autoPanSpeed: 15,
5254
5272
  connectionRadius: 20,
5255
5273
  onError: devWarn,
5256
5274
  isValidConnection: void 0,
@@ -5258,11 +5276,11 @@ const GraphView = memo(GraphViewComponent), getInitialState = ({ nodes, edges, d
5258
5276
  lib: "react",
5259
5277
  debug: !1
5260
5278
  };
5261
- }, createStore = ({ nodes, edges, defaultNodes, defaultEdges, width, height, fitView: fitView$1 }) => createWithEqualityFn((set2, get2) => ({
5262
- ...getInitialState({ nodes, edges, width, height, fitView: fitView$1, defaultNodes, defaultEdges }),
5279
+ }, createStore = ({ nodes, edges, defaultNodes, defaultEdges, width, height, fitView: fitView$1, nodeOrigin }) => createWithEqualityFn((set2, get2) => ({
5280
+ ...getInitialState({ nodes, edges, width, height, fitView: fitView$1, nodeOrigin, defaultNodes, defaultEdges }),
5263
5281
  setNodes: (nodes2) => {
5264
- const { nodeLookup, parentLookup, nodeOrigin, elevateNodesOnSelect } = get2();
5265
- adoptUserNodes(nodes2, nodeLookup, parentLookup, { nodeOrigin, elevateNodesOnSelect, checkEquality: !0 }), set2({ nodes: nodes2 });
5282
+ const { nodeLookup, parentLookup, nodeOrigin: nodeOrigin2, elevateNodesOnSelect } = get2();
5283
+ adoptUserNodes(nodes2, nodeLookup, parentLookup, { nodeOrigin: nodeOrigin2, elevateNodesOnSelect, checkEquality: !0 }), set2({ nodes: nodes2 });
5266
5284
  },
5267
5285
  setEdges: (edges2) => {
5268
5286
  const { connectionLookup, edgeLookup } = get2();
@@ -5282,12 +5300,12 @@ const GraphView = memo(GraphViewComponent), getInitialState = ({ nodes, edges, d
5282
5300
  // changes its dimensions, this function is called to measure the
5283
5301
  // new dimensions and update the nodes.
5284
5302
  updateNodeInternals: (updates) => {
5285
- const { triggerNodeChanges, fitView: fitView2, nodeLookup, parentLookup, fitViewOnInit, fitViewDone, fitViewOnInitOptions, domNode, nodeOrigin, debug } = get2(), { changes, updatedInternals } = updateNodeInternals(updates, nodeLookup, parentLookup, domNode, nodeOrigin);
5303
+ const { triggerNodeChanges, nodeLookup, parentLookup, fitViewOnInit, fitViewDone, fitViewOnInitOptions, domNode, nodeOrigin: nodeOrigin2, debug, fitViewSync } = get2(), { changes, updatedInternals } = updateNodeInternals(updates, nodeLookup, parentLookup, domNode, nodeOrigin2);
5286
5304
  if (!updatedInternals)
5287
5305
  return;
5288
- updateAbsolutePositions(nodeLookup, { nodeOrigin });
5306
+ updateAbsolutePositions(nodeLookup, parentLookup, { nodeOrigin: nodeOrigin2 });
5289
5307
  let nextFitViewDone = fitViewDone;
5290
- !fitViewDone && fitViewOnInit && (nextFitViewDone = fitView2({
5308
+ !fitViewDone && fitViewOnInit && (nextFitViewDone = fitViewSync({
5291
5309
  ...fitViewOnInitOptions,
5292
5310
  nodes: fitViewOnInitOptions == null ? void 0 : fitViewOnInitOptions.nodes
5293
5311
  })), set2({ fitViewDone: nextFitViewDone }), (changes == null ? void 0 : changes.length) > 0 && (debug && console.log("React Flow: trigger node changes", changes), triggerNodeChanges == null || triggerNodeChanges(changes));
@@ -5312,7 +5330,7 @@ const GraphView = memo(GraphViewComponent), getInitialState = ({ nodes, edges, d
5312
5330
  }), change.position.x = Math.max(0, change.position.x), change.position.y = Math.max(0, change.position.y)), changes.push(change);
5313
5331
  }
5314
5332
  if (parentExpandChildren.length > 0) {
5315
- const { nodeLookup, parentLookup } = get2(), parentExpandChanges = handleExpandParent(parentExpandChildren, nodeLookup, parentLookup);
5333
+ const { nodeLookup, parentLookup, nodeOrigin: nodeOrigin2 } = get2(), parentExpandChanges = handleExpandParent(parentExpandChildren, nodeLookup, parentLookup, nodeOrigin2);
5316
5334
  changes.push(...parentExpandChanges);
5317
5335
  }
5318
5336
  get2().triggerNodeChanges(changes);
@@ -5371,6 +5389,10 @@ const GraphView = memo(GraphViewComponent), getInitialState = ({ nodes, edges, d
5371
5389
  var _a;
5372
5390
  (_a = get2().panZoom) == null || _a.setTranslateExtent(translateExtent), set2({ translateExtent });
5373
5391
  },
5392
+ setPaneClickDistance: (clickDistance) => {
5393
+ var _a;
5394
+ (_a = get2().panZoom) == null || _a.setClickDistance(clickDistance);
5395
+ },
5374
5396
  resetSelectedElements: () => {
5375
5397
  const { edges: edges2, nodes: nodes2, triggerNodeChanges, triggerEdgeChanges } = get2(), nodeChanges = nodes2.reduce((res, node) => node.selected ? [...res, createSelectionChange(node.id, !1)] : res, []), edgeChanges = edges2.reduce((res, edge) => edge.selected ? [...res, createSelectionChange(edge.id, !1)] : res, []);
5376
5398
  triggerNodeChanges(nodeChanges), triggerEdgeChanges(edgeChanges);
@@ -5396,32 +5418,46 @@ const GraphView = memo(GraphViewComponent), getInitialState = ({ nodes, edges, d
5396
5418
  return panBy({ delta, panZoom, transform: transform2, translateExtent, width: width2, height: height2 });
5397
5419
  },
5398
5420
  fitView: (options) => {
5399
- const { panZoom, width: width2, height: height2, minZoom, maxZoom, nodeOrigin, nodeLookup } = get2();
5400
- return panZoom ? fitView({
5401
- nodeLookup,
5421
+ const { panZoom, width: width2, height: height2, minZoom, maxZoom, nodeLookup } = get2();
5422
+ if (!panZoom)
5423
+ return Promise.resolve(!1);
5424
+ const fitViewNodes = getFitViewNodes(nodeLookup, options);
5425
+ return fitView({
5426
+ nodes: fitViewNodes,
5402
5427
  width: width2,
5403
5428
  height: height2,
5404
5429
  panZoom,
5405
5430
  minZoom,
5406
- maxZoom,
5407
- nodeOrigin
5408
- }, options) : !1;
5431
+ maxZoom
5432
+ }, options);
5409
5433
  },
5410
- cancelConnection: () => set2({
5411
- connectionStatus: null,
5412
- connectionStartHandle: null,
5413
- connectionEndHandle: null
5414
- }),
5415
- updateConnection: (params) => {
5416
- const { connectionPosition } = get2(), currentConnection = {
5417
- ...params,
5418
- connectionPosition: params.connectionPosition ?? connectionPosition
5419
- };
5420
- set2(currentConnection);
5434
+ // we can't call an asnychronous function in updateNodeInternals
5435
+ // for that we created this sync version of fitView
5436
+ fitViewSync: (options) => {
5437
+ const { panZoom, width: width2, height: height2, minZoom, maxZoom, nodeLookup } = get2();
5438
+ if (!panZoom)
5439
+ return !1;
5440
+ const fitViewNodes = getFitViewNodes(nodeLookup, options);
5441
+ return fitView({
5442
+ nodes: fitViewNodes,
5443
+ width: width2,
5444
+ height: height2,
5445
+ panZoom,
5446
+ minZoom,
5447
+ maxZoom
5448
+ }, options), fitViewNodes.size > 0;
5449
+ },
5450
+ cancelConnection: () => {
5451
+ set2({
5452
+ connection: { ...initialConnection }
5453
+ });
5454
+ },
5455
+ updateConnection: (connection) => {
5456
+ set2({ connection });
5421
5457
  },
5422
5458
  reset: () => set2({ ...getInitialState() })
5423
5459
  }), Object.is);
5424
- function ReactFlowProvider({ initialNodes: nodes, initialEdges: edges, defaultNodes, defaultEdges, initialWidth: width, initialHeight: height, fitView: fitView2, children: children2 }) {
5460
+ function ReactFlowProvider({ initialNodes: nodes, initialEdges: edges, defaultNodes, defaultEdges, initialWidth: width, initialHeight: height, fitView: fitView2, nodeOrigin, children: children2 }) {
5425
5461
  const [store] = useState(() => createStore({
5426
5462
  nodes,
5427
5463
  edges,
@@ -5429,12 +5465,13 @@ function ReactFlowProvider({ initialNodes: nodes, initialEdges: edges, defaultNo
5429
5465
  defaultEdges,
5430
5466
  width,
5431
5467
  height,
5432
- fitView: fitView2
5468
+ fitView: fitView2,
5469
+ nodeOrigin
5433
5470
  }));
5434
5471
  return jsx(Provider$1, { value: store, children: jsx(BatchProvider, { children: children2 }) });
5435
5472
  }
5436
- function Wrapper({ children: children2, nodes, edges, defaultNodes, defaultEdges, width, height, fitView: fitView2 }) {
5437
- return useContext(StoreContext) ? jsx(Fragment, { children: children2 }) : jsx(ReactFlowProvider, { initialNodes: nodes, initialEdges: edges, defaultNodes, defaultEdges, initialWidth: width, initialHeight: height, fitView: fitView2, children: children2 });
5473
+ function Wrapper({ children: children2, nodes, edges, defaultNodes, defaultEdges, width, height, fitView: fitView2, nodeOrigin }) {
5474
+ return useContext(StoreContext) ? jsx(Fragment, { children: children2 }) : jsx(ReactFlowProvider, { initialNodes: nodes, initialEdges: edges, defaultNodes, defaultEdges, initialWidth: width, initialHeight: height, fitView: fitView2, nodeOrigin, children: children2 });
5438
5475
  }
5439
5476
  const wrapperStyle = {
5440
5477
  width: "100%",
@@ -5443,17 +5480,17 @@ const wrapperStyle = {
5443
5480
  position: "relative",
5444
5481
  zIndex: 0
5445
5482
  };
5446
- function ReactFlow({ nodes, edges, defaultNodes, defaultEdges, className, nodeTypes: nodeTypes2, edgeTypes: edgeTypes2, onNodeClick, onEdgeClick, onInit, onMove, onMoveStart, onMoveEnd, onConnect, onConnectStart, onConnectEnd, onClickConnectStart, onClickConnectEnd, onNodeMouseEnter, onNodeMouseMove, onNodeMouseLeave, onNodeContextMenu, onNodeDoubleClick, onNodeDragStart, onNodeDrag, onNodeDragStop, onNodesDelete, onEdgesDelete, onDelete, onSelectionChange, onSelectionDragStart, onSelectionDrag, onSelectionDragStop, onSelectionContextMenu, onSelectionStart, onSelectionEnd, onBeforeDelete, connectionMode, connectionLineType = ConnectionLineType.Bezier, connectionLineStyle, connectionLineComponent, connectionLineContainerStyle, deleteKeyCode = "Backspace", selectionKeyCode = "Shift", selectionOnDrag = !1, selectionMode = SelectionMode.Full, panActivationKeyCode = "Space", multiSelectionKeyCode = isMacOs() ? "Meta" : "Control", zoomActivationKeyCode = isMacOs() ? "Meta" : "Control", snapToGrid, snapGrid, onlyRenderVisibleElements = !1, selectNodesOnDrag, nodesDraggable, nodesConnectable, nodesFocusable, nodeOrigin = defaultNodeOrigin, edgesFocusable, edgesReconnectable, elementsSelectable = !0, defaultViewport: defaultViewport$1 = defaultViewport, minZoom = 0.5, maxZoom = 2, translateExtent = infiniteExtent, preventScrolling = !0, nodeExtent, defaultMarkerColor = "#b1b1b7", zoomOnScroll = !0, zoomOnPinch = !0, panOnScroll = !1, panOnScrollSpeed = 0.5, panOnScrollMode = PanOnScrollMode.Free, zoomOnDoubleClick = !0, panOnDrag = !0, onPaneClick, onPaneMouseEnter, onPaneMouseMove, onPaneMouseLeave, onPaneScroll, onPaneContextMenu, children: children2, onReconnect, onReconnectStart, onReconnectEnd, onEdgeContextMenu, onEdgeDoubleClick, onEdgeMouseEnter, onEdgeMouseMove, onEdgeMouseLeave, reconnectRadius = 10, onNodesChange, onEdgesChange, noDragClassName = "nodrag", noWheelClassName = "nowheel", noPanClassName = "nopan", fitView: fitView2, fitViewOptions, connectOnClick, attributionPosition, proOptions, defaultEdgeOptions, elevateNodesOnSelect, elevateEdgesOnSelect, disableKeyboardA11y = !1, autoPanOnConnect, autoPanOnNodeDrag, connectionRadius, isValidConnection, onError, style: style2, id: id2, nodeDragThreshold, viewport, onViewportChange, width, height, colorMode = "light", debug, ...rest }, ref) {
5483
+ function ReactFlow({ nodes, edges, defaultNodes, defaultEdges, className, nodeTypes: nodeTypes2, edgeTypes: edgeTypes2, onNodeClick, onEdgeClick, onInit, onMove, onMoveStart, onMoveEnd, onConnect, onConnectStart, onConnectEnd, onClickConnectStart, onClickConnectEnd, onNodeMouseEnter, onNodeMouseMove, onNodeMouseLeave, onNodeContextMenu, onNodeDoubleClick, onNodeDragStart, onNodeDrag, onNodeDragStop, onNodesDelete, onEdgesDelete, onDelete, onSelectionChange, onSelectionDragStart, onSelectionDrag, onSelectionDragStop, onSelectionContextMenu, onSelectionStart, onSelectionEnd, onBeforeDelete, connectionMode, connectionLineType = ConnectionLineType.Bezier, connectionLineStyle, connectionLineComponent, connectionLineContainerStyle, deleteKeyCode = "Backspace", selectionKeyCode = "Shift", selectionOnDrag = !1, selectionMode = SelectionMode.Full, panActivationKeyCode = "Space", multiSelectionKeyCode = isMacOs() ? "Meta" : "Control", zoomActivationKeyCode = isMacOs() ? "Meta" : "Control", snapToGrid, snapGrid, onlyRenderVisibleElements = !1, selectNodesOnDrag, nodesDraggable, nodesConnectable, nodesFocusable, nodeOrigin = defaultNodeOrigin, edgesFocusable, edgesReconnectable, elementsSelectable = !0, defaultViewport: defaultViewport$1 = defaultViewport, minZoom = 0.5, maxZoom = 2, translateExtent = infiniteExtent, preventScrolling = !0, nodeExtent, defaultMarkerColor = "#b1b1b7", zoomOnScroll = !0, zoomOnPinch = !0, panOnScroll = !1, panOnScrollSpeed = 0.5, panOnScrollMode = PanOnScrollMode.Free, zoomOnDoubleClick = !0, panOnDrag = !0, onPaneClick, onPaneMouseEnter, onPaneMouseMove, onPaneMouseLeave, onPaneScroll, onPaneContextMenu, paneClickDistance = 0, children: children2, onReconnect, onReconnectStart, onReconnectEnd, onEdgeContextMenu, onEdgeDoubleClick, onEdgeMouseEnter, onEdgeMouseMove, onEdgeMouseLeave, reconnectRadius = 10, onNodesChange, onEdgesChange, noDragClassName = "nodrag", noWheelClassName = "nowheel", noPanClassName = "nopan", fitView: fitView2, fitViewOptions, connectOnClick, attributionPosition, proOptions, defaultEdgeOptions, elevateNodesOnSelect, elevateEdgesOnSelect, disableKeyboardA11y = !1, autoPanOnConnect, autoPanOnNodeDrag, autoPanSpeed, connectionRadius, isValidConnection, onError, style: style2, id: id2, nodeDragThreshold, viewport, onViewportChange, width, height, colorMode = "light", debug, ...rest }, ref) {
5447
5484
  const rfId = id2 || "1", colorModeClassName = useColorModeClass(colorMode);
5448
- return jsx("div", { ...rest, style: { ...style2, ...wrapperStyle }, ref, className: cc(["react-flow", className, colorModeClassName]), "data-testid": "rf__wrapper", id: id2, children: jsxs(Wrapper, { nodes, edges, width, height, fitView: fitView2, children: [jsx(GraphView, { onInit, onNodeClick, onEdgeClick, onNodeMouseEnter, onNodeMouseMove, onNodeMouseLeave, onNodeContextMenu, onNodeDoubleClick, nodeTypes: nodeTypes2, edgeTypes: edgeTypes2, connectionLineType, connectionLineStyle, connectionLineComponent, connectionLineContainerStyle, selectionKeyCode, selectionOnDrag, selectionMode, deleteKeyCode, multiSelectionKeyCode, panActivationKeyCode, zoomActivationKeyCode, onlyRenderVisibleElements, defaultViewport: defaultViewport$1, translateExtent, minZoom, maxZoom, preventScrolling, zoomOnScroll, zoomOnPinch, zoomOnDoubleClick, panOnScroll, panOnScrollSpeed, panOnScrollMode, panOnDrag, onPaneClick, onPaneMouseEnter, onPaneMouseMove, onPaneMouseLeave, onPaneScroll, onPaneContextMenu, onSelectionContextMenu, onSelectionStart, onSelectionEnd, onReconnect, onReconnectStart, onReconnectEnd, onEdgeContextMenu, onEdgeDoubleClick, onEdgeMouseEnter, onEdgeMouseMove, onEdgeMouseLeave, reconnectRadius, defaultMarkerColor, noDragClassName, noWheelClassName, noPanClassName, rfId, disableKeyboardA11y, nodeOrigin, nodeExtent, viewport, onViewportChange }), jsx(StoreUpdater, { nodes, edges, defaultNodes, defaultEdges, onConnect, onConnectStart, onConnectEnd, onClickConnectStart, onClickConnectEnd, nodesDraggable, nodesConnectable, nodesFocusable, edgesFocusable, edgesReconnectable, elementsSelectable, elevateNodesOnSelect, elevateEdgesOnSelect, minZoom, maxZoom, nodeExtent, onNodesChange, onEdgesChange, snapToGrid, snapGrid, connectionMode, translateExtent, connectOnClick, defaultEdgeOptions, fitView: fitView2, fitViewOptions, onNodesDelete, onEdgesDelete, onDelete, onNodeDragStart, onNodeDrag, onNodeDragStop, onSelectionDrag, onSelectionDragStart, onSelectionDragStop, onMove, onMoveStart, onMoveEnd, noPanClassName, nodeOrigin, rfId, autoPanOnConnect, autoPanOnNodeDrag, onError, connectionRadius, isValidConnection, selectNodesOnDrag, nodeDragThreshold, onBeforeDelete, debug }), jsx(SelectionListener, { onSelectionChange }), children2, jsx(Attribution, { proOptions, position: attributionPosition }), jsx(A11yDescriptions, { rfId, disableKeyboardA11y })] }) });
5485
+ return jsx("div", { ...rest, style: { ...style2, ...wrapperStyle }, ref, className: cc(["react-flow", className, colorModeClassName]), "data-testid": "rf__wrapper", id: id2, children: jsxs(Wrapper, { nodes, edges, width, height, fitView: fitView2, nodeOrigin, children: [jsx(GraphView, { onInit, onNodeClick, onEdgeClick, onNodeMouseEnter, onNodeMouseMove, onNodeMouseLeave, onNodeContextMenu, onNodeDoubleClick, nodeTypes: nodeTypes2, edgeTypes: edgeTypes2, connectionLineType, connectionLineStyle, connectionLineComponent, connectionLineContainerStyle, selectionKeyCode, selectionOnDrag, selectionMode, deleteKeyCode, multiSelectionKeyCode, panActivationKeyCode, zoomActivationKeyCode, onlyRenderVisibleElements, defaultViewport: defaultViewport$1, translateExtent, minZoom, maxZoom, preventScrolling, zoomOnScroll, zoomOnPinch, zoomOnDoubleClick, panOnScroll, panOnScrollSpeed, panOnScrollMode, panOnDrag, onPaneClick, onPaneMouseEnter, onPaneMouseMove, onPaneMouseLeave, onPaneScroll, onPaneContextMenu, paneClickDistance, onSelectionContextMenu, onSelectionStart, onSelectionEnd, onReconnect, onReconnectStart, onReconnectEnd, onEdgeContextMenu, onEdgeDoubleClick, onEdgeMouseEnter, onEdgeMouseMove, onEdgeMouseLeave, reconnectRadius, defaultMarkerColor, noDragClassName, noWheelClassName, noPanClassName, rfId, disableKeyboardA11y, nodeExtent, viewport, onViewportChange }), jsx(StoreUpdater, { nodes, edges, defaultNodes, defaultEdges, onConnect, onConnectStart, onConnectEnd, onClickConnectStart, onClickConnectEnd, nodesDraggable, nodesConnectable, nodesFocusable, edgesFocusable, edgesReconnectable, elementsSelectable, elevateNodesOnSelect, elevateEdgesOnSelect, minZoom, maxZoom, nodeExtent, onNodesChange, onEdgesChange, snapToGrid, snapGrid, connectionMode, translateExtent, connectOnClick, defaultEdgeOptions, fitView: fitView2, fitViewOptions, onNodesDelete, onEdgesDelete, onDelete, onNodeDragStart, onNodeDrag, onNodeDragStop, onSelectionDrag, onSelectionDragStart, onSelectionDragStop, onMove, onMoveStart, onMoveEnd, noPanClassName, nodeOrigin, rfId, autoPanOnConnect, autoPanOnNodeDrag, autoPanSpeed, onError, connectionRadius, isValidConnection, selectNodesOnDrag, nodeDragThreshold, onBeforeDelete, paneClickDistance, debug }), jsx(SelectionListener, { onSelectionChange }), children2, jsx(Attribution, { proOptions, position: attributionPosition }), jsx(A11yDescriptions, { rfId, disableKeyboardA11y })] }) });
5449
5486
  }
5450
5487
  var index = fixedForwardRef(ReactFlow);
5451
- const selector$8 = (s) => {
5488
+ const selector$6 = (s) => {
5452
5489
  var _a;
5453
5490
  return (_a = s.domNode) == null ? void 0 : _a.querySelector(".react-flow__edgelabel-renderer");
5454
5491
  };
5455
5492
  function EdgeLabelRenderer({ children: children2 }) {
5456
- const edgeLabelRenderer = useStore(selector$8);
5493
+ const edgeLabelRenderer = useStore(selector$6);
5457
5494
  return edgeLabelRenderer ? createPortal(children2, edgeLabelRenderer) : null;
5458
5495
  }
5459
5496
  function useOnViewportChange({ onStart, onChange, onEnd }) {
@@ -5466,6 +5503,16 @@ function useOnViewportChange({ onStart, onChange, onEnd }) {
5466
5503
  store.setState({ onViewportChangeEnd: onEnd });
5467
5504
  }, [onEnd]);
5468
5505
  }
5506
+ function useOnSelectionChange({ onChange }) {
5507
+ const store = useStoreApi();
5508
+ useEffect(() => {
5509
+ const nextOnSelectionChangeHandlers = [...store.getState().onSelectionChangeHandlers, onChange];
5510
+ return store.setState({ onSelectionChangeHandlers: nextOnSelectionChangeHandlers }), () => {
5511
+ const nextHandlers = store.getState().onSelectionChangeHandlers.filter((fn) => fn !== onChange);
5512
+ store.setState({ onSelectionChangeHandlers: nextHandlers });
5513
+ };
5514
+ }, [onChange]);
5515
+ }
5469
5516
  function useNodesData(nodeIds) {
5470
5517
  return useStore(useCallback((s) => {
5471
5518
  const data = [], isArrayOfIds = Array.isArray(nodeIds), _nodeIds = isArrayOfIds ? nodeIds : [nodeIds];
@@ -5494,7 +5541,7 @@ const defaultSize = {
5494
5541
  [BackgroundVariant.Dots]: 1,
5495
5542
  [BackgroundVariant.Lines]: 1,
5496
5543
  [BackgroundVariant.Cross]: 6
5497
- }, selector$4 = (s) => ({ transform: s.transform, patternId: `pattern-${s.rfId}` });
5544
+ }, selector$3$1 = (s) => ({ transform: s.transform, patternId: `pattern-${s.rfId}` });
5498
5545
  function BackgroundComponent({
5499
5546
  id: id2,
5500
5547
  variant = BackgroundVariant.Dots,
@@ -5510,7 +5557,7 @@ function BackgroundComponent({
5510
5557
  className,
5511
5558
  patternClassName
5512
5559
  }) {
5513
- const ref = useRef(null), { transform: transform2, patternId } = useStore(selector$4, shallow), patternSize = size || defaultSize[variant], isDots = variant === BackgroundVariant.Dots, isCross = variant === BackgroundVariant.Cross, gapXY = Array.isArray(gap) ? gap : [gap, gap], scaledGap = [gapXY[0] * transform2[2] || 1, gapXY[1] * transform2[2] || 1], scaledSize = patternSize * transform2[2], patternDimensions = isCross ? [scaledSize, scaledSize] : scaledGap, patternOffset = isDots ? [scaledSize / offset, scaledSize / offset] : [patternDimensions[0] / offset, patternDimensions[1] / offset], _patternId = `${patternId}${id2 || ""}`;
5560
+ const ref = useRef(null), { transform: transform2, patternId } = useStore(selector$3$1, shallow), patternSize = size || defaultSize[variant], isDots = variant === BackgroundVariant.Dots, isCross = variant === BackgroundVariant.Cross, gapXY = Array.isArray(gap) ? gap : [gap, gap], scaledGap = [gapXY[0] * transform2[2] || 1, gapXY[1] * transform2[2] || 1], scaledSize = patternSize * transform2[2], patternDimensions = isCross ? [scaledSize, scaledSize] : scaledGap, patternOffset = isDots ? [scaledSize / offset, scaledSize / offset] : [patternDimensions[0] / offset, patternDimensions[1] / offset], _patternId = `${patternId}${id2 || ""}`;
5514
5561
  return jsxs("svg", { className: cc(["react-flow__background", className]), style: {
5515
5562
  ...style2,
5516
5563
  ...containerStyle,
@@ -5538,13 +5585,13 @@ function UnlockIcon() {
5538
5585
  function ControlButton({ children: children2, className, ...rest }) {
5539
5586
  return jsx("button", { type: "button", className: cc(["react-flow__controls-button", className]), ...rest, children: children2 });
5540
5587
  }
5541
- const selector$3 = (s) => ({
5588
+ const selector$2$1 = (s) => ({
5542
5589
  isInteractive: s.nodesDraggable || s.nodesConnectable || s.elementsSelectable,
5543
5590
  minZoomReached: s.transform[2] <= s.minZoom,
5544
5591
  maxZoomReached: s.transform[2] >= s.maxZoom
5545
5592
  });
5546
5593
  function ControlsComponent({ style: style2, showZoom = !0, showFitView = !0, showInteractive = !0, fitViewOptions, onZoomIn, onZoomOut, onFitView, onInteractiveChange, className, children: children2, position = "bottom-left", orientation = "vertical", "aria-label": ariaLabel = "React Flow controls" }) {
5547
- const store = useStoreApi(), { isInteractive, minZoomReached, maxZoomReached } = useStore(selector$3, shallow), { zoomIn, zoomOut, fitView: fitView2 } = useReactFlow(), onZoomInHandler = () => {
5594
+ const store = useStoreApi(), { isInteractive, minZoomReached, maxZoomReached } = useStore(selector$2$1, shallow), { zoomIn, zoomOut, fitView: fitView2 } = useReactFlow(), onZoomInHandler = () => {
5548
5595
  zoomIn(), onZoomIn == null || onZoomIn();
5549
5596
  }, onZoomOutHandler = () => {
5550
5597
  zoomOut(), onZoomOut == null || onZoomOut();
@@ -5569,7 +5616,7 @@ function MiniMapNodeComponent({ id: id2, x, y, width, height, style: style2, col
5569
5616
  strokeWidth
5570
5617
  }, shapeRendering, onClick: onClick ? (event) => onClick(event, id2) : void 0 });
5571
5618
  }
5572
- const MiniMapNode = memo(MiniMapNodeComponent), selector$2$1 = (s) => s.nodeOrigin, selectorNodeIds = (s) => s.nodes.map((node) => node.id), getAttrFunction = (func) => func instanceof Function ? func : () => func;
5619
+ const MiniMapNode = memo(MiniMapNodeComponent), selectorNodeIds = (s) => s.nodes.map((node) => node.id), getAttrFunction = (func) => func instanceof Function ? func : () => func;
5573
5620
  function MiniMapNodes({
5574
5621
  nodeStrokeColor,
5575
5622
  nodeColor,
@@ -5581,19 +5628,19 @@ function MiniMapNodes({
5581
5628
  nodeComponent: NodeComponent = MiniMapNode,
5582
5629
  onClick
5583
5630
  }) {
5584
- const nodeIds = useStore(selectorNodeIds, shallow), nodeOrigin = useStore(selector$2$1), nodeColorFunc = getAttrFunction(nodeColor), nodeStrokeColorFunc = getAttrFunction(nodeStrokeColor), nodeClassNameFunc = getAttrFunction(nodeClassName), shapeRendering = typeof window > "u" || window.chrome ? "crispEdges" : "geometricPrecision";
5631
+ const nodeIds = useStore(selectorNodeIds, shallow), nodeColorFunc = getAttrFunction(nodeColor), nodeStrokeColorFunc = getAttrFunction(nodeStrokeColor), nodeClassNameFunc = getAttrFunction(nodeClassName), shapeRendering = typeof window > "u" || window.chrome ? "crispEdges" : "geometricPrecision";
5585
5632
  return jsx(Fragment, { children: nodeIds.map((nodeId) => (
5586
5633
  // The split of responsibilities between MiniMapNodes and
5587
5634
  // NodeComponentWrapper may appear weird. However, it’s designed to
5588
5635
  // minimize the cost of updates when individual nodes change.
5589
5636
  //
5590
5637
  // For more details, see a similar commit in `NodeRenderer/index.tsx`.
5591
- jsx(NodeComponentWrapper, { id: nodeId, nodeOrigin, nodeColorFunc, nodeStrokeColorFunc, nodeClassNameFunc, nodeBorderRadius, nodeStrokeWidth, NodeComponent, onClick, shapeRendering }, nodeId)
5638
+ jsx(NodeComponentWrapper, { id: nodeId, nodeColorFunc, nodeStrokeColorFunc, nodeClassNameFunc, nodeBorderRadius, nodeStrokeWidth, NodeComponent, onClick, shapeRendering }, nodeId)
5592
5639
  )) });
5593
5640
  }
5594
- function NodeComponentWrapperInner({ id: id2, nodeOrigin, nodeColorFunc, nodeStrokeColorFunc, nodeClassNameFunc, nodeBorderRadius, nodeStrokeWidth, shapeRendering, NodeComponent, onClick }) {
5641
+ function NodeComponentWrapperInner({ id: id2, nodeColorFunc, nodeStrokeColorFunc, nodeClassNameFunc, nodeBorderRadius, nodeStrokeWidth, shapeRendering, NodeComponent, onClick }) {
5595
5642
  const { node, x, y } = useStore((s) => {
5596
- const node2 = s.nodeLookup.get(id2), { x: x2, y: y2 } = getNodePositionWithOrigin(node2, nodeOrigin).positionAbsolute;
5643
+ const node2 = s.nodeLookup.get(id2), { x: x2, y: y2 } = node2.internals.positionAbsolute;
5597
5644
  return {
5598
5645
  node: node2,
5599
5646
  x: x2,
@@ -5616,9 +5663,8 @@ const defaultWidth = 200, defaultHeight = 150, selector$1$1 = (s) => {
5616
5663
  };
5617
5664
  return {
5618
5665
  viewBB,
5619
- boundingRect: s.nodeLookup.size > 0 ? getBoundsOfRects(getInternalNodesBounds(s.nodeLookup, { nodeOrigin: s.nodeOrigin }), viewBB) : viewBB,
5666
+ boundingRect: s.nodeLookup.size > 0 ? getBoundsOfRects(getInternalNodesBounds(s.nodeLookup), viewBB) : viewBB,
5620
5667
  rfId: s.rfId,
5621
- nodeOrigin: s.nodeOrigin,
5622
5668
  panZoom: s.panZoom,
5623
5669
  translateExtent: s.translateExtent,
5624
5670
  flowWidth: s.width,
@@ -5716,19 +5762,19 @@ function ResizeControl({ nodeId, position, variant = ResizeControlVariant.Handle
5716
5762
  onChange: (change, childChanges) => {
5717
5763
  const { triggerNodeChanges, nodeLookup, parentLookup, nodeOrigin } = store.getState(), changes = [], nextPosition = { x: change.x, y: change.y }, node = nodeLookup.get(id2);
5718
5764
  if (node && node.expandParent && node.parentId) {
5719
- const child = {
5765
+ const origin = node.origin ?? nodeOrigin, width = change.width ?? node.measured.width, height = change.height ?? node.measured.height, child = {
5720
5766
  id: node.id,
5721
5767
  parentId: node.parentId,
5722
5768
  rect: {
5723
- width: change.width ?? node.measured.width,
5724
- height: change.height ?? node.measured.height,
5769
+ width,
5770
+ height,
5725
5771
  ...evaluateAbsolutePosition({
5726
5772
  x: change.x ?? node.position.x,
5727
5773
  y: change.y ?? node.position.y
5728
- }, node.parentId, nodeLookup, node.origin ?? nodeOrigin)
5774
+ }, { width, height }, node.parentId, nodeLookup, origin)
5729
5775
  }
5730
5776
  }, parentExpandChanges = handleExpandParent([child], nodeLookup, parentLookup, nodeOrigin);
5731
- changes.push(...parentExpandChanges), nextPosition.x = change.x ? Math.max(0, change.x) : void 0, nextPosition.y = change.y ? Math.max(0, change.y) : void 0;
5777
+ changes.push(...parentExpandChanges), nextPosition.x = change.x ? Math.max(origin[0] * width, change.x) : void 0, nextPosition.y = change.y ? Math.max(origin[1] * height, change.y) : void 0;
5732
5778
  }
5733
5779
  if (nextPosition.x !== void 0 && nextPosition.y !== void 0) {
5734
5780
  const positionChange = {
@@ -5839,30 +5885,7 @@ function useTilg$1(...args) {
5839
5885
  tilg.exports = production;
5840
5886
  var tilgExports = tilg.exports;
5841
5887
  const useTilg = /* @__PURE__ */ getDefaultExportFromCjs(tilgExports);
5842
- var rootClassName = "likec4-diagram-root", keepAspectRatioContainer = "_2h8g8h0", cssReactFlow = "_2h8g8h1", cssDisablePan = "_2h8g8h2", cssTransparentBg = "_2h8g8h3", cssNoControls = "_2h8g8h4";
5843
- function KeepAspectRatioContainer({
5844
- children: children2,
5845
- width,
5846
- height,
5847
- enabled,
5848
- className,
5849
- style: style2,
5850
- ...rest
5851
- }) {
5852
- return /* @__PURE__ */ jsx(
5853
- Box,
5854
- {
5855
- ...rest,
5856
- className: clsx(keepAspectRatioContainer, className),
5857
- style: enabled ? {
5858
- ...style2,
5859
- aspectRatio: `${Math.ceil(width)}/${Math.ceil(height)}`,
5860
- maxHeight: `var(--likec4-view-max-height, ${Math.ceil(height)}px)`
5861
- } : style2,
5862
- children: children2
5863
- }
5864
- );
5865
- }
5888
+ var rootClassName = "likec4-diagram-root", cssReactFlow = "_2h8g8h0", cssDisablePan = "_2h8g8h1", cssTransparentBg = "_2h8g8h2", cssNoControls = "_2h8g8h3";
5866
5889
  function EnsureMantine({ children: children2 }) {
5867
5890
  if (!useContext(MantineContext))
5868
5891
  throw new Error("LikeC4Diagram must be a child of MantineProvider");
@@ -7019,6 +7042,26 @@ function useDiagramStoreApi() {
7019
7042
  throw new Error("useDiagramStoreApi could be used only inside DiagramContext");
7020
7043
  return store;
7021
7044
  }
7045
+ function useNavigationHistory() {
7046
+ const store = useDiagramStoreApi(), viewId = useDiagramState((s) => s.view.id), [historyViewId, historyOps, {
7047
+ history,
7048
+ current: historyIndex
7049
+ }] = useStateHistory(viewId), hasBack = historyIndex > 0, hasForward = historyIndex < history.length - 1;
7050
+ return useUpdateEffect(() => {
7051
+ viewId !== historyViewId && historyOps.set(viewId);
7052
+ }, [viewId]), useUpdateEffect(() => {
7053
+ var _a, _b;
7054
+ viewId !== historyViewId && ((_b = (_a = store.getState()).onNavigateTo) == null || _b.call(_a, historyViewId));
7055
+ }, [historyViewId]), useMemo(() => ({
7056
+ hasBack,
7057
+ hasForward,
7058
+ ops: historyOps
7059
+ }), [
7060
+ hasBack,
7061
+ hasForward,
7062
+ historyOps
7063
+ ]);
7064
+ }
7022
7065
  const { abs: abs$1, cos: cos$1, sin: sin$1, acos: acos$1, atan2, sqrt: sqrt$1, pow } = Math;
7023
7066
  function crt(v) {
7024
7067
  return v < 0 ? -pow(-v, 1 / 3) : pow(v, 1 / 3);
@@ -7966,12 +8009,12 @@ function bezierControlPoints(diagramEdge) {
7966
8009
  inflections.length === 0 && inflections.push(0.5), inflections.forEach((t2) => {
7967
8010
  const { x, y } = bezier.get(t2);
7968
8011
  handles.push({
7969
- x: toDomPrecision(x),
7970
- y: toDomPrecision(y)
8012
+ x: Math.round(x),
8013
+ y: Math.round(y)
7971
8014
  });
7972
8015
  }), bezierPoints = rest, start2 = end;
7973
8016
  }
7974
- return invariant(bezierPoints.length === 0, "all points should be consumed"), diagramEdge.dir === "back" && handles.length > 0 && handles.reverse(), handles;
8017
+ return invariant(bezierPoints.length === 0, "all points should be consumed"), handles;
7975
8018
  }
7976
8019
  const isClose = (a, b) => Math.abs(a - b) < 3.1;
7977
8020
  function isSamePoint$1(a, b) {
@@ -7983,7 +8026,7 @@ function useXYStore(selector2, equalityFn) {
7983
8026
  return useStore(
7984
8027
  // @ts-expect-error - types are not correct
7985
8028
  selector2,
7986
- equalityFn ?? shallowEqual
8029
+ shallowEqual
7987
8030
  );
7988
8031
  }
7989
8032
  const useXYStoreApi = useStoreApi;
@@ -8142,14 +8185,14 @@ function useLayoutConstraints() {
8142
8185
  invariant(solverRef.current, "solverRef.current should be defined"), (_a = solverRef.current) == null || _a.onNodeDrag(xynode);
8143
8186
  },
8144
8187
  onNodeDragStop: (event, _xynode) => {
8145
- isSamePoint$1(dragStartedAt.current, { x: event.clientX, y: event.clientY }) || diagramApi.getState().triggerSaveManualLayout(xyflowApi), solverRef.current = void 0;
8188
+ isSamePoint$1(dragStartedAt.current, { x: event.clientX, y: event.clientY }) || diagramApi.getState().triggerSaveManualLayout(), solverRef.current = void 0;
8146
8189
  }
8147
8190
  }), [xyflowApi, diagramApi]);
8148
8191
  }
8149
8192
  const ZIndexes = {
8150
- Compound: 1,
8151
- Edge: 2,
8152
- Element: 3
8193
+ Compound: 2,
8194
+ Edge: 4,
8195
+ Element: 6
8153
8196
  }, MinZoom = 0.1, StringSet = Set, DEFAULT_PROPS = {
8154
8197
  viewSyncDebounceTimeout: null,
8155
8198
  initialized: !1,
@@ -8174,13 +8217,15 @@ const ZIndexes = {
8174
8217
  onCanvasClick: null,
8175
8218
  onCanvasDblClick: null
8176
8219
  }, noReplace = !1;
8177
- let storeDevId = 1;
8220
+ let StoreDevId = 1;
8178
8221
  const EmptyStringSet = new StringSet();
8179
8222
  function createDiagramStore(props) {
8223
+ const storeDevId = "DiagramStore" + String(StoreDevId++).padStart(2, "0");
8180
8224
  return createWithEqualityFn(
8181
8225
  subscribeWithSelector(
8182
8226
  devtools(
8183
8227
  (set2, get2) => ({
8228
+ storeDevId,
8184
8229
  ...DEFAULT_PROPS,
8185
8230
  ...props,
8186
8231
  isDynamicView: () => {
@@ -8203,11 +8248,13 @@ function createDiagramStore(props) {
8203
8248
  hoveredEdgeId,
8204
8249
  hoveredNodeId
8205
8250
  } = get2();
8206
- if (viewSyncDebounceTimeout !== null && (clearTimeout(viewSyncDebounceTimeout), viewSyncDebounceTimeout = null), shallowEqual(current, nextView)) {
8251
+ if (shallowEqual(current, nextView)) {
8207
8252
  DEV && console.debug("store: skip updateView");
8208
8253
  return;
8209
8254
  }
8210
- if (current.id === nextView.id) {
8255
+ viewSyncDebounceTimeout !== null && (clearTimeout(viewSyncDebounceTimeout), viewSyncDebounceTimeout = null);
8256
+ const isSameView = current.id === nextView.id;
8257
+ if (isSameView) {
8211
8258
  const nodeIds = new StringSet(nextView.nodes.map((n) => n.id)), edgeIds = new StringSet(nextView.edges.map((e) => e.id));
8212
8259
  if (lastClickedNodeId && !nodeIds.has(lastClickedNodeId) && (lastClickedNodeId = null), hoveredNodeId && !nodeIds.has(hoveredNodeId) && (hoveredNodeId = null), focusedNodeId && !nodeIds.has(focusedNodeId) && (focusedNodeId = null), lastClickedEdgeId && !edgeIds.has(lastClickedEdgeId) && (lastClickedEdgeId = null), hoveredEdgeId && !edgeIds.has(hoveredEdgeId) && (hoveredEdgeId = null), activeDynamicViewStep && !edgeIds.has(StepEdgeId(activeDynamicViewStep)) && (activeDynamicViewStep = null), xyflowSynced = deepEqual([current.nodes, current.edges], [nextView.nodes, nextView.edges]), dimmed2.size > 0) {
8213
8260
  let nextDimmed = new StringSet([...dimmed2].filter((id2) => nodeIds.has(id2) || edgeIds.has(id2)));
@@ -8239,7 +8286,7 @@ function createDiagramStore(props) {
8239
8286
  dimmed: dimmed2
8240
8287
  },
8241
8288
  noReplace,
8242
- "update-view"
8289
+ isSameView ? "update-view [same]" : "update-view [another]"
8243
8290
  );
8244
8291
  },
8245
8292
  focusOnNode: (nodeId) => {
@@ -8305,7 +8352,7 @@ function createDiagramStore(props) {
8305
8352
  if (!change.targets.includes(origin.id))
8306
8353
  return origin;
8307
8354
  let element2 = origin;
8308
- for (const [key, value] of entries.strict(change.style))
8355
+ for (const [key, value] of entries(change.style))
8309
8356
  switch (key) {
8310
8357
  case "shape":
8311
8358
  value !== element2.shape && (element2 = {
@@ -8351,14 +8398,14 @@ function createDiagramStore(props) {
8351
8398
  let { viewSyncDebounceTimeout } = get2();
8352
8399
  viewSyncDebounceTimeout !== null && (clearTimeout(viewSyncDebounceTimeout), set2({ viewSyncDebounceTimeout: null }));
8353
8400
  },
8354
- triggerSaveManualLayout: (xystore) => {
8401
+ triggerSaveManualLayout: () => {
8355
8402
  let { viewSyncDebounceTimeout: debounced, onChange } = get2();
8356
8403
  if (!onChange) {
8357
8404
  DEV && console.debug("ignore triggerSaveManualLayout, as no onChange handler is set");
8358
8405
  return;
8359
8406
  }
8360
8407
  debounced && clearTimeout(debounced), debounced = setTimeout(() => {
8361
- const { nodeLookup } = xystore.getState(), { xyflow, onChange: onChange2 } = get2();
8408
+ const { xyflow, onChange: onChange2, xystore } = get2(), { nodeLookup } = xystore.getState();
8362
8409
  set2({ viewSyncDebounceTimeout: null });
8363
8410
  const movedNodes = new StringSet(), nodes = reduce([...nodeLookup.values()], (acc, node) => {
8364
8411
  const dimensions = getNodeDimensions(node);
@@ -8394,8 +8441,10 @@ function createDiagramStore(props) {
8394
8441
  },
8395
8442
  triggerOnNavigateTo: (xynodeId, event) => {
8396
8443
  var _a, _b;
8397
- const { xyflow, view } = get2(), xynode = xyflow.getInternalNode(xynodeId), element2 = xynode == null ? void 0 : xynode.data.element;
8398
- invariant(!!xynode && (element2 == null ? void 0 : element2.navigateTo), `node is not navigable: ${xynodeId}`), set2(
8444
+ const { xyflow, view } = get2(), xynode = xyflow.getInternalNode(xynodeId);
8445
+ invariant(!!xynode, `node not found: ${xynodeId}`);
8446
+ const element2 = xynode.data.element;
8447
+ invariant(element2.navigateTo, `node is not navigable: ${xynodeId}`), set2(
8399
8448
  {
8400
8449
  lastClickedNodeId: xynodeId,
8401
8450
  lastOnNavigate: {
@@ -8421,15 +8470,16 @@ function createDiagramStore(props) {
8421
8470
  xynode.internals.userNode
8422
8471
  );
8423
8472
  },
8424
- fitDiagram: (xyStore) => {
8425
- const { width, height, panZoom } = xyStore.getState(), { fitViewPadding, view, focusedNodeId } = get2(), bounds = {
8473
+ fitDiagram: (duration = 500) => {
8474
+ const { fitViewPadding, view, focusedNodeId, activeDynamicViewStep, xystore } = get2(), { width, height, panZoom, transform: transform2 } = xystore.getState(), bounds = {
8426
8475
  x: 0,
8427
8476
  y: 0,
8428
8477
  width: view.width,
8429
8478
  height: view.height
8430
- }, viewport = getViewportForBounds(bounds, width, height, MinZoom, 1, fitViewPadding);
8431
- panZoom == null || panZoom.setViewport(viewport, { duration: 500 }), focusedNodeId && set2(
8479
+ }, maxZoom = Math.max(1, transform2[2]), viewport = getViewportForBounds(bounds, width, height, MinZoom, maxZoom, fitViewPadding);
8480
+ panZoom == null || panZoom.setViewport(viewport, { duration }), (focusedNodeId ?? activeDynamicViewStep) !== null && set2(
8432
8481
  {
8482
+ activeDynamicViewStep: null,
8433
8483
  focusedNodeId: null,
8434
8484
  dimmed: EmptyStringSet
8435
8485
  },
@@ -8438,7 +8488,7 @@ function createDiagramStore(props) {
8438
8488
  );
8439
8489
  },
8440
8490
  nextDynamicStep: (increment = 1) => {
8441
- const { view, activeDynamicViewStep, xyflow, fitViewPadding } = get2();
8491
+ const { view, activeDynamicViewStep, xyflow, xystore, fitViewPadding } = get2();
8442
8492
  invariant(view.__ === "dynamic", "view is not dynamic");
8443
8493
  const nextStep = (activeDynamicViewStep ?? 0) + increment;
8444
8494
  if (nextStep <= 0 || nextStep > view.edges.length)
@@ -8461,33 +8511,38 @@ function createDiagramStore(props) {
8461
8511
  }
8462
8512
  dimmed2.add(n.id);
8463
8513
  }
8464
- xyflow.fitView({
8514
+ const { fitView: fitView2, transform: transform2 } = xystore.getState();
8515
+ fitView2({
8465
8516
  duration: 400,
8466
- maxZoom: 1,
8517
+ includeHiddenNodes: !0,
8518
+ maxZoom: Math.max(1, transform2[2]),
8467
8519
  minZoom: MinZoom,
8468
- padding: fitViewPadding,
8520
+ padding: Math.max(fitViewPadding, 0.2),
8469
8521
  nodes: selected2
8470
- }), set2({
8471
- focusedNodeId: null,
8472
- activeDynamicViewStep: nextStep,
8473
- dimmed: dimmed2
8474
- });
8522
+ }), set2(
8523
+ {
8524
+ focusedNodeId: null,
8525
+ activeDynamicViewStep: nextStep,
8526
+ dimmed: dimmed2
8527
+ },
8528
+ noReplace,
8529
+ "nextDynamicStep"
8530
+ );
8475
8531
  },
8476
8532
  stopDynamicView: () => {
8477
- const { xyflow, fitViewPadding } = get2();
8478
- set2({
8479
- activeDynamicViewStep: null,
8480
- dimmed: EmptyStringSet
8481
- }), xyflow.fitView({
8482
- duration: 400,
8483
- maxZoom: 1,
8484
- minZoom: MinZoom,
8485
- padding: fitViewPadding
8486
- });
8533
+ get2().activeDynamicViewStep !== null && (set2(
8534
+ {
8535
+ activeDynamicViewStep: null,
8536
+ focusedNodeId: null,
8537
+ dimmed: EmptyStringSet
8538
+ },
8539
+ noReplace,
8540
+ "stopDynamicView"
8541
+ ), get2().fitDiagram());
8487
8542
  }
8488
8543
  }),
8489
8544
  {
8490
- name: `DiagramStore ${storeDevId++} - ${props.view.id}`,
8545
+ name: `${storeDevId} - ${props.view.id}`,
8491
8546
  enabled: DEV
8492
8547
  }
8493
8548
  )
@@ -8496,28 +8551,52 @@ function createDiagramStore(props) {
8496
8551
  );
8497
8552
  }
8498
8553
  const DiagramContext = createContext(null);
8499
- function DiagramContextProvider({ children: children2, view, ...props }) {
8500
- const xyflow = useXYFlow(), store = useRef();
8554
+ function DiagramContextProvider({
8555
+ children: children2,
8556
+ view,
8557
+ className,
8558
+ keepAspectRatio,
8559
+ ...props
8560
+ }) {
8561
+ const containerRef = useRef(null), xystore = useXYStoreApi(), xyflow = useXYFlow(), store = useRef();
8501
8562
  return store.current || (store.current = createDiagramStore({
8563
+ xystore,
8502
8564
  xyflow,
8503
8565
  view,
8566
+ getContainer: () => containerRef.current,
8504
8567
  ...props
8505
8568
  })), useEffect(
8506
8569
  () => {
8507
- var _a, _b;
8508
- ((_a = store.current) == null ? void 0 : _a.getState().xyflow) !== xyflow && ((_b = store.current) == null || _b.setState({ xyflow }, !1, "update xyflow"));
8570
+ if (!store.current) return;
8571
+ const state = store.current.getState();
8572
+ (state.xyflow !== xyflow || state.xystore !== xystore) && store.current.setState({ xyflow, xystore }, !1, "update xyflow and xystore");
8509
8573
  },
8510
- [xyflow]
8574
+ [xyflow, xystore]
8511
8575
  ), useUpdateEffect(
8512
8576
  () => {
8513
8577
  if (!store.current) return;
8514
8578
  const state = store.current.getState();
8515
- state.view !== view && state.updateView(view), hasSubObject(state, props) || store.current.setState(props, !1, "update incoming props");
8579
+ state.view !== view && state.updateView(view);
8580
+ const newProps = pickBy(props, isNonNullish);
8581
+ hasSubObject(state, newProps) || store.current.setState(newProps, !1, "update incoming props");
8516
8582
  },
8517
- [view, props]
8518
- ), /* @__PURE__ */ jsx(DiagramContext.Provider, { value: store.current, children: children2 });
8583
+ [view, props],
8584
+ shallowEqual
8585
+ ), /* @__PURE__ */ jsx(
8586
+ "div",
8587
+ {
8588
+ ref: containerRef,
8589
+ className,
8590
+ ...keepAspectRatio && {
8591
+ style: {
8592
+ aspectRatio: `${Math.ceil(view.width)}/${Math.ceil(view.height)}`,
8593
+ maxHeight: Math.ceil(view.height)
8594
+ }
8595
+ },
8596
+ children: /* @__PURE__ */ jsx(DiagramContext.Provider, { value: store.current, children: children2 })
8597
+ }
8598
+ );
8519
8599
  }
8520
- const nodeZIndex = (node) => node.level + 1;
8521
8600
  function diagramViewToXYFlowData(view, opts) {
8522
8601
  var _a, _b;
8523
8602
  const isDynamicView = view.__ === "dynamic", editor = {
@@ -8528,15 +8607,15 @@ function diagramViewToXYFlowData(view, opts) {
8528
8607
  new Array()
8529
8608
  ), ns = "", nodeById = (id2) => nonNullable(nodeLookup.get(id2), `Node not found: ${id2}`);
8530
8609
  let next;
8531
- for (; next = traverse.pop(); ) {
8610
+ for (; next = traverse.shift(); ) {
8532
8611
  const { node, parent } = next;
8533
- node.children.length > 0 && traverse.unshift(...node.children.map((child) => ({ node: nodeById(child), parent: node })));
8612
+ node.children.length > 0 && traverse.push(...node.children.map((child) => ({ node: nodeById(child), parent: node })));
8534
8613
  const isCompound = hasAtLeast$1(node.children, 1), position = {
8535
8614
  x: node.position[0],
8536
8615
  y: node.position[1]
8537
8616
  };
8538
8617
  parent && (position.x -= parent.position[0], position.y -= parent.position[1]);
8539
- const id2 = ns + node.id;
8618
+ const id2 = ns + node.id, draggable = opts.draggable && (!parent || parent.children.length > 1);
8540
8619
  editor.nodes.push({
8541
8620
  id: id2,
8542
8621
  type: isCompound ? "compound" : "element",
@@ -8544,72 +8623,44 @@ function diagramViewToXYFlowData(view, opts) {
8544
8623
  fqn: node.id,
8545
8624
  element: node
8546
8625
  },
8547
- draggable: opts.draggable && (!parent || parent.children.length > 1),
8626
+ draggable,
8548
8627
  selectable: opts.selectable,
8549
8628
  deletable: !1,
8550
8629
  position,
8551
- zIndex: nodeZIndex(node),
8630
+ zIndex: isCompound ? ZIndexes.Compound : ZIndexes.Element,
8552
8631
  hidden: !1,
8553
- /* initialWidth: node.width,
8554
- initialHeight: node.height, */
8632
+ initialWidth: node.width,
8633
+ initialHeight: node.height,
8555
8634
  width: node.width,
8556
8635
  height: node.height,
8557
- // measured: {
8558
- // width: node.width,
8559
- // height: node.height
8560
- // },
8561
8636
  ...parent && {
8562
8637
  parentId: ns + parent.id
8638
+ },
8639
+ ...isCompound && {
8640
+ dragHandle: ".likec4-compound-title"
8563
8641
  }
8564
- // handles: [
8565
- // ...outEdges.map(out => ({
8566
- // id: `${out.id}`,
8567
- // type: 'source' as const,
8568
- // position: Position.Bottom,
8569
- // x: out.points[0][0],
8570
- // y: out.points[0][1],
8571
- // width: 10,
8572
- // height: 10
8573
- // })),
8574
- // ...inEdges.map(out => ({
8575
- // id: out.id,
8576
- // type: 'target' as const,
8577
- // position: Position.Top,
8578
- // x: out.points[0][0],
8579
- // y: out.points[0][1],
8580
- // width: 10,
8581
- // height: 10
8582
- // }))
8583
- // ],
8584
8642
  });
8585
8643
  }
8586
8644
  for (const edge of view.edges) {
8587
8645
  const source = edge.source, target = edge.target, id2 = ns + edge.id;
8588
- invariant(hasAtLeast$1(edge.points, 2), "edge should have at least 2 points");
8589
- const level = Math.max(nodeZIndex(nodeById(source)), nodeZIndex(nodeById(target)));
8590
- editor.edges.push({
8646
+ invariant(hasAtLeast$1(edge.points, 2), "edge should have at least 2 points"), editor.edges.push({
8591
8647
  id: id2,
8592
8648
  type: "relationship",
8593
8649
  source: ns + source,
8594
8650
  target: ns + target,
8595
- zIndex: level,
8651
+ zIndex: ZIndexes.Edge,
8652
+ selectable: opts.selectable,
8596
8653
  deletable: !1,
8597
8654
  data: {
8598
8655
  edge,
8599
8656
  type: "bezier",
8600
8657
  controlPoints: ((_b = (_a = view.manualLayout) == null ? void 0 : _a.edges[edge.id]) == null ? void 0 : _b.controlPoints) || null,
8601
- headPoint: edge.headArrowPoint ?? null,
8602
- tailPoint: edge.tailArrowPoint ?? null,
8603
8658
  stepNum: isDynamicView ? extractStep(edge.id) : null,
8604
8659
  label: edge.labelBBox ? {
8605
8660
  bbox: edge.labelBBox,
8606
- // text: edge.labels ? edge.labels.map(l => l.text).join('\n') : ''
8607
8661
  text: edge.label ?? ""
8608
8662
  } : null
8609
8663
  },
8610
- // markerEnd: {
8611
- // type: MarkerType.ArrowClosed
8612
- // },
8613
8664
  interactionWidth: 20
8614
8665
  });
8615
8666
  }
@@ -8623,14 +8674,14 @@ function FitViewOnViewportResize({ diagramApi, xyflowApi }) {
8623
8674
  return useDebouncedEffect(
8624
8675
  () => {
8625
8676
  const { focusedNodeId, fitDiagram } = diagramApi.getState();
8626
- focusedNodeId || prevDimensionsRef.current === dimensions || (fitDiagram(xyflowApi), prevDimensionsRef.current = dimensions);
8677
+ focusedNodeId || prevDimensionsRef.current === dimensions || (fitDiagram(300), prevDimensionsRef.current = dimensions);
8627
8678
  },
8628
8679
  [dimensions, diagramApi, xyflowApi],
8629
- 250,
8680
+ 300,
8630
8681
  1e3
8631
8682
  ), null;
8632
8683
  }
8633
- function selector$2({ view, xyflowSynced, viewportChanged, lastOnNavigate, ...s }) {
8684
+ function selector$3({ view, xyflowSynced, viewportChanged, lastOnNavigate, ...s }) {
8634
8685
  const viewId = view.id + "_" + view.autoLayout + "_" + s.fitViewPadding, waitCorrection = lastOnNavigate && lastOnNavigate.toView === view.id && lastOnNavigate.positionCorrected === !1, elTo = waitCorrection ? view.nodes.find((n) => n.id === lastOnNavigate.element.id) : void 0;
8635
8686
  return waitCorrection && elTo ? {
8636
8687
  viewId,
@@ -8656,7 +8707,7 @@ function FitViewOnDiagramChange() {
8656
8707
  waitCorrection,
8657
8708
  elFrom,
8658
8709
  elTo
8659
- } = useDiagramState(selector$2, shallowEqual), diagramApi = useDiagramStoreApi(), processedRef = useRef(pendingViewId);
8710
+ } = useDiagramState(selector$3, shallowEqual), diagramApi = useDiagramStoreApi(), processedRef = useRef(pendingViewId), durationRef = useRef(300);
8660
8711
  return useEffect(() => {
8661
8712
  if (!(!xyflowSynced || pendingViewId === processedRef.current)) {
8662
8713
  if (waitCorrection) {
@@ -8672,57 +8723,62 @@ function FitViewOnDiagramChange() {
8672
8723
  x: toDomPrecision(fromPos.x - toPos.x),
8673
8724
  y: toDomPrecision(fromPos.y - toPos.y)
8674
8725
  };
8675
- xyflowApi.getState().panBy(diff), diagramApi.setState({ lastOnNavigate: null });
8726
+ xyflowApi.getState().panBy(diff), durationRef.current = 500, diagramApi.setState({ lastOnNavigate: null });
8676
8727
  return;
8677
8728
  }
8678
- processedRef.current = pendingViewId, diagramApi.getState().fitDiagram(xyflowApi);
8729
+ processedRef.current = pendingViewId, diagramApi.getState().fitDiagram(durationRef.current), durationRef.current = 300;
8679
8730
  }
8680
8731
  }, [pendingViewId, xyflowSynced, waitCorrection]), !viewportChanged && xyflowSynced ? /* @__PURE__ */ jsx(FitViewOnViewportResize, { xyflowApi, diagramApi }) : null;
8681
8732
  }
8682
8733
  function SelectEdgesOnNodeFocus() {
8683
- const focusedNodeId = useDiagramState((s) => s.focusedNodeId), diagramStore = useDiagramStoreApi(), xyflowApi = useXYStoreApi();
8684
- return useUpdateEffect(() => {
8685
- if (!focusedNodeId) {
8686
- xyflowApi.getState().resetSelectedElements();
8687
- return;
8688
- }
8689
- const edgeChanges = [], nodeChanges = [], { edgeLookup, nodeLookup, transform: transform2, triggerNodeChanges, fitView: fitView2, triggerEdgeChanges } = xyflowApi.getState(), fitViewNodes = /* @__PURE__ */ new Set();
8690
- fitViewNodes.add(nonNullable(nodeLookup.get(focusedNodeId)));
8691
- for (const [, edge] of edgeLookup)
8692
- if (edge.source === focusedNodeId || edge.target === focusedNodeId) {
8693
- edgeChanges.push({
8734
+ const diagramStore = useDiagramStoreApi();
8735
+ return useEffect(
8736
+ () => diagramStore.subscribe((s) => s.focusedNodeId, (focusedNodeId) => {
8737
+ if (!focusedNodeId)
8738
+ return;
8739
+ const edgeChanges = [], nodeChanges = [], {
8740
+ edgeLookup,
8741
+ nodeLookup,
8742
+ width,
8743
+ height,
8744
+ panZoom,
8745
+ transform: transform2,
8746
+ triggerNodeChanges,
8747
+ triggerEdgeChanges
8748
+ } = diagramStore.getState().xystore.getState();
8749
+ let focusBounds = nodeToRect(nonNullable(nodeLookup.get(focusedNodeId)));
8750
+ for (const [, edge] of edgeLookup) {
8751
+ if (edge.source === focusedNodeId || edge.target === focusedNodeId) {
8752
+ const anotherNodeId = edge.source === focusedNodeId ? edge.target : edge.source, nd = nodeToRect(nonNullable(nodeLookup.get(anotherNodeId)));
8753
+ focusBounds = getBoundsOfRects(focusBounds, nd);
8754
+ }
8755
+ edge.selected && edgeChanges.push({
8694
8756
  id: edge.id,
8695
8757
  type: "select",
8696
- selected: !0
8758
+ selected: !1
8697
8759
  });
8698
- const anotherNode = nonNullable(nodeLookup.get(edge.source === focusedNodeId ? edge.target : edge.source));
8699
- fitViewNodes.add(anotherNode);
8700
- } else edge.selected && edgeChanges.push({
8701
- id: edge.id,
8702
- type: "select",
8703
- selected: !1
8704
- });
8705
- for (const [, node] of nodeLookup)
8706
- node.selected && node.id !== focusedNodeId && nodeChanges.push({
8707
- id: node.id,
8760
+ }
8761
+ for (const [, node] of nodeLookup)
8762
+ node.selected && node.id !== focusedNodeId && nodeChanges.push({
8763
+ id: node.id,
8764
+ type: "select",
8765
+ selected: !1
8766
+ });
8767
+ nodeChanges.push({
8768
+ id: focusedNodeId,
8708
8769
  type: "select",
8709
- selected: !1
8770
+ selected: !0
8771
+ }), edgeChanges.length > 0 && triggerEdgeChanges(edgeChanges), triggerNodeChanges(nodeChanges);
8772
+ const maxZoom = Math.max(1, transform2[2]), viewport = getViewportForBounds(focusBounds, width, height, MinZoom, maxZoom, 0.2);
8773
+ panZoom == null || panZoom.setViewport(viewport, {
8774
+ duration: 350
8710
8775
  });
8711
- nodeChanges.push({
8712
- id: focusedNodeId,
8713
- type: "select",
8714
- selected: !0
8715
- }), edgeChanges.length > 0 && triggerEdgeChanges(edgeChanges), triggerNodeChanges(nodeChanges), fitView2({
8716
- duration: 350,
8717
- padding: 0.1,
8718
- minZoom: MinZoom,
8719
- maxZoom: Math.max(1, transform2[2]),
8720
- nodes: Array.from(fitViewNodes)
8721
- });
8722
- }, [diagramStore, xyflowApi, focusedNodeId]), null;
8776
+ }),
8777
+ [diagramStore]
8778
+ ), null;
8723
8779
  }
8724
8780
  function SyncWithDiagram() {
8725
- const xyflowSynced = useDiagramState((s) => s.xyflowSynced), xyflowApi = useXYStoreApi(), diagramStoreApi = useDiagramStoreApi();
8781
+ const xyflowSynced = useDiagramState((s) => s.xyflowSynced), diagramStoreApi = useDiagramStoreApi();
8726
8782
  return useEffect(() => {
8727
8783
  if (xyflowSynced)
8728
8784
  return;
@@ -8730,7 +8786,8 @@ function SyncWithDiagram() {
8730
8786
  view,
8731
8787
  nodesDraggable,
8732
8788
  nodesSelectable,
8733
- focusedNodeId
8789
+ focusedNodeId,
8790
+ xystore
8734
8791
  } = diagramStoreApi.getState(), updates = diagramViewToXYFlowData(view, {
8735
8792
  draggable: nodesDraggable,
8736
8793
  selectable: nodesSelectable || focusedNodeId !== null
@@ -8739,7 +8796,7 @@ function SyncWithDiagram() {
8739
8796
  edgeLookup,
8740
8797
  setNodes,
8741
8798
  setEdges
8742
- } = xyflowApi.getState();
8799
+ } = xystore.getState();
8743
8800
  setNodes(updates.nodes.map((update) => {
8744
8801
  var _a;
8745
8802
  const existing = (_a = nodeLookup.get(update.id)) == null ? void 0 : _a.internals.userNode;
@@ -8749,8 +8806,8 @@ function SyncWithDiagram() {
8749
8806
  } : update;
8750
8807
  })), setEdges(updates.edges.map((update) => {
8751
8808
  const existing = edgeLookup.get(update.id);
8752
- return existing ? deepEqual(existing.data.controlPoints, update.data.controlPoints) && deepEqual(existing.data.edge, update.data.edge) ? existing : {
8753
- ...existing,
8809
+ return existing ? deepEqual(existing.data.controlPoints, update.data.controlPoints) && deepEqual(existing.markerStart, update.markerStart) && deepEqual(existing.markerEnd, update.markerEnd) && deepEqual(existing.data.edge, update.data.edge) ? existing : {
8810
+ ...omit(existing, ["data", "markerStart", "markerEnd"]),
8754
8811
  ...update,
8755
8812
  data: {
8756
8813
  ...existing.data,
@@ -8764,22 +8821,204 @@ function SyncWithDiagram() {
8764
8821
  !1,
8765
8822
  "xyflowSynced"
8766
8823
  );
8767
- }, [xyflowSynced, xyflowApi, diagramStoreApi]), null;
8768
- }
8769
- var container$4 = "bexn7q1", dimmed$2 = "bexn7q2", edgePathBg = "bexn7q3", markerContext = "bexn7q4", controlPoint = "bexn7q5", cssEdgePath = "bexn7q7", varLabelX = "var(--bexn7q8)", varLabelY = "var(--bexn7q9)", edgeLabel = "bexn7qb", stepEdgeNumber = "bexn7qc", edgeLabelText = "bexn7qd";
8770
- function getNodeIntersectionFromCenterToPoint(intersectionNode, { x: x1, y: y1 }) {
8771
- const {
8772
- width: intersectionNodeWidth,
8773
- height: intersectionNodeHeight
8774
- } = getNodeDimensions(intersectionNode), intersectionNodePosition = intersectionNode.internals.positionAbsolute, w = intersectionNodeWidth / 2, h = intersectionNodeHeight / 2, x2 = intersectionNodePosition.x + w, y2 = intersectionNodePosition.y + h, xx1 = (x1 - x2) / (2 * w) - (y1 - y2) / (2 * h), yy1 = (x1 - x2) / (2 * w) + (y1 - y2) / (2 * h), a = 1 / (Math.abs(xx1) + Math.abs(yy1)), xx3 = a * xx1, yy3 = a * yy1, x = w * (xx3 + yy3) + x2, y = h * (-xx3 + yy3) + y2;
8775
- return { x, y };
8824
+ }, [xyflowSynced, diagramStoreApi]), null;
8776
8825
  }
8777
- function bezierPath(bezierSpline) {
8778
- let [start2, ...points] = bezierSpline;
8779
- invariant(start2, "start should be defined");
8780
- let path = `M ${start2[0]},${start2[1]}`;
8781
- for (; hasAtLeast$1(points, 3); ) {
8782
- const [cp1, cp2, end, ...rest] = points;
8826
+ const Open = (props) => /* @__PURE__ */ jsx(
8827
+ "marker",
8828
+ {
8829
+ viewBox: "-4 -4 14 16",
8830
+ refX: 5,
8831
+ refY: 4,
8832
+ markerWidth: "7",
8833
+ markerHeight: "8",
8834
+ preserveAspectRatio: "xMaxYMid meet",
8835
+ orient: "auto-start-reverse",
8836
+ ...props,
8837
+ children: /* @__PURE__ */ jsx(
8838
+ "path",
8839
+ {
8840
+ d: "M0,0 L7,4 L0,8 L4,4 Z",
8841
+ stroke: "context-stroke",
8842
+ fill: "context-stroke",
8843
+ strokeDasharray: 0,
8844
+ strokeWidth: 1,
8845
+ strokeLinecap: "round"
8846
+ }
8847
+ )
8848
+ }
8849
+ ), Arrow = (props) => /* @__PURE__ */ jsx(
8850
+ "marker",
8851
+ {
8852
+ viewBox: "-1 -1 12 10",
8853
+ refX: 4,
8854
+ refY: 3,
8855
+ markerWidth: "8",
8856
+ markerHeight: "6",
8857
+ preserveAspectRatio: "xMaxYMid meet",
8858
+ orient: "auto-start-reverse",
8859
+ ...props,
8860
+ children: /* @__PURE__ */ jsx(
8861
+ "path",
8862
+ {
8863
+ d: "M 0 0 L 8 3 L 0 6 L 1 3 z",
8864
+ fill: "context-stroke",
8865
+ strokeWidth: 0
8866
+ }
8867
+ )
8868
+ }
8869
+ ), OArrow = (props) => /* @__PURE__ */ jsx(
8870
+ "marker",
8871
+ {
8872
+ viewBox: "-1 -1 12 10",
8873
+ refX: 4,
8874
+ refY: 3,
8875
+ markerWidth: "8",
8876
+ markerHeight: "6",
8877
+ preserveAspectRatio: "xMaxYMid meet",
8878
+ orient: "auto-start-reverse",
8879
+ ...props,
8880
+ children: /* @__PURE__ */ jsx(
8881
+ "path",
8882
+ {
8883
+ d: "M 0 0 L 8 3 L 0 6 L 1 3 z",
8884
+ stroke: "context-stroke",
8885
+ fill: "var(--likec4-background-color)",
8886
+ strokeWidth: 1.25,
8887
+ strokeLinejoin: "miter",
8888
+ strokeLinecap: "square"
8889
+ }
8890
+ )
8891
+ }
8892
+ ), Diamond = (props) => /* @__PURE__ */ jsx(
8893
+ "marker",
8894
+ {
8895
+ viewBox: "-4 -4 16 14",
8896
+ refX: 5,
8897
+ refY: 4,
8898
+ markerWidth: "10",
8899
+ markerHeight: "8",
8900
+ preserveAspectRatio: "xMaxYMid meet",
8901
+ orient: "auto-start-reverse",
8902
+ ...props,
8903
+ children: /* @__PURE__ */ jsx(
8904
+ "path",
8905
+ {
8906
+ d: "M5,0 L10,4 L5,8 L0,4 Z",
8907
+ fill: "context-stroke",
8908
+ strokeWidth: 0,
8909
+ strokeLinecap: "round"
8910
+ }
8911
+ )
8912
+ }
8913
+ ), ODiamond = (props) => /* @__PURE__ */ jsx(
8914
+ "marker",
8915
+ {
8916
+ viewBox: "-4 -4 16 14",
8917
+ refX: 6,
8918
+ refY: 4,
8919
+ markerWidth: "10",
8920
+ markerHeight: "8",
8921
+ preserveAspectRatio: "xMaxYMid meet",
8922
+ orient: "auto-start-reverse",
8923
+ ...props,
8924
+ children: /* @__PURE__ */ jsx(
8925
+ "path",
8926
+ {
8927
+ d: "M5,0 L10,4 L5,8 L0,4 Z",
8928
+ stroke: "context-stroke",
8929
+ fill: "var(--likec4-background-color)",
8930
+ strokeWidth: 1.25,
8931
+ strokeLinecap: "round"
8932
+ }
8933
+ )
8934
+ }
8935
+ ), Dot = (props) => /* @__PURE__ */ jsx(
8936
+ "marker",
8937
+ {
8938
+ viewBox: "0 0 10 10",
8939
+ refX: 4,
8940
+ refY: 4,
8941
+ markerWidth: "6",
8942
+ markerHeight: "6",
8943
+ ...props,
8944
+ children: /* @__PURE__ */ jsx(
8945
+ "circle",
8946
+ {
8947
+ strokeWidth: 0,
8948
+ fill: "context-stroke",
8949
+ cx: 4,
8950
+ cy: 4,
8951
+ r: 3
8952
+ }
8953
+ )
8954
+ }
8955
+ ), ODot = (props) => /* @__PURE__ */ jsx(
8956
+ "marker",
8957
+ {
8958
+ viewBox: "0 0 10 10",
8959
+ refX: 4,
8960
+ refY: 4,
8961
+ markerWidth: "6",
8962
+ markerHeight: "6",
8963
+ ...props,
8964
+ children: /* @__PURE__ */ jsx(
8965
+ "circle",
8966
+ {
8967
+ strokeWidth: 1.25,
8968
+ stroke: "context-stroke",
8969
+ fill: "var(--likec4-background-color)",
8970
+ cx: 4,
8971
+ cy: 4,
8972
+ r: 3
8973
+ }
8974
+ )
8975
+ }
8976
+ ), EdgeMarkers = {
8977
+ Arrow,
8978
+ OArrow,
8979
+ Open,
8980
+ Diamond,
8981
+ ODiamond,
8982
+ Dot,
8983
+ ODot
8984
+ };
8985
+ var container$4 = "bexn7q1", dimmed$2 = "bexn7q2", edgePathBg = "bexn7q3", markerContext = "bexn7q4", controlPoint = "bexn7q5", controlDragging = "bexn7q6", cssEdgePath = "bexn7q8", varLabelX = "var(--bexn7q9)", varLabelY = "var(--bexn7qa)", edgeLabel = "bexn7qc", stepEdgeNumber = "bexn7qd", edgeLabelText = "bexn7qe";
8986
+ function getNodeIntersectionFromCenterToPoint(intersectionNode, { x: x1, y: y1 }) {
8987
+ const {
8988
+ width: intersectionNodeWidth,
8989
+ height: intersectionNodeHeight
8990
+ } = getNodeDimensions(intersectionNode), intersectionNodePosition = intersectionNode.internals.positionAbsolute, w = intersectionNodeWidth / 2, h = intersectionNodeHeight / 2, x2 = intersectionNodePosition.x + w, y2 = intersectionNodePosition.y + h, xx1 = (x1 - x2) / (2 * w) - (y1 - y2) / (2 * h), yy1 = (x1 - x2) / (2 * w) + (y1 - y2) / (2 * h), a = 1 / (Math.abs(xx1) + Math.abs(yy1)), xx3 = a * xx1, yy3 = a * yy1, x = w * (xx3 + yy3) + x2, y = h * (-xx3 + yy3) + y2;
8991
+ return { x, y };
8992
+ }
8993
+ const toMarker = (arrowType) => {
8994
+ if (!(!arrowType || arrowType === "none"))
8995
+ switch (arrowType) {
8996
+ case "normal":
8997
+ case "crow":
8998
+ return "Arrow";
8999
+ case "onormal":
9000
+ return "OArrow";
9001
+ case "diamond":
9002
+ return "Diamond";
9003
+ case "odiamond":
9004
+ return "ODiamond";
9005
+ case "open":
9006
+ case "vee":
9007
+ return "Open";
9008
+ case "dot":
9009
+ return "Dot";
9010
+ case "odot":
9011
+ return "ODot";
9012
+ default:
9013
+ nonexhaustive(arrowType);
9014
+ }
9015
+ };
9016
+ function bezierPath(bezierSpline) {
9017
+ let [start2, ...points] = bezierSpline;
9018
+ invariant(start2, "start should be defined");
9019
+ let path = `M ${start2[0]},${start2[1]}`;
9020
+ for (; hasAtLeast$1(points, 3); ) {
9021
+ const [cp1, cp2, end, ...rest] = points;
8783
9022
  path = path + ` C ${cp1[0]},${cp1[1]} ${cp2[0]},${cp2[1]} ${end[0]},${end[1]}`, points = rest;
8784
9023
  }
8785
9024
  return invariant(points.length === 0, "all points should be consumed"), path;
@@ -8787,17 +9026,20 @@ function bezierPath(bezierSpline) {
8787
9026
  const isSame = (a, b) => Math.abs(a - b) < 3.1, isSamePoint = (a, b) => {
8788
9027
  const [ax, ay] = isArray(a) ? a : [a.x, a.y], [bx, by] = isArray(b) ? b : [b.x, b.y];
8789
9028
  return isSame(ax, bx) && isSame(ay, by);
8790
- }, sameControlPoints = (a, b) => a === b ? !0 : !a || !b || a.length !== b.length ? !1 : a.every((ap, i) => isSamePoint(ap, b[i])), isEqualProps$2 = (prev, next) => prev.id === next.id && prev.source === next.source && prev.target === next.target && deepEqual(prev.selected ?? !1, next.selected ?? !1) && isSame(prev.sourceX, next.sourceX) && isSame(prev.sourceY, next.sourceY) && isSame(prev.targetX, next.targetX) && isSame(prev.targetY, next.targetY) && deepEqual(prev.data.stepNum, next.data.stepNum) && sameControlPoints(prev.data.controlPoints, next.data.controlPoints) && deepEqual(prev.data.edge, next.data.edge), curve = line().curve(curveCatmullRomOpen).x((d) => d.x).y((d) => d.y), RelationshipEdge = /* @__PURE__ */ memo(function({
9029
+ }, sameControlPoints = (a, b) => a === b ? !0 : !a || !b || a.length !== b.length ? !1 : a.every((ap, i) => isSamePoint(ap, b[i])), isEqualProps$2 = (prev, next) => prev.id === next.id && deepEqual(prev.source, next.source) && deepEqual(prev.target, next.target) && deepEqual(prev.selected ?? !1, next.selected ?? !1) && isSame(prev.sourceX, next.sourceX) && isSame(prev.sourceY, next.sourceY) && isSame(prev.targetX, next.targetX) && isSame(prev.targetY, next.targetY) && deepEqual(prev.data.stepNum, next.data.stepNum) && sameControlPoints(prev.data.controlPoints, next.data.controlPoints) && deepEqual(prev.data.edge, next.data.edge), curve = line().curve(curveCatmullRomOpen).x((d) => d.x).y((d) => d.y), RelationshipEdge = /* @__PURE__ */ memo(function({
8791
9030
  id: id2,
8792
9031
  data,
8793
- selected: _selected,
9032
+ selected: selected2,
9033
+ sourceX,
9034
+ sourceY,
9035
+ targetX,
9036
+ targetY,
8794
9037
  style: style2,
8795
9038
  source,
8796
9039
  target,
8797
9040
  interactionWidth
8798
9041
  }) {
8799
- var _a, _b;
8800
- const diagramStore = useDiagramStoreApi(), xyflowStore = useXYStoreApi(), { isActive, isEditable, isEdgePathEditable, isHovered, isDimmed } = useDiagramState((s) => ({
9042
+ const [isControlPointDragging, setIsControlPointDragging] = useState(!1), diagramStore = useDiagramStoreApi(), xyflowStore = useXYStoreApi(), { isActive, isEditable, isEdgePathEditable, isHovered, isDimmed } = useDiagramState((s) => ({
8801
9043
  isEditable: s.readonly !== !0,
8802
9044
  isEdgePathEditable: s.readonly !== !0 && s.experimentalEdgeEditing === !0,
8803
9045
  isActive: s.focusedNodeId === source || s.focusedNodeId === target || s.activeDynamicViewStep !== null && s.activeDynamicViewStep === data.stepNum,
@@ -8824,12 +9066,18 @@ const isSame = (a, b) => Math.abs(a - b) < 3.1, isSamePoint = (a, b) => {
8824
9066
  let edgePath;
8825
9067
  if (isModified) {
8826
9068
  labelX = labelPos.x, labelY = labelPos.y;
8827
- const sourceCenterPos = getNodePositionWithOrigin(sourceNode, [-0.5, -0.5]), targetCenterPos = getNodePositionWithOrigin(targetNode, [-0.5, -0.5]), points = [
8828
- sourceCenterPos.positionAbsolute,
8829
- getNodeIntersectionFromCenterToPoint(sourceNode, first(controlPoints)),
9069
+ const sourceCenterPos = { x: sourceX, y: sourceY }, targetCenterPos = { x: targetX, y: targetY }, points = diagramEdge.dir === "back" ? [
9070
+ targetCenterPos,
9071
+ getNodeIntersectionFromCenterToPoint(targetNode, first(controlPoints) ?? sourceCenterPos),
9072
+ ...controlPoints,
9073
+ getNodeIntersectionFromCenterToPoint(sourceNode, last(controlPoints) ?? targetCenterPos),
9074
+ sourceCenterPos
9075
+ ] : [
9076
+ sourceCenterPos,
9077
+ getNodeIntersectionFromCenterToPoint(sourceNode, first(controlPoints) ?? targetCenterPos),
8830
9078
  ...controlPoints,
8831
- getNodeIntersectionFromCenterToPoint(targetNode, last(controlPoints)),
8832
- targetCenterPos.positionAbsolute
9079
+ getNodeIntersectionFromCenterToPoint(targetNode, last(controlPoints) ?? sourceCenterPos),
9080
+ targetCenterPos
8833
9081
  ];
8834
9082
  edgePath = nonNullable(curve(points));
8835
9083
  } else
@@ -8846,31 +9094,44 @@ const isSame = (a, b) => Math.abs(a - b) < 3.1, isSamePoint = (a, b) => {
8846
9094
  }, [edgePath]);
8847
9095
  const onControlPointerDown = (index2, e) => {
8848
9096
  const { domNode } = xyflowStore.getState();
8849
- if (!domNode) return;
9097
+ if (!domNode || e.pointerType !== "mouse")
9098
+ return;
8850
9099
  const { xyflow } = diagramStore.getState();
9100
+ if (e.button === 2 && controlPoints.length > 1) {
9101
+ const newControlPoints = controlPoints.slice();
9102
+ newControlPoints.splice(index2, 1), e.stopPropagation(), setTimeout(() => {
9103
+ xyflow.updateEdgeData(id2, { controlPoints: newControlPoints });
9104
+ }, 10);
9105
+ return;
9106
+ }
9107
+ if (e.button !== 0)
9108
+ return;
8851
9109
  e.stopPropagation();
8852
9110
  let hasMoved = !1, pointer2 = { x: e.clientX, y: e.clientY };
8853
9111
  const onPointerMove = (e2) => {
8854
9112
  if (!isSamePoint(pointer2, [e2.clientX, e2.clientY])) {
8855
- hasMoved || diagramStore.getState().cancelSaveManualLayout(), hasMoved = !0, pointer2 = { x: e2.clientX, y: e2.clientY };
9113
+ setIsControlPointDragging(!0), hasMoved || diagramStore.getState().cancelSaveManualLayout(), hasMoved = !0, pointer2 = { x: e2.clientX, y: e2.clientY };
8856
9114
  const { x, y } = xyflow.screenToFlowPosition(pointer2, { snapToGrid: !1 }), newControlPoints = controlPoints.slice();
8857
9115
  newControlPoints[index2] = {
8858
- x: toDomPrecision(x),
8859
- y: toDomPrecision(y)
9116
+ x: Math.round(x),
9117
+ y: Math.round(y)
8860
9118
  }, xyflow.updateEdgeData(id2, { controlPoints: newControlPoints });
8861
9119
  }
8862
9120
  }, onPointerUp = () => {
8863
- domNode.removeEventListener("pointermove", onPointerMove), domNode.removeEventListener("pointerup", onPointerUp), hasMoved && diagramStore.getState().triggerSaveManualLayout(xyflowStore);
9121
+ setIsControlPointDragging(!1), domNode.removeEventListener("pointermove", onPointerMove), domNode.removeEventListener("pointerup", onPointerUp), hasMoved && diagramStore.getState().triggerSaveManualLayout();
8864
9122
  };
8865
9123
  domNode.addEventListener("pointermove", onPointerMove), domNode.addEventListener("pointerup", onPointerUp, { once: !0 });
8866
- }, marker = `url(#arrow-${id2})`;
8867
- let markerStart = diagramEdge.tailArrow ? marker : void 0, markerEnd = diagramEdge.headArrow ? marker : void 0;
8868
- return isModified && diagramEdge.dir === "back" && ([markerStart, markerEnd] = [markerEnd, markerStart]), /* @__PURE__ */ jsxs(
9124
+ };
9125
+ let markerStartName = toMarker(diagramEdge.tail), markerEndName = toMarker(diagramEdge.head ?? "normal");
9126
+ diagramEdge.dir === "back" && ([markerStartName, markerEndName] = [markerEndName, markerStartName]);
9127
+ const MarkerStart = markerStartName ? EdgeMarkers[markerStartName] : null, MarkerEnd = markerEndName ? EdgeMarkers[markerEndName] : null;
9128
+ return /* @__PURE__ */ jsxs(
8869
9129
  "g",
8870
9130
  {
8871
9131
  className: clsx([
8872
9132
  container$4,
8873
- isDimmed && dimmed$2
9133
+ isDimmed && dimmed$2,
9134
+ isControlPointDragging && controlDragging
8874
9135
  ]),
8875
9136
  "data-likec4-color": color2,
8876
9137
  "data-edge-dir": diagramEdge.dir,
@@ -8888,21 +9149,10 @@ const isSame = (a, b) => Math.abs(a - b) < 3.1, isSamePoint = (a, b) => {
8888
9149
  }
8889
9150
  ),
8890
9151
  /* @__PURE__ */ jsxs("g", { className: markerContext, children: [
8891
- /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsx(
8892
- "marker",
8893
- {
8894
- id: `arrow-${id2}`,
8895
- viewBox: "0 0 16 10",
8896
- refX: isModified ? "15" : "1",
8897
- refY: "5",
8898
- markerWidth: "5",
8899
- markerHeight: "4",
8900
- markerUnits: "strokeWidth",
8901
- preserveAspectRatio: "xMaxYMid meet",
8902
- orient: "auto-start-reverse",
8903
- children: /* @__PURE__ */ jsx("path", { d: "M 0 0 L 16 5 L 0 10 z", stroke: "context-stroke", fill: "context-stroke" })
8904
- }
8905
- ) }),
9152
+ /* @__PURE__ */ jsxs("defs", { children: [
9153
+ MarkerStart && /* @__PURE__ */ jsx(MarkerStart, { id: "start" + id2 }),
9154
+ MarkerEnd && /* @__PURE__ */ jsx(MarkerEnd, { id: "end" + id2 })
9155
+ ] }),
8906
9156
  /* @__PURE__ */ jsx(
8907
9157
  "path",
8908
9158
  {
@@ -8921,58 +9171,97 @@ const isSame = (a, b) => Math.abs(a - b) < 3.1, isSamePoint = (a, b) => {
8921
9171
  style: style2,
8922
9172
  strokeLinecap: "round",
8923
9173
  strokeDasharray,
8924
- markerStart,
8925
- markerEnd
9174
+ markerStart: MarkerStart ? `url(#start${id2})` : void 0,
9175
+ markerEnd: MarkerEnd ? `url(#end${id2})` : void 0
8926
9176
  }
8927
9177
  )
8928
9178
  ] }),
8929
- isEdgePathEditable && controlPoints.map((p, i) => /* @__PURE__ */ jsx(
8930
- "circle",
8931
- {
8932
- onPointerDown: (e) => onControlPointerDown(i, e),
8933
- className: controlPoint,
8934
- cx: p.x,
8935
- cy: p.y,
8936
- r: 3
8937
- },
8938
- i
8939
- )),
8940
- (data.label || isStepEdge) && /* @__PURE__ */ jsx(EdgeLabelRenderer, { children: /* @__PURE__ */ jsxs(
8941
- Box,
9179
+ isEdgePathEditable && /* @__PURE__ */ jsx(
9180
+ "g",
8942
9181
  {
8943
- className: clsx([
8944
- container$4,
8945
- edgeLabel,
8946
- isDimmed && dimmed$2
8947
- ]),
8948
- "data-likec4-color": color2,
8949
- style: {
8950
- ...assignInlineVars({
8951
- [varLabelX]: isModified ? `calc(${labelX}px - 10%)` : `${labelX}px`,
8952
- [varLabelY]: isModified ? `${labelY - 5}px` : `${labelY}px`
8953
- }),
8954
- ...isEdgePathEditable && {
8955
- pointerEvents: "none"
8956
- },
8957
- ...data.label && {
8958
- maxWidth: data.label.bbox.width + 12
8959
- },
8960
- zIndex: ((_a = edgeLookup.get(id2)) == null ? void 0 : _a.zIndex) ?? ZIndexes.Edge
9182
+ onContextMenu: (e) => {
9183
+ e.preventDefault(), e.stopPropagation();
8961
9184
  },
8962
- mod: {
8963
- "data-edge-hovered": isHovered,
8964
- "data-edge-active": isActive
8965
- },
8966
- children: [
8967
- isStepEdge && /* @__PURE__ */ jsx(Box, { className: stepEdgeNumber, children: data.stepNum }),
8968
- ((_b = data.label) == null ? void 0 : _b.text) && /* @__PURE__ */ jsx(Box, { className: edgeLabelText, children: data.label.text })
8969
- ]
9185
+ children: controlPoints.map((p, i) => /* @__PURE__ */ jsx(
9186
+ "circle",
9187
+ {
9188
+ onPointerDown: (e) => onControlPointerDown(i, e),
9189
+ className: controlPoint,
9190
+ cx: p.x,
9191
+ cy: p.y,
9192
+ r: 3
9193
+ },
9194
+ i
9195
+ ))
8970
9196
  }
8971
- ) })
9197
+ ),
9198
+ (data.label || isStepEdge) && /* @__PURE__ */ jsx(
9199
+ EdgeLabel,
9200
+ {
9201
+ isDimmed,
9202
+ color: color2,
9203
+ isModified,
9204
+ labelX,
9205
+ labelY,
9206
+ isEdgePathEditable,
9207
+ selected: selected2 ?? !1,
9208
+ stepNum: data.stepNum,
9209
+ label: data.label,
9210
+ zIndex: edgeLookup.get(id2).zIndex ?? ZIndexes.Edge,
9211
+ isHovered,
9212
+ isActive,
9213
+ isStepEdge
9214
+ }
9215
+ )
8972
9216
  ]
8973
9217
  }
8974
9218
  );
8975
- }, isEqualProps$2);
9219
+ }, isEqualProps$2), EdgeLabel = memo(({
9220
+ isDimmed,
9221
+ color: color2,
9222
+ isModified,
9223
+ labelX,
9224
+ labelY,
9225
+ isEdgePathEditable,
9226
+ selected: selected2,
9227
+ label,
9228
+ stepNum,
9229
+ isHovered,
9230
+ isActive,
9231
+ zIndex
9232
+ }) => /* @__PURE__ */ jsx(EdgeLabelRenderer, { children: /* @__PURE__ */ jsxs(
9233
+ Box,
9234
+ {
9235
+ className: clsx([
9236
+ "nodrag nopan",
9237
+ container$4,
9238
+ edgeLabel,
9239
+ isDimmed && dimmed$2
9240
+ ]),
9241
+ style: {
9242
+ ...assignInlineVars({
9243
+ [varLabelX]: isModified ? `calc(${labelX}px - 10%)` : `${labelX}px`,
9244
+ [varLabelY]: isModified ? `${labelY - 5}px` : `${labelY}px`
9245
+ }),
9246
+ ...isEdgePathEditable && selected2 && {
9247
+ pointerEvents: "none"
9248
+ },
9249
+ ...label && {
9250
+ maxWidth: label.bbox.width + 18
9251
+ },
9252
+ zIndex
9253
+ },
9254
+ mod: {
9255
+ "data-likec4-color": color2,
9256
+ "data-edge-hovered": isHovered,
9257
+ "data-edge-active": isActive
9258
+ },
9259
+ children: [
9260
+ stepNum !== null && /* @__PURE__ */ jsx(Box, { className: stepEdgeNumber, children: stepNum }),
9261
+ isTruthy(label == null ? void 0 : label.text) && /* @__PURE__ */ jsx(Box, { className: edgeLabelText, children: label.text })
9262
+ ]
9263
+ }
9264
+ ) }), deepEqual);
8976
9265
  function NavigateToBtn({ xynodeId, className }) {
8977
9266
  const diagramApi = useDiagramStoreApi();
8978
9267
  return /* @__PURE__ */ jsx(
@@ -8997,14 +9286,13 @@ function NavigateToBtn({ xynodeId, className }) {
8997
9286
  }
8998
9287
  );
8999
9288
  }
9000
- var container$3 = "lbtzdo0", dimmed$1 = "lbtzdo1", varOpacity = "var(--lbtzdo2)", varBorderTransparency = "var(--lbtzdo3)", compoundBody = "lbtzdo4", transparent = "lbtzdo6", title$2 = "lbtzdo7", titleWithNavigation = "lbtzdo8", indicator$1 = "lbtzdoc", navigateBtn = "lbtzdoe";
9289
+ var container$3 = "lbtzdo0", nodeHandlerInCenter = "lbtzdo1", dimmed$1 = "lbtzdo2", varOpacity = "var(--lbtzdo3)", varBorderTransparency = "var(--lbtzdo4)", compoundBody = "lbtzdo5", transparent = "lbtzdo7", title$2 = "lbtzdo8", titleWithNavigation = "lbtzdo9", indicator$1 = "lbtzdod", navigateBtn = "lbtzdof";
9001
9290
  const isEqualProps$1 = (prev, next) => prev.id === next.id && deepEqual(prev.data.element, next.data.element), CompoundNodeMemo = /* @__PURE__ */ memo(function({
9002
9291
  id: id2,
9003
9292
  data: {
9004
9293
  element: element2
9005
9294
  }
9006
9295
  }) {
9007
- DEV && useTilg();
9008
9296
  const { color: color2, style: style2, depth = 1, ...compound } = element2, opacity = clamp$1((style2.opacity ?? 100) / 100, {
9009
9297
  min: 0,
9010
9298
  max: 1
@@ -9016,138 +9304,118 @@ const isEqualProps$1 = (prev, next) => prev.id === next.id && deepEqual(prev.dat
9016
9304
  isDimmed: s.dimmed.has(id2),
9017
9305
  hasOnNavigateTo: !!s.onNavigateTo
9018
9306
  })), isnavigable = !!compound.navigateTo && hasOnNavigateTo;
9019
- return /* @__PURE__ */ jsxs(
9020
- Box,
9021
- {
9022
- className: clsx(
9023
- container$3,
9024
- "likec4-compound-node",
9025
- opacity < 1 && "likec4-compound-transparent",
9026
- isDimmed && dimmed$1
9027
- ),
9028
- mod: {
9029
- "compound-depth": depth,
9030
- "likec4-color": color2,
9031
- hovered: isHovered
9032
- },
9033
- children: [
9034
- /* @__PURE__ */ jsx(
9035
- Handle,
9036
- {
9037
- type: "target",
9038
- position: Position.Top,
9039
- style: { visibility: "hidden" }
9040
- }
9041
- ),
9042
- /* @__PURE__ */ jsx("svg", { className: indicator$1, children: /* @__PURE__ */ jsx(
9043
- "rect",
9044
- {
9045
- x: 0,
9046
- y: 0,
9047
- width: "100%",
9048
- height: "100%",
9049
- rx: 6
9050
- }
9051
- ) }),
9052
- /* @__PURE__ */ jsx(
9053
- "div",
9054
- {
9055
- className: clsx(
9056
- compoundBody,
9057
- opacity < 1 && transparent,
9058
- "likec4-compound"
9059
- ),
9060
- style: opacity < 1 ? {
9061
- ...assignInlineVars({
9062
- [varBorderTransparency]: `${borderTransparency}%`,
9063
- [varOpacity]: opacity.toFixed(2)
9064
- }),
9065
- borderStyle: style2.border ?? "dashed"
9066
- } : void 0,
9067
- children: /* @__PURE__ */ jsx(
9068
- Text,
9069
- {
9070
- component: "div",
9071
- className: clsx(
9072
- title$2,
9073
- isnavigable && titleWithNavigation,
9074
- "likec4-compound-title"
9075
- ),
9076
- children: compound.title
9077
- }
9078
- )
9079
- }
9307
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
9308
+ /* @__PURE__ */ jsx(
9309
+ Handle,
9310
+ {
9311
+ type: "target",
9312
+ position: Position.Top,
9313
+ className: nodeHandlerInCenter
9314
+ }
9315
+ ),
9316
+ /* @__PURE__ */ jsxs(
9317
+ Box,
9318
+ {
9319
+ className: clsx(
9320
+ container$3,
9321
+ "likec4-compound-node",
9322
+ opacity < 1 && "likec4-compound-transparent",
9323
+ isDimmed && dimmed$1
9080
9324
  ),
9081
- isnavigable && /* @__PURE__ */ jsx(NavigateToBtn, { xynodeId: id2, className: navigateBtn }),
9082
- /* @__PURE__ */ jsx(
9083
- Handle,
9084
- {
9085
- type: "source",
9086
- position: Position.Bottom,
9087
- style: { visibility: "hidden" }
9088
- }
9089
- )
9090
- ]
9091
- }
9092
- );
9325
+ mod: {
9326
+ "compound-depth": depth,
9327
+ "likec4-color": color2,
9328
+ hovered: isHovered
9329
+ },
9330
+ children: [
9331
+ /* @__PURE__ */ jsx("svg", { className: indicator$1, children: /* @__PURE__ */ jsx(
9332
+ "rect",
9333
+ {
9334
+ x: 0,
9335
+ y: 0,
9336
+ width: "100%",
9337
+ height: "100%",
9338
+ rx: 6
9339
+ }
9340
+ ) }),
9341
+ /* @__PURE__ */ jsx(
9342
+ "div",
9343
+ {
9344
+ className: clsx(
9345
+ compoundBody,
9346
+ opacity < 1 && transparent,
9347
+ "likec4-compound"
9348
+ ),
9349
+ style: opacity < 1 ? {
9350
+ ...assignInlineVars({
9351
+ [varBorderTransparency]: `${borderTransparency}%`,
9352
+ [varOpacity]: opacity.toFixed(2)
9353
+ }),
9354
+ borderStyle: style2.border ?? "dashed"
9355
+ } : void 0,
9356
+ children: /* @__PURE__ */ jsx(
9357
+ Text,
9358
+ {
9359
+ component: "div",
9360
+ className: clsx(
9361
+ title$2,
9362
+ isnavigable && titleWithNavigation,
9363
+ "likec4-compound-title"
9364
+ ),
9365
+ children: compound.title
9366
+ }
9367
+ )
9368
+ }
9369
+ ),
9370
+ isnavigable && /* @__PURE__ */ jsx(NavigateToBtn, { xynodeId: id2, className: navigateBtn })
9371
+ ]
9372
+ }
9373
+ ),
9374
+ /* @__PURE__ */ jsx(
9375
+ Handle,
9376
+ {
9377
+ type: "source",
9378
+ position: Position.Top,
9379
+ className: nodeHandlerInCenter
9380
+ }
9381
+ )
9382
+ ] });
9093
9383
  }, isEqualProps$1);
9094
- var container$2 = "_1b6tkn2", containerAnimated = "_1b6tkn3", dimmed = "_1b6tkn4", indicator = "_1b6tkn6", fillElementFill = "_1b6tkn7", fillMixStroke = "_1b6tkn9", title$1 = "_1b6tkna", description$1 = "_1b6tknb", technology = "_1b6tknc", element = "_1b6tknd", iconMaxH = "var(--_1b6tkne)", elementIcon = "_1b6tknf", cssShapeSvg = "_1b6tkni", cssNavigateBtn = "_1b6tknj";
9384
+ var container$2 = "_1b6tkn2", handleCenter = "_1b6tkn3", containerAnimated = "_1b6tkn4", dimmed = "_1b6tkn5", indicator = "_1b6tkn8", fillElementFill = "_1b6tkn9", fillMixStroke = "_1b6tknb", title$1 = "_1b6tknc", description$1 = "_1b6tknd", technology = "_1b6tkne", element = "_1b6tknf", iconOffsetY = "var(--_1b6tkng)", elementIcon = "_1b6tkni", cssShapeSvg = "_1b6tknk", cssNavigateBtn = "_1b6tknl";
9095
9385
  function ElementIcon({
9096
- node,
9097
- paddingY = 32
9386
+ node: {
9387
+ icon,
9388
+ title: title2,
9389
+ labelBBox
9390
+ }
9098
9391
  }) {
9099
- if (!node.icon)
9100
- return null;
9101
- const firstLabel = node.labels[0];
9102
- if (!firstLabel)
9103
- return null;
9104
- const firstLabelY = Math.floor(firstLabel.pt[1] - firstLabel.fontSize * 1.25), maxIconHeight = Math.floor(firstLabelY - paddingY - 16);
9105
- return /* @__PURE__ */ jsx(
9392
+ return icon ? /* @__PURE__ */ jsx(
9106
9393
  "div",
9107
9394
  {
9108
9395
  className: clsx(elementIcon, "likec4-element-icon"),
9109
- style: assignInlineVars({ iconMaxH }, {
9110
- iconMaxH: maxIconHeight + "px"
9396
+ style: assignInlineVars({ iconOffsetY }, {
9397
+ iconOffsetY: labelBBox.y + "px"
9111
9398
  }),
9112
9399
  children: /* @__PURE__ */ jsx(
9113
9400
  "img",
9114
9401
  {
9115
- src: node.icon,
9116
- alt: node.title
9402
+ src: icon,
9403
+ alt: title2
9117
9404
  }
9118
9405
  )
9119
9406
  }
9120
- );
9407
+ ) : null;
9121
9408
  }
9122
- const Link = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
9123
- "svg",
9124
- {
9125
- ref,
9126
- className: clsx("icon icon-tabler", className),
9127
- stroke: "currentColor",
9128
- fill: "currentColor",
9129
- strokeWidth: "0",
9130
- viewBox: "0 0 20 20",
9131
- height: "20",
9132
- width: "20",
9133
- xmlns: "http://www.w3.org/2000/svg",
9134
- ...props,
9135
- children: /* @__PURE__ */ jsx(
9136
- "path",
9137
- {
9138
- fillRule: "evenodd",
9139
- 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",
9140
- clipRule: "evenodd"
9141
- }
9142
- )
9143
- }
9144
- ));
9145
9409
  var elementLink = "_4ysv0o0", trigger = "_4ysv0o1";
9410
+ const selector$2 = (s) => {
9411
+ const target = s.getContainer();
9412
+ return target ? { target } : null;
9413
+ };
9146
9414
  function ElementLink({
9147
9415
  element: element2
9148
9416
  }) {
9149
9417
  invariant(element2.links, "ElementLink: links are required");
9150
- const id2 = useId();
9418
+ const id2 = useId(), portalProps = useDiagramState(selector$2);
9151
9419
  return /* @__PURE__ */ jsx("div", { className: elementLink, "data-likec4-linkid": id2, children: /* @__PURE__ */ jsxs(
9152
9420
  HoverCard,
9153
9421
  {
@@ -9160,7 +9428,7 @@ function ElementLink({
9160
9428
  transitionProps: {
9161
9429
  transition: "pop"
9162
9430
  },
9163
- withinPortal: !1,
9431
+ ...portalProps ? { portalProps } : { withinPortal: !1 },
9164
9432
  floatingStrategy: "fixed",
9165
9433
  openDelay: 350,
9166
9434
  closeDelay: 800,
@@ -9175,7 +9443,7 @@ function ElementLink({
9175
9443
  className: clsx("nodrag nopan", trigger),
9176
9444
  autoFocus: !1,
9177
9445
  children: [
9178
- /* @__PURE__ */ jsx(Link, {}),
9446
+ /* @__PURE__ */ jsx(IconLink, { size: 12 }),
9179
9447
  /* @__PURE__ */ jsx("span", { children: "links" })
9180
9448
  ]
9181
9449
  }
@@ -9399,17 +9667,17 @@ const selectedScale = 1.015, variants = {
9399
9667
  // tap: {
9400
9668
  // scale: 0.9
9401
9669
  // }
9402
- }, isEqualProps = (prev, next) => prev.id === next.id && deepEqual(prev.selected ?? !1, next.selected ?? !1) && deepEqual(prev.dragging ?? !1, next.dragging ?? !1) && deepEqual(prev.width ?? 0, next.width ?? 0) && deepEqual(prev.height ?? 0, next.height ?? 0) && deepEqual(prev.data.element, next.data.element), ElementNodeMemo = memo(function({
9670
+ }, isEqualProps = (prev, next) => prev.id === next.id && deepEqual(prev.selected ?? !1, next.selected ?? !1) && deepEqual(prev.dragging ?? !1, next.dragging ?? !1) && deepEqual(prev.draggable ?? !1, next.draggable ?? !1) && deepEqual(prev.width ?? 0, next.width ?? 0) && deepEqual(prev.height ?? 0, next.height ?? 0) && deepEqual(prev.data.element, next.data.element), ElementNodeMemo = memo(function({
9403
9671
  id: id2,
9404
9672
  data: {
9405
9673
  element: element$1
9406
9674
  },
9407
9675
  dragging,
9676
+ // draggable = false,
9408
9677
  selected: selected2 = !1,
9409
9678
  width,
9410
9679
  height
9411
9680
  }) {
9412
- DEV && useTilg();
9413
9681
  const { isHovered, isDimmed, hasOnNavigateTo, isHovercards, isInteractive } = useDiagramState((s) => ({
9414
9682
  isHovered: s.hoveredNodeId === id2,
9415
9683
  isDimmed: s.dimmed.has(id2),
@@ -9432,211 +9700,234 @@ const selectedScale = 1.015, variants = {
9432
9700
  animate = "selected";
9433
9701
  break;
9434
9702
  }
9435
- return /* @__PURE__ */ jsxs(
9436
- m.div,
9437
- {
9438
- id: id2,
9439
- className: clsx([
9440
- container$2,
9441
- isDimmed && dimmed,
9442
- animate !== "idle" && containerAnimated,
9443
- "likec4-element-node"
9444
- ]),
9445
- "data-hovered": !dragging && isHovered,
9446
- "data-likec4-color": element$1.color,
9447
- "data-likec4-shape": element$1.shape,
9448
- variants,
9449
- initial: !1,
9450
- animate,
9451
- ...isInteractive && {
9452
- whileTap: dragging ? animate : "tap"
9453
- },
9454
- children: [
9455
- /* @__PURE__ */ jsx(
9456
- Handle,
9457
- {
9458
- type: "target",
9459
- position: Position.Top,
9460
- style: { visibility: "hidden" }
9461
- }
9462
- ),
9463
- /* @__PURE__ */ jsxs(
9464
- "svg",
9465
- {
9466
- className: clsx(
9467
- cssShapeSvg
9468
- ),
9469
- viewBox: `0 0 ${w} ${h}`,
9470
- width: w,
9471
- height: h,
9472
- children: [
9473
- /* @__PURE__ */ jsx("g", { className: indicator, children: /* @__PURE__ */ jsx(
9474
- SelectedIndicator,
9475
- {
9476
- shape: element$1.shape,
9477
- w,
9478
- h
9479
- }
9480
- ) }),
9481
- /* @__PURE__ */ jsx(
9482
- ElementShapeSvg,
9483
- {
9484
- shape: element$1.shape,
9485
- w,
9486
- h
9487
- }
9488
- )
9489
- ]
9490
- }
9491
- ),
9492
- /* @__PURE__ */ jsxs("div", { className: clsx(element, "likec4-element"), children: [
9493
- element$1.icon && /* @__PURE__ */ jsx(ElementIcon, { node: element$1 }),
9494
- /* @__PURE__ */ jsx(
9495
- Text,
9496
- {
9497
- component: "div",
9498
- className: clsx(title$1, "likec4-element-title"),
9499
- children: element$1.title
9500
- }
9501
- ),
9502
- element$1.technology && /* @__PURE__ */ jsx(
9503
- Text,
9703
+ return /* @__PURE__ */ jsxs(Fragment, { children: [
9704
+ /* @__PURE__ */ jsx(
9705
+ Handle,
9706
+ {
9707
+ type: "target",
9708
+ position: Position.Top,
9709
+ className: handleCenter
9710
+ }
9711
+ ),
9712
+ /* @__PURE__ */ jsxs(
9713
+ m.div,
9714
+ {
9715
+ id: id2,
9716
+ className: clsx([
9717
+ container$2,
9718
+ isDimmed && dimmed,
9719
+ animate !== "idle" && containerAnimated,
9720
+ "likec4-element-node"
9721
+ ]),
9722
+ "data-hovered": !dragging && isHovered,
9723
+ "data-likec4-color": element$1.color,
9724
+ "data-likec4-shape": element$1.shape,
9725
+ variants,
9726
+ initial: !1,
9727
+ animate,
9728
+ ...isInteractive && {
9729
+ whileTap: dragging ? animate : "tap"
9730
+ },
9731
+ children: [
9732
+ /* @__PURE__ */ jsxs(
9733
+ "svg",
9504
9734
  {
9505
- component: "div",
9506
- className: clsx(technology, "likec4-element-technology"),
9507
- children: element$1.technology
9735
+ className: clsx(
9736
+ cssShapeSvg
9737
+ ),
9738
+ viewBox: `0 0 ${w} ${h}`,
9739
+ width: w,
9740
+ height: h,
9741
+ children: [
9742
+ /* @__PURE__ */ jsx("g", { className: indicator, children: /* @__PURE__ */ jsx(
9743
+ SelectedIndicator,
9744
+ {
9745
+ shape: element$1.shape,
9746
+ w,
9747
+ h
9748
+ }
9749
+ ) }),
9750
+ /* @__PURE__ */ jsx(
9751
+ ElementShapeSvg,
9752
+ {
9753
+ shape: element$1.shape,
9754
+ w,
9755
+ h
9756
+ }
9757
+ )
9758
+ ]
9508
9759
  }
9509
9760
  ),
9510
- element$1.description && /* @__PURE__ */ jsx(
9511
- Text,
9512
- {
9513
- component: "div",
9514
- className: clsx(description$1, "likec4-element-description"),
9515
- children: element$1.description
9516
- }
9517
- )
9518
- ] }),
9519
- /* @__PURE__ */ jsx(
9520
- Handle,
9521
- {
9522
- type: "source",
9523
- position: Position.Bottom,
9524
- style: { visibility: "hidden" }
9525
- }
9526
- ),
9527
- isHovercards && element$1.links && /* @__PURE__ */ jsx(ElementLink, { element: element$1 }),
9528
- isNavigable && /* @__PURE__ */ jsx(NavigateToBtn, { xynodeId: id2, className: cssNavigateBtn })
9529
- ]
9530
- }
9531
- );
9761
+ /* @__PURE__ */ jsxs("div", { className: clsx(element, "likec4-element"), children: [
9762
+ /* @__PURE__ */ jsx(ElementIcon, { node: element$1 }),
9763
+ /* @__PURE__ */ jsx(
9764
+ Text,
9765
+ {
9766
+ component: "div",
9767
+ className: clsx(title$1, "likec4-element-title"),
9768
+ children: element$1.title
9769
+ }
9770
+ ),
9771
+ element$1.technology && /* @__PURE__ */ jsx(
9772
+ Text,
9773
+ {
9774
+ component: "div",
9775
+ className: clsx(technology, "likec4-element-technology"),
9776
+ children: element$1.technology
9777
+ }
9778
+ ),
9779
+ element$1.description && /* @__PURE__ */ jsx(
9780
+ Text,
9781
+ {
9782
+ component: "div",
9783
+ className: clsx(description$1, "likec4-element-description"),
9784
+ children: element$1.description
9785
+ }
9786
+ )
9787
+ ] }),
9788
+ isHovercards && element$1.links && /* @__PURE__ */ jsx(ElementLink, { element: element$1 }),
9789
+ isNavigable && /* @__PURE__ */ jsx(NavigateToBtn, { xynodeId: id2, className: cssNavigateBtn })
9790
+ ]
9791
+ }
9792
+ ),
9793
+ /* @__PURE__ */ jsx(
9794
+ Handle,
9795
+ {
9796
+ type: "source",
9797
+ position: Position.Top,
9798
+ className: handleCenter
9799
+ }
9800
+ )
9801
+ ] });
9532
9802
  }, isEqualProps);
9533
9803
  function useXYFlowEvents() {
9534
- const diagramApi = useDiagramStoreApi(), xyflowApi = useXYStoreApi(), lastClickTimestamp = useRef(), dblclickTimeout = useRef(), dbclickLock = () => dblclickTimeout.current !== void 0 ? !0 : (dblclickTimeout.current = window.setTimeout(() => {
9535
- dblclickTimeout.current = void 0;
9536
- }, 250), !1), lastClickWasRecent = (ms = 1500) => lastClickTimestamp.current && Date.now() - lastClickTimestamp.current < ms, hoveredNodeFromOnEdgeEnterRef = useRef("");
9537
- return useMemo(() => ({
9538
- onDoubleClick: (event) => {
9539
- const {
9540
- fitViewEnabled,
9541
- onCanvasDblClick,
9542
- resetLastClicked,
9543
- fitDiagram
9544
- } = diagramApi.getState();
9545
- fitViewEnabled && (fitDiagram(xyflowApi), onCanvasDblClick || event.stopPropagation()), resetLastClicked(), onCanvasDblClick == null || onCanvasDblClick(event);
9546
- },
9547
- onPaneClick: (event) => {
9548
- if (dbclickLock())
9549
- return;
9550
- const {
9551
- focusedNodeId,
9552
- activeDynamicViewStep,
9553
- fitDiagram,
9554
- onCanvasClick,
9555
- resetLastClicked
9556
- } = diagramApi.getState();
9557
- (focusedNodeId || activeDynamicViewStep) && (fitDiagram(xyflowApi), onCanvasClick || event.stopPropagation()), resetLastClicked(), onCanvasClick == null || onCanvasClick(event);
9558
- },
9559
- onNodeContextMenu: (event, xynode) => {
9560
- var _a, _b;
9561
- diagramApi.getState().setLastClickedNode(xynode.id), (_b = (_a = diagramApi.getState()).onNodeContextMenu) == null || _b.call(_a, {
9562
- element: xynode.data.element,
9563
- xynode,
9564
- event
9565
- });
9566
- },
9567
- onPaneContextMenu: (event) => {
9568
- var _a, _b;
9569
- diagramApi.getState().resetLastClicked(), (_b = (_a = diagramApi.getState()).onCanvasContextMenu) == null || _b.call(_a, event);
9570
- },
9571
- onEdgeContextMenu: (event, xyedge) => {
9572
- var _a, _b;
9573
- diagramApi.getState().setLastClickedEdge(xyedge.id), (_b = (_a = diagramApi.getState()).onEdgeContextMenu) == null || _b.call(_a, {
9574
- relation: xyedge.data.edge,
9575
- xyedge,
9576
- event
9577
- });
9578
- },
9579
- onNodeClick: (event, xynode) => {
9580
- const {
9581
- zoomable,
9582
- fitViewEnabled,
9583
- focusedNodeId,
9584
- focusOnNode,
9585
- onNodeClick,
9586
- lastClickedNodeId,
9587
- setLastClickedNode
9588
- } = diagramApi.getState();
9589
- setLastClickedNode(xynode.id);
9590
- const focusPossible = zoomable && fitViewEnabled, shallChangeFocus = !!focusedNodeId && focusedNodeId !== xynode.id, clickedRecently = isNullish(focusedNodeId) && lastClickedNodeId === xynode.id && lastClickWasRecent();
9591
- focusPossible && (shallChangeFocus || clickedRecently) && (focusOnNode(xynode.id), onNodeClick || event.stopPropagation()), lastClickTimestamp.current = Date.now(), onNodeClick == null || onNodeClick({
9592
- element: xynode.data.element,
9593
- xynode,
9594
- event
9595
- });
9596
- },
9597
- onNodeDoubleClick: (event, xynode) => {
9598
- const {
9599
- focusedNodeId,
9600
- zoomable,
9601
- fitViewEnabled,
9602
- fitDiagram,
9603
- focusOnNode,
9604
- setLastClickedNode
9605
- } = diagramApi.getState();
9606
- setLastClickedNode(xynode.id), (focusedNodeId || zoomable && fitViewEnabled) && (focusedNodeId === xynode.id ? fitDiagram(xyflowApi) : focusOnNode(xynode.id), event.stopPropagation());
9607
- },
9608
- onEdgeClick: (event, xyedge) => {
9609
- diagramApi.getState().setLastClickedEdge(xyedge.id);
9610
- const { focusedNodeId, focusOnNode, onEdgeClick } = diagramApi.getState();
9611
- focusedNodeId && (focusedNodeId === xyedge.source || focusedNodeId === xyedge.target) && (focusOnNode(focusedNodeId === xyedge.source ? xyedge.target : xyedge.source), onEdgeClick || event.stopPropagation()), onEdgeClick == null || onEdgeClick({
9612
- relation: xyedge.data.edge,
9613
- xyedge,
9614
- event
9615
- });
9616
- },
9617
- onMoveEnd: (event, _viewport) => {
9618
- const viewportChanged = !!event;
9619
- viewportChanged !== diagramApi.getState().viewportChanged && diagramApi.setState({ viewportChanged }, !1, `viewport-changed: ${viewportChanged}`);
9620
- },
9621
- onNodeMouseEnter: (_event, xynode) => {
9622
- hoveredNodeFromOnEdgeEnterRef.current = "", diagramApi.getState().setHoveredNode(xynode.id);
9623
- },
9624
- onNodeMouseLeave: (_event, xynode) => {
9625
- const { hoveredNodeId, setHoveredNode } = diagramApi.getState();
9626
- hoveredNodeId === xynode.id && setHoveredNode(null);
9627
- },
9628
- onEdgeMouseEnter: (_event, { id: id2, source, target }) => {
9629
- const { hoveredNodeId, focusedNodeId, setHoveredEdge, setHoveredNode } = diagramApi.getState();
9630
- if (setHoveredEdge(id2), (focusedNodeId === source || focusedNodeId === target) && focusedNodeId !== hoveredNodeId) {
9631
- const next = hoveredNodeFromOnEdgeEnterRef.current = source === focusedNodeId ? target : source;
9632
- setHoveredNode(next);
9804
+ const diagramApi = useDiagramStoreApi(), lastClickTimestamp = useRef(), dblclickTimeout = useRef(), hoveredNodeFromOnEdgeEnterRef = useRef("");
9805
+ return useMemo(() => {
9806
+ const dbclickLock = () => dblclickTimeout.current !== void 0 ? !0 : (dblclickTimeout.current = window.setTimeout(() => {
9807
+ dblclickTimeout.current = void 0;
9808
+ }, 250), !1), lastClickWasRecent = (ms = 1500) => lastClickTimestamp.current && Date.now() - lastClickTimestamp.current < ms;
9809
+ return {
9810
+ onDoubleClick: (event) => {
9811
+ const {
9812
+ fitViewEnabled,
9813
+ onCanvasDblClick,
9814
+ resetLastClicked,
9815
+ fitDiagram
9816
+ } = diagramApi.getState();
9817
+ fitViewEnabled && (fitDiagram(), onCanvasDblClick || event.stopPropagation()), resetLastClicked(), onCanvasDblClick == null || onCanvasDblClick(event);
9818
+ },
9819
+ onPaneClick: (event) => {
9820
+ if (dbclickLock())
9821
+ return;
9822
+ const {
9823
+ focusedNodeId,
9824
+ activeDynamicViewStep,
9825
+ fitDiagram,
9826
+ onCanvasClick,
9827
+ resetLastClicked
9828
+ } = diagramApi.getState();
9829
+ (focusedNodeId ?? activeDynamicViewStep) !== null && (fitDiagram(), onCanvasClick || event.stopPropagation()), resetLastClicked(), onCanvasClick == null || onCanvasClick(event);
9830
+ },
9831
+ onNodeContextMenu: (event, xynode) => {
9832
+ var _a, _b;
9833
+ diagramApi.getState().setLastClickedNode(xynode.id), (_b = (_a = diagramApi.getState()).onNodeContextMenu) == null || _b.call(_a, {
9834
+ element: xynode.data.element,
9835
+ xynode,
9836
+ event
9837
+ });
9838
+ },
9839
+ onPaneContextMenu: (event) => {
9840
+ var _a, _b;
9841
+ diagramApi.getState().resetLastClicked(), (_b = (_a = diagramApi.getState()).onCanvasContextMenu) == null || _b.call(_a, event);
9842
+ },
9843
+ onEdgeContextMenu: (event, xyedge) => {
9844
+ var _a, _b;
9845
+ diagramApi.getState().setLastClickedEdge(xyedge.id), (_b = (_a = diagramApi.getState()).onEdgeContextMenu) == null || _b.call(_a, {
9846
+ edge: xyedge.data.edge,
9847
+ xyedge,
9848
+ event
9849
+ });
9850
+ },
9851
+ onNodeClick: (event, xynode) => {
9852
+ const {
9853
+ zoomable,
9854
+ fitViewEnabled,
9855
+ focusedNodeId,
9856
+ fitDiagram,
9857
+ focusOnNode,
9858
+ onNodeClick,
9859
+ lastClickedNodeId,
9860
+ setLastClickedNode
9861
+ } = diagramApi.getState();
9862
+ setLastClickedNode(xynode.id);
9863
+ const focusPossible = zoomable && fitViewEnabled, shallChangeFocus = !!focusedNodeId && focusedNodeId !== xynode.id, clickedRecently = lastClickedNodeId === xynode.id && lastClickWasRecent();
9864
+ if (focusPossible) {
9865
+ let stopPropagation = !1;
9866
+ switch (!0) {
9867
+ case (!focusedNodeId && clickedRecently):
9868
+ case shallChangeFocus:
9869
+ stopPropagation = !0, focusOnNode(xynode.id);
9870
+ break;
9871
+ case (focusedNodeId === xynode.id && clickedRecently):
9872
+ stopPropagation = !0, fitDiagram();
9873
+ break;
9874
+ }
9875
+ !onNodeClick && stopPropagation && event.stopPropagation();
9876
+ }
9877
+ lastClickTimestamp.current = Date.now(), onNodeClick == null || onNodeClick({
9878
+ element: xynode.data.element,
9879
+ xynode,
9880
+ event
9881
+ });
9882
+ },
9883
+ onNodeDoubleClick: (event, xynode) => {
9884
+ const {
9885
+ focusedNodeId,
9886
+ zoomable,
9887
+ fitViewEnabled,
9888
+ fitDiagram,
9889
+ focusOnNode,
9890
+ setLastClickedNode
9891
+ } = diagramApi.getState();
9892
+ setLastClickedNode(xynode.id), lastClickTimestamp.current = Date.now(), (focusedNodeId || zoomable && fitViewEnabled) && (focusedNodeId === xynode.id ? fitDiagram() : focusOnNode(xynode.id), event.stopPropagation());
9893
+ },
9894
+ onEdgeClick: (event, xyedge) => {
9895
+ diagramApi.getState().setLastClickedEdge(xyedge.id);
9896
+ const {
9897
+ focusedNodeId,
9898
+ focusOnNode,
9899
+ onEdgeClick
9900
+ } = diagramApi.getState();
9901
+ focusedNodeId && (focusedNodeId === xyedge.source || focusedNodeId === xyedge.target) && (focusOnNode(focusedNodeId === xyedge.source ? xyedge.target : xyedge.source), onEdgeClick || event.stopPropagation()), onEdgeClick == null || onEdgeClick({
9902
+ edge: xyedge.data.edge,
9903
+ xyedge,
9904
+ event
9905
+ });
9906
+ },
9907
+ onMoveEnd: (event, _viewport) => {
9908
+ const viewportChanged = !!event;
9909
+ viewportChanged !== diagramApi.getState().viewportChanged && diagramApi.setState({ viewportChanged }, !1, `viewport-changed: ${viewportChanged}`);
9910
+ },
9911
+ onNodeMouseEnter: (_event, xynode) => {
9912
+ hoveredNodeFromOnEdgeEnterRef.current = "", diagramApi.getState().setHoveredNode(xynode.id);
9913
+ },
9914
+ onNodeMouseLeave: (_event, xynode) => {
9915
+ const { hoveredNodeId, setHoveredNode } = diagramApi.getState();
9916
+ hoveredNodeId === xynode.id && setHoveredNode(null);
9917
+ },
9918
+ onEdgeMouseEnter: (_event, { id: id2, source, target }) => {
9919
+ const { hoveredNodeId, focusedNodeId, setHoveredEdge, setHoveredNode } = diagramApi.getState();
9920
+ if (setHoveredEdge(id2), (focusedNodeId === source || focusedNodeId === target) && focusedNodeId !== hoveredNodeId) {
9921
+ const next = hoveredNodeFromOnEdgeEnterRef.current = source === focusedNodeId ? target : source;
9922
+ setHoveredNode(next);
9923
+ }
9924
+ },
9925
+ onEdgeMouseLeave: (_event, xyedge) => {
9926
+ const { hoveredEdgeId, setHoveredEdge, hoveredNodeId, setHoveredNode } = diagramApi.getState();
9927
+ hoveredEdgeId === xyedge.id && setHoveredEdge(null), hoveredNodeId === hoveredNodeFromOnEdgeEnterRef.current && setHoveredNode(null), hoveredNodeFromOnEdgeEnterRef.current = "";
9633
9928
  }
9634
- },
9635
- onEdgeMouseLeave: (_event, xyedge) => {
9636
- const { hoveredEdgeId, setHoveredEdge, hoveredNodeId, setHoveredNode } = diagramApi.getState();
9637
- hoveredEdgeId === xyedge.id && setHoveredEdge(null), hoveredNodeId === hoveredNodeFromOnEdgeEnterRef.current && setHoveredNode(null), hoveredNodeFromOnEdgeEnterRef.current = "";
9638
- }
9639
- }), [diagramApi, xyflowApi]);
9929
+ };
9930
+ }, [diagramApi]);
9640
9931
  }
9641
9932
  const nodeTypes = {
9642
9933
  element: ElementNodeMemo,
@@ -9721,9 +10012,6 @@ function XYFlow({
9721
10012
  elementsSelectable: nodesSelectable,
9722
10013
  nodesFocusable: nodesDraggable || nodesSelectable || hasOnNodeClick || hasOnNavigateTo,
9723
10014
  edgesFocusable: hasOnEdgeClick,
9724
- ...!nodesSelectable && {
9725
- selectionKeyCode: null
9726
- },
9727
10015
  nodesDraggable,
9728
10016
  ...nodesDraggable && {
9729
10017
  onNodeDragStart: layoutConstraints.onNodeDragStart,
@@ -9733,6 +10021,7 @@ function XYFlow({
9733
10021
  zoomOnDoubleClick: !1,
9734
10022
  elevateNodesOnSelect: !1,
9735
10023
  selectNodesOnDrag: !1,
10024
+ selectionKeyCode: null,
9736
10025
  onDoubleClick: handlers.onDoubleClick,
9737
10026
  onPaneClick: handlers.onPaneClick,
9738
10027
  onMoveEnd: handlers.onMoveEnd,
@@ -9759,26 +10048,6 @@ function XYFlow({
9759
10048
  }
9760
10049
  );
9761
10050
  }
9762
- function useNavigationHistory() {
9763
- const store = useDiagramStoreApi(), viewId = useDiagramState((s) => s.view.id), [historyViewId, historyOps, {
9764
- history,
9765
- current: historyIndex
9766
- }] = useStateHistory(viewId), hasBack = historyIndex > 0, hasForward = historyIndex < history.length - 1;
9767
- return useUpdateEffect(() => {
9768
- viewId !== historyViewId && historyOps.set(viewId);
9769
- }, [viewId]), useUpdateEffect(() => {
9770
- var _a, _b;
9771
- viewId !== historyViewId && ((_b = (_a = store.getState()).onNavigateTo) == null || _b.call(_a, historyViewId));
9772
- }, [historyViewId]), useMemo(() => ({
9773
- hasBack,
9774
- hasForward,
9775
- ops: historyOps
9776
- }), [
9777
- hasBack,
9778
- hasForward,
9779
- historyOps
9780
- ]);
9781
- }
9782
10051
  var panel$1 = "_19mimxc0";
9783
10052
  function BackwardForwardPanel() {
9784
10053
  const { hasBack, hasForward, ops } = useNavigationHistory();
@@ -9870,10 +10139,12 @@ function DiagramTitlePanel() {
9870
10139
  {
9871
10140
  radius: "sm",
9872
10141
  className: card,
10142
+ withBorder: !0,
9873
10143
  p: "md",
10144
+ pb: isCollapsed ? "sm" : "md",
9874
10145
  onDoubleClick: (e) => e.stopPropagation(),
9875
10146
  children: [
9876
- /* @__PURE__ */ jsx(CardSection, { mb: 4, children: /* @__PURE__ */ jsx(
10147
+ /* @__PURE__ */ jsx(CardSection, { mb: isCollapsed ? 10 : "sm", children: /* @__PURE__ */ jsx(
9877
10148
  Button,
9878
10149
  {
9879
10150
  fullWidth: !0,
@@ -9881,7 +10152,7 @@ function DiagramTitlePanel() {
9881
10152
  h: "sm",
9882
10153
  py: 2,
9883
10154
  radius: "0",
9884
- variant: "subtle",
10155
+ variant: isCollapsed ? "light" : "subtle",
9885
10156
  color: "gray",
9886
10157
  onClick: toggle,
9887
10158
  children: /* @__PURE__ */ jsx(IconMenu, { size: 11, opacity: 0.7 })
@@ -10028,6 +10299,8 @@ function DynamicViewWalkthrough() {
10028
10299
  Box,
10029
10300
  {
10030
10301
  className: clsx("react-flow__panel", container),
10302
+ onClick: (e) => e.stopPropagation(),
10303
+ onDoubleClick: (e) => e.stopPropagation(),
10031
10304
  children: [
10032
10305
  isNullish(activeDynamicViewStep) && /* @__PURE__ */ jsx(
10033
10306
  Button,
@@ -10040,7 +10313,7 @@ function DynamicViewWalkthrough() {
10040
10313
  children: "Start"
10041
10314
  }
10042
10315
  ),
10043
- isNumber(activeDynamicViewStep) && /* @__PURE__ */ jsxs(Button.Group, { className: buttons, children: [
10316
+ isNumber(activeDynamicViewStep) && /* @__PURE__ */ jsxs(ButtonGroup, { className: buttons, children: [
10044
10317
  /* @__PURE__ */ jsx(
10045
10318
  Button,
10046
10319
  {
@@ -10088,17 +10361,16 @@ const {
10088
10361
  { key: "primary", value: primary.fill },
10089
10362
  { key: "secondary", value: secondary.fill },
10090
10363
  { key: "muted", value: muted.fill }
10091
- ], colors = keys.strict(otherColors).map((key) => ({
10364
+ ], colors = keys(otherColors).map((key) => ({
10092
10365
  key,
10093
10366
  value: defaultTheme.elements[key].fill
10094
- }));
10095
- function NodeOptions({ selectedNodeIds }) {
10367
+ })), NodeOptions = memo(({ selectedNodeIds }) => {
10096
10368
  const diagramApi = useDiagramStoreApi(), nodes = useXYNodesData(selectedNodeIds);
10097
10369
  if (!hasAtLeast$1(nodes, 1))
10098
10370
  return null;
10099
10371
  if (nodes.length !== selectedNodeIds.length)
10100
10372
  throw new Error("NodeOptions: nodes and props.nodes should have the same length");
10101
- const showShapeOption = nodes.some((node) => node.type === "element"), [firstNode, ...rest] = nodes, showOpacityOption = rest.length === 0 && firstNode.type === "compound", triggerChange = (style2) => {
10373
+ const showShapeOption = nodes.some((node) => node.type === "element"), [firstNode, ...rest] = nodes, showOpacityOption = firstNode.type === "compound" && (rest.length === 0 || rest.every((node) => node.type === "compound")), triggerChange = (style2) => {
10102
10374
  const targets = nodes.map((node) => node.data.element.id);
10103
10375
  invariant(hasAtLeast$1(targets, 1), "At least one target is required"), diagramApi.getState().triggerChangeElementStyle({
10104
10376
  op: "change-element-style",
@@ -10106,8 +10378,14 @@ function NodeOptions({ selectedNodeIds }) {
10106
10378
  targets
10107
10379
  });
10108
10380
  };
10109
- return /* @__PURE__ */ jsxs(Stack, { children: [
10110
- /* @__PURE__ */ jsx("div", { children: /* @__PURE__ */ jsx(Text, { size: "xs", c: rest.length > 0 ? "dimmed" : "", truncate: !0, children: rest.length === 0 ? firstNode.data.element.title : "[ multiple ]" }) }),
10381
+ return /* @__PURE__ */ jsxs(Stack, { gap: "xs", children: [
10382
+ /* @__PURE__ */ jsxs("div", { children: [
10383
+ /* @__PURE__ */ jsxs(Text, { fz: rem(9), fw: "500", c: "dimmed", children: [
10384
+ "ELEMENT",
10385
+ rest.length > 0 ? "S" : ""
10386
+ ] }),
10387
+ /* @__PURE__ */ jsx(Text, { size: "xs", c: rest.length > 0 ? "dimmed" : "", truncate: !0, children: rest.length === 0 ? firstNode.data.element.title : "[ multiple ]" })
10388
+ ] }),
10111
10389
  showShapeOption && /* @__PURE__ */ jsx(
10112
10390
  ShapeOption,
10113
10391
  {
@@ -10128,6 +10406,7 @@ function NodeOptions({ selectedNodeIds }) {
10128
10406
  ),
10129
10407
  showOpacityOption && /* @__PURE__ */ jsxs("div", { children: [
10130
10408
  /* @__PURE__ */ jsx(Divider, { label: "opacity and border", labelPosition: "left" }),
10409
+ /* @__PURE__ */ jsx(Space, { h: "xs" }),
10131
10410
  /* @__PURE__ */ jsx(
10132
10411
  OpacityOption,
10133
10412
  {
@@ -10137,6 +10416,7 @@ function NodeOptions({ selectedNodeIds }) {
10137
10416
  }
10138
10417
  }
10139
10418
  ),
10419
+ /* @__PURE__ */ jsx(Space, { h: "sm" }),
10140
10420
  /* @__PURE__ */ jsx(
10141
10421
  BorderStyleOption,
10142
10422
  {
@@ -10149,7 +10429,7 @@ function NodeOptions({ selectedNodeIds }) {
10149
10429
  ] }, firstNode.id),
10150
10430
  /* @__PURE__ */ jsx(NavigateToOption, { nodes })
10151
10431
  ] });
10152
- }
10432
+ }, (prevProps, nextProps) => shallowEqual(prevProps.selectedNodeIds, nextProps.selectedNodeIds));
10153
10433
  function Colors({
10154
10434
  nodes: [firstNode, ...nodes],
10155
10435
  onColorChange
@@ -10237,20 +10517,22 @@ function NavigateToOption({
10237
10517
  const isMultiple = nodes.length >= 1;
10238
10518
  return /* @__PURE__ */ jsxs("div", { children: [
10239
10519
  /* @__PURE__ */ jsx(Divider, { label: "navigate to", labelPosition: "left" }),
10240
- /* @__PURE__ */ jsx(
10241
- Select,
10242
- {
10243
- mt: "xs",
10244
- size: "xs",
10245
- variant: "filled",
10246
- value: isMultiple ? null : node.data.element.navigateTo ?? null,
10247
- disabled: isMultiple,
10248
- placeholder: isMultiple ? "[ multiple ]" : "select",
10249
- data: node.data.element.navigateTo ? [{ value: node.data.element.navigateTo, label: node.data.element.navigateTo }] : [],
10250
- allowDeselect: !0,
10251
- checkIconPosition: "right"
10252
- }
10253
- )
10520
+ isMultiple && /* @__PURE__ */ jsx(Text, { size: "xs", c: "dimmed", children: "[ multiple ]" }),
10521
+ !isMultiple && /* @__PURE__ */ jsxs(Fragment, { children: [
10522
+ /* @__PURE__ */ jsx(Space, { h: "xs" }),
10523
+ /* @__PURE__ */ jsx(
10524
+ Select,
10525
+ {
10526
+ size: "xs",
10527
+ variant: "filled",
10528
+ value: node.data.element.navigateTo ?? null,
10529
+ placeholder: "select",
10530
+ data: node.data.element.navigateTo ? [{ value: node.data.element.navigateTo, label: node.data.element.navigateTo }] : [],
10531
+ allowDeselect: !0,
10532
+ checkIconPosition: "right"
10533
+ }
10534
+ )
10535
+ ] })
10254
10536
  ] });
10255
10537
  }
10256
10538
  function OpacityOption({
@@ -10264,7 +10546,6 @@ function OpacityOption({
10264
10546
  }, [selectedOpacity]), /* @__PURE__ */ jsx(
10265
10547
  Slider,
10266
10548
  {
10267
- mt: "xs",
10268
10549
  size: "sm",
10269
10550
  color: "dark",
10270
10551
  value,
@@ -10281,7 +10562,7 @@ function BorderStyleOption({
10281
10562
  const [value, setValue] = useState(selecteBorderStyle);
10282
10563
  return useUpdateEffect(() => {
10283
10564
  setValue(selecteBorderStyle);
10284
- }, [selecteBorderStyle]), /* @__PURE__ */ jsx(Box, { mt: "md", children: /* @__PURE__ */ jsx(
10565
+ }, [selecteBorderStyle]), /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(
10285
10566
  SegmentedControl,
10286
10567
  {
10287
10568
  size: "xs",
@@ -10301,16 +10582,25 @@ function BorderStyleOption({
10301
10582
  ) });
10302
10583
  }
10303
10584
  var panel = "_1lmzt1h0";
10304
- const Empty = [];
10305
10585
  function OptionsPanel() {
10306
- const { isFocusDisabled, viewId } = useDiagramState((s) => ({
10586
+ const { isFocused, viewId } = useDiagramState((s) => ({
10307
10587
  viewId: s.view.id,
10308
- isFocusDisabled: s.focusedNodeId === null && s.activeDynamicViewStep === null
10309
- })), selectedNodes = useXYStore(
10310
- useCallback((s) => s.elementsSelectable && isFocusDisabled ? reduce(s.nodes, (acc, n) => (n.selected && acc.push(n.id), acc), []) : Empty, [isFocusDisabled]),
10311
- shallowEqual
10312
- );
10313
- return DEV && useTilg(), /* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", children: selectedNodes.length > 0 && /* @__PURE__ */ jsx(
10588
+ isFocused: s.focusedNodeId !== null || s.activeDynamicViewStep !== null
10589
+ })), [selected2, setSelected] = useState({
10590
+ nodes: [],
10591
+ edges: []
10592
+ });
10593
+ useOnSelectionChange({
10594
+ onChange: ({ nodes: nodes2, edges }) => {
10595
+ const newSelected = {
10596
+ nodes: nodes2.map((n) => n.id).sort(),
10597
+ edges: edges.map((e) => e.id).sort()
10598
+ };
10599
+ deepEqual(selected2, newSelected) || setSelected(newSelected);
10600
+ }
10601
+ });
10602
+ const { nodes } = selected2, hasAnySelection = !isFocused && nodes.length > 0;
10603
+ return /* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", children: hasAnySelection && /* @__PURE__ */ jsx(
10314
10604
  m.div,
10315
10605
  {
10316
10606
  initial: { opacity: 0, scale: 0.85 },
@@ -10322,9 +10612,10 @@ function OptionsPanel() {
10322
10612
  transition: { duration: 0.14 },
10323
10613
  className: clsx("react-flow__panel", panel),
10324
10614
  style: {
10325
- transformOrigin: "center right"
10615
+ transformOrigin: "center right",
10616
+ maxWidth: "320px"
10326
10617
  },
10327
- children: /* @__PURE__ */ jsx(Card, { shadow: "sm", children: /* @__PURE__ */ jsx(NodeOptions, { selectedNodeIds: selectedNodes }) })
10618
+ children: /* @__PURE__ */ jsx(Card, { shadow: "md", children: nodes.length > 0 && /* @__PURE__ */ jsx(NodeOptions, { selectedNodeIds: nodes }) })
10328
10619
  },
10329
10620
  viewId
10330
10621
  ) });
@@ -10427,6 +10718,8 @@ function LikeC4Diagram({
10427
10718
  DiagramContextProvider,
10428
10719
  {
10429
10720
  view,
10721
+ keepAspectRatio,
10722
+ className: clsx(rootClassName, className),
10430
10723
  readonly,
10431
10724
  pannable,
10432
10725
  zoomable,
@@ -10446,27 +10739,18 @@ function LikeC4Diagram({
10446
10739
  onNavigateTo,
10447
10740
  onCanvasDblClick,
10448
10741
  children: /* @__PURE__ */ jsx(LazyMotion, { features: domAnimation, strict: !0, children: /* @__PURE__ */ jsx(
10449
- KeepAspectRatioContainer,
10742
+ LikeC4DiagramInnerMemo,
10450
10743
  {
10451
- className: clsx(rootClassName, className),
10452
- enabled: keepAspectRatio,
10453
- width: view.width,
10454
- height: view.height,
10455
- children: /* @__PURE__ */ jsx(
10456
- LikeC4DiagramInnerMemo,
10457
- {
10458
- defaultNodes: initialRef.current.defaultNodes,
10459
- defaultEdges: initialRef.current.defaultEdges,
10460
- fitView: fitView2,
10461
- zoomable,
10462
- background,
10463
- controls,
10464
- pannable,
10465
- showDiagramTitle,
10466
- showNavigationButtons,
10467
- enableDynamicViewWalkthrough
10468
- }
10469
- )
10744
+ defaultNodes: initialRef.current.defaultNodes,
10745
+ defaultEdges: initialRef.current.defaultEdges,
10746
+ fitView: fitView2,
10747
+ zoomable,
10748
+ background,
10749
+ controls,
10750
+ pannable,
10751
+ showDiagramTitle,
10752
+ showNavigationButtons,
10753
+ enableDynamicViewWalkthrough
10470
10754
  }
10471
10755
  ) })
10472
10756
  }