@likec4/diagram 1.3.0 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (95) hide show
  1. package/dist/LikeC4Diagram.css.d.ts +0 -1
  2. package/dist/LikeC4Diagram.d.ts +1 -1
  3. package/dist/LikeC4Diagram.props.d.ts +7 -2
  4. package/dist/index.d.ts +1 -1
  5. package/dist/index.mjs +1580 -1194
  6. package/dist/state/DiagramContext.d.ts +97 -4169
  7. package/dist/state/diagramStore.d.ts +98 -4172
  8. package/dist/state/hooks.d.ts +4 -0
  9. package/dist/state/index.d.ts +1 -3
  10. package/dist/state/useDiagramStore.d.ts +3 -4622
  11. package/dist/state/useNavigationHistory.d.ts +5 -0
  12. package/dist/style.css +217 -159
  13. package/dist/theme.css.d.ts +5 -0
  14. package/dist/ui/BackwardForwardPanel.css.d.ts +1 -0
  15. package/dist/ui/BackwardForwardPanel.d.ts +1 -0
  16. package/dist/ui/DiagramTitlePanel.css.d.ts +1 -1
  17. package/dist/ui/OptionsPanel.d.ts +1 -3
  18. package/dist/ui/options/EdgeOptions.d.ts +19 -0
  19. package/dist/ui/options/NodeOptions.d.ts +2 -2
  20. package/dist/xyflow/EdgeMarkers.d.ts +11 -0
  21. package/dist/xyflow/XYFlowEvents.d.ts +12 -9
  22. package/dist/xyflow/XYFlowInner.d.ts +1 -0
  23. package/dist/xyflow/const.d.ts +3 -3
  24. package/dist/xyflow/diagram-to-xyflow.d.ts +1 -1
  25. package/dist/xyflow/edges/RelationshipEdge.d.ts +4 -3
  26. package/dist/xyflow/edges/edges.css.d.ts +1 -0
  27. package/dist/xyflow/edges/utils.d.ts +1 -0
  28. package/dist/xyflow/hooks/index.d.ts +3 -2
  29. package/dist/xyflow/hooks/useXYFlow.d.ts +22 -21
  30. package/dist/xyflow/nodes/compound/CompoundNode.css.d.ts +1 -0
  31. package/dist/xyflow/nodes/element/ElementIcon.d.ts +1 -4
  32. package/dist/xyflow/nodes/element/element.css.d.ts +3 -1
  33. package/dist/xyflow/types.d.ts +2 -32
  34. package/package.json +21 -21
  35. package/src/LikeC4Diagram.css.ts +10 -8
  36. package/src/LikeC4Diagram.props.ts +12 -5
  37. package/src/LikeC4Diagram.tsx +43 -26
  38. package/src/globals.css.ts +11 -4
  39. package/src/index.ts +1 -1
  40. package/src/mantine.css.ts +2 -2
  41. package/src/state/DiagramContext.tsx +47 -16
  42. package/src/state/diagramStore.ts +89 -80
  43. package/src/state/hooks.ts +5 -0
  44. package/src/state/index.ts +1 -3
  45. package/src/state/useDiagramStore.ts +6 -13
  46. package/src/state/useNavigationHistory.ts +39 -0
  47. package/src/theme.css.ts +5 -0
  48. package/src/ui/BackwardForwardPanel.css.ts +22 -0
  49. package/src/ui/BackwardForwardPanel.tsx +59 -0
  50. package/src/ui/DiagramTitlePanel.css.ts +17 -6
  51. package/src/ui/DiagramTitlePanel.tsx +108 -94
  52. package/src/ui/DynamicViewWalkthrough.tsx +6 -4
  53. package/src/ui/OptionsPanel.tsx +37 -18
  54. package/src/ui/options/EdgeOptions.tsx +157 -0
  55. package/src/ui/options/NodeOptions.tsx +37 -29
  56. package/src/xyflow/EdgeMarkers.tsx +148 -0
  57. package/src/xyflow/FitviewOnDiagramChange.tsx +8 -4
  58. package/src/xyflow/SelectEdgesOnNodeFocus.tsx +59 -55
  59. package/src/xyflow/SyncWithDiagram.tsx +13 -20
  60. package/src/xyflow/XYFlow.tsx +2 -4
  61. package/src/xyflow/XYFlowEvents.tsx +48 -33
  62. package/src/xyflow/XYFlowInner.tsx +6 -3
  63. package/src/xyflow/const.ts +3 -3
  64. package/src/xyflow/diagram-to-xyflow.ts +18 -53
  65. package/src/xyflow/edges/RelationshipEdge.tsx +218 -126
  66. package/src/xyflow/edges/edges.css.ts +44 -26
  67. package/src/xyflow/edges/utils.ts +10 -0
  68. package/src/xyflow/hooks/index.ts +4 -2
  69. package/src/xyflow/hooks/useLayoutConstraints.ts +5 -5
  70. package/src/xyflow/hooks/useXYFlow.ts +28 -1
  71. package/src/xyflow/nodes/compound/CompoundNode.css.ts +41 -31
  72. package/src/xyflow/nodes/compound/CompoundNode.tsx +52 -53
  73. package/src/xyflow/nodes/element/ElementIcon.tsx +11 -22
  74. package/src/xyflow/nodes/element/ElementLink.tsx +11 -16
  75. package/src/xyflow/nodes/element/ElementNode.tsx +69 -114
  76. package/src/xyflow/nodes/element/element.css.ts +48 -15
  77. package/src/xyflow/nodes/shared/NavigateToBtn.tsx +1 -1
  78. package/src/xyflow/types.ts +2 -4
  79. package/src/xyflow/utils.ts +3 -6
  80. package/dist/KeepAspectRatioContainer.d.ts +0 -9
  81. package/dist/icons/Clipboard.d.ts +0 -3
  82. package/dist/icons/Link.d.ts +0 -3
  83. package/dist/icons/ZoomIn.d.ts +0 -3
  84. package/dist/icons/index.d.ts +0 -3
  85. package/dist/mantine/theme.d.ts +0 -3
  86. package/dist/state/WhenInitialized.d.ts +0 -3
  87. package/dist/ui/Camera.d.ts +0 -3
  88. package/src/KeepAspectRatioContainer.tsx +0 -36
  89. package/src/icons/Clipboard.tsx +0 -24
  90. package/src/icons/Link.tsx +0 -23
  91. package/src/icons/ZoomIn.tsx +0 -25
  92. package/src/icons/index.ts +0 -3
  93. package/src/mantine/theme.ts +0 -20
  94. package/src/state/WhenInitialized.tsx +0 -24
  95. package/src/ui/Camera.tsx +0 -174
package/dist/index.mjs CHANGED
@@ -9,15 +9,15 @@ 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, Paper, Spoiler, Divider, TooltipGroup, Flex, Tooltip, ColorSwatch, CheckIcon, rem, Select, Slider, SegmentedControl, Card } from "@mantine/core";
13
- import { isArray, isNullish, entries, reduce, 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, IconPlayerPlayFilled, IconPlayerSkipBackFilled, IconPlayerStopFilled, IconPlayerSkipForwardFilled } from "@tabler/icons-react";
20
- import { useLocalStorage, useHotkeys } from "@mantine/hooks";
19
+ import { IconZoomScan, IconLink, IconChevronLeft, IconChevronRight, IconMenu, IconPlayerPlayFilled, IconPlayerSkipBackFilled, IconPlayerStopFilled, IconPlayerSkipForwardFilled } from "@tabler/icons-react";
20
+ import { useStateHistory, useLocalStorage, useHotkeys } from "@mantine/hooks";
21
21
  function cc(names) {
22
22
  if (typeof names == "string" || typeof names == "number") return "" + names;
23
23
  let out = "";
@@ -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
  });
@@ -2638,19 +2636,19 @@ function getEdgePosition(params) {
2638
2636
  // when connection type is loose we can define all handles as sources and connect source -> source
2639
2637
  params.connectionMode === ConnectionMode.Strict ? (targetHandleBounds == null ? void 0 : targetHandleBounds.target) ?? [] : ((targetHandleBounds == null ? void 0 : targetHandleBounds.target) ?? []).concat((targetHandleBounds == null ? void 0 : targetHandleBounds.source) ?? []),
2640
2638
  params.targetHandle
2641
- ), sourcePosition = (sourceHandle == null ? void 0 : sourceHandle.position) || Position.Bottom, targetPosition = (targetHandle == null ? void 0 : targetHandle.position) || Position.Top;
2639
+ );
2642
2640
  if (!sourceHandle || !targetHandle)
2643
2641
  return (_a = params.onError) == null || _a.call(params, "008", errorMessages.error008(sourceHandle ? "target" : "source", {
2644
2642
  id: params.id,
2645
2643
  sourceHandle: params.sourceHandle,
2646
2644
  targetHandle: params.targetHandle
2647
2645
  })), null;
2648
- const [sourceX, sourceY] = getHandlePosition(sourcePosition, sourceNode, sourceHandle), [targetX, targetY] = getHandlePosition(targetPosition, targetNode, targetHandle);
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(position, node, handle = null) {
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);
2671
- switch (position) {
2669
+ if (center)
2670
+ return { x: x + width / 2, y: y + height / 2 };
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,13 +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, h) => (`${node.id}-${h.id}-${type}` !== currentHandle && res.push({
3050
- id: h.id || null,
3051
- type,
3052
- nodeId: node.id,
3053
- x: node.internals.positionAbsolute.x + h.x + h.width / 2,
3054
- y: node.internals.positionAbsolute.y + h.y + h.height / 2
3055
- }), res), []);
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 });
3050
+ }
3051
+ return res;
3052
+ }, []), excludedHandle];
3056
3053
  }
3057
3054
  function getClosestHandle(pos, connectionRadius, handles) {
3058
3055
  let closestHandles = [], minDistance = 1 / 0;
@@ -3066,31 +3063,31 @@ function getClosestHandle(pos, connectionRadius, handles) {
3066
3063
  ) : null;
3067
3064
  }
3068
3065
  function getHandleLookup({ nodeLookup, nodeId, handleId, handleType }) {
3069
- const connectionHandles = [];
3070
- for (const [, node] of nodeLookup)
3066
+ const connectionHandles = [], currentHandle = { nodeId, handleId, handleType };
3067
+ let excludedHandle = null;
3068
+ for (const node of nodeLookup.values())
3071
3069
  if (node.internals.handleBounds) {
3072
- const id2 = `${nodeId}-${handleId}-${handleType}`, sourceHandles = getHandles(node, node.internals.handleBounds, "source", id2), targetHandles = getHandles(node, node.internals.handleBounds, "target", id2);
3073
- 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);
3074
3072
  }
3075
- return connectionHandles;
3073
+ return [connectionHandles, excludedHandle];
3076
3074
  }
3077
3075
  function getHandleType(edgeUpdaterType, handleDomNode) {
3078
3076
  return edgeUpdaterType || (handleDomNode != null && handleDomNode.classList.contains("target") ? "target" : handleDomNode != null && handleDomNode.classList.contains("source") ? "source" : null);
3079
3077
  }
3080
- function getConnectionStatus(isInsideConnectionRadius, isHandleValid) {
3081
- let connectionStatus = null;
3082
- 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;
3083
3081
  }
3084
3082
  const alwaysValid = () => !0;
3085
- let connectionStartHandle = null;
3086
- function onPointerDown(event, { connectionMode, connectionRadius, handleId, nodeId, edgeUpdaterType, isTarget, domNode, nodeLookup, lib, autoPanOnConnect, flowId, panBy: panBy2, cancelConnection, onConnectStart, onConnect, onConnectEnd, isValidConnection = alwaysValid, onEdgeUpdateEnd, 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 }) {
3087
3084
  const doc = getHostForElement(event.target);
3088
3085
  let autoPanId = 0, closestHandle;
3089
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();
3090
3087
  if (!containerBounds || !handleType)
3091
3088
  return;
3092
- let connectionPosition = getEventPosition(event, containerBounds), autoPanStarted = !1, connection = null, isValid = !1, handleDomNode = null;
3093
- const handleLookup = getHandleLookup({
3089
+ let position = getEventPosition(event, containerBounds), autoPanStarted = !1, connection = null, isValid = !1, handleDomNode = null;
3090
+ const [handleLookup, fromHandleInternal] = getHandleLookup({
3094
3091
  nodeLookup,
3095
3092
  nodeId,
3096
3093
  handleId,
@@ -3099,24 +3096,36 @@ function onPointerDown(event, { connectionMode, connectionRadius, handleId, node
3099
3096
  function autoPan() {
3100
3097
  if (!autoPanOnConnect || !containerBounds)
3101
3098
  return;
3102
- const [x2, y2] = calcAutoPan(connectionPosition, containerBounds);
3099
+ const [x2, y2] = calcAutoPan(position, containerBounds, autoPanSpeed);
3103
3100
  panBy2({ x: x2, y: y2 }), autoPanId = requestAnimationFrame(autoPan);
3104
3101
  }
3105
- connectionStartHandle = {
3102
+ const fromHandle = {
3103
+ ...fromHandleInternal,
3106
3104
  nodeId,
3107
- handleId,
3108
- type: handleType
3109
- }, updateConnection({
3110
- connectionPosition,
3111
- connectionStatus: null,
3112
- // connectionNodeId etc will be removed in the next major in favor of connectionStartHandle
3113
- connectionStartHandle,
3114
- connectionEndHandle: null
3115
- }), onConnectStart == null || onConnectStart(event, { nodeId, handleId, handleType });
3105
+ type: 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 });
3116
3122
  function onPointerMove(event2) {
3117
- getConnectionStartHandle() || onPointerUp(event2);
3123
+ if (!getFromHandle() || !fromHandle) {
3124
+ onPointerUp(event2);
3125
+ return;
3126
+ }
3118
3127
  const transform2 = getTransform();
3119
- 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);
3120
3129
  const result = isValidHandle(event2, {
3121
3130
  handle: closestHandle,
3122
3131
  connectionMode,
@@ -3126,29 +3135,32 @@ function onPointerDown(event, { connectionMode, connectionRadius, handleId, node
3126
3135
  isValidConnection,
3127
3136
  doc,
3128
3137
  lib,
3129
- flowId
3130
- });
3131
- handleDomNode = result.handleDomNode, connection = result.connection, isValid = result.isValid, updateConnection({
3132
- connectionStartHandle,
3133
- connectionPosition: closestHandle && isValid ? rendererPointToPoint({
3134
- x: closestHandle.x,
3135
- y: closestHandle.y
3136
- }, transform2) : connectionPosition,
3137
- connectionStatus: getConnectionStatus(!!closestHandle, isValid),
3138
- connectionEndHandle: result.endHandle
3138
+ flowId,
3139
+ handleLookup
3139
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);
3140
3152
  }
3141
3153
  function onPointerUp(event2) {
3142
- (closestHandle || handleDomNode) && connection && isValid && (onConnect == null || onConnect(connection)), onConnectEnd == null || onConnectEnd(event2), edgeUpdaterType && (onEdgeUpdateEnd == null || onEdgeUpdateEnd(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);
3143
3155
  }
3144
3156
  doc.addEventListener("mousemove", onPointerMove), doc.addEventListener("mouseup", onPointerUp), doc.addEventListener("touchmove", onPointerMove), doc.addEventListener("touchend", onPointerUp);
3145
3157
  }
3146
- 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 }) {
3147
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 = {
3148
3160
  handleDomNode: handleToCheck,
3149
3161
  isValid: !1,
3150
3162
  connection: null,
3151
- endHandle: null
3163
+ toHandle: null
3152
3164
  };
3153
3165
  if (handleToCheck) {
3154
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");
@@ -3160,11 +3172,14 @@ function isValidHandle(event, { handle, connectionMode, fromNodeId, fromHandleId
3160
3172
  target: isTarget ? fromNodeId : handleNodeId,
3161
3173
  targetHandle: isTarget ? fromHandleId : handleId
3162
3174
  };
3163
- result.connection = connection, connectable && connectableEnd && (connectionMode === ConnectionMode.Strict ? isTarget && handleType === "source" || !isTarget && handleType === "target" : handleNodeId !== fromNodeId || handleId !== fromHandleId) && (result.endHandle = {
3164
- nodeId: handleNodeId,
3165
- handleId,
3166
- type: handleType
3167
- }, result.isValid = isValidConnection(connection));
3175
+ result.connection = connection;
3176
+ const isValid = connectable && connectableEnd && (connectionMode === ConnectionMode.Strict ? isTarget && handleType === "source" || !isTarget && handleType === "target" : handleNodeId !== fromNodeId || handleId !== fromHandleId);
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
+ }
3168
3183
  }
3169
3184
  return result;
3170
3185
  }
@@ -3225,7 +3240,11 @@ const viewChanged = (prevViewport, eventViewport) => prevViewport.x !== eventVie
3225
3240
  x: transform2.x,
3226
3241
  y: transform2.y,
3227
3242
  zoom: transform2.k
3228
- }), 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) => {
3229
3248
  const factor = event.ctrlKey && isMacOs() ? 10 : 1;
3230
3249
  return -event.deltaY * (event.deltaMode === 1 ? 0.05 : event.deltaMode ? 1 : 2e-3) * factor;
3231
3250
  };
@@ -3308,7 +3327,7 @@ function createFilter({ zoomActivationKeyPressed, zoomOnScroll, zoomOnPinch, pan
3308
3327
  return (!event.ctrlKey || event.type === "wheel") && buttonAllowed;
3309
3328
  };
3310
3329
  }
3311
- 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 }) {
3312
3331
  const zoomPanValues = {
3313
3332
  isZoomingOrPanning: !1,
3314
3333
  usedRightMouseButton: !1,
@@ -3317,7 +3336,7 @@ function XYPanZoom({ domNode, minZoom, maxZoom, translateExtent, viewport, onPan
3317
3336
  timerId: void 0,
3318
3337
  panScrollTimeout: void 0,
3319
3338
  isPanScrolling: !1
3320
- }, 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);
3321
3340
  setViewportConstrained({
3322
3341
  x: viewport.x,
3323
3342
  y: viewport.y,
@@ -3329,7 +3348,9 @@ function XYPanZoom({ domNode, minZoom, maxZoom, translateExtent, viewport, onPan
3329
3348
  const d3ZoomHandler = d3Selection.on("wheel.zoom"), d3DblClickZoomHandler = d3Selection.on("dblclick.zoom");
3330
3349
  d3ZoomInstance.wheelDelta(wheelDelta);
3331
3350
  function setTransform(transform2, options) {
3332
- 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);
3333
3354
  }
3334
3355
  function update({ noWheelClassName, noPanClassName, onPaneContextMenu, userSelectionActive, panOnScroll, panOnDrag, panOnScrollMode, panOnScrollSpeed, preventScrolling, zoomOnPinch, zoomOnScroll, zoomOnDoubleClick, zoomActivationKeyPressed, lib }) {
3335
3356
  userSelectionActive && !zoomPanValues.isZoomingOrPanning && destroy();
@@ -3391,13 +3412,13 @@ function XYPanZoom({ domNode, minZoom, maxZoom, translateExtent, viewport, onPan
3391
3412
  function destroy() {
3392
3413
  d3ZoomInstance.on("zoom", null);
3393
3414
  }
3394
- function setViewportConstrained(viewport2, extent, translateExtent2) {
3415
+ async function setViewportConstrained(viewport2, extent, translateExtent2) {
3395
3416
  const nextTransform = viewportToTransform(viewport2), contrainedTransform = d3ZoomInstance == null ? void 0 : d3ZoomInstance.constrain()(nextTransform, extent, translateExtent2);
3396
- return contrainedTransform && setTransform(contrainedTransform), contrainedTransform;
3417
+ return contrainedTransform && await setTransform(contrainedTransform), new Promise((resolve) => resolve(contrainedTransform));
3397
3418
  }
3398
- function setViewport(viewport2, options) {
3419
+ async function setViewport(viewport2, options) {
3399
3420
  const nextTransform = viewportToTransform(viewport2);
3400
- return setTransform(nextTransform, options), nextTransform;
3421
+ return await setTransform(nextTransform, options), new Promise((resolve) => resolve(nextTransform));
3401
3422
  }
3402
3423
  function syncViewport(viewport2) {
3403
3424
  if (d3Selection) {
@@ -3410,10 +3431,14 @@ function XYPanZoom({ domNode, minZoom, maxZoom, translateExtent, viewport, onPan
3410
3431
  return { x: transform$1.x, y: transform$1.y, zoom: transform$1.k };
3411
3432
  }
3412
3433
  function scaleTo(zoom2, options) {
3413
- 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);
3414
3437
  }
3415
3438
  function scaleBy(factor, options) {
3416
- 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);
3417
3442
  }
3418
3443
  function setScaleExtent(scaleExtent) {
3419
3444
  d3ZoomInstance == null || d3ZoomInstance.scaleExtent(scaleExtent);
@@ -3421,6 +3446,10 @@ function XYPanZoom({ domNode, minZoom, maxZoom, translateExtent, viewport, onPan
3421
3446
  function setTranslateExtent(translateExtent2) {
3422
3447
  d3ZoomInstance == null || d3ZoomInstance.translateExtent(translateExtent2);
3423
3448
  }
3449
+ function setClickDistance(distance2) {
3450
+ const validDistance = !isNumeric(distance2) || distance2 < 0 ? 0 : distance2;
3451
+ d3ZoomInstance == null || d3ZoomInstance.clickDistance(validDistance);
3452
+ }
3424
3453
  return {
3425
3454
  update,
3426
3455
  destroy,
@@ -3431,7 +3460,8 @@ function XYPanZoom({ domNode, minZoom, maxZoom, translateExtent, viewport, onPan
3431
3460
  scaleBy,
3432
3461
  setScaleExtent,
3433
3462
  setTranslateExtent,
3434
- syncViewport
3463
+ syncViewport,
3464
+ setClickDistance
3435
3465
  };
3436
3466
  }
3437
3467
  var ResizeControlVariant;
@@ -3536,14 +3566,13 @@ function XYResizer({ domNode, nodeId, getStoreItems, onChange, onEnd }) {
3536
3566
  const controlDirection = getControlDirection(controlPosition);
3537
3567
  let node, childNodes = [], parentNode, parentExtent, childExtent;
3538
3568
  const dragHandler = drag().on("start", (event) => {
3539
- var _a, _b;
3540
3569
  const { nodeLookup, transform: transform2, snapGrid, snapToGrid, nodeOrigin } = getStoreItems();
3541
3570
  if (node = nodeLookup.get(nodeId), !node)
3542
3571
  return;
3543
3572
  const { xSnapped, ySnapped } = getPointerPosition(event.sourceEvent, { transform: transform2, snapGrid, snapToGrid });
3544
3573
  prevValues = {
3545
- width: ((_a = node.measured) == null ? void 0 : _a.width) ?? 0,
3546
- height: ((_b = node.measured) == null ? void 0 : _b.height) ?? 0,
3574
+ width: node.measured.width ?? 0,
3575
+ height: node.measured.height ?? 0,
3547
3576
  x: node.position.x ?? 0,
3548
3577
  y: node.position.y ?? 0
3549
3578
  }, startValues = {
@@ -3551,7 +3580,7 @@ function XYResizer({ domNode, nodeId, getStoreItems, onChange, onEnd }) {
3551
3580
  pointerX: xSnapped,
3552
3581
  pointerY: ySnapped,
3553
3582
  aspectRatio: prevValues.width / prevValues.height
3554
- }, 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;
3555
3584
  for (const [childId, child] of nodeLookup)
3556
3585
  if (child.parentId === nodeId && (childNodes.push({
3557
3586
  id: childId,
@@ -3572,7 +3601,7 @@ function XYResizer({ domNode, nodeId, getStoreItems, onChange, onEnd }) {
3572
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;
3573
3602
  if (!isXPosChange && !isYPosChange && !isWidthChange && !isHeightChange)
3574
3603
  return;
3575
- 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)) {
3576
3605
  const xChange = x - prevX, yChange = y - prevY;
3577
3606
  for (const childNode of childNodes)
3578
3607
  childNode.position = {
@@ -3580,7 +3609,12 @@ function XYResizer({ domNode, nodeId, getStoreItems, onChange, onEnd }) {
3580
3609
  y: childNode.position.y - yChange + nodeOrigin[1] * (height - prevHeight)
3581
3610
  }, childChanges.push(childNode);
3582
3611
  }
3583
- (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
+ }
3584
3618
  const direction = getResizeDirection({
3585
3619
  width: prevValues.width,
3586
3620
  prevWidth,
@@ -3630,23 +3664,23 @@ const style = { display: "none" }, ariaLiveStyle = {
3630
3664
  overflow: "hidden",
3631
3665
  clip: "rect(0px, 0px, 0px, 0px)",
3632
3666
  clipPath: "inset(100%)"
3633
- }, 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;
3634
3668
  function AriaLiveMessage({ rfId }) {
3635
- const ariaLiveMessage = useStore(selector$q);
3669
+ const ariaLiveMessage = useStore(selector$p);
3636
3670
  return jsx("div", { id: `${ARIA_LIVE_MESSAGE}-${rfId}`, "aria-live": "assertive", "aria-atomic": "true", style: ariaLiveStyle, children: ariaLiveMessage });
3637
3671
  }
3638
3672
  function A11yDescriptions({ rfId, disableKeyboardA11y }) {
3639
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 })] });
3640
3674
  }
3641
- const selector$p = (s) => s.userSelectionActive ? "none" : "all";
3675
+ const selector$o = (s) => s.userSelectionActive ? "none" : "all";
3642
3676
  function Panel({ position = "top-left", children: children2, className, style: style2, ...rest }) {
3643
- const pointerEvents = useStore(selector$p), positionClasses = `${position}`.split("-");
3677
+ const pointerEvents = useStore(selector$o), positionClasses = `${position}`.split("-");
3644
3678
  return jsx("div", { className: cc(["react-flow__panel", className, ...positionClasses]), style: { ...style2, pointerEvents }, ...rest, children: children2 });
3645
3679
  }
3646
3680
  function Attribution({ proOptions, position = "bottom-right" }) {
3647
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" }) });
3648
3682
  }
3649
- const selector$o = (s) => {
3683
+ const selector$n = (s) => {
3650
3684
  const selectedNodes = [], selectedEdges = [];
3651
3685
  for (const [, node] of s.nodeLookup)
3652
3686
  node.selected && selectedNodes.push(node.internals.userNode);
@@ -3658,7 +3692,7 @@ function areEqual(a, b) {
3658
3692
  return shallow(a.selectedNodes.map(selectId), b.selectedNodes.map(selectId)) && shallow(a.selectedEdges.map(selectId), b.selectedEdges.map(selectId));
3659
3693
  }
3660
3694
  function SelectionListenerInner({ onSelectionChange }) {
3661
- const store = useStoreApi(), { selectedNodes, selectedEdges } = useStore(selector$o, areEqual);
3695
+ const store = useStoreApi(), { selectedNodes, selectedEdges } = useStore(selector$n, areEqual);
3662
3696
  return useEffect(() => {
3663
3697
  const params = { nodes: selectedNodes, edges: selectedEdges };
3664
3698
  onSelectionChange == null || onSelectionChange(params), store.getState().onSelectionChangeHandlers.forEach((fn) => fn(params));
@@ -3683,7 +3717,7 @@ const defaultNodeOrigin = [0, 0], defaultViewport = { x: 0, y: 0, zoom: 1 }, rea
3683
3717
  "nodesConnectable",
3684
3718
  "nodesFocusable",
3685
3719
  "edgesFocusable",
3686
- "edgesUpdatable",
3720
+ "edgesReconnectable",
3687
3721
  "elevateNodesOnSelect",
3688
3722
  "elevateEdgesOnSelect",
3689
3723
  "minZoom",
@@ -3722,8 +3756,10 @@ const defaultNodeOrigin = [0, 0], defaultViewport = { x: 0, y: 0, zoom: 1 }, rea
3722
3756
  "selectNodesOnDrag",
3723
3757
  "nodeDragThreshold",
3724
3758
  "onBeforeDelete",
3725
- "debug"
3726
- ], fieldsToTrack = [...reactFlowFieldsToTrack, "rfId"], selector$n = (s) => ({
3759
+ "debug",
3760
+ "autoPanSpeed",
3761
+ "paneClickDistance"
3762
+ ], fieldsToTrack = [...reactFlowFieldsToTrack, "rfId"], selector$m = (s) => ({
3727
3763
  setNodes: s.setNodes,
3728
3764
  setEdges: s.setEdges,
3729
3765
  setMinZoom: s.setMinZoom,
@@ -3731,7 +3767,8 @@ const defaultNodeOrigin = [0, 0], defaultViewport = { x: 0, y: 0, zoom: 1 }, rea
3731
3767
  setTranslateExtent: s.setTranslateExtent,
3732
3768
  setNodeExtent: s.setNodeExtent,
3733
3769
  reset: s.reset,
3734
- setDefaultNodesAndEdges: s.setDefaultNodesAndEdges
3770
+ setDefaultNodesAndEdges: s.setDefaultNodesAndEdges,
3771
+ setPaneClickDistance: s.setPaneClickDistance
3735
3772
  }), initPrevValues = {
3736
3773
  // these are values that are also passed directly to other components
3737
3774
  // than the StoreUpdater. We can reduce the number of setStore calls
@@ -3742,10 +3779,11 @@ const defaultNodeOrigin = [0, 0], defaultViewport = { x: 0, y: 0, zoom: 1 }, rea
3742
3779
  maxZoom: 2,
3743
3780
  elementsSelectable: !0,
3744
3781
  noPanClassName: "nopan",
3745
- rfId: "1"
3782
+ rfId: "1",
3783
+ paneClickDistance: 0
3746
3784
  };
3747
3785
  function StoreUpdater(props) {
3748
- 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();
3749
3787
  useEffect(() => (setDefaultNodesAndEdges(props.defaultNodes, props.defaultEdges), () => {
3750
3788
  previousFields.current = initPrevValues, reset();
3751
3789
  }), []);
@@ -3754,7 +3792,7 @@ function StoreUpdater(props) {
3754
3792
  () => {
3755
3793
  for (const fieldName of fieldsToTrack) {
3756
3794
  const fieldValue = props[fieldName], previousFieldValue = previousFields.current[fieldName];
3757
- 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 })));
3758
3796
  }
3759
3797
  previousFields.current = props;
3760
3798
  },
@@ -3820,53 +3858,52 @@ const useViewportHelper = () => {
3820
3858
  const store = useStoreApi();
3821
3859
  return useMemo(() => ({
3822
3860
  zoomIn: (options) => {
3823
- var _a;
3824
- 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);
3825
3863
  },
3826
3864
  zoomOut: (options) => {
3827
- var _a;
3828
- 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);
3829
3867
  },
3830
3868
  zoomTo: (zoomLevel, options) => {
3831
- var _a;
3832
- 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);
3833
3871
  },
3834
3872
  getZoom: () => store.getState().transform[2],
3835
- setViewport: (viewport, options) => {
3873
+ setViewport: async (viewport, options) => {
3836
3874
  const { transform: [tX, tY, tZoom], panZoom } = store.getState();
3837
- panZoom == null || panZoom.setViewport({
3875
+ return panZoom ? (await panZoom.setViewport({
3838
3876
  x: viewport.x ?? tX,
3839
3877
  y: viewport.y ?? tY,
3840
3878
  zoom: viewport.zoom ?? tZoom
3841
- }, { duration: options == null ? void 0 : options.duration });
3879
+ }, { duration: options == null ? void 0 : options.duration }), Promise.resolve(!0)) : Promise.resolve(!1);
3842
3880
  },
3843
3881
  getViewport: () => {
3844
3882
  const [x, y, zoom2] = store.getState().transform;
3845
3883
  return { x, y, zoom: zoom2 };
3846
3884
  },
3847
3885
  fitView: (options) => {
3848
- const { nodeLookup, width, height, nodeOrigin, minZoom, maxZoom, panZoom } = store.getState();
3886
+ const { nodeLookup, width, height, minZoom, maxZoom, panZoom } = store.getState(), fitViewNodes = getFitViewNodes(nodeLookup, options);
3849
3887
  return panZoom ? fitView({
3850
- nodeLookup,
3888
+ nodes: fitViewNodes,
3851
3889
  width,
3852
3890
  height,
3853
- nodeOrigin,
3854
3891
  minZoom,
3855
3892
  maxZoom,
3856
3893
  panZoom
3857
- }, options) : !1;
3894
+ }, options) : Promise.resolve(!1);
3858
3895
  },
3859
- setCenter: (x, y, options) => {
3896
+ setCenter: async (x, y, options) => {
3860
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;
3861
- panZoom == null || panZoom.setViewport({
3898
+ return panZoom ? (await panZoom.setViewport({
3862
3899
  x: centerX,
3863
3900
  y: centerY,
3864
3901
  zoom: nextZoom
3865
- }, { duration: options == null ? void 0 : options.duration });
3902
+ }, { duration: options == null ? void 0 : options.duration }), Promise.resolve(!0)) : Promise.resolve(!1);
3866
3903
  },
3867
- fitBounds: (bounds, options) => {
3904
+ fitBounds: async (bounds, options) => {
3868
3905
  const { width, height, minZoom, maxZoom, panZoom } = store.getState(), viewport = getViewportForBounds(bounds, width, height, minZoom, maxZoom, (options == null ? void 0 : options.padding) ?? 0.1);
3869
- 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);
3870
3907
  },
3871
3908
  screenToFlowPosition: (clientPosition, options = { snapToGrid: !0 }) => {
3872
3909
  const { transform: transform2, snapGrid, domNode } = store.getState();
@@ -4032,16 +4069,16 @@ function useBatchContext() {
4032
4069
  throw new Error("useBatchContext must be used within a BatchProvider");
4033
4070
  return batchContext;
4034
4071
  }
4035
- const selector$m = (s) => !!s.panZoom;
4072
+ const selector$l = (s) => !!s.panZoom;
4036
4073
  function useReactFlow() {
4037
- 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(() => {
4038
4075
  const getInternalNode = (id2) => store.getState().nodeLookup.get(id2), setNodes = (payload) => {
4039
4076
  batchContext.nodeQueue.push(payload);
4040
4077
  }, setEdges = (payload) => {
4041
4078
  batchContext.edgeQueue.push(payload);
4042
4079
  }, getNodeRect = (node) => {
4043
4080
  var _a, _b;
4044
- 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 = {
4045
4082
  id: nodeToUse.id,
4046
4083
  position,
4047
4084
  width: ((_a = nodeToUse.measured) == null ? void 0 : _a.width) ?? nodeToUse.width,
@@ -4057,7 +4094,7 @@ function useReactFlow() {
4057
4094
  }
4058
4095
  return node;
4059
4096
  }));
4060
- }, updateEdge2 = (id2, edgeUpdate, options = { replace: !1 }) => {
4097
+ }, updateEdge = (id2, edgeUpdate, options = { replace: !1 }) => {
4061
4098
  setEdges((prevEdges) => prevEdges.map((edge) => {
4062
4099
  if (edge.id === id2) {
4063
4100
  const nextEdge = typeof edgeUpdate == "function" ? edgeUpdate(edge) : edgeUpdate;
@@ -4142,9 +4179,9 @@ function useReactFlow() {
4142
4179
  return options.replace ? { ...node, data: nextData } : { ...node, data: { ...node.data, ...nextData } };
4143
4180
  }, options);
4144
4181
  },
4145
- updateEdge: updateEdge2,
4182
+ updateEdge,
4146
4183
  updateEdgeData: (id2, dataUpdate, options = { replace: !1 }) => {
4147
- updateEdge2(id2, (edge) => {
4184
+ updateEdge(id2, (edge) => {
4148
4185
  const nextData = typeof dataUpdate == "function" ? dataUpdate(edge) : dataUpdate;
4149
4186
  return options.replace ? { ...edge, data: nextData } : { ...edge, data: { ...edge.data, ...nextData } };
4150
4187
  }, options);
@@ -4157,9 +4194,9 @@ function useReactFlow() {
4157
4194
  viewportInitialized
4158
4195
  }), [viewportInitialized]);
4159
4196
  }
4160
- const selected = (item) => item.selected, deleteKeyOptions = { actInsideInputWithModifier: !1 };
4197
+ const selected = (item) => item.selected, deleteKeyOptions = { actInsideInputWithModifier: !1 }, win$1 = typeof window < "u" ? window : void 0;
4161
4198
  function useGlobalKeyHandler({ deleteKeyCode, multiSelectionKeyCode }) {
4162
- const store = useStoreApi(), { deleteElements } = useReactFlow(), deleteKeyPressed = useKeyPress(deleteKeyCode, deleteKeyOptions), multiSelectionKeyPressed = useKeyPress(multiSelectionKeyCode);
4199
+ const store = useStoreApi(), { deleteElements } = useReactFlow(), deleteKeyPressed = useKeyPress(deleteKeyCode, deleteKeyOptions), multiSelectionKeyPressed = useKeyPress(multiSelectionKeyCode, { target: win$1 });
4163
4200
  useEffect(() => {
4164
4201
  if (deleteKeyPressed) {
4165
4202
  const { edges, nodes } = store.getState();
@@ -4194,12 +4231,12 @@ const containerStyle = {
4194
4231
  height: "100%",
4195
4232
  top: 0,
4196
4233
  left: 0
4197
- }, selector$l = (s) => ({
4234
+ }, selector$k = (s) => ({
4198
4235
  userSelectionActive: s.userSelectionActive,
4199
4236
  lib: s.lib
4200
4237
  });
4201
- 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 }) {
4202
- 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();
4203
4240
  return useResizeHandler(zoomPane), useEffect(() => {
4204
4241
  if (zoomPane.current) {
4205
4242
  panZoom.current = XYPanZoom({
@@ -4208,6 +4245,7 @@ function ZoomPane({ onPaneContextMenu, zoomOnScroll = !0, zoomOnPinch = !0, panO
4208
4245
  maxZoom,
4209
4246
  translateExtent,
4210
4247
  viewport: defaultViewport2,
4248
+ paneClickDistance,
4211
4249
  onTransformChange: (transform2) => {
4212
4250
  onViewportChange == null || onViewportChange({ x: transform2[0], y: transform2[1], zoom: transform2[2] }), isControlledViewport || store.setState({ transform: transform2 });
4213
4251
  },
@@ -4270,12 +4308,12 @@ function ZoomPane({ onPaneContextMenu, zoomOnScroll = !0, zoomOnPinch = !0, panO
4270
4308
  lib
4271
4309
  ]), jsx("div", { className: "react-flow__renderer", ref: zoomPane, style: containerStyle, children: children2 });
4272
4310
  }
4273
- const selector$k = (s) => ({
4311
+ const selector$j = (s) => ({
4274
4312
  userSelectionActive: s.userSelectionActive,
4275
4313
  userSelectionRect: s.userSelectionRect
4276
4314
  });
4277
4315
  function UserSelection() {
4278
- const { userSelectionActive, userSelectionRect } = useStore(selector$k, shallow);
4316
+ const { userSelectionActive, userSelectionRect } = useStore(selector$j, shallow);
4279
4317
  return userSelectionActive && userSelectionRect ? jsx("div", { className: "react-flow__selection react-flow__container", style: {
4280
4318
  width: userSelectionRect.width,
4281
4319
  height: userSelectionRect.height,
@@ -4284,15 +4322,19 @@ function UserSelection() {
4284
4322
  }
4285
4323
  const wrapHandler = (handler, containerRef) => (event) => {
4286
4324
  event.target === containerRef.current && (handler == null || handler(event));
4287
- }, selector$j = (s) => ({
4325
+ }, selector$i = (s) => ({
4288
4326
  userSelectionActive: s.userSelectionActive,
4289
4327
  elementsSelectable: s.elementsSelectable,
4290
4328
  dragging: s.paneDragging
4291
4329
  });
4292
- function Pane({ isSelecting, selectionMode = SelectionMode.Full, panOnDrag, onSelectionStart, onSelectionEnd, onPaneClick, onPaneContextMenu, onPaneScroll, onPaneMouseEnter, onPaneMouseMove, onPaneMouseLeave, children: children2 }) {
4293
- 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), resetUserSelection = () => {
4330
+ function Pane({ isSelecting, selectionKeyPressed, selectionMode = SelectionMode.Full, panOnDrag, onSelectionStart, onSelectionEnd, onPaneClick, onPaneContextMenu, onPaneScroll, onPaneMouseEnter, onPaneMouseMove, onPaneMouseLeave, children: children2 }) {
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 = () => {
4294
4332
  store.setState({ userSelectionActive: !1, userSelectionRect: null }), prevSelectedNodesCount.current = 0, prevSelectedEdgesCount.current = 0;
4295
4333
  }, onClick = (event) => {
4334
+ if (selectionInProgress.current) {
4335
+ selectionInProgress.current = !1;
4336
+ return;
4337
+ }
4296
4338
  onPaneClick == null || onPaneClick(event), store.getState().resetSelectedElements(), store.setState({ nodesSelectionActive: !1 });
4297
4339
  }, onContextMenu = (event) => {
4298
4340
  if (Array.isArray(panOnDrag) && (panOnDrag != null && panOnDrag.includes(2))) {
@@ -4300,14 +4342,14 @@ function Pane({ isSelecting, selectionMode = SelectionMode.Full, panOnDrag, onSe
4300
4342
  return;
4301
4343
  }
4302
4344
  onPaneContextMenu == null || onPaneContextMenu(event);
4303
- }, onWheel = onPaneScroll ? (event) => onPaneScroll(event) : void 0, onMouseDown = (event) => {
4304
- var _a, _b;
4345
+ }, onWheel = onPaneScroll ? (event) => onPaneScroll(event) : void 0, onPointerDown2 = (event) => {
4346
+ var _a, _b, _c, _d;
4305
4347
  const { resetSelectedElements, domNode, edgeLookup } = store.getState();
4306
- if (containerBounds.current = domNode == null ? void 0 : domNode.getBoundingClientRect(), !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)
4307
4349
  return;
4308
4350
  edgeIdLookup.current = /* @__PURE__ */ new Map();
4309
4351
  for (const [id2, edge] of edgeLookup)
4310
- edgeIdLookup.current.set(edge.source, ((_a = edgeIdLookup.current.get(edge.source)) == null ? void 0 : _a.add(id2)) || /* @__PURE__ */ new Set([id2])), edgeIdLookup.current.set(edge.target, ((_b = edgeIdLookup.current.get(edge.target)) == null ? void 0 : _b.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]));
4311
4353
  const { x, y } = getEventPosition(event.nativeEvent, containerBounds.current);
4312
4354
  resetSelectedElements(), store.setState({
4313
4355
  userSelectionRect: {
@@ -4319,10 +4361,11 @@ function Pane({ isSelecting, selectionMode = SelectionMode.Full, panOnDrag, onSe
4319
4361
  y
4320
4362
  }
4321
4363
  }), onSelectionStart == null || onSelectionStart(event);
4322
- }, onMouseMove = (event) => {
4323
- const { userSelectionRect, edgeLookup, transform: transform2, nodeOrigin, nodeLookup, triggerNodeChanges, triggerEdgeChanges } = store.getState();
4324
- if (!isSelecting || !containerBounds.current || !userSelectionRect)
4364
+ }, onPointerMove = (event) => {
4365
+ const { userSelectionRect, edgeLookup, transform: transform2, nodeLookup, triggerNodeChanges, triggerEdgeChanges } = store.getState();
4366
+ if (!containerBounds.current || !userSelectionRect)
4325
4367
  return;
4368
+ selectionInProgress.current = !0;
4326
4369
  const { x: mouseX, y: mouseY } = getEventPosition(event.nativeEvent, containerBounds.current), { startX, startY } = userSelectionRect, nextUserSelectRect = {
4327
4370
  startX,
4328
4371
  startY,
@@ -4330,7 +4373,7 @@ function Pane({ isSelecting, selectionMode = SelectionMode.Full, panOnDrag, onSe
4330
4373
  y: mouseY < startY ? mouseY : startY,
4331
4374
  width: Math.abs(mouseX - startX),
4332
4375
  height: Math.abs(mouseY - startY)
4333
- }, 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();
4334
4377
  for (const selectedNode of selectedNodes) {
4335
4378
  selectedNodeIds.add(selectedNode.id);
4336
4379
  const edgeIds = edgeIdLookup.current.get(selectedNode.id);
@@ -4353,15 +4396,15 @@ function Pane({ isSelecting, selectionMode = SelectionMode.Full, panOnDrag, onSe
4353
4396
  userSelectionActive: !0,
4354
4397
  nodesSelectionActive: !1
4355
4398
  });
4356
- }, onMouseUp = (event) => {
4399
+ }, onPointerUp = (event) => {
4400
+ var _a, _b;
4357
4401
  if (event.button !== 0)
4358
4402
  return;
4403
+ (_b = (_a = event.target) == null ? void 0 : _a.releasePointerCapture) == null || _b.call(_a, event.pointerId);
4359
4404
  const { userSelectionRect } = store.getState();
4360
- !userSelectionActive && userSelectionRect && event.target === container2.current && (onClick == null || onClick(event)), store.setState({ nodesSelectionActive: prevSelectedNodesCount.current > 0 }), resetUserSelection(), onSelectionEnd == null || onSelectionEnd(event);
4361
- }, onMouseLeave = (event) => {
4362
- userSelectionActive && (store.setState({ nodesSelectionActive: prevSelectedNodesCount.current > 0 }), onSelectionEnd == null || onSelectionEnd(event)), resetUserSelection();
4363
- }, hasActiveSelection = elementsSelectable && (isSelecting || userSelectionActive);
4364
- 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), onMouseEnter: hasActiveSelection ? void 0 : onPaneMouseEnter, onMouseDown: hasActiveSelection ? onMouseDown : void 0, onMouseMove: hasActiveSelection ? onMouseMove : onPaneMouseMove, onMouseUp: hasActiveSelection ? onMouseUp : void 0, onMouseLeave: hasActiveSelection ? onMouseLeave : onPaneMouseLeave, ref: container2, style: containerStyle, children: [children2, jsx(UserSelection, {})] });
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);
4406
+ };
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, {})] });
4365
4408
  }
4366
4409
  function handleNodeClick({ id: id2, store, unselect = !1, nodeRef }) {
4367
4410
  const { addSelectedNodes, unselectNodesAndEdges, multiSelectionActive, nodeLookup, onError } = store.getState(), node = nodeLookup.get(id2);
@@ -4438,24 +4481,24 @@ function useMoveSelectedNodes() {
4438
4481
  }
4439
4482
  const NodeIdContext = createContext(null), Provider = NodeIdContext.Provider;
4440
4483
  NodeIdContext.Consumer;
4441
- const useNodeId = () => useContext(NodeIdContext), selector$i = (s) => ({
4484
+ const useNodeId = () => useContext(NodeIdContext), selector$h = (s) => ({
4442
4485
  connectOnClick: s.connectOnClick,
4443
4486
  noPanClassName: s.noPanClassName,
4444
4487
  rfId: s.rfId
4445
4488
  }), connectingSelector = (nodeId, handleId, type) => (state) => {
4446
- 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;
4447
4490
  return {
4448
- 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,
4449
4492
  connectingTo,
4450
- clickConnecting: (clickHandle == null ? void 0 : clickHandle.nodeId) === nodeId && (clickHandle == null ? void 0 : clickHandle.handleId) === handleId && (clickHandle == null ? void 0 : clickHandle.type) === type,
4451
- 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),
4452
- connectionInProcess: !!startHandle,
4453
- 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
4454
4497
  };
4455
4498
  };
4456
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) {
4457
4500
  var _a, _b;
4458
- 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);
4459
4502
  nodeId || (_b = (_a = store.getState()).onError) == null || _b.call(_a, "010", errorMessages.error010());
4460
4503
  const onConnectExtended = (params) => {
4461
4504
  const { defaultEdgeOptions, onConnect: onConnectAction, hasDefaultEdges } = store.getState(), edgeParams = {
@@ -4492,7 +4535,8 @@ function HandleComponent({ type = "source", position = Position.Top, isValidConn
4492
4535
  onConnect: onConnectExtended,
4493
4536
  isValidConnection: isValidConnection || currentStore.isValidConnection,
4494
4537
  getTransform: () => store.getState().transform,
4495
- getConnectionStartHandle: () => store.getState().connectionStartHandle
4538
+ getFromHandle: () => store.getState().connection.fromHandle,
4539
+ autoPanSpeed: currentStore.autoPanSpeed
4496
4540
  });
4497
4541
  }
4498
4542
  isMouseTriggered ? onMouseDown == null || onMouseDown(event) : onTouchStart == null || onTouchStart(event);
@@ -4501,7 +4545,7 @@ function HandleComponent({ type = "source", position = Position.Top, isValidConn
4501
4545
  if (!nodeId || !connectionClickStartHandle && !isConnectableStart)
4502
4546
  return;
4503
4547
  if (!connectionClickStartHandle) {
4504
- 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 } });
4505
4549
  return;
4506
4550
  }
4507
4551
  const doc = getHostForElement(event.target), isValidConnectionHandler = isValidConnection || isValidConnectionStore, { connection, isValid } = XYHandle.isValid(event.nativeEvent, {
@@ -4512,7 +4556,7 @@ function HandleComponent({ type = "source", position = Position.Top, isValidConn
4512
4556
  },
4513
4557
  connectionMode,
4514
4558
  fromNodeId: connectionClickStartHandle.nodeId,
4515
- fromHandleId: connectionClickStartHandle.handleId || null,
4559
+ fromHandleId: connectionClickStartHandle.id || null,
4516
4560
  fromType: connectionClickStartHandle.type,
4517
4561
  isValidConnection: isValidConnectionHandler,
4518
4562
  flowId,
@@ -4577,9 +4621,8 @@ function getNodeInlineStyleDimensions(node) {
4577
4621
  height: node.height ?? ((_d = node.style) == null ? void 0 : _d.height)
4578
4622
  };
4579
4623
  }
4580
- const selector$h = (s) => {
4624
+ const selector$g = (s) => {
4581
4625
  const { width, height, x, y } = getInternalNodesBounds(s.nodeLookup, {
4582
- nodeOrigin: s.nodeOrigin,
4583
4626
  filter: (node) => !!node.selected
4584
4627
  });
4585
4628
  return {
@@ -4590,7 +4633,7 @@ const selector$h = (s) => {
4590
4633
  };
4591
4634
  };
4592
4635
  function NodesSelection({ onSelectionContextMenu, noPanClassName, disableKeyboardA11y }) {
4593
- 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);
4594
4637
  if (useEffect(() => {
4595
4638
  var _a;
4596
4639
  disableKeyboardA11y || (_a = nodeRef.current) == null || _a.focus({
@@ -4616,19 +4659,19 @@ function NodesSelection({ onSelectionContextMenu, noPanClassName, disableKeyboar
4616
4659
  height
4617
4660
  } }) });
4618
4661
  }
4619
- const selector$g = (s) => ({ nodesSelectionActive: s.nodesSelectionActive, userSelectionActive: s.userSelectionActive });
4620
- 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 }) {
4621
- const { nodesSelectionActive, userSelectionActive } = useStore(selector$g), selectionKeyPressed = useKeyPress(selectionKeyCode), panActivationKeyPressed = useKeyPress(panActivationKeyCode), panOnDrag = panActivationKeyPressed || _panOnDrag, panOnScroll = panActivationKeyPressed || _panOnScroll, isSelecting = selectionKeyPressed || userSelectionActive || selectionOnDrag && panOnDrag !== !0;
4622
- 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, 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 })] }) });
4623
4666
  }
4624
4667
  FlowRendererComponent.displayName = "FlowRenderer";
4625
- 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());
4626
4669
  function useVisibleNodeIds(onlyRenderVisible) {
4627
- return useStore(useCallback(selector$f(onlyRenderVisible), [onlyRenderVisible]), shallow);
4670
+ return useStore(useCallback(selector$e(onlyRenderVisible), [onlyRenderVisible]), shallow);
4628
4671
  }
4629
- const selector$e = (s) => s.updateNodeInternals;
4672
+ const selector$d = (s) => s.updateNodeInternals;
4630
4673
  function useResizeObserver() {
4631
- 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) => {
4632
4675
  const updates = /* @__PURE__ */ new Map();
4633
4676
  entries2.forEach((entry) => {
4634
4677
  const id2 = entry.target.getAttribute("data-id");
@@ -4656,7 +4699,7 @@ function useNodeObserver({ node, nodeType, hasDimensions, resizeObserver }) {
4656
4699
  }
4657
4700
  }, [node.id, nodeType, node.sourcePosition, node.targetPosition]), nodeRef;
4658
4701
  }
4659
- 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 }) {
4660
4703
  const { node, internals, isParent } = useStore((s) => {
4661
4704
  const node2 = s.nodeLookup.get(id2), isParent2 = s.parentLookup.has(id2);
4662
4705
  return {
@@ -4677,11 +4720,7 @@ function NodeWrapper({ id: id2, onClick, onMouseEnter, onMouseMove, onMouseLeave
4677
4720
  }), moveSelectedNodes = useMoveSelectedNodes();
4678
4721
  if (node.hidden)
4679
4722
  return null;
4680
- const nodeDimensions = getNodeDimensions(node), inlineDimensions = getNodeInlineStyleDimensions(node), clampedPosition = nodeExtent ? clampPosition(internals.positionAbsolute, nodeExtent) : internals.positionAbsolute, positionWithOrigin = getPositionWithOrigin({
4681
- ...clampedPosition,
4682
- ...nodeDimensions,
4683
- origin: node.origin || nodeOrigin
4684
- }), 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) => {
4685
4724
  const { selectNodesOnDrag, nodeDragThreshold } = store.getState();
4686
4725
  isSelectable && (!selectNodesOnDrag || !isDraggable || nodeDragThreshold > 0) && handleNodeClick({
4687
4726
  id: id2,
@@ -4722,14 +4761,14 @@ function NodeWrapper({ id: id2, onClick, onMouseEnter, onMouseMove, onMouseLeave
4722
4761
  }
4723
4762
  ]), ref: nodeRef, style: {
4724
4763
  zIndex: internals.z,
4725
- transform: `translate(${positionWithOrigin.x}px,${positionWithOrigin.y}px)`,
4764
+ transform: `translate(${clampedPosition.x}px,${clampedPosition.y}px)`,
4726
4765
  pointerEvents: hasPointerEvents ? "all" : "none",
4727
4766
  visibility: hasDimensions ? "visible" : "hidden",
4728
4767
  ...node.style,
4729
4768
  ...inlineDimensions
4730
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 }) }) });
4731
4770
  }
4732
- const selector$d = (s) => ({
4771
+ const selector$c = (s) => ({
4733
4772
  nodesDraggable: s.nodesDraggable,
4734
4773
  nodesConnectable: s.nodesConnectable,
4735
4774
  nodesFocusable: s.nodesFocusable,
@@ -4737,7 +4776,7 @@ const selector$d = (s) => ({
4737
4776
  onError: s.onError
4738
4777
  });
4739
4778
  function NodeRendererComponent(props) {
4740
- 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();
4741
4780
  return jsx("div", { className: "react-flow__nodes", style: containerStyle, children: nodeIds.map((nodeId) => (
4742
4781
  // The split of responsibilities between NodeRenderer and
4743
4782
  // NodeComponentWrapper may appear weird. However, it’s designed to
@@ -4762,7 +4801,7 @@ function NodeRendererComponent(props) {
4762
4801
  // moved into `NodeComponentWrapper`. This ensures they are
4763
4802
  // memorized – so if `NodeRenderer` *has* to rerender, it only
4764
4803
  // needs to regenerate the list of nodes, nothing else.
4765
- 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)
4766
4805
  )) });
4767
4806
  }
4768
4807
  NodeRendererComponent.displayName = "NodeRenderer";
@@ -4961,15 +5000,15 @@ const builtinEdgeTypes = {
4961
5000
  function EdgeAnchor({ position, centerX, centerY, radius = 10, onMouseDown, onMouseEnter, onMouseOut, type }) {
4962
5001
  return jsx("circle", { onMouseDown, onMouseEnter, onMouseOut, className: cc([EdgeUpdaterClassName, `${EdgeUpdaterClassName}-${type}`]), cx: shiftX(centerX, radius, position), cy: shiftY(centerY, radius, position), r: radius, stroke: "transparent", fill: "transparent" });
4963
5002
  }
4964
- function EdgeUpdateAnchors({ isUpdatable, edgeUpdaterRadius, edge, targetHandleId, sourceHandleId, sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, onEdgeUpdate, onEdgeUpdateStart, onEdgeUpdateEnd, setUpdating, setUpdateHover }) {
5003
+ function EdgeUpdateAnchors({ isReconnectable, reconnectRadius, edge, targetHandleId, sourceHandleId, sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, onReconnect, onReconnectStart, onReconnectEnd, setReconnecting, setUpdateHover }) {
4965
5004
  const store = useStoreApi(), handleEdgeUpdater = (event, isSourceHandle) => {
4966
5005
  if (event.button !== 0)
4967
5006
  return;
4968
5007
  const { autoPanOnConnect, domNode, isValidConnection, connectionMode, connectionRadius, lib, onConnectStart, onConnectEnd, cancelConnection, nodeLookup, rfId: flowId, panBy: panBy2, updateConnection } = store.getState(), nodeId = isSourceHandle ? edge.target : edge.source, handleId = (isSourceHandle ? targetHandleId : sourceHandleId) || null, handleType = isSourceHandle ? "target" : "source", isTarget = isSourceHandle;
4969
- setUpdating(!0), onEdgeUpdateStart == null || onEdgeUpdateStart(event, edge, handleType);
4970
- const _onEdgeUpdateEnd = (evt) => {
4971
- setUpdating(!1), onEdgeUpdateEnd == null || onEdgeUpdateEnd(evt, edge, handleType);
4972
- }, onConnectEdge = (connection) => onEdgeUpdate == null ? void 0 : onEdgeUpdate(edge, connection);
5008
+ setReconnecting(!0), onReconnectStart == null || onReconnectStart(event, edge, handleType);
5009
+ const _onReconnectEnd = (evt) => {
5010
+ setReconnecting(!1), onReconnectEnd == null || onReconnectEnd(evt, edge, handleType);
5011
+ }, onConnectEdge = (connection) => onReconnect == null ? void 0 : onReconnect(edge, connection);
4973
5012
  XYHandle.onPointerDown(event.nativeEvent, {
4974
5013
  autoPanOnConnect,
4975
5014
  connectionMode,
@@ -4988,21 +5027,21 @@ function EdgeUpdateAnchors({ isUpdatable, edgeUpdaterRadius, edge, targetHandleI
4988
5027
  onConnect: onConnectEdge,
4989
5028
  onConnectStart,
4990
5029
  onConnectEnd,
4991
- onEdgeUpdateEnd: _onEdgeUpdateEnd,
5030
+ onReconnectEnd: _onReconnectEnd,
4992
5031
  updateConnection,
4993
5032
  getTransform: () => store.getState().transform,
4994
- getConnectionStartHandle: () => store.getState().connectionStartHandle
5033
+ getFromHandle: () => store.getState().connection.fromHandle
4995
5034
  });
4996
- }, onEdgeUpdaterSourceMouseDown = (event) => handleEdgeUpdater(event, !0), onEdgeUpdaterTargetMouseDown = (event) => handleEdgeUpdater(event, !1), onEdgeUpdaterMouseEnter = () => setUpdateHover(!0), onEdgeUpdaterMouseOut = () => setUpdateHover(!1);
4997
- return jsxs(Fragment, { children: [(isUpdatable === "source" || isUpdatable === !0) && jsx(EdgeAnchor, { position: sourcePosition, centerX: sourceX, centerY: sourceY, radius: edgeUpdaterRadius, onMouseDown: onEdgeUpdaterSourceMouseDown, onMouseEnter: onEdgeUpdaterMouseEnter, onMouseOut: onEdgeUpdaterMouseOut, type: "source" }), (isUpdatable === "target" || isUpdatable === !0) && jsx(EdgeAnchor, { position: targetPosition, centerX: targetX, centerY: targetY, radius: edgeUpdaterRadius, onMouseDown: onEdgeUpdaterTargetMouseDown, onMouseEnter: onEdgeUpdaterMouseEnter, onMouseOut: onEdgeUpdaterMouseOut, type: "target" })] });
5035
+ }, onReconnectSourceMouseDown = (event) => handleEdgeUpdater(event, !0), onReconnectTargetMouseDown = (event) => handleEdgeUpdater(event, !1), onReconnectMouseEnter = () => setUpdateHover(!0), onReconnectMouseOut = () => setUpdateHover(!1);
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" })] });
4998
5037
  }
4999
- function EdgeWrapper({ id: id2, edgesFocusable, edgesUpdatable, elementsSelectable, onClick, onDoubleClick, onContextMenu, onMouseEnter, onMouseMove, onMouseLeave, edgeUpdaterRadius, onEdgeUpdate, onEdgeUpdateStart, onEdgeUpdateEnd, rfId, edgeTypes: edgeTypes2, noPanClassName, onError, disableKeyboardA11y }) {
5038
+ function EdgeWrapper({ id: id2, edgesFocusable, edgesReconnectable, elementsSelectable, onClick, onDoubleClick, onContextMenu, onMouseEnter, onMouseMove, onMouseLeave, reconnectRadius, onReconnect, onReconnectStart, onReconnectEnd, rfId, edgeTypes: edgeTypes2, noPanClassName, onError, disableKeyboardA11y }) {
5000
5039
  let edge = useStore((s) => s.edgeLookup.get(id2));
5001
5040
  const defaultEdgeOptions = useStore((s) => s.defaultEdgeOptions);
5002
5041
  edge = defaultEdgeOptions ? { ...defaultEdgeOptions, ...edge } : edge;
5003
5042
  let edgeType = edge.type || "default", EdgeComponent = (edgeTypes2 == null ? void 0 : edgeTypes2[edgeType]) || builtinEdgeTypes[edgeType];
5004
5043
  EdgeComponent === void 0 && (onError == null || onError("011", errorMessages.error011(edgeType)), edgeType = "default", EdgeComponent = builtinEdgeTypes.default);
5005
- const isFocusable = !!(edge.focusable || edgesFocusable && typeof edge.focusable > "u"), isUpdatable = typeof onEdgeUpdate < "u" && (edge.updatable || edgesUpdatable && typeof edge.updatable > "u"), isSelectable = !!(edge.selectable || elementsSelectable && typeof edge.selectable > "u"), edgeRef = useRef(null), [updateHover, setUpdateHover] = useState(!1), [updating, setUpdating] = useState(!1), store = useStoreApi(), { zIndex, sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition } = useStore(useCallback((store2) => {
5044
+ const isFocusable = !!(edge.focusable || edgesFocusable && typeof edge.focusable > "u"), isReconnectable = typeof onReconnect < "u" && (edge.reconnectable || edgesReconnectable && typeof edge.reconnectable > "u"), isSelectable = !!(edge.selectable || elementsSelectable && typeof edge.selectable > "u"), edgeRef = useRef(null), [updateHover, setUpdateHover] = useState(!1), [reconnecting, setReconnecting] = useState(!1), store = useStoreApi(), { zIndex, sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition } = useStore(useCallback((store2) => {
5006
5045
  const sourceNode = store2.nodeLookup.get(edge.source), targetNode = store2.nodeLookup.get(edge.target);
5007
5046
  if (!sourceNode || !targetNode)
5008
5047
  return {
@@ -5064,25 +5103,25 @@ function EdgeWrapper({ id: id2, edgesFocusable, edgesUpdatable, elementsSelectab
5064
5103
  updating: updateHover,
5065
5104
  selectable: isSelectable
5066
5105
  }
5067
- ]), 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: [!updating && 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 }), isUpdatable && jsx(EdgeUpdateAnchors, { edge, isUpdatable, edgeUpdaterRadius, onEdgeUpdate, onEdgeUpdateStart, onEdgeUpdateEnd, sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, setUpdateHover, setUpdating, sourceHandleId: edge.sourceHandle, targetHandleId: edge.targetHandle })] }) });
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 })] }) });
5068
5107
  }
5069
- const selector$c = (s) => ({
5108
+ const selector$b = (s) => ({
5070
5109
  width: s.width,
5071
5110
  height: s.height,
5072
5111
  edgesFocusable: s.edgesFocusable,
5073
- edgesUpdatable: s.edgesUpdatable,
5112
+ edgesReconnectable: s.edgesReconnectable,
5074
5113
  elementsSelectable: s.elementsSelectable,
5075
5114
  connectionMode: s.connectionMode,
5076
5115
  onError: s.onError
5077
5116
  });
5078
- function EdgeRendererComponent({ defaultMarkerColor, onlyRenderVisibleElements, rfId, edgeTypes: edgeTypes2, noPanClassName, onEdgeUpdate, onEdgeContextMenu, onEdgeMouseEnter, onEdgeMouseMove, onEdgeMouseLeave, onEdgeClick, edgeUpdaterRadius, onEdgeDoubleClick, onEdgeUpdateStart, onEdgeUpdateEnd, disableKeyboardA11y }) {
5079
- const { edgesFocusable, edgesUpdatable, elementsSelectable, onError } = useStore(selector$c, shallow), edgeIds = useVisibleEdgeIds(onlyRenderVisibleElements);
5080
- return jsxs("div", { className: "react-flow__edges", children: [jsx(MarkerDefinitions$1, { defaultColor: defaultMarkerColor, rfId }), edgeIds.map((id2) => jsx(EdgeWrapper, { id: id2, edgesFocusable, edgesUpdatable, elementsSelectable, noPanClassName, onEdgeUpdate, onContextMenu: onEdgeContextMenu, onMouseEnter: onEdgeMouseEnter, onMouseMove: onEdgeMouseMove, onMouseLeave: onEdgeMouseLeave, onClick: onEdgeClick, edgeUpdaterRadius, onDoubleClick: onEdgeDoubleClick, onEdgeUpdateStart, onEdgeUpdateEnd, rfId, onError, edgeTypes: edgeTypes2, disableKeyboardA11y }, id2))] });
5117
+ function EdgeRendererComponent({ defaultMarkerColor, onlyRenderVisibleElements, rfId, edgeTypes: edgeTypes2, noPanClassName, onReconnect, onEdgeContextMenu, onEdgeMouseEnter, onEdgeMouseMove, onEdgeMouseLeave, onEdgeClick, reconnectRadius, onEdgeDoubleClick, onReconnectStart, onReconnectEnd, disableKeyboardA11y }) {
5118
+ const { edgesFocusable, edgesReconnectable, elementsSelectable, onError } = useStore(selector$b, shallow), edgeIds = useVisibleEdgeIds(onlyRenderVisibleElements);
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))] });
5081
5120
  }
5082
5121
  EdgeRendererComponent.displayName = "EdgeRenderer";
5083
- 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]})`;
5084
5123
  function Viewport({ children: children2 }) {
5085
- const transform2 = useStore(selector$b);
5124
+ const transform2 = useStore(selector$a);
5086
5125
  return jsx("div", { className: "react-flow__viewport xyflow__viewport react-flow__container", style: { transform: transform2 }, children: children2 });
5087
5126
  }
5088
5127
  function useOnInitHandler(onInit) {
@@ -5091,70 +5130,68 @@ function useOnInitHandler(onInit) {
5091
5130
  !isInitialized.current && rfInstance.viewportInitialized && onInit && (setTimeout(() => onInit(rfInstance), 1), isInitialized.current = !0);
5092
5131
  }, [onInit, rfInstance.viewportInitialized]);
5093
5132
  }
5094
- const selector$a = (state) => {
5133
+ const selector$9 = (state) => {
5095
5134
  var _a;
5096
5135
  return (_a = state.panZoom) == null ? void 0 : _a.syncViewport;
5097
5136
  };
5098
5137
  function useViewportSync(viewport) {
5099
- const syncViewport = useStore(selector$a), store = useStoreApi();
5138
+ const syncViewport = useStore(selector$9), store = useStoreApi();
5100
5139
  return useEffect(() => {
5101
5140
  viewport && (syncViewport == null || syncViewport(viewport), store.setState({ transform: [viewport.x, viewport.y, viewport.zoom] }));
5102
5141
  }, [viewport, syncViewport]), null;
5103
5142
  }
5104
- const oppositePosition = {
5105
- [Position.Left]: Position.Right,
5106
- [Position.Right]: Position.Left,
5107
- [Position.Top]: Position.Bottom,
5108
- [Position.Bottom]: Position.Top
5109
- }, ConnectionLine = ({ nodeId, handleType, style: style2, type = ConnectionLineType.Bezier, CustomComponent, connectionStatus }) => {
5110
- const { fromNode, handleId, toX, toY, connectionMode } = useStore(useCallback((s) => {
5111
- var _a;
5112
- return {
5113
- fromNode: s.nodeLookup.get(nodeId),
5114
- handleId: (_a = s.connectionStartHandle) == null ? void 0 : _a.handleId,
5115
- toX: (s.connectionPosition.x - s.transform[0]) / s.transform[2],
5116
- toY: (s.connectionPosition.y - s.transform[1]) / s.transform[2],
5117
- connectionMode: s.connectionMode
5118
- };
5119
- }, [nodeId]), shallow), fromHandleBounds = fromNode == null ? void 0 : fromNode.internals.handleBounds;
5120
- let handleBounds = fromHandleBounds == null ? void 0 : fromHandleBounds[handleType];
5121
- if (connectionMode === ConnectionMode.Loose && (handleBounds = handleBounds || (fromHandleBounds == null ? void 0 : fromHandleBounds[handleType === "source" ? "target" : "source"])), !fromNode || !handleBounds)
5122
- return null;
5123
- 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 = fromPosition ? oppositePosition[fromPosition] : null;
5124
- if (!fromPosition || !toPosition)
5125
- 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;
5126
5162
  if (CustomComponent)
5127
- return jsx(CustomComponent, { connectionLineType: type, connectionLineStyle: style2, fromNode, fromHandle, fromX, fromY, toX, toY, fromPosition, toPosition, connectionStatus });
5128
- 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 = "";
5129
5165
  const pathParams = {
5130
- sourceX: fromX,
5131
- sourceY: fromY,
5166
+ sourceX: from.x,
5167
+ sourceY: from.y,
5132
5168
  sourcePosition: fromPosition,
5133
- targetX: toX,
5134
- targetY: toY,
5169
+ targetX: to.x,
5170
+ targetY: to.y,
5135
5171
  targetPosition: toPosition
5136
5172
  };
5137
- return type === ConnectionLineType.Bezier ? [dAttr] = getBezierPath(pathParams) : type === ConnectionLineType.Step ? [dAttr] = getSmoothStepPath({
5138
- ...pathParams,
5139
- borderRadius: 0
5140
- }) : 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 });
5141
5193
  };
5142
5194
  ConnectionLine.displayName = "ConnectionLine";
5143
- const selector$9 = (s) => {
5144
- var _a, _b;
5145
- return {
5146
- nodeId: (_a = s.connectionStartHandle) == null ? void 0 : _a.nodeId,
5147
- handleType: (_b = s.connectionStartHandle) == null ? void 0 : _b.type,
5148
- nodesConnectable: s.nodesConnectable,
5149
- connectionStatus: s.connectionStatus,
5150
- width: s.width,
5151
- height: s.height
5152
- };
5153
- };
5154
- function ConnectionLineWrapper({ containerStyle: containerStyle2, style: style2, type, component }) {
5155
- const { nodeId, handleType, nodesConnectable, width, height, connectionStatus } = useStore(selector$9, shallow);
5156
- 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 }) }) });
5157
- }
5158
5195
  const emptyTypes = {};
5159
5196
  function useNodeOrEdgeTypesWarning(nodeOrEdgeTypes = emptyTypes) {
5160
5197
  useRef(nodeOrEdgeTypes), useStoreApi(), useEffect(() => {
@@ -5164,20 +5201,19 @@ function useStylesLoadedWarning() {
5164
5201
  useStoreApi(), useRef(!1), useEffect(() => {
5165
5202
  }, []);
5166
5203
  }
5167
- 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, onEdgeUpdate, onEdgeContextMenu, onEdgeMouseEnter, onEdgeMouseMove, onEdgeMouseLeave, edgeUpdaterRadius, onEdgeUpdateStart, onEdgeUpdateEnd, noDragClassName, noWheelClassName, noPanClassName, disableKeyboardA11y, nodeOrigin, nodeExtent, rfId, viewport, onViewportChange }) {
5168
- 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, onEdgeUpdate, onlyRenderVisibleElements, onEdgeContextMenu, onEdgeMouseEnter, onEdgeMouseMove, onEdgeMouseLeave, onEdgeUpdateStart, onEdgeUpdateEnd, edgeUpdaterRadius, 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" })] }) });
5169
5206
  }
5170
5207
  GraphViewComponent.displayName = "GraphView";
5171
- const GraphView = memo(GraphViewComponent), getInitialState = ({ nodes, edges, defaultNodes, defaultEdges, width, height, fitView: fitView2 } = {}) => {
5172
- 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];
5173
5210
  updateConnectionLookup(connectionLookup, edgeLookup, storeEdges), adoptUserNodes(storeNodes, nodeLookup, parentLookup, {
5174
- nodeOrigin: [0, 0],
5211
+ nodeOrigin: storeNodeOrigin,
5175
5212
  elevateNodesOnSelect: !1
5176
5213
  });
5177
5214
  let transform2 = [0, 0, 1];
5178
5215
  if (fitView2 && width && height) {
5179
5216
  const bounds = getInternalNodesBounds(nodeLookup, {
5180
- nodeOrigin: [0, 0],
5181
5217
  filter: (node) => !!((node.width || node.initialWidth) && (node.height || node.initialHeight))
5182
5218
  }), { x, y, zoom: zoom2 } = getViewportForBounds(bounds, width, height, 0.5, 2, 0.1);
5183
5219
  transform2 = [x, y, zoom2];
@@ -5205,13 +5241,11 @@ const GraphView = memo(GraphViewComponent), getInitialState = ({ nodes, edges, d
5205
5241
  nodesSelectionActive: !1,
5206
5242
  userSelectionActive: !1,
5207
5243
  userSelectionRect: null,
5208
- connectionPosition: { x: 0, y: 0 },
5209
- connectionStatus: null,
5210
5244
  connectionMode: ConnectionMode.Strict,
5211
5245
  domNode: null,
5212
5246
  paneDragging: !1,
5213
5247
  noPanClassName: "nopan",
5214
- nodeOrigin: [0, 0],
5248
+ nodeOrigin: storeNodeOrigin,
5215
5249
  nodeDragThreshold: 1,
5216
5250
  snapGrid: [15, 15],
5217
5251
  snapToGrid: !1,
@@ -5219,7 +5253,7 @@ const GraphView = memo(GraphViewComponent), getInitialState = ({ nodes, edges, d
5219
5253
  nodesConnectable: !0,
5220
5254
  nodesFocusable: !0,
5221
5255
  edgesFocusable: !0,
5222
- edgesUpdatable: !0,
5256
+ edgesReconnectable: !0,
5223
5257
  elementsSelectable: !0,
5224
5258
  elevateNodesOnSelect: !0,
5225
5259
  elevateEdgesOnSelect: !1,
@@ -5228,13 +5262,13 @@ const GraphView = memo(GraphViewComponent), getInitialState = ({ nodes, edges, d
5228
5262
  fitViewOnInitOptions: void 0,
5229
5263
  selectNodesOnDrag: !0,
5230
5264
  multiSelectionActive: !1,
5231
- connectionStartHandle: null,
5232
- connectionEndHandle: null,
5265
+ connection: { ...initialConnection },
5233
5266
  connectionClickStartHandle: null,
5234
5267
  connectOnClick: !0,
5235
5268
  ariaLiveMessage: "",
5236
5269
  autoPanOnConnect: !0,
5237
5270
  autoPanOnNodeDrag: !0,
5271
+ autoPanSpeed: 15,
5238
5272
  connectionRadius: 20,
5239
5273
  onError: devWarn,
5240
5274
  isValidConnection: void 0,
@@ -5242,11 +5276,11 @@ const GraphView = memo(GraphViewComponent), getInitialState = ({ nodes, edges, d
5242
5276
  lib: "react",
5243
5277
  debug: !1
5244
5278
  };
5245
- }, createStore = ({ nodes, edges, defaultNodes, defaultEdges, width, height, fitView: fitView$1 }) => createWithEqualityFn((set2, get2) => ({
5246
- ...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 }),
5247
5281
  setNodes: (nodes2) => {
5248
- const { nodeLookup, parentLookup, nodeOrigin, elevateNodesOnSelect } = get2();
5249
- 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 });
5250
5284
  },
5251
5285
  setEdges: (edges2) => {
5252
5286
  const { connectionLookup, edgeLookup } = get2();
@@ -5266,12 +5300,12 @@ const GraphView = memo(GraphViewComponent), getInitialState = ({ nodes, edges, d
5266
5300
  // changes its dimensions, this function is called to measure the
5267
5301
  // new dimensions and update the nodes.
5268
5302
  updateNodeInternals: (updates) => {
5269
- 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);
5270
5304
  if (!updatedInternals)
5271
5305
  return;
5272
- updateAbsolutePositions(nodeLookup, { nodeOrigin });
5306
+ updateAbsolutePositions(nodeLookup, parentLookup, { nodeOrigin: nodeOrigin2 });
5273
5307
  let nextFitViewDone = fitViewDone;
5274
- !fitViewDone && fitViewOnInit && (nextFitViewDone = fitView2({
5308
+ !fitViewDone && fitViewOnInit && (nextFitViewDone = fitViewSync({
5275
5309
  ...fitViewOnInitOptions,
5276
5310
  nodes: fitViewOnInitOptions == null ? void 0 : fitViewOnInitOptions.nodes
5277
5311
  })), set2({ fitViewDone: nextFitViewDone }), (changes == null ? void 0 : changes.length) > 0 && (debug && console.log("React Flow: trigger node changes", changes), triggerNodeChanges == null || triggerNodeChanges(changes));
@@ -5296,7 +5330,7 @@ const GraphView = memo(GraphViewComponent), getInitialState = ({ nodes, edges, d
5296
5330
  }), change.position.x = Math.max(0, change.position.x), change.position.y = Math.max(0, change.position.y)), changes.push(change);
5297
5331
  }
5298
5332
  if (parentExpandChildren.length > 0) {
5299
- const { nodeLookup, parentLookup } = get2(), parentExpandChanges = handleExpandParent(parentExpandChildren, nodeLookup, parentLookup);
5333
+ const { nodeLookup, parentLookup, nodeOrigin: nodeOrigin2 } = get2(), parentExpandChanges = handleExpandParent(parentExpandChildren, nodeLookup, parentLookup, nodeOrigin2);
5300
5334
  changes.push(...parentExpandChanges);
5301
5335
  }
5302
5336
  get2().triggerNodeChanges(changes);
@@ -5355,6 +5389,10 @@ const GraphView = memo(GraphViewComponent), getInitialState = ({ nodes, edges, d
5355
5389
  var _a;
5356
5390
  (_a = get2().panZoom) == null || _a.setTranslateExtent(translateExtent), set2({ translateExtent });
5357
5391
  },
5392
+ setPaneClickDistance: (clickDistance) => {
5393
+ var _a;
5394
+ (_a = get2().panZoom) == null || _a.setClickDistance(clickDistance);
5395
+ },
5358
5396
  resetSelectedElements: () => {
5359
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, []);
5360
5398
  triggerNodeChanges(nodeChanges), triggerEdgeChanges(edgeChanges);
@@ -5380,32 +5418,46 @@ const GraphView = memo(GraphViewComponent), getInitialState = ({ nodes, edges, d
5380
5418
  return panBy({ delta, panZoom, transform: transform2, translateExtent, width: width2, height: height2 });
5381
5419
  },
5382
5420
  fitView: (options) => {
5383
- const { panZoom, width: width2, height: height2, minZoom, maxZoom, nodeOrigin, nodeLookup } = get2();
5384
- return panZoom ? fitView({
5385
- 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,
5386
5427
  width: width2,
5387
5428
  height: height2,
5388
5429
  panZoom,
5389
5430
  minZoom,
5390
- maxZoom,
5391
- nodeOrigin
5392
- }, options) : !1;
5431
+ maxZoom
5432
+ }, options);
5393
5433
  },
5394
- cancelConnection: () => set2({
5395
- connectionStatus: null,
5396
- connectionStartHandle: null,
5397
- connectionEndHandle: null
5398
- }),
5399
- updateConnection: (params) => {
5400
- const { connectionPosition } = get2(), currentConnection = {
5401
- ...params,
5402
- connectionPosition: params.connectionPosition ?? connectionPosition
5403
- };
5404
- 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 });
5405
5457
  },
5406
5458
  reset: () => set2({ ...getInitialState() })
5407
5459
  }), Object.is);
5408
- 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 }) {
5409
5461
  const [store] = useState(() => createStore({
5410
5462
  nodes,
5411
5463
  edges,
@@ -5413,12 +5465,13 @@ function ReactFlowProvider({ initialNodes: nodes, initialEdges: edges, defaultNo
5413
5465
  defaultEdges,
5414
5466
  width,
5415
5467
  height,
5416
- fitView: fitView2
5468
+ fitView: fitView2,
5469
+ nodeOrigin
5417
5470
  }));
5418
5471
  return jsx(Provider$1, { value: store, children: jsx(BatchProvider, { children: children2 }) });
5419
5472
  }
5420
- function Wrapper({ children: children2, nodes, edges, defaultNodes, defaultEdges, width, height, fitView: fitView2 }) {
5421
- 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 });
5422
5475
  }
5423
5476
  const wrapperStyle = {
5424
5477
  width: "100%",
@@ -5427,17 +5480,17 @@ const wrapperStyle = {
5427
5480
  position: "relative",
5428
5481
  zIndex: 0
5429
5482
  };
5430
- 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, edgesUpdatable, 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, onEdgeUpdate, onEdgeContextMenu, onEdgeDoubleClick, onEdgeMouseEnter, onEdgeMouseMove, onEdgeMouseLeave, onEdgeUpdateStart, onEdgeUpdateEnd, edgeUpdaterRadius = 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) {
5431
5484
  const rfId = id2 || "1", colorModeClassName = useColorModeClass(colorMode);
5432
- 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, onEdgeUpdate, onEdgeContextMenu, onEdgeDoubleClick, onEdgeMouseEnter, onEdgeMouseMove, onEdgeMouseLeave, onEdgeUpdateStart, onEdgeUpdateEnd, edgeUpdaterRadius, 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, edgesUpdatable, 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 })] }) });
5433
5486
  }
5434
5487
  var index = fixedForwardRef(ReactFlow);
5435
- const selector$8 = (s) => {
5488
+ const selector$6 = (s) => {
5436
5489
  var _a;
5437
5490
  return (_a = s.domNode) == null ? void 0 : _a.querySelector(".react-flow__edgelabel-renderer");
5438
5491
  };
5439
5492
  function EdgeLabelRenderer({ children: children2 }) {
5440
- const edgeLabelRenderer = useStore(selector$8);
5493
+ const edgeLabelRenderer = useStore(selector$6);
5441
5494
  return edgeLabelRenderer ? createPortal(children2, edgeLabelRenderer) : null;
5442
5495
  }
5443
5496
  function useOnViewportChange({ onStart, onChange, onEnd }) {
@@ -5488,7 +5541,7 @@ const defaultSize = {
5488
5541
  [BackgroundVariant.Dots]: 1,
5489
5542
  [BackgroundVariant.Lines]: 1,
5490
5543
  [BackgroundVariant.Cross]: 6
5491
- }, selector$4 = (s) => ({ transform: s.transform, patternId: `pattern-${s.rfId}` });
5544
+ }, selector$3$1 = (s) => ({ transform: s.transform, patternId: `pattern-${s.rfId}` });
5492
5545
  function BackgroundComponent({
5493
5546
  id: id2,
5494
5547
  variant = BackgroundVariant.Dots,
@@ -5504,7 +5557,7 @@ function BackgroundComponent({
5504
5557
  className,
5505
5558
  patternClassName
5506
5559
  }) {
5507
- 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 || ""}`;
5508
5561
  return jsxs("svg", { className: cc(["react-flow__background", className]), style: {
5509
5562
  ...style2,
5510
5563
  ...containerStyle,
@@ -5532,13 +5585,13 @@ function UnlockIcon() {
5532
5585
  function ControlButton({ children: children2, className, ...rest }) {
5533
5586
  return jsx("button", { type: "button", className: cc(["react-flow__controls-button", className]), ...rest, children: children2 });
5534
5587
  }
5535
- const selector$3 = (s) => ({
5588
+ const selector$2$1 = (s) => ({
5536
5589
  isInteractive: s.nodesDraggable || s.nodesConnectable || s.elementsSelectable,
5537
5590
  minZoomReached: s.transform[2] <= s.minZoom,
5538
5591
  maxZoomReached: s.transform[2] >= s.maxZoom
5539
5592
  });
5540
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" }) {
5541
- 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 = () => {
5542
5595
  zoomIn(), onZoomIn == null || onZoomIn();
5543
5596
  }, onZoomOutHandler = () => {
5544
5597
  zoomOut(), onZoomOut == null || onZoomOut();
@@ -5563,7 +5616,7 @@ function MiniMapNodeComponent({ id: id2, x, y, width, height, style: style2, col
5563
5616
  strokeWidth
5564
5617
  }, shapeRendering, onClick: onClick ? (event) => onClick(event, id2) : void 0 });
5565
5618
  }
5566
- 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;
5567
5620
  function MiniMapNodes({
5568
5621
  nodeStrokeColor,
5569
5622
  nodeColor,
@@ -5575,19 +5628,19 @@ function MiniMapNodes({
5575
5628
  nodeComponent: NodeComponent = MiniMapNode,
5576
5629
  onClick
5577
5630
  }) {
5578
- 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";
5579
5632
  return jsx(Fragment, { children: nodeIds.map((nodeId) => (
5580
5633
  // The split of responsibilities between MiniMapNodes and
5581
5634
  // NodeComponentWrapper may appear weird. However, it’s designed to
5582
5635
  // minimize the cost of updates when individual nodes change.
5583
5636
  //
5584
5637
  // For more details, see a similar commit in `NodeRenderer/index.tsx`.
5585
- 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)
5586
5639
  )) });
5587
5640
  }
5588
- 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 }) {
5589
5642
  const { node, x, y } = useStore((s) => {
5590
- 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;
5591
5644
  return {
5592
5645
  node: node2,
5593
5646
  x: x2,
@@ -5610,9 +5663,8 @@ const defaultWidth = 200, defaultHeight = 150, selector$1$1 = (s) => {
5610
5663
  };
5611
5664
  return {
5612
5665
  viewBB,
5613
- 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,
5614
5667
  rfId: s.rfId,
5615
- nodeOrigin: s.nodeOrigin,
5616
5668
  panZoom: s.panZoom,
5617
5669
  translateExtent: s.translateExtent,
5618
5670
  flowWidth: s.width,
@@ -5710,19 +5762,19 @@ function ResizeControl({ nodeId, position, variant = ResizeControlVariant.Handle
5710
5762
  onChange: (change, childChanges) => {
5711
5763
  const { triggerNodeChanges, nodeLookup, parentLookup, nodeOrigin } = store.getState(), changes = [], nextPosition = { x: change.x, y: change.y }, node = nodeLookup.get(id2);
5712
5764
  if (node && node.expandParent && node.parentId) {
5713
- const child = {
5765
+ const origin = node.origin ?? nodeOrigin, width = change.width ?? node.measured.width, height = change.height ?? node.measured.height, child = {
5714
5766
  id: node.id,
5715
5767
  parentId: node.parentId,
5716
5768
  rect: {
5717
- width: change.width ?? node.measured.width,
5718
- height: change.height ?? node.measured.height,
5769
+ width,
5770
+ height,
5719
5771
  ...evaluateAbsolutePosition({
5720
5772
  x: change.x ?? node.position.x,
5721
5773
  y: change.y ?? node.position.y
5722
- }, node.parentId, nodeLookup, node.origin ?? nodeOrigin)
5774
+ }, { width, height }, node.parentId, nodeLookup, origin)
5723
5775
  }
5724
5776
  }, parentExpandChanges = handleExpandParent([child], nodeLookup, parentLookup, nodeOrigin);
5725
- 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;
5726
5778
  }
5727
5779
  if (nextPosition.x !== void 0 && nextPosition.y !== void 0) {
5728
5780
  const positionChange = {
@@ -5833,30 +5885,7 @@ function useTilg$1(...args) {
5833
5885
  tilg.exports = production;
5834
5886
  var tilgExports = tilg.exports;
5835
5887
  const useTilg = /* @__PURE__ */ getDefaultExportFromCjs(tilgExports);
5836
- var rootClassName = "likec4-diagram-root", keepAspectRatioContainer = "_2h8g8h0", cssReactFlow = "_2h8g8h1", cssDisablePan = "_2h8g8h2", cssTransparentBg = "_2h8g8h3", cssNoControls = "_2h8g8h4";
5837
- function KeepAspectRatioContainer({
5838
- children: children2,
5839
- width,
5840
- height,
5841
- enabled,
5842
- className,
5843
- style: style2,
5844
- ...rest
5845
- }) {
5846
- return /* @__PURE__ */ jsx(
5847
- Box,
5848
- {
5849
- ...rest,
5850
- className: clsx(keepAspectRatioContainer, className),
5851
- style: enabled ? {
5852
- ...style2,
5853
- aspectRatio: `${Math.ceil(width)}/${Math.ceil(height)}`,
5854
- maxHeight: `var(--likec4-view-max-height, ${Math.ceil(height)}px)`
5855
- } : style2,
5856
- children: children2
5857
- }
5858
- );
5859
- }
5888
+ var rootClassName = "likec4-diagram-root", cssReactFlow = "_2h8g8h0", cssDisablePan = "_2h8g8h1", cssTransparentBg = "_2h8g8h2", cssNoControls = "_2h8g8h3";
5860
5889
  function EnsureMantine({ children: children2 }) {
5861
5890
  if (!useContext(MantineContext))
5862
5891
  throw new Error("LikeC4Diagram must be a child of MantineProvider");
@@ -7011,24 +7040,27 @@ function useDiagramStoreApi() {
7011
7040
  const store = useContext(DiagramContext);
7012
7041
  if (store === null)
7013
7042
  throw new Error("useDiagramStoreApi could be used only inside DiagramContext");
7014
- return useMemo(
7015
- () => ({
7016
- getState: store.getState,
7017
- setState: store.setState,
7018
- subscribe: store.subscribe
7019
- }),
7020
- [store]
7021
- );
7043
+ return store;
7022
7044
  }
7023
- function WhenInitialized({ children: children2 }) {
7024
- const diagramApi = useDiagramStoreApi(), [isInitialized, setIsInitialized] = useState(diagramApi.getState().initialized);
7025
- return useEffect(() => {
7026
- if (!isInitialized)
7027
- return diagramApi.subscribe(
7028
- (s) => s.initialized,
7029
- setIsInitialized
7030
- );
7031
- }, [isInitialized]), isInitialized ? /* @__PURE__ */ jsx(Fragment, { children: children2 }) : null;
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
+ ]);
7032
7064
  }
7033
7065
  const { abs: abs$1, cos: cos$1, sin: sin$1, acos: acos$1, atan2, sqrt: sqrt$1, pow } = Math;
7034
7066
  function crt(v) {
@@ -7977,12 +8009,12 @@ function bezierControlPoints(diagramEdge) {
7977
8009
  inflections.length === 0 && inflections.push(0.5), inflections.forEach((t2) => {
7978
8010
  const { x, y } = bezier.get(t2);
7979
8011
  handles.push({
7980
- x: toDomPrecision(x),
7981
- y: toDomPrecision(y)
8012
+ x: Math.round(x),
8013
+ y: Math.round(y)
7982
8014
  });
7983
8015
  }), bezierPoints = rest, start2 = end;
7984
8016
  }
7985
- 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;
7986
8018
  }
7987
8019
  const isClose = (a, b) => Math.abs(a - b) < 3.1;
7988
8020
  function isSamePoint$1(a, b) {
@@ -7994,7 +8026,7 @@ function useXYStore(selector2, equalityFn) {
7994
8026
  return useStore(
7995
8027
  // @ts-expect-error - types are not correct
7996
8028
  selector2,
7997
- equalityFn ?? shallowEqual
8029
+ shallowEqual
7998
8030
  );
7999
8031
  }
8000
8032
  const useXYStoreApi = useStoreApi;
@@ -8145,24 +8177,23 @@ function useLayoutConstraints() {
8145
8177
  x: event.clientX,
8146
8178
  y: event.clientY
8147
8179
  };
8148
- const { xyflow } = diagramApi.getState();
8149
- solverRef.current = createLayoutConstraints(xyflow, xyflowApi, xynode.id);
8180
+ const { xyflow, cancelSaveManualLayout } = diagramApi.getState();
8181
+ cancelSaveManualLayout(), solverRef.current = createLayoutConstraints(xyflow, xyflowApi, xynode.id);
8150
8182
  },
8151
8183
  onNodeDrag: (_event, xynode) => {
8152
8184
  var _a;
8153
8185
  invariant(solverRef.current, "solverRef.current should be defined"), (_a = solverRef.current) == null || _a.onNodeDrag(xynode);
8154
8186
  },
8155
8187
  onNodeDragStop: (event, _xynode) => {
8156
- 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;
8157
8189
  }
8158
8190
  }), [xyflowApi, diagramApi]);
8159
8191
  }
8160
8192
  const ZIndexes = {
8161
- Compound: 1,
8162
- Edge: 2,
8163
- Element: 3
8193
+ Compound: 2,
8194
+ Edge: 4,
8195
+ Element: 6
8164
8196
  }, MinZoom = 0.1, StringSet = Set, DEFAULT_PROPS = {
8165
- viewSyncState: "synced",
8166
8197
  viewSyncDebounceTimeout: null,
8167
8198
  initialized: !1,
8168
8199
  xyflowSynced: !1,
@@ -8186,13 +8217,15 @@ const ZIndexes = {
8186
8217
  onCanvasClick: null,
8187
8218
  onCanvasDblClick: null
8188
8219
  }, noReplace = !1;
8189
- let storeDevId = 1;
8220
+ let StoreDevId = 1;
8190
8221
  const EmptyStringSet = new StringSet();
8191
8222
  function createDiagramStore(props) {
8223
+ const storeDevId = "DiagramStore" + String(StoreDevId++).padStart(2, "0");
8192
8224
  return createWithEqualityFn(
8193
8225
  subscribeWithSelector(
8194
8226
  devtools(
8195
8227
  (set2, get2) => ({
8228
+ storeDevId,
8196
8229
  ...DEFAULT_PROPS,
8197
8230
  ...props,
8198
8231
  isDynamicView: () => {
@@ -8202,7 +8235,6 @@ function createDiagramStore(props) {
8202
8235
  updateView: (nextView) => {
8203
8236
  let {
8204
8237
  viewSyncDebounceTimeout,
8205
- viewSyncState,
8206
8238
  xyflow,
8207
8239
  dimmed: dimmed2,
8208
8240
  xyflowSynced,
@@ -8216,18 +8248,13 @@ function createDiagramStore(props) {
8216
8248
  hoveredEdgeId,
8217
8249
  hoveredNodeId
8218
8250
  } = get2();
8219
- if (viewSyncDebounceTimeout && (clearTimeout(viewSyncDebounceTimeout), viewSyncDebounceTimeout = null), shallowEqual(current, nextView)) {
8220
- (!xyflowSynced || viewSyncState === "changed") && set2(
8221
- {
8222
- viewSyncState: "synced",
8223
- xyflowSynced: !0
8224
- },
8225
- noReplace,
8226
- "updateView: xyflow synced"
8227
- ), DEV && console.debug("store: skip updateView");
8251
+ if (shallowEqual(current, nextView)) {
8252
+ DEV && console.debug("store: skip updateView");
8228
8253
  return;
8229
8254
  }
8230
- if (current.id === nextView.id) {
8255
+ viewSyncDebounceTimeout !== null && (clearTimeout(viewSyncDebounceTimeout), viewSyncDebounceTimeout = null);
8256
+ const isSameView = current.id === nextView.id;
8257
+ if (isSameView) {
8231
8258
  const nodeIds = new StringSet(nextView.nodes.map((n) => n.id)), edgeIds = new StringSet(nextView.edges.map((e) => e.id));
8232
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) {
8233
8260
  let nextDimmed = new StringSet([...dimmed2].filter((id2) => nodeIds.has(id2) || edgeIds.has(id2)));
@@ -8245,7 +8272,6 @@ function createDiagramStore(props) {
8245
8272
  }
8246
8273
  set2(
8247
8274
  {
8248
- viewSyncState: "synced",
8249
8275
  viewSyncDebounceTimeout,
8250
8276
  view: nextView,
8251
8277
  activeDynamicViewStep,
@@ -8260,7 +8286,7 @@ function createDiagramStore(props) {
8260
8286
  dimmed: dimmed2
8261
8287
  },
8262
8288
  noReplace,
8263
- "update-view"
8289
+ isSameView ? "update-view [same]" : "update-view [another]"
8264
8290
  );
8265
8291
  },
8266
8292
  focusOnNode: (nodeId) => {
@@ -8283,16 +8309,16 @@ function createDiagramStore(props) {
8283
8309
  }
8284
8310
  },
8285
8311
  setHoveredNode: (nodeId) => {
8286
- nodeId !== get2().hoveredNodeId && set2({ hoveredNodeId: nodeId }, noReplace, nodeId ? "setHoveredNode" : "unsetHoveredNode");
8312
+ nodeId !== get2().hoveredNodeId && set2({ hoveredNodeId: nodeId });
8287
8313
  },
8288
8314
  setHoveredEdge: (edgeId) => {
8289
- edgeId !== get2().hoveredEdgeId && set2({ hoveredEdgeId: edgeId }, noReplace, edgeId ? "setHoveredEdge" : "unsetHoveredEdge");
8315
+ edgeId !== get2().hoveredEdgeId && set2({ hoveredEdgeId: edgeId });
8290
8316
  },
8291
8317
  setLastClickedNode: (nodeId) => {
8292
- nodeId !== get2().lastClickedNodeId && set2({ lastClickedNodeId: nodeId }, noReplace, nodeId ? "setLastClickedNode" : "unsetLastClickedNode");
8318
+ nodeId !== get2().lastClickedNodeId && set2({ lastClickedNodeId: nodeId });
8293
8319
  },
8294
8320
  setLastClickedEdge: (edgeId) => {
8295
- edgeId !== get2().lastClickedEdgeId && set2({ lastClickedEdgeId: edgeId }, noReplace, edgeId ? "setLastClickedEdge" : "unsetLastClickedEdge");
8321
+ edgeId !== get2().lastClickedEdgeId && set2({ lastClickedEdgeId: edgeId });
8296
8322
  },
8297
8323
  resetLastClicked: () => {
8298
8324
  let {
@@ -8326,7 +8352,7 @@ function createDiagramStore(props) {
8326
8352
  if (!change.targets.includes(origin.id))
8327
8353
  return origin;
8328
8354
  let element2 = origin;
8329
- for (const [key, value] of entries.strict(change.style))
8355
+ for (const [key, value] of entries(change.style))
8330
8356
  switch (key) {
8331
8357
  case "shape":
8332
8358
  value !== element2.shape && (element2 = {
@@ -8363,19 +8389,25 @@ function createDiagramStore(props) {
8363
8389
  }
8364
8390
  return element2 !== origin ? (hasChanges = !0, element2) : origin;
8365
8391
  });
8366
- hasChanges && (updateView({
8392
+ hasChanges && updateView({
8367
8393
  ...view,
8368
8394
  nodes
8369
- }), onChange && set2({ viewSyncState: "changed" }, noReplace, "change sync state")), onChange == null || onChange({ change });
8395
+ }), onChange == null || onChange({ change });
8370
8396
  },
8371
- triggerSaveManualLayout: (xystore) => {
8397
+ cancelSaveManualLayout: () => {
8398
+ let { viewSyncDebounceTimeout } = get2();
8399
+ viewSyncDebounceTimeout !== null && (clearTimeout(viewSyncDebounceTimeout), set2({ viewSyncDebounceTimeout: null }));
8400
+ },
8401
+ triggerSaveManualLayout: () => {
8372
8402
  let { viewSyncDebounceTimeout: debounced, onChange } = get2();
8373
8403
  if (!onChange) {
8374
8404
  DEV && console.debug("ignore triggerSaveManualLayout, as no onChange handler is set");
8375
8405
  return;
8376
8406
  }
8377
8407
  debounced && clearTimeout(debounced), debounced = setTimeout(() => {
8378
- const { nodeLookup } = xystore.getState(), { xyflow, onChange: onChange2 } = get2(), movedNodes = new StringSet(), nodes = reduce([...nodeLookup.values()], (acc, node) => {
8408
+ const { xyflow, onChange: onChange2, xystore } = get2(), { nodeLookup } = xystore.getState();
8409
+ set2({ viewSyncDebounceTimeout: null });
8410
+ const movedNodes = new StringSet(), nodes = reduce([...nodeLookup.values()], (acc, node) => {
8379
8411
  const dimensions = getNodeDimensions(node);
8380
8412
  return isSamePoint$1(node.internals.positionAbsolute, node.data.element.position) || movedNodes.add(node.id), acc[node.data.fqn] = {
8381
8413
  x: node.internals.positionAbsolute.x,
@@ -8388,25 +8420,31 @@ function createDiagramStore(props) {
8388
8420
  return !controlPoints && (movedNodes.has(source) || movedNodes.has(target)) && (controlPoints = bezierControlPoints(data.edge)), controlPoints && (acc[data.edge.id] = {
8389
8421
  controlPoints
8390
8422
  }), acc;
8391
- }, {}), change = {
8423
+ }, {});
8424
+ if (movedNodes.size === 0 && isEmpty(edges)) {
8425
+ DEV && console.debug("ignore triggerSaveManualLayout, as no changes detected");
8426
+ return;
8427
+ }
8428
+ const change = {
8392
8429
  op: "save-manual-layout",
8393
8430
  nodes,
8394
8431
  edges
8395
8432
  };
8396
- DEV && console.debug("triggerSaveManualLayout", change), set2({ viewSyncDebounceTimeout: null }, noReplace, "clear debounce timeout"), onChange2 == null || onChange2({ change });
8397
- }, 5e3), set2(
8433
+ DEV && console.debug("triggerSaveManualLayout", change), onChange2 == null || onChange2({ change });
8434
+ }, 2e3), set2(
8398
8435
  {
8399
- viewSyncDebounceTimeout: debounced,
8400
- viewSyncState: "changed"
8436
+ viewSyncDebounceTimeout: debounced
8401
8437
  },
8402
8438
  noReplace,
8403
- "change sync state"
8439
+ "debounce sync state"
8404
8440
  );
8405
8441
  },
8406
8442
  triggerOnNavigateTo: (xynodeId, event) => {
8407
8443
  var _a, _b;
8408
- const { xyflow, view } = get2(), xynode = xyflow.getInternalNode(xynodeId), element2 = xynode == null ? void 0 : xynode.data.element;
8409
- 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(
8410
8448
  {
8411
8449
  lastClickedNodeId: xynodeId,
8412
8450
  lastOnNavigate: {
@@ -8432,15 +8470,16 @@ function createDiagramStore(props) {
8432
8470
  xynode.internals.userNode
8433
8471
  );
8434
8472
  },
8435
- fitDiagram: (xyStore) => {
8436
- 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 = {
8437
8475
  x: 0,
8438
8476
  y: 0,
8439
8477
  width: view.width,
8440
8478
  height: view.height
8441
- }, viewport = getViewportForBounds(bounds, width, height, MinZoom, 1, fitViewPadding);
8442
- 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(
8443
8481
  {
8482
+ activeDynamicViewStep: null,
8444
8483
  focusedNodeId: null,
8445
8484
  dimmed: EmptyStringSet
8446
8485
  },
@@ -8449,7 +8488,7 @@ function createDiagramStore(props) {
8449
8488
  );
8450
8489
  },
8451
8490
  nextDynamicStep: (increment = 1) => {
8452
- const { view, activeDynamicViewStep, xyflow, fitViewPadding } = get2();
8491
+ const { view, activeDynamicViewStep, xyflow, xystore, fitViewPadding } = get2();
8453
8492
  invariant(view.__ === "dynamic", "view is not dynamic");
8454
8493
  const nextStep = (activeDynamicViewStep ?? 0) + increment;
8455
8494
  if (nextStep <= 0 || nextStep > view.edges.length)
@@ -8472,33 +8511,38 @@ function createDiagramStore(props) {
8472
8511
  }
8473
8512
  dimmed2.add(n.id);
8474
8513
  }
8475
- xyflow.fitView({
8514
+ const { fitView: fitView2, transform: transform2 } = xystore.getState();
8515
+ fitView2({
8476
8516
  duration: 400,
8477
- maxZoom: 1,
8517
+ includeHiddenNodes: !0,
8518
+ maxZoom: Math.max(1, transform2[2]),
8478
8519
  minZoom: MinZoom,
8479
- padding: fitViewPadding,
8520
+ padding: Math.max(fitViewPadding, 0.2),
8480
8521
  nodes: selected2
8481
- }), set2({
8482
- focusedNodeId: null,
8483
- activeDynamicViewStep: nextStep,
8484
- dimmed: dimmed2
8485
- });
8522
+ }), set2(
8523
+ {
8524
+ focusedNodeId: null,
8525
+ activeDynamicViewStep: nextStep,
8526
+ dimmed: dimmed2
8527
+ },
8528
+ noReplace,
8529
+ "nextDynamicStep"
8530
+ );
8486
8531
  },
8487
8532
  stopDynamicView: () => {
8488
- const { xyflow, fitViewPadding } = get2();
8489
- set2({
8490
- activeDynamicViewStep: null,
8491
- dimmed: EmptyStringSet
8492
- }), xyflow.fitView({
8493
- duration: 400,
8494
- maxZoom: 1,
8495
- minZoom: MinZoom,
8496
- padding: fitViewPadding
8497
- });
8533
+ get2().activeDynamicViewStep !== null && (set2(
8534
+ {
8535
+ activeDynamicViewStep: null,
8536
+ focusedNodeId: null,
8537
+ dimmed: EmptyStringSet
8538
+ },
8539
+ noReplace,
8540
+ "stopDynamicView"
8541
+ ), get2().fitDiagram());
8498
8542
  }
8499
8543
  }),
8500
8544
  {
8501
- name: `DiagramStore ${storeDevId++} - ${props.view.id}`,
8545
+ name: `${storeDevId} - ${props.view.id}`,
8502
8546
  enabled: DEV
8503
8547
  }
8504
8548
  )
@@ -8507,28 +8551,52 @@ function createDiagramStore(props) {
8507
8551
  );
8508
8552
  }
8509
8553
  const DiagramContext = createContext(null);
8510
- function DiagramContextProvider({ children: children2, view, ...props }) {
8511
- 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();
8512
8562
  return store.current || (store.current = createDiagramStore({
8563
+ xystore,
8513
8564
  xyflow,
8514
8565
  view,
8566
+ getContainer: () => containerRef.current,
8515
8567
  ...props
8516
8568
  })), useEffect(
8517
8569
  () => {
8518
- var _a, _b;
8519
- ((_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");
8520
8573
  },
8521
- [xyflow]
8574
+ [xyflow, xystore]
8522
8575
  ), useUpdateEffect(
8523
8576
  () => {
8524
8577
  if (!store.current) return;
8525
8578
  const state = store.current.getState();
8526
- 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");
8527
8582
  },
8528
- [view, props]
8529
- ), /* @__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
+ );
8530
8599
  }
8531
- const nodeZIndex = (node) => node.level + 1;
8532
8600
  function diagramViewToXYFlowData(view, opts) {
8533
8601
  var _a, _b;
8534
8602
  const isDynamicView = view.__ === "dynamic", editor = {
@@ -8539,15 +8607,15 @@ function diagramViewToXYFlowData(view, opts) {
8539
8607
  new Array()
8540
8608
  ), ns = "", nodeById = (id2) => nonNullable(nodeLookup.get(id2), `Node not found: ${id2}`);
8541
8609
  let next;
8542
- for (; next = traverse.pop(); ) {
8610
+ for (; next = traverse.shift(); ) {
8543
8611
  const { node, parent } = next;
8544
- 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 })));
8545
8613
  const isCompound = hasAtLeast$1(node.children, 1), position = {
8546
8614
  x: node.position[0],
8547
8615
  y: node.position[1]
8548
8616
  };
8549
8617
  parent && (position.x -= parent.position[0], position.y -= parent.position[1]);
8550
- const id2 = ns + node.id;
8618
+ const id2 = ns + node.id, draggable = opts.draggable && (!parent || parent.children.length > 1);
8551
8619
  editor.nodes.push({
8552
8620
  id: id2,
8553
8621
  type: isCompound ? "compound" : "element",
@@ -8555,72 +8623,44 @@ function diagramViewToXYFlowData(view, opts) {
8555
8623
  fqn: node.id,
8556
8624
  element: node
8557
8625
  },
8558
- draggable: opts.draggable && (!parent || parent.children.length > 1),
8626
+ draggable,
8559
8627
  selectable: opts.selectable,
8560
8628
  deletable: !1,
8561
8629
  position,
8562
- zIndex: nodeZIndex(node),
8630
+ zIndex: isCompound ? ZIndexes.Compound : ZIndexes.Element,
8563
8631
  hidden: !1,
8564
- /* initialWidth: node.width,
8565
- initialHeight: node.height, */
8632
+ initialWidth: node.width,
8633
+ initialHeight: node.height,
8566
8634
  width: node.width,
8567
8635
  height: node.height,
8568
- // measured: {
8569
- // width: node.width,
8570
- // height: node.height
8571
- // },
8572
8636
  ...parent && {
8573
8637
  parentId: ns + parent.id
8638
+ },
8639
+ ...isCompound && {
8640
+ dragHandle: ".likec4-compound-title"
8574
8641
  }
8575
- // handles: [
8576
- // ...outEdges.map(out => ({
8577
- // id: `${out.id}`,
8578
- // type: 'source' as const,
8579
- // position: Position.Bottom,
8580
- // x: out.points[0][0],
8581
- // y: out.points[0][1],
8582
- // width: 10,
8583
- // height: 10
8584
- // })),
8585
- // ...inEdges.map(out => ({
8586
- // id: out.id,
8587
- // type: 'target' as const,
8588
- // position: Position.Top,
8589
- // x: out.points[0][0],
8590
- // y: out.points[0][1],
8591
- // width: 10,
8592
- // height: 10
8593
- // }))
8594
- // ],
8595
8642
  });
8596
8643
  }
8597
8644
  for (const edge of view.edges) {
8598
8645
  const source = edge.source, target = edge.target, id2 = ns + edge.id;
8599
- invariant(hasAtLeast$1(edge.points, 2), "edge should have at least 2 points");
8600
- const level = Math.max(nodeZIndex(nodeById(source)), nodeZIndex(nodeById(target)));
8601
- editor.edges.push({
8646
+ invariant(hasAtLeast$1(edge.points, 2), "edge should have at least 2 points"), editor.edges.push({
8602
8647
  id: id2,
8603
8648
  type: "relationship",
8604
8649
  source: ns + source,
8605
8650
  target: ns + target,
8606
- zIndex: level,
8651
+ zIndex: ZIndexes.Edge,
8652
+ selectable: opts.selectable,
8607
8653
  deletable: !1,
8608
8654
  data: {
8609
8655
  edge,
8610
8656
  type: "bezier",
8611
8657
  controlPoints: ((_b = (_a = view.manualLayout) == null ? void 0 : _a.edges[edge.id]) == null ? void 0 : _b.controlPoints) || null,
8612
- headPoint: edge.headArrowPoint ?? null,
8613
- tailPoint: edge.tailArrowPoint ?? null,
8614
8658
  stepNum: isDynamicView ? extractStep(edge.id) : null,
8615
8659
  label: edge.labelBBox ? {
8616
8660
  bbox: edge.labelBBox,
8617
- // text: edge.labels ? edge.labels.map(l => l.text).join('\n') : ''
8618
8661
  text: edge.label ?? ""
8619
8662
  } : null
8620
8663
  },
8621
- // markerEnd: {
8622
- // type: MarkerType.ArrowClosed
8623
- // },
8624
8664
  interactionWidth: 20
8625
8665
  });
8626
8666
  }
@@ -8634,14 +8674,14 @@ function FitViewOnViewportResize({ diagramApi, xyflowApi }) {
8634
8674
  return useDebouncedEffect(
8635
8675
  () => {
8636
8676
  const { focusedNodeId, fitDiagram } = diagramApi.getState();
8637
- focusedNodeId || prevDimensionsRef.current === dimensions || (fitDiagram(xyflowApi), prevDimensionsRef.current = dimensions);
8677
+ focusedNodeId || prevDimensionsRef.current === dimensions || (fitDiagram(300), prevDimensionsRef.current = dimensions);
8638
8678
  },
8639
8679
  [dimensions, diagramApi, xyflowApi],
8640
- 250,
8680
+ 300,
8641
8681
  1e3
8642
8682
  ), null;
8643
8683
  }
8644
- function selector$2({ view, xyflowSynced, viewportChanged, lastOnNavigate, ...s }) {
8684
+ function selector$3({ view, xyflowSynced, viewportChanged, lastOnNavigate, ...s }) {
8645
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;
8646
8686
  return waitCorrection && elTo ? {
8647
8687
  viewId,
@@ -8667,7 +8707,7 @@ function FitViewOnDiagramChange() {
8667
8707
  waitCorrection,
8668
8708
  elFrom,
8669
8709
  elTo
8670
- } = useDiagramState(selector$2, shallowEqual), diagramApi = useDiagramStoreApi(), processedRef = useRef(pendingViewId);
8710
+ } = useDiagramState(selector$3, shallowEqual), diagramApi = useDiagramStoreApi(), processedRef = useRef(pendingViewId), durationRef = useRef(300);
8671
8711
  return useEffect(() => {
8672
8712
  if (!(!xyflowSynced || pendingViewId === processedRef.current)) {
8673
8713
  if (waitCorrection) {
@@ -8683,57 +8723,62 @@ function FitViewOnDiagramChange() {
8683
8723
  x: toDomPrecision(fromPos.x - toPos.x),
8684
8724
  y: toDomPrecision(fromPos.y - toPos.y)
8685
8725
  };
8686
- xyflowApi.getState().panBy(diff), diagramApi.setState({ lastOnNavigate: null });
8726
+ xyflowApi.getState().panBy(diff), durationRef.current = 500, diagramApi.setState({ lastOnNavigate: null });
8687
8727
  return;
8688
8728
  }
8689
- processedRef.current = pendingViewId, diagramApi.getState().fitDiagram(xyflowApi);
8729
+ processedRef.current = pendingViewId, diagramApi.getState().fitDiagram(durationRef.current), durationRef.current = 300;
8690
8730
  }
8691
8731
  }, [pendingViewId, xyflowSynced, waitCorrection]), !viewportChanged && xyflowSynced ? /* @__PURE__ */ jsx(FitViewOnViewportResize, { xyflowApi, diagramApi }) : null;
8692
8732
  }
8693
8733
  function SelectEdgesOnNodeFocus() {
8694
- const focusedNodeId = useDiagramState((s) => s.focusedNodeId), diagramStore = useDiagramStoreApi(), xyflowApi = useXYStoreApi();
8695
- return useUpdateEffect(() => {
8696
- if (!focusedNodeId) {
8697
- xyflowApi.getState().resetSelectedElements();
8698
- return;
8699
- }
8700
- const edgeChanges = [], nodeChanges = [], { edgeLookup, nodeLookup, transform: transform2, triggerNodeChanges, fitView: fitView2, triggerEdgeChanges } = xyflowApi.getState(), fitViewNodes = /* @__PURE__ */ new Set();
8701
- fitViewNodes.add(nonNullable(nodeLookup.get(focusedNodeId)));
8702
- for (const [, edge] of edgeLookup)
8703
- if (edge.source === focusedNodeId || edge.target === focusedNodeId) {
8704
- 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({
8705
8756
  id: edge.id,
8706
8757
  type: "select",
8707
- selected: !0
8758
+ selected: !1
8708
8759
  });
8709
- const anotherNode = nonNullable(nodeLookup.get(edge.source === focusedNodeId ? edge.target : edge.source));
8710
- fitViewNodes.add(anotherNode);
8711
- } else edge.selected && edgeChanges.push({
8712
- id: edge.id,
8713
- type: "select",
8714
- selected: !1
8715
- });
8716
- for (const [, node] of nodeLookup)
8717
- node.selected && node.id !== focusedNodeId && nodeChanges.push({
8718
- 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,
8719
8769
  type: "select",
8720
- 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
8721
8775
  });
8722
- nodeChanges.push({
8723
- id: focusedNodeId,
8724
- type: "select",
8725
- selected: !0
8726
- }), edgeChanges.length > 0 && triggerEdgeChanges(edgeChanges), triggerNodeChanges(nodeChanges), fitView2({
8727
- duration: 350,
8728
- padding: 0.1,
8729
- minZoom: MinZoom,
8730
- maxZoom: Math.max(1, transform2[2]),
8731
- nodes: Array.from(fitViewNodes)
8732
- });
8733
- }, [diagramStore, xyflowApi, focusedNodeId]), null;
8776
+ }),
8777
+ [diagramStore]
8778
+ ), null;
8734
8779
  }
8735
8780
  function SyncWithDiagram() {
8736
- const xyflowSynced = useDiagramState((s) => s.xyflowSynced), xyflowApi = useXYStoreApi(), diagramStoreApi = useDiagramStoreApi();
8781
+ const xyflowSynced = useDiagramState((s) => s.xyflowSynced), diagramStoreApi = useDiagramStoreApi();
8737
8782
  return useEffect(() => {
8738
8783
  if (xyflowSynced)
8739
8784
  return;
@@ -8741,7 +8786,8 @@ function SyncWithDiagram() {
8741
8786
  view,
8742
8787
  nodesDraggable,
8743
8788
  nodesSelectable,
8744
- focusedNodeId
8789
+ focusedNodeId,
8790
+ xystore
8745
8791
  } = diagramStoreApi.getState(), updates = diagramViewToXYFlowData(view, {
8746
8792
  draggable: nodesDraggable,
8747
8793
  selectable: nodesSelectable || focusedNodeId !== null
@@ -8750,7 +8796,7 @@ function SyncWithDiagram() {
8750
8796
  edgeLookup,
8751
8797
  setNodes,
8752
8798
  setEdges
8753
- } = xyflowApi.getState();
8799
+ } = xystore.getState();
8754
8800
  setNodes(updates.nodes.map((update) => {
8755
8801
  var _a;
8756
8802
  const existing = (_a = nodeLookup.get(update.id)) == null ? void 0 : _a.internals.userNode;
@@ -8760,8 +8806,8 @@ function SyncWithDiagram() {
8760
8806
  } : update;
8761
8807
  })), setEdges(updates.edges.map((update) => {
8762
8808
  const existing = edgeLookup.get(update.id);
8763
- return existing ? deepEqual(existing.data.controlPoints, update.data.controlPoints) && deepEqual(existing.data.edge, update.data.edge) ? existing : {
8764
- ...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"]),
8765
8811
  ...update,
8766
8812
  data: {
8767
8813
  ...existing.data,
@@ -8775,40 +8821,225 @@ function SyncWithDiagram() {
8775
8821
  !1,
8776
8822
  "xyflowSynced"
8777
8823
  );
8778
- }, [xyflowSynced, xyflowApi, diagramStoreApi]), null;
8779
- }
8780
- 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";
8781
- function getNodeIntersectionFromCenterToPoint(intersectionNode, { x: x1, y: y1 }) {
8782
- const {
8783
- width: intersectionNodeWidth,
8784
- height: intersectionNodeHeight
8785
- } = 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;
8786
- return { x, y };
8824
+ }, [xyflowSynced, diagramStoreApi]), null;
8787
8825
  }
8788
- function bezierPath(bezierSpline) {
8789
- let [start2, ...points] = bezierSpline;
8790
- invariant(start2, "start should be defined");
8791
- let path = `M ${start2[0]},${start2[1]}`;
8792
- for (; hasAtLeast$1(points, 3); ) {
8793
- const [cp1, cp2, end, ...rest] = points;
8794
- path = path + ` C ${cp1[0]},${cp1[1]} ${cp2[0]},${cp2[1]} ${end[0]},${end[1]}`, points = rest;
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
+ )
8795
8848
  }
8796
- return invariant(points.length === 0, "all points should be consumed"), path;
8797
- }
8798
- const isSame = (a, b) => Math.abs(a - b) < 3.1, isSamePoint = (a, b) => {
8799
- const [ax, ay] = isArray(a) ? a : [a.x, a.y], [bx, by] = isArray(b) ? b : [b.x, b.y];
8800
- return isSame(ax, bx) && isSame(ay, by);
8801
- }, 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({
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;
9022
+ path = path + ` C ${cp1[0]},${cp1[1]} ${cp2[0]},${cp2[1]} ${end[0]},${end[1]}`, points = rest;
9023
+ }
9024
+ return invariant(points.length === 0, "all points should be consumed"), path;
9025
+ }
9026
+ const isSame = (a, b) => Math.abs(a - b) < 3.1, isSamePoint = (a, b) => {
9027
+ const [ax, ay] = isArray(a) ? a : [a.x, a.y], [bx, by] = isArray(b) ? b : [b.x, b.y];
9028
+ return isSame(ax, bx) && isSame(ay, by);
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({
8802
9030
  id: id2,
8803
9031
  data,
8804
- selected: _selected,
9032
+ selected: selected2,
9033
+ sourceX,
9034
+ sourceY,
9035
+ targetX,
9036
+ targetY,
8805
9037
  style: style2,
8806
9038
  source,
8807
9039
  target,
8808
9040
  interactionWidth
8809
9041
  }) {
8810
- var _a, _b;
8811
- 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) => ({
8812
9043
  isEditable: s.readonly !== !0,
8813
9044
  isEdgePathEditable: s.readonly !== !0 && s.experimentalEdgeEditing === !0,
8814
9045
  isActive: s.focusedNodeId === source || s.focusedNodeId === target || s.activeDynamicViewStep !== null && s.activeDynamicViewStep === data.stepNum,
@@ -8835,12 +9066,18 @@ const isSame = (a, b) => Math.abs(a - b) < 3.1, isSamePoint = (a, b) => {
8835
9066
  let edgePath;
8836
9067
  if (isModified) {
8837
9068
  labelX = labelPos.x, labelY = labelPos.y;
8838
- const sourceCenterPos = getNodePositionWithOrigin(sourceNode, [-0.5, -0.5]), targetCenterPos = getNodePositionWithOrigin(targetNode, [-0.5, -0.5]), points = [
8839
- sourceCenterPos.positionAbsolute,
8840
- 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),
8841
9078
  ...controlPoints,
8842
- getNodeIntersectionFromCenterToPoint(targetNode, last(controlPoints)),
8843
- targetCenterPos.positionAbsolute
9079
+ getNodeIntersectionFromCenterToPoint(targetNode, last(controlPoints) ?? sourceCenterPos),
9080
+ targetCenterPos
8844
9081
  ];
8845
9082
  edgePath = nonNullable(curve(points));
8846
9083
  } else
@@ -8857,53 +9094,65 @@ const isSame = (a, b) => Math.abs(a - b) < 3.1, isSamePoint = (a, b) => {
8857
9094
  }, [edgePath]);
8858
9095
  const onControlPointerDown = (index2, e) => {
8859
9096
  const { domNode } = xyflowStore.getState();
8860
- if (!domNode) return;
9097
+ if (!domNode || e.pointerType !== "mouse")
9098
+ return;
8861
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;
8862
9109
  e.stopPropagation();
8863
9110
  let hasMoved = !1, pointer2 = { x: e.clientX, y: e.clientY };
8864
9111
  const onPointerMove = (e2) => {
8865
9112
  if (!isSamePoint(pointer2, [e2.clientX, e2.clientY])) {
8866
- 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 };
8867
9114
  const { x, y } = xyflow.screenToFlowPosition(pointer2, { snapToGrid: !1 }), newControlPoints = controlPoints.slice();
8868
9115
  newControlPoints[index2] = {
8869
- x: toDomPrecision(x),
8870
- y: toDomPrecision(y)
9116
+ x: Math.round(x),
9117
+ y: Math.round(y)
8871
9118
  }, xyflow.updateEdgeData(id2, { controlPoints: newControlPoints });
8872
9119
  }
8873
9120
  }, onPointerUp = () => {
8874
- 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();
8875
9122
  };
8876
9123
  domNode.addEventListener("pointermove", onPointerMove), domNode.addEventListener("pointerup", onPointerUp, { once: !0 });
8877
- }, marker = `url(#arrow-${id2})`;
8878
- let markerStart = diagramEdge.tailArrow ? marker : void 0, markerEnd = diagramEdge.headArrow ? marker : void 0;
8879
- 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(
8880
9129
  "g",
8881
9130
  {
8882
9131
  className: clsx([
8883
9132
  container$4,
8884
- isDimmed && dimmed$2
9133
+ isDimmed && dimmed$2,
9134
+ isControlPointDragging && controlDragging
8885
9135
  ]),
8886
9136
  "data-likec4-color": color2,
8887
9137
  "data-edge-dir": diagramEdge.dir,
8888
9138
  "data-edge-active": isActive,
8889
9139
  "data-edge-hovered": isHovered,
8890
9140
  children: [
9141
+ /* @__PURE__ */ jsx(
9142
+ "path",
9143
+ {
9144
+ className: clsx("react-flow__edge-interaction"),
9145
+ d: edgePath,
9146
+ fill: "none",
9147
+ stroke: "transparent",
9148
+ strokeWidth: interactionWidth ?? 10
9149
+ }
9150
+ ),
8891
9151
  /* @__PURE__ */ jsxs("g", { className: markerContext, children: [
8892
- /* @__PURE__ */ jsx("defs", { children: /* @__PURE__ */ jsx(
8893
- "marker",
8894
- {
8895
- id: `arrow-${id2}`,
8896
- viewBox: "0 0 16 10",
8897
- refX: isModified ? "15" : "1",
8898
- refY: "5",
8899
- markerWidth: "5",
8900
- markerHeight: "4",
8901
- markerUnits: "strokeWidth",
8902
- preserveAspectRatio: "xMaxYMid meet",
8903
- orient: "auto-start-reverse",
8904
- children: /* @__PURE__ */ jsx("path", { d: "M 0 0 L 16 5 L 0 10 z", stroke: "context-stroke", fill: "context-stroke" })
8905
- }
8906
- ) }),
9152
+ /* @__PURE__ */ jsxs("defs", { children: [
9153
+ MarkerStart && /* @__PURE__ */ jsx(MarkerStart, { id: "start" + id2 }),
9154
+ MarkerEnd && /* @__PURE__ */ jsx(MarkerEnd, { id: "end" + id2 })
9155
+ ] }),
8907
9156
  /* @__PURE__ */ jsx(
8908
9157
  "path",
8909
9158
  {
@@ -8922,68 +9171,97 @@ const isSame = (a, b) => Math.abs(a - b) < 3.1, isSamePoint = (a, b) => {
8922
9171
  style: style2,
8923
9172
  strokeLinecap: "round",
8924
9173
  strokeDasharray,
8925
- markerStart,
8926
- markerEnd
9174
+ markerStart: MarkerStart ? `url(#start${id2})` : void 0,
9175
+ markerEnd: MarkerEnd ? `url(#end${id2})` : void 0
8927
9176
  }
8928
9177
  )
8929
9178
  ] }),
8930
- /* @__PURE__ */ jsx(
8931
- "path",
9179
+ isEdgePathEditable && /* @__PURE__ */ jsx(
9180
+ "g",
8932
9181
  {
8933
- className: clsx("react-flow__edge-interaction"),
8934
- d: edgePath,
8935
- fill: "none",
8936
- strokeOpacity: 0,
8937
- strokeWidth: interactionWidth ?? 10
9182
+ onContextMenu: (e) => {
9183
+ e.preventDefault(), e.stopPropagation();
9184
+ },
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
+ ))
8938
9196
  }
8939
9197
  ),
8940
- isEdgePathEditable && controlPoints.map((p, i) => /* @__PURE__ */ jsx(
8941
- "circle",
9198
+ (data.label || isStepEdge) && /* @__PURE__ */ jsx(
9199
+ EdgeLabel,
8942
9200
  {
8943
- onPointerDown: (e) => onControlPointerDown(i, e),
8944
- className: controlPoint,
8945
- cx: p.x,
8946
- cy: p.y,
8947
- r: 3
8948
- },
8949
- i
8950
- )),
8951
- (data.label || isStepEdge) && /* @__PURE__ */ jsx(EdgeLabelRenderer, { children: /* @__PURE__ */ jsxs(
8952
- Box,
8953
- {
8954
- className: clsx([
8955
- container$4,
8956
- edgeLabel,
8957
- isDimmed && dimmed$2
8958
- ]),
8959
- "data-likec4-color": color2,
8960
- style: {
8961
- ...assignInlineVars({
8962
- [varLabelX]: isModified ? `calc(${labelX}px - 10%)` : `${labelX}px`,
8963
- [varLabelY]: isModified ? `${labelY - 5}px` : `${labelY}px`
8964
- }),
8965
- ...isEdgePathEditable && {
8966
- pointerEvents: "none"
8967
- },
8968
- ...data.label && {
8969
- maxWidth: data.label.bbox.width + 12
8970
- },
8971
- zIndex: ((_a = edgeLookup.get(id2)) == null ? void 0 : _a.zIndex) ?? ZIndexes.Edge
8972
- },
8973
- mod: {
8974
- "data-edge-hovered": isHovered,
8975
- "data-edge-active": isActive
8976
- },
8977
- children: [
8978
- isStepEdge && /* @__PURE__ */ jsx(Box, { className: stepEdgeNumber, children: data.stepNum }),
8979
- ((_b = data.label) == null ? void 0 : _b.text) && /* @__PURE__ */ jsx(Box, { className: edgeLabelText, children: data.label.text })
8980
- ]
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
8981
9214
  }
8982
- ) })
9215
+ )
8983
9216
  ]
8984
9217
  }
8985
9218
  );
8986
- }, 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);
8987
9265
  function NavigateToBtn({ xynodeId, className }) {
8988
9266
  const diagramApi = useDiagramStoreApi();
8989
9267
  return /* @__PURE__ */ jsx(
@@ -9008,14 +9286,13 @@ function NavigateToBtn({ xynodeId, className }) {
9008
9286
  }
9009
9287
  );
9010
9288
  }
9011
- 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";
9012
9290
  const isEqualProps$1 = (prev, next) => prev.id === next.id && deepEqual(prev.data.element, next.data.element), CompoundNodeMemo = /* @__PURE__ */ memo(function({
9013
9291
  id: id2,
9014
9292
  data: {
9015
9293
  element: element2
9016
9294
  }
9017
9295
  }) {
9018
- DEV && useTilg();
9019
9296
  const { color: color2, style: style2, depth = 1, ...compound } = element2, opacity = clamp$1((style2.opacity ?? 100) / 100, {
9020
9297
  min: 0,
9021
9298
  max: 1
@@ -9027,138 +9304,118 @@ const isEqualProps$1 = (prev, next) => prev.id === next.id && deepEqual(prev.dat
9027
9304
  isDimmed: s.dimmed.has(id2),
9028
9305
  hasOnNavigateTo: !!s.onNavigateTo
9029
9306
  })), isnavigable = !!compound.navigateTo && hasOnNavigateTo;
9030
- return /* @__PURE__ */ jsxs(
9031
- Box,
9032
- {
9033
- className: clsx(
9034
- container$3,
9035
- "likec4-compound-node",
9036
- opacity < 1 && "likec4-compound-transparent",
9037
- isDimmed && dimmed$1
9038
- ),
9039
- mod: {
9040
- "compound-depth": depth,
9041
- "likec4-color": color2,
9042
- hovered: isHovered
9043
- },
9044
- children: [
9045
- /* @__PURE__ */ jsx(
9046
- Handle,
9047
- {
9048
- type: "target",
9049
- position: Position.Top,
9050
- style: { visibility: "hidden" }
9051
- }
9052
- ),
9053
- /* @__PURE__ */ jsx("svg", { className: indicator$1, children: /* @__PURE__ */ jsx(
9054
- "rect",
9055
- {
9056
- x: 0,
9057
- y: 0,
9058
- width: "100%",
9059
- height: "100%",
9060
- rx: 6
9061
- }
9062
- ) }),
9063
- /* @__PURE__ */ jsx(
9064
- "div",
9065
- {
9066
- className: clsx(
9067
- compoundBody,
9068
- opacity < 1 && transparent,
9069
- "likec4-compound"
9070
- ),
9071
- style: opacity < 1 ? {
9072
- ...assignInlineVars({
9073
- [varBorderTransparency]: `${borderTransparency}%`,
9074
- [varOpacity]: opacity.toFixed(2)
9075
- }),
9076
- borderStyle: style2.border ?? "dashed"
9077
- } : void 0,
9078
- children: /* @__PURE__ */ jsx(
9079
- Text,
9080
- {
9081
- component: "div",
9082
- className: clsx(
9083
- title$2,
9084
- isnavigable && titleWithNavigation,
9085
- "likec4-compound-title"
9086
- ),
9087
- children: compound.title
9088
- }
9089
- )
9090
- }
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
9091
9324
  ),
9092
- isnavigable && /* @__PURE__ */ jsx(NavigateToBtn, { xynodeId: id2, className: navigateBtn }),
9093
- /* @__PURE__ */ jsx(
9094
- Handle,
9095
- {
9096
- type: "source",
9097
- position: Position.Bottom,
9098
- style: { visibility: "hidden" }
9099
- }
9100
- )
9101
- ]
9102
- }
9103
- );
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
+ ] });
9104
9383
  }, isEqualProps$1);
9105
- var container$2 = "_1b6tkn2", dimmed = "_1b6tkn3", indicator = "_1b6tkn5", fillElementFill = "_1b6tkn6", fillMixStroke = "_1b6tkn8", title$1 = "_1b6tkn9", description$1 = "_1b6tkna", technology = "_1b6tknb", element = "_1b6tknc", iconMaxH = "var(--_1b6tknd)", elementIcon = "_1b6tkne", cssShapeSvg = "_1b6tknh", cssNavigateBtn = "_1b6tkni";
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";
9106
9385
  function ElementIcon({
9107
- node,
9108
- paddingY = 32
9386
+ node: {
9387
+ icon,
9388
+ title: title2,
9389
+ labelBBox
9390
+ }
9109
9391
  }) {
9110
- if (!node.icon)
9111
- return null;
9112
- const firstLabel = node.labels[0];
9113
- if (!firstLabel)
9114
- return null;
9115
- const firstLabelY = Math.floor(firstLabel.pt[1] - firstLabel.fontSize * 1.25), maxIconHeight = Math.floor(firstLabelY - paddingY - 16);
9116
- return /* @__PURE__ */ jsx(
9392
+ return icon ? /* @__PURE__ */ jsx(
9117
9393
  "div",
9118
9394
  {
9119
9395
  className: clsx(elementIcon, "likec4-element-icon"),
9120
- style: assignInlineVars({ iconMaxH }, {
9121
- iconMaxH: maxIconHeight + "px"
9396
+ style: assignInlineVars({ iconOffsetY }, {
9397
+ iconOffsetY: labelBBox.y + "px"
9122
9398
  }),
9123
9399
  children: /* @__PURE__ */ jsx(
9124
9400
  "img",
9125
9401
  {
9126
- src: node.icon,
9127
- alt: node.title
9402
+ src: icon,
9403
+ alt: title2
9128
9404
  }
9129
9405
  )
9130
9406
  }
9131
- );
9407
+ ) : null;
9132
9408
  }
9133
- const Link = forwardRef(({ className, ...props }, ref) => /* @__PURE__ */ jsx(
9134
- "svg",
9135
- {
9136
- ref,
9137
- className: clsx("icon icon-tabler", className),
9138
- stroke: "currentColor",
9139
- fill: "currentColor",
9140
- strokeWidth: "0",
9141
- viewBox: "0 0 20 20",
9142
- height: "20",
9143
- width: "20",
9144
- xmlns: "http://www.w3.org/2000/svg",
9145
- ...props,
9146
- children: /* @__PURE__ */ jsx(
9147
- "path",
9148
- {
9149
- fillRule: "evenodd",
9150
- 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",
9151
- clipRule: "evenodd"
9152
- }
9153
- )
9154
- }
9155
- ));
9156
9409
  var elementLink = "_4ysv0o0", trigger = "_4ysv0o1";
9410
+ const selector$2 = (s) => {
9411
+ const target = s.getContainer();
9412
+ return target ? { target } : null;
9413
+ };
9157
9414
  function ElementLink({
9158
9415
  element: element2
9159
9416
  }) {
9160
9417
  invariant(element2.links, "ElementLink: links are required");
9161
- const id2 = useId();
9418
+ const id2 = useId(), portalProps = useDiagramState(selector$2);
9162
9419
  return /* @__PURE__ */ jsx("div", { className: elementLink, "data-likec4-linkid": id2, children: /* @__PURE__ */ jsxs(
9163
9420
  HoverCard,
9164
9421
  {
@@ -9171,7 +9428,7 @@ function ElementLink({
9171
9428
  transitionProps: {
9172
9429
  transition: "pop"
9173
9430
  },
9174
- withinPortal: !1,
9431
+ ...portalProps ? { portalProps } : { withinPortal: !1 },
9175
9432
  floatingStrategy: "fixed",
9176
9433
  openDelay: 350,
9177
9434
  closeDelay: 800,
@@ -9186,7 +9443,7 @@ function ElementLink({
9186
9443
  className: clsx("nodrag nopan", trigger),
9187
9444
  autoFocus: !1,
9188
9445
  children: [
9189
- /* @__PURE__ */ jsx(Link, {}),
9446
+ /* @__PURE__ */ jsx(IconLink, { size: 12 }),
9190
9447
  /* @__PURE__ */ jsx("span", { children: "links" })
9191
9448
  ]
9192
9449
  }
@@ -9371,13 +9628,13 @@ const selectedScale = 1.015, variants = {
9371
9628
  idle: (_, { scale }) => ({
9372
9629
  scale: 1,
9373
9630
  transition: {
9374
- delay: isNumber(scale) && scale > selectedScale ? 0.075 : 0
9631
+ delay: isNumber(scale) && scale > selectedScale ? 0.09 : 0
9375
9632
  }
9376
9633
  }),
9377
9634
  selected: (_, { scale }) => ({
9378
9635
  scale: selectedScale,
9379
9636
  transition: {
9380
- delay: isNumber(scale) && scale > selectedScale ? 0.075 : 0
9637
+ delay: isNumber(scale) && scale > selectedScale ? 0.09 : 0
9381
9638
  }
9382
9639
  }),
9383
9640
  // dimmed: {
@@ -9401,29 +9658,26 @@ const selectedScale = 1.015, variants = {
9401
9658
  // delay: 1
9402
9659
  // }
9403
9660
  // }),
9404
- hovered: (_, { scale }) => ({
9405
- scale: 1.06,
9406
- transition: {
9407
- delay: isNumber(scale) && scale !== 1 && scale !== selectedScale ? 0 : 0.15
9408
- }
9409
- }),
9661
+ hovered: {
9662
+ scale: 1.06
9663
+ },
9410
9664
  tap: {
9411
9665
  scale: 0.975
9412
9666
  }
9413
9667
  // tap: {
9414
9668
  // scale: 0.9
9415
9669
  // }
9416
- }, 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({
9417
9671
  id: id2,
9418
9672
  data: {
9419
9673
  element: element$1
9420
9674
  },
9421
9675
  dragging,
9676
+ // draggable = false,
9422
9677
  selected: selected2 = !1,
9423
9678
  width,
9424
9679
  height
9425
9680
  }) {
9426
- DEV && useTilg();
9427
9681
  const { isHovered, isDimmed, hasOnNavigateTo, isHovercards, isInteractive } = useDiagramState((s) => ({
9428
9682
  isHovered: s.hoveredNodeId === id2,
9429
9683
  isDimmed: s.dimmed.has(id2),
@@ -9446,209 +9700,234 @@ const selectedScale = 1.015, variants = {
9446
9700
  animate = "selected";
9447
9701
  break;
9448
9702
  }
9449
- return /* @__PURE__ */ jsxs(
9450
- m.div,
9451
- {
9452
- id: id2,
9453
- className: clsx([
9454
- container$2,
9455
- isDimmed && dimmed,
9456
- "likec4-element-node"
9457
- ]),
9458
- "data-likec4-color": element$1.color,
9459
- "data-likec4-shape": element$1.shape,
9460
- variants,
9461
- initial: !1,
9462
- animate,
9463
- ...isInteractive && {
9464
- whileTap: dragging ? animate : "tap"
9465
- },
9466
- children: [
9467
- /* @__PURE__ */ jsx(
9468
- Handle,
9469
- {
9470
- type: "target",
9471
- position: Position.Top,
9472
- style: { visibility: "hidden" }
9473
- }
9474
- ),
9475
- /* @__PURE__ */ jsxs(
9476
- "svg",
9477
- {
9478
- className: clsx(
9479
- cssShapeSvg
9480
- ),
9481
- viewBox: `0 0 ${w} ${h}`,
9482
- width: w,
9483
- height: h,
9484
- children: [
9485
- /* @__PURE__ */ jsx("g", { className: indicator, children: /* @__PURE__ */ jsx(
9486
- SelectedIndicator,
9487
- {
9488
- shape: element$1.shape,
9489
- w,
9490
- h
9491
- }
9492
- ) }),
9493
- /* @__PURE__ */ jsx(
9494
- ElementShapeSvg,
9495
- {
9496
- shape: element$1.shape,
9497
- w,
9498
- h
9499
- }
9500
- )
9501
- ]
9502
- }
9503
- ),
9504
- /* @__PURE__ */ jsxs("div", { className: clsx(element, "likec4-element"), children: [
9505
- element$1.icon && /* @__PURE__ */ jsx(ElementIcon, { node: element$1 }),
9506
- /* @__PURE__ */ jsx(
9507
- Text,
9508
- {
9509
- component: "div",
9510
- className: clsx(title$1, "likec4-element-title"),
9511
- children: element$1.title
9512
- }
9513
- ),
9514
- element$1.technology && /* @__PURE__ */ jsx(
9515
- 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",
9516
9734
  {
9517
- component: "div",
9518
- className: clsx(technology, "likec4-element-technology"),
9519
- 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
+ ]
9520
9759
  }
9521
9760
  ),
9522
- element$1.description && /* @__PURE__ */ jsx(
9523
- Text,
9524
- {
9525
- component: "div",
9526
- className: clsx(description$1, "likec4-element-description"),
9527
- children: element$1.description
9528
- }
9529
- )
9530
- ] }),
9531
- /* @__PURE__ */ jsx(
9532
- Handle,
9533
- {
9534
- type: "source",
9535
- position: Position.Bottom,
9536
- style: { visibility: "hidden" }
9537
- }
9538
- ),
9539
- isHovercards && element$1.links && /* @__PURE__ */ jsx(ElementLink, { element: element$1 }),
9540
- isNavigable && /* @__PURE__ */ jsx(NavigateToBtn, { xynodeId: id2, className: cssNavigateBtn })
9541
- ]
9542
- }
9543
- );
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
+ ] });
9544
9802
  }, isEqualProps);
9545
9803
  function useXYFlowEvents() {
9546
- const diagramApi = useDiagramStoreApi(), xyflowApi = useXYStoreApi(), lastClickTimestamp = useRef(), dblclickTimeout = useRef(), dbclickLock = () => dblclickTimeout.current !== void 0 ? !0 : (dblclickTimeout.current = window.setTimeout(() => {
9547
- dblclickTimeout.current = void 0;
9548
- }, 250), !1), lastClickWasRecent = (ms = 1500) => lastClickTimestamp.current && Date.now() - lastClickTimestamp.current < ms, hoveredNodeFromOnEdgeEnterRef = useRef("");
9549
- return useMemo(() => ({
9550
- onDoubleClick: (event) => {
9551
- const {
9552
- fitViewEnabled,
9553
- onCanvasDblClick,
9554
- resetLastClicked,
9555
- fitDiagram
9556
- } = diagramApi.getState();
9557
- fitViewEnabled && (fitDiagram(xyflowApi), onCanvasDblClick || event.stopPropagation()), resetLastClicked(), onCanvasDblClick == null || onCanvasDblClick(event);
9558
- },
9559
- onPaneClick: (event) => {
9560
- if (dbclickLock())
9561
- return;
9562
- const {
9563
- focusedNodeId,
9564
- activeDynamicViewStep,
9565
- fitDiagram,
9566
- onCanvasClick,
9567
- resetLastClicked
9568
- } = diagramApi.getState();
9569
- (focusedNodeId || activeDynamicViewStep) && (fitDiagram(xyflowApi), onCanvasClick || event.stopPropagation()), resetLastClicked(), onCanvasClick == null || onCanvasClick(event);
9570
- },
9571
- onNodeContextMenu: (event, xynode) => {
9572
- var _a, _b;
9573
- diagramApi.getState().setLastClickedNode(xynode.id), (_b = (_a = diagramApi.getState()).onNodeContextMenu) == null || _b.call(_a, {
9574
- element: xynode.data.element,
9575
- xynode,
9576
- event
9577
- });
9578
- },
9579
- onPaneContextMenu: (event) => {
9580
- var _a, _b;
9581
- diagramApi.getState().resetLastClicked(), (_b = (_a = diagramApi.getState()).onCanvasContextMenu) == null || _b.call(_a, event);
9582
- },
9583
- onEdgeContextMenu: (event, xyedge) => {
9584
- var _a, _b;
9585
- diagramApi.getState().setLastClickedEdge(xyedge.id), (_b = (_a = diagramApi.getState()).onEdgeContextMenu) == null || _b.call(_a, {
9586
- relation: xyedge.data.edge,
9587
- xyedge,
9588
- event
9589
- });
9590
- },
9591
- onNodeClick: (event, xynode) => {
9592
- const {
9593
- zoomable,
9594
- fitViewEnabled,
9595
- focusedNodeId,
9596
- focusOnNode,
9597
- onNodeClick,
9598
- lastClickedNodeId,
9599
- setLastClickedNode
9600
- } = diagramApi.getState();
9601
- setLastClickedNode(xynode.id);
9602
- const focusPossible = zoomable && fitViewEnabled, shallChangeFocus = !!focusedNodeId && focusedNodeId !== xynode.id, clickedRecently = isNullish(focusedNodeId) && lastClickedNodeId === xynode.id && lastClickWasRecent();
9603
- focusPossible && (shallChangeFocus || clickedRecently) && (focusOnNode(xynode.id), onNodeClick || event.stopPropagation()), lastClickTimestamp.current = Date.now(), onNodeClick == null || onNodeClick({
9604
- element: xynode.data.element,
9605
- xynode,
9606
- event
9607
- });
9608
- },
9609
- onNodeDoubleClick: (event, xynode) => {
9610
- const {
9611
- focusedNodeId,
9612
- zoomable,
9613
- fitViewEnabled,
9614
- fitDiagram,
9615
- focusOnNode,
9616
- setLastClickedNode
9617
- } = diagramApi.getState();
9618
- setLastClickedNode(xynode.id), (focusedNodeId || zoomable && fitViewEnabled) && (focusedNodeId === xynode.id ? fitDiagram(xyflowApi) : focusOnNode(xynode.id), event.stopPropagation());
9619
- },
9620
- onEdgeClick: (event, xyedge) => {
9621
- diagramApi.getState().setLastClickedEdge(xyedge.id);
9622
- const { focusedNodeId, focusOnNode, onEdgeClick } = diagramApi.getState();
9623
- focusedNodeId && (focusedNodeId === xyedge.source || focusedNodeId === xyedge.target) && (focusOnNode(focusedNodeId === xyedge.source ? xyedge.target : xyedge.source), onEdgeClick || event.stopPropagation()), onEdgeClick == null || onEdgeClick({
9624
- relation: xyedge.data.edge,
9625
- xyedge,
9626
- event
9627
- });
9628
- },
9629
- onMoveEnd: (event, _viewport) => {
9630
- const viewportChanged = !!event;
9631
- viewportChanged !== diagramApi.getState().viewportChanged && diagramApi.setState({ viewportChanged }, !1, `viewport-changed: ${viewportChanged}`);
9632
- },
9633
- onNodeMouseEnter: (_event, xynode) => {
9634
- hoveredNodeFromOnEdgeEnterRef.current = "", diagramApi.getState().setHoveredNode(xynode.id);
9635
- },
9636
- onNodeMouseLeave: (_event, xynode) => {
9637
- const { hoveredNodeId, setHoveredNode } = diagramApi.getState();
9638
- hoveredNodeId === xynode.id && setHoveredNode(null);
9639
- },
9640
- onEdgeMouseEnter: (_event, { id: id2, source, target }) => {
9641
- const { hoveredNodeId, focusedNodeId, setHoveredEdge, setHoveredNode } = diagramApi.getState();
9642
- if (setHoveredEdge(id2), (focusedNodeId === source || focusedNodeId === target) && focusedNodeId !== hoveredNodeId) {
9643
- const next = hoveredNodeFromOnEdgeEnterRef.current = source === focusedNodeId ? target : source;
9644
- 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 = "";
9645
9928
  }
9646
- },
9647
- onEdgeMouseLeave: (_event, xyedge) => {
9648
- const { hoveredEdgeId, setHoveredEdge, hoveredNodeId, setHoveredNode } = diagramApi.getState();
9649
- hoveredEdgeId === xyedge.id && setHoveredEdge(null), hoveredNodeId === hoveredNodeFromOnEdgeEnterRef.current && setHoveredNode(null), hoveredNodeFromOnEdgeEnterRef.current = "";
9650
- }
9651
- }), [diagramApi, xyflowApi]);
9929
+ };
9930
+ }, [diagramApi]);
9652
9931
  }
9653
9932
  const nodeTypes = {
9654
9933
  element: ElementNodeMemo,
@@ -9733,9 +10012,6 @@ function XYFlow({
9733
10012
  elementsSelectable: nodesSelectable,
9734
10013
  nodesFocusable: nodesDraggable || nodesSelectable || hasOnNodeClick || hasOnNavigateTo,
9735
10014
  edgesFocusable: hasOnEdgeClick,
9736
- ...!nodesSelectable && {
9737
- selectionKeyCode: null
9738
- },
9739
10015
  nodesDraggable,
9740
10016
  ...nodesDraggable && {
9741
10017
  onNodeDragStart: layoutConstraints.onNodeDragStart,
@@ -9745,6 +10021,7 @@ function XYFlow({
9745
10021
  zoomOnDoubleClick: !1,
9746
10022
  elevateNodesOnSelect: !1,
9747
10023
  selectNodesOnDrag: !1,
10024
+ selectionKeyCode: null,
9748
10025
  onDoubleClick: handlers.onDoubleClick,
9749
10026
  onPaneClick: handlers.onPaneClick,
9750
10027
  onMoveEnd: handlers.onMoveEnd,
@@ -9771,7 +10048,68 @@ function XYFlow({
9771
10048
  }
9772
10049
  );
9773
10050
  }
9774
- var container$1 = "hbkbtj0", paper = "hbkbtj1", title = "hbkbtj2", description = "hbkbtj3";
10051
+ var panel$1 = "_19mimxc0";
10052
+ function BackwardForwardPanel() {
10053
+ const { hasBack, hasForward, ops } = useNavigationHistory();
10054
+ return /* @__PURE__ */ jsx(
10055
+ Group,
10056
+ {
10057
+ className: clsx(
10058
+ "react-flow__panel",
10059
+ panel$1,
10060
+ "likec4-navigation-panel"
10061
+ ),
10062
+ gap: "xs",
10063
+ children: /* @__PURE__ */ jsxs(AnimatePresence, { children: [
10064
+ hasBack && /* @__PURE__ */ jsx(
10065
+ m.div,
10066
+ {
10067
+ layout: !0,
10068
+ initial: { opacity: 0.05, transform: "translateX(-10px)" },
10069
+ animate: { opacity: 1, transform: "translateX(0)" },
10070
+ exit: {
10071
+ opacity: 0.05,
10072
+ transform: "translateX(-10px)"
10073
+ },
10074
+ children: /* @__PURE__ */ jsx(
10075
+ ActionIcon,
10076
+ {
10077
+ variant: "light",
10078
+ color: "gray",
10079
+ onClick: () => ops.back(),
10080
+ children: /* @__PURE__ */ jsx(IconChevronLeft, {})
10081
+ }
10082
+ )
10083
+ },
10084
+ "back"
10085
+ ),
10086
+ hasForward && /* @__PURE__ */ jsx(
10087
+ m.div,
10088
+ {
10089
+ layout: !0,
10090
+ initial: { opacity: 0.05, transform: "translateX(10px)" },
10091
+ animate: { opacity: 1, transform: "translateX(0)" },
10092
+ exit: {
10093
+ opacity: 0,
10094
+ transform: "translateX(10px)"
10095
+ },
10096
+ children: /* @__PURE__ */ jsx(
10097
+ ActionIcon,
10098
+ {
10099
+ variant: "light",
10100
+ color: "gray",
10101
+ onClick: () => ops.forward(),
10102
+ children: /* @__PURE__ */ jsx(IconChevronRight, {})
10103
+ }
10104
+ )
10105
+ },
10106
+ "forward"
10107
+ )
10108
+ ] })
10109
+ }
10110
+ );
10111
+ }
10112
+ var container$1 = "hbkbtj0", card = "hbkbtj1", title = "hbkbtj2", description = "hbkbtj3";
9775
10113
  const selector = (s) => ({
9776
10114
  id: s.view.id,
9777
10115
  title: s.view.title ?? "untitled",
@@ -9796,16 +10134,31 @@ function DiagramTitlePanel() {
9796
10134
  style: {
9797
10135
  transformOrigin: "left center"
9798
10136
  },
9799
- children: /* @__PURE__ */ jsx(
9800
- Paper,
10137
+ children: /* @__PURE__ */ jsxs(
10138
+ Card,
9801
10139
  {
9802
10140
  radius: "sm",
9803
- withBorder: !isCollapsed,
9804
- className: paper,
9805
- p: isCollapsed ? "xs" : "lg",
10141
+ className: card,
10142
+ withBorder: !0,
10143
+ p: "md",
10144
+ pb: isCollapsed ? "sm" : "md",
9806
10145
  onDoubleClick: (e) => e.stopPropagation(),
9807
- children: /* @__PURE__ */ jsxs(Stack, { gap: "sm", justify: "stretch", align: "stretch", children: [
9808
- /* @__PURE__ */ jsxs(Group, { justify: "stretch", wrap: "nowrap", onClick: toggle, style: { cursor: "pointer" }, children: [
10146
+ children: [
10147
+ /* @__PURE__ */ jsx(CardSection, { mb: isCollapsed ? 10 : "sm", children: /* @__PURE__ */ jsx(
10148
+ Button,
10149
+ {
10150
+ fullWidth: !0,
10151
+ size: "xs",
10152
+ h: "sm",
10153
+ py: 2,
10154
+ radius: "0",
10155
+ variant: isCollapsed ? "light" : "subtle",
10156
+ color: "gray",
10157
+ onClick: toggle,
10158
+ children: /* @__PURE__ */ jsx(IconMenu, { size: 11, opacity: 0.7 })
10159
+ }
10160
+ ) }),
10161
+ /* @__PURE__ */ jsxs(Group, { justify: "stretch", wrap: "nowrap", mb: isCollapsed ? 0 : "sm", children: [
9809
10162
  /* @__PURE__ */ jsx(
9810
10163
  Text,
9811
10164
  {
@@ -9903,7 +10256,7 @@ function DiagramTitlePanel() {
9903
10256
  }
9904
10257
  )
9905
10258
  ] })
9906
- ] })
10259
+ ]
9907
10260
  }
9908
10261
  )
9909
10262
  },
@@ -9946,6 +10299,8 @@ function DynamicViewWalkthrough() {
9946
10299
  Box,
9947
10300
  {
9948
10301
  className: clsx("react-flow__panel", container),
10302
+ onClick: (e) => e.stopPropagation(),
10303
+ onDoubleClick: (e) => e.stopPropagation(),
9949
10304
  children: [
9950
10305
  isNullish(activeDynamicViewStep) && /* @__PURE__ */ jsx(
9951
10306
  Button,
@@ -9958,7 +10313,7 @@ function DynamicViewWalkthrough() {
9958
10313
  children: "Start"
9959
10314
  }
9960
10315
  ),
9961
- isNumber(activeDynamicViewStep) && /* @__PURE__ */ jsxs(Button.Group, { className: buttons, children: [
10316
+ isNumber(activeDynamicViewStep) && /* @__PURE__ */ jsxs(ButtonGroup, { className: buttons, children: [
9962
10317
  /* @__PURE__ */ jsx(
9963
10318
  Button,
9964
10319
  {
@@ -10006,17 +10361,16 @@ const {
10006
10361
  { key: "primary", value: primary.fill },
10007
10362
  { key: "secondary", value: secondary.fill },
10008
10363
  { key: "muted", value: muted.fill }
10009
- ], colors = keys.strict(otherColors).map((key) => ({
10364
+ ], colors = keys(otherColors).map((key) => ({
10010
10365
  key,
10011
10366
  value: defaultTheme.elements[key].fill
10012
- }));
10013
- function NodeOptions({ selectedNodeIds }) {
10367
+ })), NodeOptions = memo(({ selectedNodeIds }) => {
10014
10368
  const diagramApi = useDiagramStoreApi(), nodes = useXYNodesData(selectedNodeIds);
10015
10369
  if (!hasAtLeast$1(nodes, 1))
10016
10370
  return null;
10017
10371
  if (nodes.length !== selectedNodeIds.length)
10018
10372
  throw new Error("NodeOptions: nodes and props.nodes should have the same length");
10019
- 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) => {
10020
10374
  const targets = nodes.map((node) => node.data.element.id);
10021
10375
  invariant(hasAtLeast$1(targets, 1), "At least one target is required"), diagramApi.getState().triggerChangeElementStyle({
10022
10376
  op: "change-element-style",
@@ -10024,8 +10378,14 @@ function NodeOptions({ selectedNodeIds }) {
10024
10378
  targets
10025
10379
  });
10026
10380
  };
10027
- return /* @__PURE__ */ jsxs(Stack, { children: [
10028
- /* @__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
+ ] }),
10029
10389
  showShapeOption && /* @__PURE__ */ jsx(
10030
10390
  ShapeOption,
10031
10391
  {
@@ -10046,6 +10406,7 @@ function NodeOptions({ selectedNodeIds }) {
10046
10406
  ),
10047
10407
  showOpacityOption && /* @__PURE__ */ jsxs("div", { children: [
10048
10408
  /* @__PURE__ */ jsx(Divider, { label: "opacity and border", labelPosition: "left" }),
10409
+ /* @__PURE__ */ jsx(Space, { h: "xs" }),
10049
10410
  /* @__PURE__ */ jsx(
10050
10411
  OpacityOption,
10051
10412
  {
@@ -10055,6 +10416,7 @@ function NodeOptions({ selectedNodeIds }) {
10055
10416
  }
10056
10417
  }
10057
10418
  ),
10419
+ /* @__PURE__ */ jsx(Space, { h: "sm" }),
10058
10420
  /* @__PURE__ */ jsx(
10059
10421
  BorderStyleOption,
10060
10422
  {
@@ -10067,7 +10429,7 @@ function NodeOptions({ selectedNodeIds }) {
10067
10429
  ] }, firstNode.id),
10068
10430
  /* @__PURE__ */ jsx(NavigateToOption, { nodes })
10069
10431
  ] });
10070
- }
10432
+ }, (prevProps, nextProps) => shallowEqual(prevProps.selectedNodeIds, nextProps.selectedNodeIds));
10071
10433
  function Colors({
10072
10434
  nodes: [firstNode, ...nodes],
10073
10435
  onColorChange
@@ -10155,20 +10517,22 @@ function NavigateToOption({
10155
10517
  const isMultiple = nodes.length >= 1;
10156
10518
  return /* @__PURE__ */ jsxs("div", { children: [
10157
10519
  /* @__PURE__ */ jsx(Divider, { label: "navigate to", labelPosition: "left" }),
10158
- /* @__PURE__ */ jsx(
10159
- Select,
10160
- {
10161
- mt: "xs",
10162
- size: "xs",
10163
- variant: "filled",
10164
- value: isMultiple ? null : node.data.element.navigateTo ?? null,
10165
- disabled: isMultiple,
10166
- placeholder: isMultiple ? "[ multiple ]" : "select",
10167
- data: node.data.element.navigateTo ? [{ value: node.data.element.navigateTo, label: node.data.element.navigateTo }] : [],
10168
- allowDeselect: !0,
10169
- checkIconPosition: "right"
10170
- }
10171
- )
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
+ ] })
10172
10536
  ] });
10173
10537
  }
10174
10538
  function OpacityOption({
@@ -10182,7 +10546,6 @@ function OpacityOption({
10182
10546
  }, [selectedOpacity]), /* @__PURE__ */ jsx(
10183
10547
  Slider,
10184
10548
  {
10185
- mt: "xs",
10186
10549
  size: "sm",
10187
10550
  color: "dark",
10188
10551
  value,
@@ -10199,7 +10562,7 @@ function BorderStyleOption({
10199
10562
  const [value, setValue] = useState(selecteBorderStyle);
10200
10563
  return useUpdateEffect(() => {
10201
10564
  setValue(selecteBorderStyle);
10202
- }, [selecteBorderStyle]), /* @__PURE__ */ jsx(Box, { mt: "md", children: /* @__PURE__ */ jsx(
10565
+ }, [selecteBorderStyle]), /* @__PURE__ */ jsx(Box, { children: /* @__PURE__ */ jsx(
10203
10566
  SegmentedControl,
10204
10567
  {
10205
10568
  size: "xs",
@@ -10219,14 +10582,25 @@ function BorderStyleOption({
10219
10582
  ) });
10220
10583
  }
10221
10584
  var panel = "_1lmzt1h0";
10222
- const OptionsPanelMemo = memo(function() {
10223
- const isFocusDisabled = useDiagramState((s) => isNullish(s.focusedNodeId)), [selectedNodes, setSelectedNodes] = useState([]);
10224
- return useOnSelectionChange({
10225
- onChange: ({ nodes }) => {
10226
- const next = nodes.map((n) => n.id);
10227
- setSelectedNodes((prev) => deepEqual(prev, next) ? prev : next);
10228
- }
10229
- }), /* @__PURE__ */ jsx(AnimatePresence, { mode: "wait", children: isFocusDisabled && selectedNodes.length > 0 && /* @__PURE__ */ jsx(
10585
+ function OptionsPanel() {
10586
+ const { isFocused, viewId } = useDiagramState((s) => ({
10587
+ viewId: s.view.id,
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(
10230
10604
  m.div,
10231
10605
  {
10232
10606
  initial: { opacity: 0, scale: 0.85 },
@@ -10238,12 +10612,14 @@ const OptionsPanelMemo = memo(function() {
10238
10612
  transition: { duration: 0.14 },
10239
10613
  className: clsx("react-flow__panel", panel),
10240
10614
  style: {
10241
- transformOrigin: "center right"
10615
+ transformOrigin: "center right",
10616
+ maxWidth: "320px"
10242
10617
  },
10243
- children: /* @__PURE__ */ jsx(Card, { shadow: "sm", children: /* @__PURE__ */ jsx(NodeOptions, { selectedNodeIds: selectedNodes }) })
10244
- }
10618
+ children: /* @__PURE__ */ jsx(Card, { shadow: "md", children: nodes.length > 0 && /* @__PURE__ */ jsx(NodeOptions, { selectedNodeIds: nodes }) })
10619
+ },
10620
+ viewId
10245
10621
  ) });
10246
- }), OptionsPanel2 = OptionsPanelMemo;
10622
+ }
10247
10623
  function literalToEnum(value) {
10248
10624
  switch (value) {
10249
10625
  case "dots":
@@ -10267,10 +10643,11 @@ const XYFlowInner = memo(function({
10267
10643
  background,
10268
10644
  controls,
10269
10645
  showDiagramTitle,
10646
+ showNavigationButtons,
10270
10647
  enableDynamicViewWalkthrough
10271
10648
  }) {
10272
10649
  const {
10273
- isDynamicView: isDynamicView2,
10650
+ isDynamicView,
10274
10651
  isDynamicViewActive,
10275
10652
  readonly
10276
10653
  } = useDiagramState((s) => ({
@@ -10281,9 +10658,10 @@ const XYFlowInner = memo(function({
10281
10658
  return /* @__PURE__ */ jsxs(Fragment, { children: [
10282
10659
  background !== "transparent" && background !== "solid" && /* @__PURE__ */ jsx(XYFlowBackground, { background }),
10283
10660
  controls && /* @__PURE__ */ jsx(Controls, { position: "bottom-right" }),
10284
- readonly === !1 && /* @__PURE__ */ jsx(OptionsPanel2, {}),
10661
+ readonly === !1 && /* @__PURE__ */ jsx(OptionsPanel, {}),
10285
10662
  !isDynamicViewActive && showDiagramTitle === !0 && /* @__PURE__ */ jsx(DiagramTitlePanel, {}),
10286
- isDynamicView2 && enableDynamicViewWalkthrough && /* @__PURE__ */ jsx(DynamicViewWalkthrough, {}),
10663
+ isDynamicView && enableDynamicViewWalkthrough && /* @__PURE__ */ jsx(DynamicViewWalkthrough, {}),
10664
+ showNavigationButtons && /* @__PURE__ */ jsx(BackwardForwardPanel, {}),
10287
10665
  children2
10288
10666
  ] });
10289
10667
  }, shallowEqual);
@@ -10301,6 +10679,7 @@ function LikeC4Diagram({
10301
10679
  controls = !1,
10302
10680
  showElementLinks = !0,
10303
10681
  showDiagramTitle = !0,
10682
+ showNavigationButtons = !1,
10304
10683
  enableDynamicViewWalkthrough = !0,
10305
10684
  initialWidth,
10306
10685
  initialHeight,
@@ -10339,6 +10718,8 @@ function LikeC4Diagram({
10339
10718
  DiagramContextProvider,
10340
10719
  {
10341
10720
  view,
10721
+ keepAspectRatio,
10722
+ className: clsx(rootClassName, className),
10342
10723
  readonly,
10343
10724
  pannable,
10344
10725
  zoomable,
@@ -10358,26 +10739,18 @@ function LikeC4Diagram({
10358
10739
  onNavigateTo,
10359
10740
  onCanvasDblClick,
10360
10741
  children: /* @__PURE__ */ jsx(LazyMotion, { features: domAnimation, strict: !0, children: /* @__PURE__ */ jsx(
10361
- KeepAspectRatioContainer,
10742
+ LikeC4DiagramInnerMemo,
10362
10743
  {
10363
- className: clsx(rootClassName, className),
10364
- enabled: keepAspectRatio,
10365
- width: view.width,
10366
- height: view.height,
10367
- children: /* @__PURE__ */ jsx(
10368
- LikeC4DiagramInnerMemo,
10369
- {
10370
- defaultNodes: initialRef.current.defaultNodes,
10371
- defaultEdges: initialRef.current.defaultEdges,
10372
- fitView: fitView2,
10373
- zoomable,
10374
- background,
10375
- controls,
10376
- pannable,
10377
- showDiagramTitle,
10378
- enableDynamicViewWalkthrough
10379
- }
10380
- )
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
10381
10754
  }
10382
10755
  ) })
10383
10756
  }
@@ -10394,9 +10767,21 @@ const LikeC4DiagramInnerMemo = memo(function({
10394
10767
  defaultNodes,
10395
10768
  defaultEdges,
10396
10769
  showDiagramTitle,
10770
+ showNavigationButtons,
10397
10771
  enableDynamicViewWalkthrough
10398
10772
  }) {
10399
- return DEV && useTilg(), /* @__PURE__ */ jsxs(Fragment, { children: [
10773
+ DEV && useTilg();
10774
+ const diagramApi = useDiagramStoreApi(), [isInitialized, setIsInitialized] = useState(diagramApi.getState().initialized);
10775
+ return useEffect(() => {
10776
+ if (!isInitialized)
10777
+ return diagramApi.subscribe(
10778
+ (s) => s.initialized,
10779
+ setIsInitialized,
10780
+ {
10781
+ fireImmediately: !0
10782
+ }
10783
+ );
10784
+ }, [isInitialized]), /* @__PURE__ */ jsxs(Fragment, { children: [
10400
10785
  /* @__PURE__ */ jsx(
10401
10786
  XYFlow,
10402
10787
  {
@@ -10412,6 +10797,7 @@ const LikeC4DiagramInnerMemo = memo(function({
10412
10797
  children: /* @__PURE__ */ jsx(
10413
10798
  XYFlowInner,
10414
10799
  {
10800
+ showNavigationButtons,
10415
10801
  showDiagramTitle,
10416
10802
  enableDynamicViewWalkthrough,
10417
10803
  background,
@@ -10420,7 +10806,7 @@ const LikeC4DiagramInnerMemo = memo(function({
10420
10806
  )
10421
10807
  }
10422
10808
  ),
10423
- /* @__PURE__ */ jsxs(WhenInitialized, { children: [
10809
+ isInitialized && /* @__PURE__ */ jsxs(Fragment, { children: [
10424
10810
  /* @__PURE__ */ jsx(SyncWithDiagram, {}),
10425
10811
  fitView2 && /* @__PURE__ */ jsx(FitViewOnDiagramChange, {}),
10426
10812
  fitView2 && zoomable && /* @__PURE__ */ jsx(SelectEdgesOnNodeFocus, {})