react-cosmos-diagram 0.2.0 → 0.4.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 (118) hide show
  1. package/dist/esm/components/Background/LinePath.d.ts +8 -0
  2. package/dist/esm/components/Background/LinePath.d.ts.map +1 -0
  3. package/dist/esm/components/Background/index.d.ts +9 -0
  4. package/dist/esm/components/Background/index.d.ts.map +1 -0
  5. package/dist/esm/components/Background/type.d.ts +6 -0
  6. package/dist/esm/components/Background/type.d.ts.map +1 -0
  7. package/dist/esm/components/Edges/Anchor.d.ts +2 -2
  8. package/dist/esm/components/Edges/Anchor.d.ts.map +1 -1
  9. package/dist/esm/components/Edges/EdgeWrapper/index.d.ts.map +1 -1
  10. package/dist/esm/components/Edges/EdgeWrapper/type.d.ts +3 -1
  11. package/dist/esm/components/Edges/EdgeWrapper/type.d.ts.map +1 -1
  12. package/dist/esm/components/Port/utils.d.ts +9 -1
  13. package/dist/esm/components/Port/utils.d.ts.map +1 -1
  14. package/dist/esm/components/ReactDiagramProvider/type.d.ts +5 -2
  15. package/dist/esm/components/ReactDiagramProvider/type.d.ts.map +1 -1
  16. package/dist/esm/components/SelectionBox/index.d.ts.map +1 -1
  17. package/dist/esm/components/StoreUpdater/index.d.ts +2 -2
  18. package/dist/esm/components/StoreUpdater/index.d.ts.map +1 -1
  19. package/dist/esm/container/ConnectionLineRenderer/ConnectionPath.d.ts +17 -0
  20. package/dist/esm/container/ConnectionLineRenderer/ConnectionPath.d.ts.map +1 -0
  21. package/dist/esm/container/ConnectionLineRenderer/index.d.ts +11 -0
  22. package/dist/esm/container/ConnectionLineRenderer/index.d.ts.map +1 -0
  23. package/dist/esm/container/ConnectionLineRenderer/type.d.ts +15 -0
  24. package/dist/esm/container/ConnectionLineRenderer/type.d.ts.map +1 -0
  25. package/dist/esm/container/DragSelection/index.d.ts +0 -3
  26. package/dist/esm/container/DragSelection/index.d.ts.map +1 -1
  27. package/dist/esm/container/EdgeRenderer/index.d.ts +2 -2
  28. package/dist/esm/container/EdgeRenderer/index.d.ts.map +1 -1
  29. package/dist/esm/container/EdgeRenderer/type.d.ts +3 -3
  30. package/dist/esm/container/EdgeRenderer/type.d.ts.map +1 -1
  31. package/dist/esm/container/NodeRenderer/index.d.ts.map +1 -1
  32. package/dist/esm/container/Pane/index.d.ts.map +1 -1
  33. package/dist/esm/container/ReactDiagram/DiagramView.d.ts +1 -1
  34. package/dist/esm/container/ReactDiagram/DiagramView.d.ts.map +1 -1
  35. package/dist/esm/container/ReactDiagram/index.d.ts +6 -4
  36. package/dist/esm/container/ReactDiagram/index.d.ts.map +1 -1
  37. package/dist/esm/hooks/useDrag/index.d.ts.map +1 -1
  38. package/dist/esm/hooks/useDrag/type.d.ts +3 -10
  39. package/dist/esm/hooks/useDrag/type.d.ts.map +1 -1
  40. package/dist/esm/hooks/useDrag/utils.d.ts +7 -6
  41. package/dist/esm/hooks/useDrag/utils.d.ts.map +1 -1
  42. package/dist/esm/hooks/useGetPointerPosition.d.ts +14 -2
  43. package/dist/esm/hooks/useGetPointerPosition.d.ts.map +1 -1
  44. package/dist/esm/index.d.ts +1 -0
  45. package/dist/esm/index.d.ts.map +1 -1
  46. package/dist/esm/index.js +1597 -1548
  47. package/dist/esm/store/index.d.ts.map +1 -1
  48. package/dist/esm/store/initialState.d.ts.map +1 -1
  49. package/dist/esm/types/core.d.ts +7 -5
  50. package/dist/esm/types/core.d.ts.map +1 -1
  51. package/dist/esm/types/index.d.ts +2 -1
  52. package/dist/esm/types/index.d.ts.map +1 -1
  53. package/dist/style.css +12 -6
  54. package/dist/umd/components/Background/LinePath.d.ts +8 -0
  55. package/dist/umd/components/Background/LinePath.d.ts.map +1 -0
  56. package/dist/umd/components/Background/index.d.ts +9 -0
  57. package/dist/umd/components/Background/index.d.ts.map +1 -0
  58. package/dist/umd/components/Background/type.d.ts +6 -0
  59. package/dist/umd/components/Background/type.d.ts.map +1 -0
  60. package/dist/umd/components/Edges/Anchor.d.ts +2 -2
  61. package/dist/umd/components/Edges/Anchor.d.ts.map +1 -1
  62. package/dist/umd/components/Edges/EdgeWrapper/index.d.ts.map +1 -1
  63. package/dist/umd/components/Edges/EdgeWrapper/type.d.ts +3 -1
  64. package/dist/umd/components/Edges/EdgeWrapper/type.d.ts.map +1 -1
  65. package/dist/umd/components/Port/utils.d.ts +9 -1
  66. package/dist/umd/components/Port/utils.d.ts.map +1 -1
  67. package/dist/umd/components/ReactDiagramProvider/type.d.ts +5 -2
  68. package/dist/umd/components/ReactDiagramProvider/type.d.ts.map +1 -1
  69. package/dist/umd/components/SelectionBox/index.d.ts.map +1 -1
  70. package/dist/umd/components/StoreUpdater/index.d.ts +2 -2
  71. package/dist/umd/components/StoreUpdater/index.d.ts.map +1 -1
  72. package/dist/umd/container/ConnectionLineRenderer/ConnectionPath.d.ts +17 -0
  73. package/dist/umd/container/ConnectionLineRenderer/ConnectionPath.d.ts.map +1 -0
  74. package/dist/umd/container/ConnectionLineRenderer/index.d.ts +11 -0
  75. package/dist/umd/container/ConnectionLineRenderer/index.d.ts.map +1 -0
  76. package/dist/umd/container/ConnectionLineRenderer/type.d.ts +15 -0
  77. package/dist/umd/container/ConnectionLineRenderer/type.d.ts.map +1 -0
  78. package/dist/umd/container/DragSelection/index.d.ts +0 -3
  79. package/dist/umd/container/DragSelection/index.d.ts.map +1 -1
  80. package/dist/umd/container/EdgeRenderer/index.d.ts +2 -2
  81. package/dist/umd/container/EdgeRenderer/index.d.ts.map +1 -1
  82. package/dist/umd/container/EdgeRenderer/type.d.ts +3 -3
  83. package/dist/umd/container/EdgeRenderer/type.d.ts.map +1 -1
  84. package/dist/umd/container/NodeRenderer/index.d.ts.map +1 -1
  85. package/dist/umd/container/Pane/index.d.ts.map +1 -1
  86. package/dist/umd/container/ReactDiagram/DiagramView.d.ts +1 -1
  87. package/dist/umd/container/ReactDiagram/DiagramView.d.ts.map +1 -1
  88. package/dist/umd/container/ReactDiagram/index.d.ts +6 -4
  89. package/dist/umd/container/ReactDiagram/index.d.ts.map +1 -1
  90. package/dist/umd/hooks/useDrag/index.d.ts.map +1 -1
  91. package/dist/umd/hooks/useDrag/type.d.ts +3 -10
  92. package/dist/umd/hooks/useDrag/type.d.ts.map +1 -1
  93. package/dist/umd/hooks/useDrag/utils.d.ts +7 -6
  94. package/dist/umd/hooks/useDrag/utils.d.ts.map +1 -1
  95. package/dist/umd/hooks/useGetPointerPosition.d.ts +14 -2
  96. package/dist/umd/hooks/useGetPointerPosition.d.ts.map +1 -1
  97. package/dist/umd/index.d.ts +1 -0
  98. package/dist/umd/index.d.ts.map +1 -1
  99. package/dist/umd/index.js +2 -2
  100. package/dist/umd/store/index.d.ts.map +1 -1
  101. package/dist/umd/store/initialState.d.ts.map +1 -1
  102. package/dist/umd/types/core.d.ts +7 -5
  103. package/dist/umd/types/core.d.ts.map +1 -1
  104. package/dist/umd/types/index.d.ts +2 -1
  105. package/dist/umd/types/index.d.ts.map +1 -1
  106. package/package.json +1 -1
  107. package/dist/esm/components/ConnectionEdge/ConnectionPath.d.ts +0 -16
  108. package/dist/esm/components/ConnectionEdge/ConnectionPath.d.ts.map +0 -1
  109. package/dist/esm/components/ConnectionEdge/index.d.ts +0 -11
  110. package/dist/esm/components/ConnectionEdge/index.d.ts.map +0 -1
  111. package/dist/esm/components/ConnectionEdge/type.d.ts +0 -22
  112. package/dist/esm/components/ConnectionEdge/type.d.ts.map +0 -1
  113. package/dist/umd/components/ConnectionEdge/ConnectionPath.d.ts +0 -16
  114. package/dist/umd/components/ConnectionEdge/ConnectionPath.d.ts.map +0 -1
  115. package/dist/umd/components/ConnectionEdge/index.d.ts +0 -11
  116. package/dist/umd/components/ConnectionEdge/index.d.ts.map +0 -1
  117. package/dist/umd/components/ConnectionEdge/type.d.ts +0 -22
  118. package/dist/umd/components/ConnectionEdge/type.d.ts.map +0 -1
package/dist/esm/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
2
- import { createContext, useContext, useMemo, useState, useEffect, useRef, memo, useCallback, forwardRef } from 'react';
2
+ import { createContext, useContext, useMemo, useState, useEffect, useRef, useCallback, memo, forwardRef } from 'react';
3
3
  import { useStore as useStore$1, createStore } from 'zustand';
4
4
  import { zoom, zoomIdentity } from 'd3-zoom';
5
5
  import { select } from 'd3-selection';
@@ -112,11 +112,11 @@ const getBoundsOfBoxes = (box1, box2) => ({
112
112
  const isMouseEvent = (event) => 'clientX' in event;
113
113
  const getEventPosition = (event, bounds) => {
114
114
  const isMouseTriggered = isMouseEvent(event);
115
- const evtX = isMouseTriggered ? event.clientX : event.touches?.[0].clientX;
116
- const evtY = isMouseTriggered ? event.clientY : event.touches?.[0].clientY;
115
+ const eventX = isMouseTriggered ? event.clientX : event.touches?.[0].clientX;
116
+ const eventY = isMouseTriggered ? event.clientY : event.touches?.[0].clientY;
117
117
  return {
118
- x: evtX - (bounds?.left ?? 0),
119
- y: evtY - (bounds?.top ?? 0),
118
+ x: eventX - (bounds?.left ?? 0),
119
+ y: eventY - (bounds?.top ?? 0),
120
120
  };
121
121
  };
122
122
  const calcAutoPanVelocity = (value, bound, radius, velocity) => {
@@ -149,10 +149,9 @@ const isViewChanged = (prevViewport, eventViewport) => {
149
149
  const { x, y, k } = eventViewport;
150
150
  return prevX !== x || prevY !== y || prevZoom !== k;
151
151
  };
152
- const selector$7 = (s) => ({
152
+ const selector$8 = (s) => ({
153
153
  d3Zoom: s.d3Zoom,
154
154
  d3Selection: s.d3Selection,
155
- elementsSelectable: s.elementsSelectable,
156
155
  });
157
156
  function Pane({ noPanClassName, panning, minZoom, maxZoom, defaultViewport, translateExtent, children, onMove, onMoveStart, onMoveEnd, }) {
158
157
  const store = useStoreApi();
@@ -161,7 +160,7 @@ function Pane({ noPanClassName, panning, minZoom, maxZoom, defaultViewport, tran
161
160
  const d3ZoomHandler = useRef();
162
161
  const prevTransform = useRef({ x: 0, y: 0, zoom: 0 });
163
162
  const timerId = useRef();
164
- const { d3Zoom, d3Selection } = useStore(selector$7, shallow);
163
+ const { d3Zoom, d3Selection } = useStore(selector$8, shallow);
165
164
  useEffect(() => {
166
165
  if (Pane.current) {
167
166
  const bbox = Pane.current.getBoundingClientRect();
@@ -269,9 +268,9 @@ function Pane({ noPanClassName, panning, minZoom, maxZoom, defaultViewport, tran
269
268
  return (jsx("div", { className: "react-diagram__pane react-diagram__container", ref: Pane, children: children }));
270
269
  }
271
270
 
272
- const selector$6 = (s) => `translate(${s.transform[0]}px,${s.transform[1]}px) scale(${s.transform[2]})`;
271
+ const selector$7 = (s) => `translate(${s.transform[0]}px,${s.transform[1]}px) scale(${s.transform[2]})`;
273
272
  function Viewport({ children }) {
274
- const transform = useStore(selector$6);
273
+ const transform = useStore(selector$7);
275
274
  return (jsx("div", { className: "react-diagram__viewport react-diagram__container", style: { transform }, children: children }));
276
275
  }
277
276
 
@@ -286,22 +285,92 @@ function DragBox({ rect }) {
286
285
  } }));
287
286
  }
288
287
 
289
- function SelectionBox({ rect, transform }) {
290
- const nodeRef = useRef(null);
291
- const { width, height, x, y } = rect;
292
- return (jsx("div", { className: cc([
293
- 'react-diagram__selection-box',
294
- 'react-diagram__container',
295
- ]), style: {
296
- transform,
297
- }, children: jsx("div", { ref: nodeRef, className: "react-diagram__selection-box-rect", tabIndex: -1, style: {
298
- width,
299
- height,
300
- top: y,
301
- left: x,
302
- } }) }));
288
+ function useGetPointerPosition() {
289
+ const store = useStoreApi();
290
+ const getPointerPosition = useCallback(({ sourceEvent }) => {
291
+ const { transform, gridStep, centerStep } = store.getState();
292
+ const x = sourceEvent.changedTouches
293
+ ? sourceEvent.changedTouches[0].clientX
294
+ : sourceEvent.clientX;
295
+ const y = sourceEvent.changedTouches
296
+ ? sourceEvent.changedTouches[0].clientY
297
+ : sourceEvent.clientY;
298
+ const pointerPos = {
299
+ x: (x - transform[0]) / transform[2],
300
+ y: (y - transform[1]) / transform[2],
301
+ };
302
+ const getStepPosition = (params = {
303
+ position: pointerPos,
304
+ }) => {
305
+ const { position, nodeSize } = params;
306
+ if (!gridStep)
307
+ return position;
308
+ let x = gridStep[0] * Math.round(position.x / gridStep[0]), y = gridStep[1] * Math.round(position.y / gridStep[1]);
309
+ if (centerStep && nodeSize) {
310
+ const centerX = (gridStep[0] - nodeSize.width) / 2;
311
+ const centerY = (gridStep[1] - nodeSize.height) / 2;
312
+ const positionX = position.x - centerX;
313
+ const positionY = position.y - centerY;
314
+ x = gridStep[0] * Math.round(positionX / gridStep[0]) + centerX;
315
+ y = gridStep[1] * Math.round(positionY / gridStep[1]) + centerY;
316
+ }
317
+ return {
318
+ x,
319
+ y,
320
+ };
321
+ };
322
+ return {
323
+ getStepPosition,
324
+ ...pointerPos,
325
+ };
326
+ }, []);
327
+ return getPointerPosition;
328
+ }
329
+
330
+ const getPortBounds = (selector, nodeElement, zoom, nodeOrigin) => {
331
+ const ports = nodeElement.querySelectorAll(selector);
332
+ if (!ports || !ports.length) {
333
+ return null;
334
+ }
335
+ const portsArray = Array.from(ports);
336
+ const nodeBounds = nodeElement.getBoundingClientRect();
337
+ const nodeOffset = {
338
+ x: nodeBounds.width * nodeOrigin[0],
339
+ y: nodeBounds.height * nodeOrigin[1],
340
+ };
341
+ return portsArray.map((port) => {
342
+ const portBounds = port.getBoundingClientRect();
343
+ return {
344
+ id: port.getAttribute('data-portid'),
345
+ position: port.dataset.portPosition,
346
+ x: (portBounds.left - nodeBounds.left - nodeOffset.x) / zoom,
347
+ y: (portBounds.top - nodeBounds.top - nodeOffset.y) / zoom,
348
+ ...getDimensions(port),
349
+ };
350
+ });
351
+ };
352
+ function getMouseHandler$1(id, getState, handler) {
353
+ return handler === undefined
354
+ ? handler
355
+ : (event) => {
356
+ const node = getState().nodeInternals.get(id);
357
+ handler(event, { ...node });
358
+ };
359
+ }
360
+ function handleNodeClick({ id, store, isSelectable, unselect = false, nodeRef, }) {
361
+ if (!isSelectable)
362
+ return;
363
+ const { addSelectedNodes, unselectNodes, multiSelectionActive, nodeInternals, } = store.getState();
364
+ const node = nodeInternals.get(id);
365
+ store.setState({ selectionBoxActive: false });
366
+ if (!node.selected) {
367
+ addSelectedNodes([id]);
368
+ }
369
+ else if (unselect || (node.selected && multiSelectionActive)) {
370
+ unselectNodes({ nodes: [node] });
371
+ requestAnimationFrame(() => nodeRef?.current?.blur());
372
+ }
303
373
  }
304
- var SelectionBox$1 = memo(SelectionBox);
305
374
 
306
375
  const isNode = (element) => 'id' in element && !('source' in element) && !('target' in element);
307
376
  const isEdge = (element) => 'source' in element && 'target' in element;
@@ -381,7 +450,7 @@ const getMarkerId = (marker, rfId) => {
381
450
  .map((key) => `${key}=${marker[key]}`)
382
451
  .join('&')}`;
383
452
  };
384
- const getEdgeId = ({ source, target }) => `reactdiagram__edge-${source}-${target}`;
453
+ const getEdgeId = ({ source, target }) => `react-diagram__edge-${source}-${target}`;
385
454
  const isExistsConnection = (edge, edges) => edges.some((el) => el.source === edge.source && el.target === edge.target);
386
455
  const addEdge = (edgeParams, edges) => {
387
456
  if (!isEdge(edgeParams)) {
@@ -433,401 +502,694 @@ const getRectOfNodes = (nodes, nodeOrigin = [0, 0]) => {
433
502
  return boxToRect(box);
434
503
  };
435
504
 
436
- const handleParentExpand = (res, updateItem) => {
437
- const parent = res.find((e) => e.id === updateItem.parentNode);
438
- if (parent) {
439
- const extendWidth = updateItem.position.x + updateItem.width - parent.width;
440
- const extendHeight = updateItem.position.y + updateItem.height - parent.height;
441
- if (extendWidth > 0 ||
442
- extendHeight > 0 ||
443
- updateItem.position.x < 0 ||
444
- updateItem.position.y < 0) {
445
- parent.style = { ...parent.style } || {};
446
- parent.style.width = parent.style.width ?? parent.width;
447
- parent.style.height = parent.style.height ?? parent.height;
448
- if (extendWidth > 0) {
449
- parent.style.width += extendWidth;
450
- }
451
- if (extendHeight > 0) {
452
- parent.style.height += extendHeight;
453
- }
454
- if (updateItem.position.x < 0) {
455
- const xDiff = Math.abs(updateItem.position.x);
456
- parent.position.x = parent.position.x - xDiff;
457
- parent.style.width += xDiff;
458
- updateItem.position.x = 0;
459
- }
460
- if (updateItem.position.y < 0) {
461
- const yDiff = Math.abs(updateItem.position.y);
462
- parent.position.y = parent.position.y - yDiff;
463
- parent.style.height += yDiff;
464
- updateItem.position.y = 0;
465
- }
466
- parent.width = parent.style.width;
467
- parent.height = parent.style.height;
468
- }
505
+ function isParentSelected(node, nodeInternals) {
506
+ if (!node.parentNode) {
507
+ return false;
469
508
  }
470
- };
471
- const applyChanges = (changes, elements) => {
472
- // we need this hack to handle the setNodes and setEdges function of the useReactDiagram hook for controlled flows
473
- if (changes.some((c) => c.type === 'reset')) {
474
- return changes.filter((c) => c.type === 'reset').map((c) => c.item);
509
+ const parentNode = nodeInternals.get(node.parentNode);
510
+ if (!parentNode) {
511
+ return false;
475
512
  }
476
- const initElements = changes
477
- .filter((c) => c.type === 'add')
478
- .map((c) => c.item);
479
- return elements.reduce((res, item) => {
480
- const currentChanges = changes.filter((c) => c.id === item.id);
481
- if (currentChanges.length === 0) {
482
- res.push(item);
483
- return res;
484
- }
485
- const updateItem = { ...item };
486
- for (const currentChange of currentChanges) {
487
- if (currentChange) {
488
- switch (currentChange.type) {
489
- case 'select': {
490
- updateItem.selected = currentChange.selected;
491
- break;
492
- }
493
- case 'position': {
494
- if (typeof currentChange.position !== 'undefined') {
495
- updateItem.position = currentChange.position;
496
- }
497
- if (typeof currentChange.positionAbsolute !== 'undefined') {
498
- updateItem.positionAbsolute =
499
- currentChange.positionAbsolute;
500
- }
501
- if (typeof currentChange.dragging !== 'undefined') {
502
- updateItem.dragging = currentChange.dragging;
503
- }
504
- if (updateItem.expandParent) {
505
- handleParentExpand(res, updateItem);
506
- }
507
- break;
508
- }
509
- case 'dimensions': {
510
- if (typeof currentChange.dimensions !== 'undefined') {
511
- updateItem.width = currentChange.dimensions.width;
512
- updateItem.height = currentChange.dimensions.height;
513
- }
514
- if (typeof currentChange.updateStyle !== 'undefined') {
515
- updateItem.style = {
516
- ...(updateItem.style || {}),
517
- ...currentChange.dimensions,
518
- };
519
- }
520
- if (typeof currentChange.resizing === 'boolean') {
521
- updateItem.resizing = currentChange.resizing;
522
- }
523
- if (updateItem.expandParent) {
524
- handleParentExpand(res, updateItem);
525
- }
526
- break;
527
- }
528
- case 'remove': {
529
- return res;
530
- }
531
- }
532
- }
533
- }
534
- res.push(updateItem);
535
- return res;
536
- }, initElements);
537
- };
538
- function applyNodeChanges(changes, nodes) {
539
- return applyChanges(changes, nodes);
540
- }
541
- function applyEdgeChanges(changes, edges) {
542
- return applyChanges(changes, edges);
513
+ if (parentNode.selected) {
514
+ return true;
515
+ }
516
+ return isParentSelected(parentNode, nodeInternals);
543
517
  }
544
- const createSelectionChange = (id, selected) => ({
545
- id,
546
- type: 'select',
547
- selected,
548
- });
549
- function getSelectionChanges(items, selectedIds) {
550
- return items.reduce((res, item) => {
551
- const willBeSelected = selectedIds.includes(item.id);
552
- if (!item.selected && willBeSelected) {
553
- item.selected = true;
554
- res.push(createSelectionChange(item.id, true));
518
+ const getDragItems = (nodeInternals, nodesDraggable, mousePosition, nodeId) => {
519
+ const filteredNode = Array.from(nodeInternals.values()).filter((n) => {
520
+ const hasSize = n.width && n.height;
521
+ const isSelected = n.selected || n.id === nodeId;
522
+ const hasNoParent = !n.parentNode || !isParentSelected(n, nodeInternals);
523
+ const isDraggable = n.draggable || (nodesDraggable && typeof n.draggable === 'undefined');
524
+ return hasSize && isSelected && hasNoParent && isDraggable;
525
+ });
526
+ return filteredNode.map((n) => ({
527
+ id: n.id,
528
+ position: n.position || { x: 0, y: 0 },
529
+ positionAbsolute: n.positionAbsolute || { x: 0, y: 0 },
530
+ distance: {
531
+ x: mousePosition.x - (n.positionAbsolute?.x ?? 0),
532
+ y: mousePosition.y - (n.positionAbsolute?.y ?? 0),
533
+ },
534
+ extent: n.extent,
535
+ parentNode: n.parentNode,
536
+ width: n.width,
537
+ height: n.height,
538
+ }));
539
+ };
540
+ const calcNextPosition = (node, nextPosition, nodeInternals, nodeExtent, nodeOrigin = [0, 0], onError) => {
541
+ let currentExtent = node.extent || nodeExtent;
542
+ if (node.extent === 'parent') {
543
+ if (node.parentNode && node.width && node.height) {
544
+ const parent = nodeInternals.get(node.parentNode);
545
+ const { x: parentX, y: parentY } = getNodePositionWithOrigin(parent, nodeOrigin).positionAbsolute;
546
+ currentExtent =
547
+ parent &&
548
+ isNumeric(parentX) &&
549
+ isNumeric(parentY) &&
550
+ isNumeric(parent.width) &&
551
+ isNumeric(parent.height)
552
+ ? [
553
+ [
554
+ parentX + node.width * nodeOrigin[0],
555
+ parentY + node.height * nodeOrigin[1],
556
+ ],
557
+ [
558
+ parentX +
559
+ parent.width -
560
+ node.width +
561
+ node.width * nodeOrigin[0],
562
+ parentY +
563
+ parent.height -
564
+ node.height +
565
+ node.height * nodeOrigin[1],
566
+ ],
567
+ ]
568
+ : currentExtent;
555
569
  }
556
- else if (item.selected && !willBeSelected) {
557
- item.selected = false;
558
- res.push(createSelectionChange(item.id, false));
570
+ else {
571
+ onError?.('011');
572
+ currentExtent = nodeExtent;
559
573
  }
560
- return res;
561
- }, []);
562
- }
563
-
564
- const selector$5 = (s) => {
574
+ }
575
+ else if (node.extent && node.parentNode) {
576
+ const parent = nodeInternals.get(node.parentNode);
577
+ const { x: parentX, y: parentY } = getNodePositionWithOrigin(parent, nodeOrigin).positionAbsolute;
578
+ currentExtent = [
579
+ [node.extent[0][0] + parentX, node.extent[0][1] + parentY],
580
+ [node.extent[1][0] + parentX, node.extent[1][1] + parentY],
581
+ ];
582
+ }
583
+ let parentPosition = { x: 0, y: 0 };
584
+ if (node.parentNode) {
585
+ const parentNode = nodeInternals.get(node.parentNode);
586
+ parentPosition = getNodePositionWithOrigin(parentNode, nodeOrigin).positionAbsolute;
587
+ }
588
+ const positionAbsolute = currentExtent
589
+ ? clampPosition(nextPosition, currentExtent)
590
+ : nextPosition;
565
591
  return {
566
- elementsSelectable: s.elementsSelectable,
567
- transform: `translate(${s.transform[0]}px,${s.transform[1]}px) scale(${s.transform[2]})`,
592
+ position: {
593
+ x: positionAbsolute.x - parentPosition.x,
594
+ y: positionAbsolute.y - parentPosition.y,
595
+ },
596
+ positionAbsolute,
568
597
  };
569
598
  };
570
- function DragSelection({ children, dragSelectionKeyPressed, }) {
571
- const store = useStoreApi();
572
- const dragSelection = useRef(null);
573
- const prevSelectedNodesCount = useRef(0);
574
- const containerBounds = useRef();
575
- const { elementsSelectable, transform } = useStore(selector$5, shallow);
576
- const [dragBoxStartPosition, setDragBoxStartPosition] = useState({
577
- x: 0,
578
- y: 0,
579
- });
580
- const [dragBoxRect, setDragBoxRect] = useState({
581
- width: 0,
582
- height: 0,
583
- x: 0,
584
- y: 0,
585
- });
586
- const [selectionBoxRect, setSelectionBoxRect] = useState({
587
- width: 0,
588
- height: 0,
589
- x: 0,
590
- y: 0,
599
+ const getEventHandlerParams = ({ nodeId, dragItems, nodeInternals, }) => {
600
+ const extentedDragItems = dragItems.map((n) => {
601
+ const node = nodeInternals.get(n.id);
602
+ return {
603
+ ...node,
604
+ position: n.position,
605
+ positionAbsolute: n.positionAbsolute,
606
+ };
591
607
  });
592
- const [dragBoxActive, setDragBoxActive] = useState(false);
593
- const [selectionBoxActive, setSelectionBoxActive] = useState(false);
594
- const resetDragBox = () => {
595
- setDragBoxStartPosition({
596
- x: 0,
597
- y: 0,
598
- });
599
- setDragBoxRect({
600
- width: 0,
601
- height: 0,
602
- x: 0,
603
- y: 0,
604
- });
605
- setDragBoxActive(false);
606
- };
607
- const onClick = (e) => {
608
- if (e.target === dragSelection.current) {
609
- store.getState().resetSelectedElements();
610
- setDragBoxActive(false);
611
- setSelectionBoxActive(false);
612
- }
613
- };
614
- const onMouseDown = (event) => {
615
- const { resetSelectedElements, domNode } = store.getState();
616
- containerBounds.current = domNode?.getBoundingClientRect();
617
- if (!elementsSelectable ||
618
- event.button !== 0 ||
619
- event.target !== dragSelection.current ||
620
- !containerBounds.current ||
621
- !dragSelectionKeyPressed) {
622
- return;
623
- }
624
- const { x, y } = getEventPosition(event, containerBounds.current);
625
- resetSelectedElements();
626
- setDragBoxRect({
627
- width: 0,
628
- height: 0,
629
- x,
630
- y,
631
- });
632
- setDragBoxStartPosition({
633
- x,
634
- y,
635
- });
636
- };
637
- const onMouseMove = (event) => {
638
- const { nodeInternals, transform, nodeOrigin, getNodes, onNodesChange } = store.getState();
639
- // const hasDragBoxPosition = dragBoxRect.x > 0 && dragBoxRect.y > 0;
640
- const hasDragBoxStartPosition = dragBoxStartPosition.x > 0 && dragBoxStartPosition.y > 0;
641
- if (
642
- // !hasDragBoxPosition ||
643
- !hasDragBoxStartPosition ||
644
- !containerBounds.current ||
645
- !dragSelectionKeyPressed) {
608
+ return [
609
+ nodeId
610
+ ? extentedDragItems.find((n) => n.id === nodeId)
611
+ : extentedDragItems[0],
612
+ extentedDragItems,
613
+ ];
614
+ };
615
+ const hasSelector = (target, selector, nodeRef) => {
616
+ let current = target;
617
+ do {
618
+ if (current?.matches(selector))
619
+ return true;
620
+ if (current === nodeRef.current)
621
+ return false;
622
+ current = current.parentElement;
623
+ } while (current);
624
+ return false;
625
+ };
626
+ const hasChangedPosition = (beforePositions, currentPosition) => beforePositions.x !== currentPosition.x ||
627
+ beforePositions.y !== currentPosition.y;
628
+
629
+ const isDragItem = (node) => 'distance' in node;
630
+ function useDrag({ nodeRef, nodeId, isSelectable, noDragClassName, }) {
631
+ const store = useStoreApi();
632
+ const dragItems = useRef([]);
633
+ const containerBounds = useRef(null);
634
+ const mousePosition = useRef({ x: 0, y: 0 });
635
+ const lastPosition = useRef({ x: 0, y: 0 });
636
+ const dragEvent = useRef(null);
637
+ const autoPanStarted = useRef(false);
638
+ const autoPanId = useRef(0);
639
+ const [dragging, setDragging] = useState(false);
640
+ const getPointerPosition = useGetPointerPosition();
641
+ const updateNodePosition = (pointerPositions, dragEnd = false) => (dragItem) => {
642
+ if (!isDragItem(dragItem))
646
643
  return;
647
- }
648
- setDragBoxActive(true);
649
- setSelectionBoxActive(false);
650
- const mousePos = getEventPosition(event, containerBounds.current);
651
- const startX = dragBoxStartPosition.x ?? 0;
652
- const startY = dragBoxStartPosition.y ?? 0;
653
- const rect = {
654
- x: mousePos.x < startX ? mousePos.x : startX,
655
- y: mousePos.y < startY ? mousePos.y : startY,
656
- width: Math.abs(mousePos.x - startX),
657
- height: Math.abs(mousePos.y - startY),
644
+ const { nodeInternals, nodeExtent, nodeOrigin, smoothStep, gridStep, onError, } = store.getState();
645
+ const { distance, width, height } = dragItem;
646
+ const { x, y, getStepPosition } = pointerPositions;
647
+ let nextPosition = {
648
+ x: x - distance.x,
649
+ y: y - distance.y,
658
650
  };
659
- const nodes = getNodes();
660
- const selectedNodes = getNodesInside(nodeInternals, rect, transform, false, true, nodeOrigin);
661
- const selectedNodeIds = selectedNodes.map((n) => n.id);
662
- const selectionBoxRect = getRectOfNodes(selectedNodes, nodeOrigin);
663
- setSelectionBoxRect(selectionBoxRect);
664
- if (prevSelectedNodesCount.current !== selectedNodeIds.length) {
665
- prevSelectedNodesCount.current = selectedNodeIds.length;
666
- const changes = getSelectionChanges(nodes, selectedNodeIds);
667
- if (changes.length) {
668
- onNodesChange?.(changes);
651
+ if (gridStep && getStepPosition) {
652
+ const nodeSize = { width, height };
653
+ const stepPosition = getStepPosition({
654
+ position: nextPosition,
655
+ nodeSize,
656
+ });
657
+ if (!smoothStep || (smoothStep && dragEnd)) {
658
+ nextPosition = stepPosition;
669
659
  }
670
660
  }
671
- setDragBoxRect(rect);
672
- };
673
- const onMouseUp = (event) => {
674
- if (event.button !== 0) {
661
+ const updatedPosition = calcNextPosition(dragItem, nextPosition, nodeInternals, nodeExtent, nodeOrigin, onError);
662
+ const hasChange = hasChangedPosition(dragItem.position, updatedPosition.position);
663
+ if (!hasChange)
675
664
  return;
676
- }
677
- setSelectionBoxActive(prevSelectedNodesCount.current > 0);
678
- resetDragBox();
679
- };
680
- const onMouseLeave = () => {
681
- setSelectionBoxActive(prevSelectedNodesCount.current > 0);
682
- resetDragBox();
665
+ dragItem.position = updatedPosition.position;
666
+ dragItem.positionAbsolute = updatedPosition.positionAbsolute;
683
667
  };
684
- const isPossibleDragSelection = elementsSelectable && dragSelectionKeyPressed;
685
- return (jsxs("div", { ref: dragSelection, className: "react-diagram__container react-diagram__drag-selection", onClick: onClick, onMouseDown: isPossibleDragSelection ? onMouseDown : undefined, onMouseMove: isPossibleDragSelection ? onMouseMove : undefined, onMouseUp: elementsSelectable && dragBoxRect ? onMouseUp : undefined, onMouseLeave: isPossibleDragSelection ? onMouseLeave : undefined, children: [children, dragBoxActive && jsx(DragBox, { rect: dragBoxRect }), selectionBoxActive && (jsx(SelectionBox$1, { rect: selectionBoxRect, transform: transform }))] }));
668
+ useEffect(() => {
669
+ if (nodeRef?.current) {
670
+ const selection = select(nodeRef.current);
671
+ const updateNodes = (pointerPosition) => {
672
+ const { nodeInternals, onNodeDrag, updateNodesPosition } = store.getState();
673
+ const { x, y } = pointerPosition;
674
+ lastPosition.current = { x, y };
675
+ updateNodesPosition(dragItems.current, true, updateNodePosition(pointerPosition));
676
+ setDragging(true);
677
+ if (onNodeDrag && dragEvent.current) {
678
+ const [currentNode, nodes] = getEventHandlerParams({
679
+ nodeId,
680
+ dragItems: dragItems.current,
681
+ nodeInternals,
682
+ });
683
+ onNodeDrag(dragEvent.current, currentNode, nodes);
684
+ }
685
+ };
686
+ const autoPan = () => {
687
+ if (!containerBounds.current) {
688
+ return;
689
+ }
690
+ const [xMovement, yMovement] = calcAutoPanPosition(mousePosition.current, containerBounds.current);
691
+ if (xMovement !== 0 || yMovement !== 0) {
692
+ const { transform, panBy } = store.getState();
693
+ lastPosition.current.x -= xMovement / transform[2];
694
+ lastPosition.current.y -= yMovement / transform[2];
695
+ updateNodes(lastPosition.current);
696
+ panBy({ x: xMovement, y: yMovement });
697
+ }
698
+ autoPanId.current = requestAnimationFrame(autoPan);
699
+ };
700
+ const dragHandle = drag()
701
+ .on('start', (e) => {
702
+ const { nodeInternals, nodesDraggable, domNode, onNodeDragStart, } = store.getState();
703
+ if (nodeId) {
704
+ handleNodeClick({
705
+ id: nodeId,
706
+ store,
707
+ nodeRef: nodeRef,
708
+ isSelectable,
709
+ });
710
+ }
711
+ const pointerPosition = getPointerPosition(e);
712
+ dragItems.current = getDragItems(nodeInternals, nodesDraggable, pointerPosition, nodeId);
713
+ if (onNodeDragStart && dragItems.current) {
714
+ const [currentNode, nodes] = getEventHandlerParams({
715
+ nodeId,
716
+ dragItems: dragItems.current,
717
+ nodeInternals,
718
+ });
719
+ onNodeDragStart(e.sourceEvent, currentNode, nodes);
720
+ }
721
+ containerBounds.current =
722
+ domNode?.getBoundingClientRect() || null;
723
+ mousePosition.current = getEventPosition(e.sourceEvent, containerBounds.current);
724
+ })
725
+ .on('drag', (e) => {
726
+ const pointerPosition = getPointerPosition(e);
727
+ const { autoPanOnNodeDrag } = store.getState();
728
+ if (!autoPanStarted.current && autoPanOnNodeDrag) {
729
+ autoPanStarted.current = true;
730
+ autoPan();
731
+ }
732
+ const isChanged = hasChangedPosition(lastPosition.current, pointerPosition.getStepPosition());
733
+ if (isChanged && dragItems.current) {
734
+ dragEvent.current = e.sourceEvent;
735
+ mousePosition.current = getEventPosition(e.sourceEvent, containerBounds.current);
736
+ updateNodes(pointerPosition);
737
+ }
738
+ })
739
+ .on('end', (event) => {
740
+ setDragging(false);
741
+ autoPanStarted.current = false;
742
+ cancelAnimationFrame(autoPanId.current);
743
+ if (dragItems.current) {
744
+ const { nodeInternals, smoothStep, gridStep, updateNodesPosition, onNodeDragEnd, } = store.getState();
745
+ const isSmoothStep = !!gridStep && smoothStep;
746
+ if (isSmoothStep) {
747
+ const pointerPosition = getPointerPosition(event);
748
+ updateNodesPosition(dragItems.current, false, updateNodePosition(pointerPosition, true));
749
+ }
750
+ else {
751
+ updateNodesPosition(dragItems.current, false);
752
+ }
753
+ if (onNodeDragEnd) {
754
+ const [currentNode, nodes] = getEventHandlerParams({
755
+ nodeId,
756
+ dragItems: dragItems.current,
757
+ nodeInternals,
758
+ });
759
+ onNodeDragEnd(event.sourceEvent, currentNode, nodes);
760
+ }
761
+ }
762
+ })
763
+ .filter((event) => {
764
+ const target = event.target;
765
+ const isDraggable = !event.button &&
766
+ (!noDragClassName ||
767
+ !hasSelector(target, `.${noDragClassName}`, nodeRef));
768
+ return isDraggable;
769
+ });
770
+ selection.call(dragHandle);
771
+ return () => {
772
+ selection.on('.drag', null);
773
+ };
774
+ }
775
+ }, [
776
+ store,
777
+ nodeRef,
778
+ nodeId,
779
+ isSelectable,
780
+ noDragClassName,
781
+ getPointerPosition,
782
+ ]);
783
+ return dragging;
686
784
  }
687
- DragSelection.displayName = 'DragSelection';
688
785
 
689
- const selector$4 = (s) => {
690
- const { minZoom, maxZoom, translateExtent } = s;
691
- return {
692
- minZoom,
693
- maxZoom,
694
- translateExtent,
695
- };
786
+ function SelectionBox({ rect, transform }) {
787
+ const nodeRef = useRef(null);
788
+ useDrag({ nodeRef });
789
+ const { width, height, x, y } = rect;
790
+ return (jsx("div", { className: cc([
791
+ 'react-diagram__selection-box',
792
+ 'react-diagram__container',
793
+ ]), style: {
794
+ transform,
795
+ }, children: jsx("div", { ref: nodeRef, className: "react-diagram__selection-box-rect", tabIndex: -1, style: {
796
+ width,
797
+ height,
798
+ top: y,
799
+ left: x,
800
+ } }) }));
801
+ }
802
+ var SelectionBox$1 = memo(SelectionBox);
803
+
804
+ const handleParentExpand = (res, updateItem) => {
805
+ const parent = res.find((e) => e.id === updateItem.parentNode);
806
+ if (parent) {
807
+ const extendWidth = updateItem.position.x + updateItem.width - parent.width;
808
+ const extendHeight = updateItem.position.y + updateItem.height - parent.height;
809
+ if (extendWidth > 0 ||
810
+ extendHeight > 0 ||
811
+ updateItem.position.x < 0 ||
812
+ updateItem.position.y < 0) {
813
+ parent.style = { ...parent.style } || {};
814
+ parent.style.width = parent.style.width ?? parent.width;
815
+ parent.style.height = parent.style.height ?? parent.height;
816
+ if (extendWidth > 0) {
817
+ parent.style.width += extendWidth;
818
+ }
819
+ if (extendHeight > 0) {
820
+ parent.style.height += extendHeight;
821
+ }
822
+ if (updateItem.position.x < 0) {
823
+ const xDiff = Math.abs(updateItem.position.x);
824
+ parent.position.x = parent.position.x - xDiff;
825
+ parent.style.width += xDiff;
826
+ updateItem.position.x = 0;
827
+ }
828
+ if (updateItem.position.y < 0) {
829
+ const yDiff = Math.abs(updateItem.position.y);
830
+ parent.position.y = parent.position.y - yDiff;
831
+ parent.style.height += yDiff;
832
+ updateItem.position.y = 0;
833
+ }
834
+ parent.width = parent.style.width;
835
+ parent.height = parent.style.height;
836
+ }
837
+ }
696
838
  };
697
- function DiagramRenderer({ children, multiSelectionKeyCode, noPanClassName, panning, defaultViewport, onMove, onMoveStart, onMoveEnd, }) {
698
- const { minZoom, maxZoom, translateExtent } = useStore(selector$4);
699
- const [dragSelectionKeyPressed, setDragSelectionKeyPressed] = useState(false);
700
- useGlobalKeyHandler(multiSelectionKeyCode);
701
- const handleKeyDown = (e) => {
702
- if (e.key === 'Shift') {
703
- setDragSelectionKeyPressed(true);
839
+ const applyChanges = (changes, elements) => {
840
+ // we need this hack to handle the setNodes and setEdges function of the useReactDiagram hook for controlled flows
841
+ if (changes.some((c) => c.type === 'reset')) {
842
+ return changes.filter((c) => c.type === 'reset').map((c) => c.item);
843
+ }
844
+ const initElements = changes
845
+ .filter((c) => c.type === 'add')
846
+ .map((c) => c.item);
847
+ return elements.reduce((res, item) => {
848
+ const currentChanges = changes.filter((c) => c.id === item.id);
849
+ if (currentChanges.length === 0) {
850
+ res.push(item);
851
+ return res;
704
852
  }
705
- };
706
- const handleKeyUp = () => {
707
- setDragSelectionKeyPressed(false);
708
- };
709
- useEffect(() => {
710
- document.addEventListener('keydown', handleKeyDown);
711
- document.addEventListener('keyup', handleKeyUp);
712
- return () => {
713
- document.removeEventListener('keydown', handleKeyDown);
714
- document.removeEventListener('keyup', handleKeyUp);
715
- };
716
- }, []);
717
- return (jsx(Pane, { noPanClassName: noPanClassName, panning: panning && !dragSelectionKeyPressed, minZoom: minZoom, maxZoom: maxZoom, translateExtent: translateExtent, defaultViewport: defaultViewport, onMove: onMove, onMoveStart: onMoveStart, onMoveEnd: onMoveEnd, children: jsx(DragSelection, { dragSelectionKeyPressed: dragSelectionKeyPressed, children: jsx(Viewport, { children: children }) }) }));
853
+ const updateItem = { ...item };
854
+ for (const currentChange of currentChanges) {
855
+ if (currentChange) {
856
+ switch (currentChange.type) {
857
+ case 'select': {
858
+ updateItem.selected = currentChange.selected;
859
+ break;
860
+ }
861
+ case 'position': {
862
+ if (typeof currentChange.position !== 'undefined') {
863
+ updateItem.position = currentChange.position;
864
+ }
865
+ if (typeof currentChange.positionAbsolute !== 'undefined') {
866
+ updateItem.positionAbsolute =
867
+ currentChange.positionAbsolute;
868
+ }
869
+ if (typeof currentChange.dragging !== 'undefined') {
870
+ updateItem.dragging = currentChange.dragging;
871
+ }
872
+ if (updateItem.expandParent) {
873
+ handleParentExpand(res, updateItem);
874
+ }
875
+ break;
876
+ }
877
+ case 'dimensions': {
878
+ if (typeof currentChange.dimensions !== 'undefined') {
879
+ updateItem.width = currentChange.dimensions.width;
880
+ updateItem.height = currentChange.dimensions.height;
881
+ }
882
+ if (typeof currentChange.updateStyle !== 'undefined') {
883
+ updateItem.style = {
884
+ ...(updateItem.style || {}),
885
+ ...currentChange.dimensions,
886
+ };
887
+ }
888
+ if (typeof currentChange.resizing === 'boolean') {
889
+ updateItem.resizing = currentChange.resizing;
890
+ }
891
+ if (updateItem.expandParent) {
892
+ handleParentExpand(res, updateItem);
893
+ }
894
+ break;
895
+ }
896
+ case 'remove': {
897
+ return res;
898
+ }
899
+ }
900
+ }
901
+ }
902
+ res.push(updateItem);
903
+ return res;
904
+ }, initElements);
905
+ };
906
+ function applyNodeChanges(changes, nodes) {
907
+ return applyChanges(changes, nodes);
718
908
  }
719
- DiagramRenderer.displayName = 'DiagramRenderer';
720
- var DiagramRenderer$1 = memo(DiagramRenderer);
721
-
722
- function useVisibleNodes() {
723
- const nodes = useStore(useCallback((s) => s.getNodes(), []));
724
- return nodes;
909
+ function applyEdgeChanges(changes, edges) {
910
+ return applyChanges(changes, edges);
725
911
  }
726
-
727
- var Position;
728
- (function (Position) {
729
- Position["Left"] = "left";
730
- Position["Top"] = "top";
731
- Position["Right"] = "right";
732
- Position["Bottom"] = "bottom";
733
- })(Position || (Position = {}));
734
-
735
- var MarkerType;
736
- (function (MarkerType) {
737
- MarkerType["Arrow"] = "arrow";
738
- })(MarkerType || (MarkerType = {}));
739
-
740
- var ConnectionEdgeType;
741
- (function (ConnectionEdgeType) {
742
- ConnectionEdgeType["Straight"] = "straight";
743
- ConnectionEdgeType["Bezier"] = "bezier";
744
- ConnectionEdgeType["Step"] = "step";
745
- })(ConnectionEdgeType || (ConnectionEdgeType = {}));
746
-
747
- const selector$3 = (s) => ({
748
- nodesDraggable: s.nodesDraggable,
749
- elementsSelectable: s.elementsSelectable,
750
- updateNodeDimensions: s.updateNodeDimensions,
751
- onError: s.onError,
912
+ const createSelectionChange = (id, selected) => ({
913
+ id,
914
+ type: 'select',
915
+ selected,
752
916
  });
753
- function NodeRenderer({ nodeTypes, onNodeClick, onNodeMouseEnter, onNodeMouseMove, onNodeMouseLeave, onNodeContextMenu, onNodeDoubleClick, ...props }) {
754
- const { nodesDraggable, elementsSelectable, updateNodeDimensions, onError } = useStore(selector$3, shallow);
755
- const nodes = useVisibleNodes();
756
- const resizeObserverRef = useRef();
757
- const resizeObserver = useMemo(() => {
758
- if (typeof ResizeObserver === 'undefined') {
759
- return null;
917
+ function getSelectionChanges(items, selectedIds) {
918
+ return items.reduce((res, item) => {
919
+ const willBeSelected = selectedIds.includes(item.id);
920
+ if (!item.selected && willBeSelected) {
921
+ item.selected = true;
922
+ res.push(createSelectionChange(item.id, true));
760
923
  }
761
- const observer = new ResizeObserver((entries) => {
762
- const updates = entries.map((entry) => ({
763
- id: entry.target.getAttribute('data-id'),
764
- nodeElement: entry.target,
765
- forceUpdate: true,
766
- }));
767
- updateNodeDimensions(updates);
768
- });
769
- resizeObserverRef.current = observer;
770
- return observer;
771
- }, []);
772
- useEffect(() => () => {
773
- resizeObserverRef?.current?.disconnect();
924
+ else if (item.selected && !willBeSelected) {
925
+ item.selected = false;
926
+ res.push(createSelectionChange(item.id, false));
927
+ }
928
+ return res;
774
929
  }, []);
775
- return (jsx("div", { className: "react-diagram__nodes react-diagram__container", children: nodes.map((node) => {
776
- const { data, type,
777
- // elProps
778
- id, className, style, ariaLabel, positionAbsolute, hidden, selected, selectable, draggable, } = node;
779
- let nodeType = type || 'default';
780
- if (!nodeTypes[nodeType]) {
781
- onError?.('010', nodeType);
782
- nodeType = 'default';
783
- }
784
- const NodeComponent = (nodeTypes[nodeType] ||
785
- nodeTypes.default);
786
- const isDraggable = !!(draggable ||
787
- (nodesDraggable && typeof draggable === 'undefined'));
788
- const isSelectable = !!(selectable ||
789
- (elementsSelectable && typeof selectable === 'undefined'));
790
- const elProps = {
791
- id,
792
- className,
793
- style: {
794
- ...style,
795
- width: node.width,
796
- height: node.height,
797
- },
798
- ariaLabel,
799
- };
800
- const events = {
801
- onClick: onNodeClick,
802
- onMouseEnter: onNodeMouseEnter,
803
- onMouseMove: onNodeMouseMove,
804
- onMouseLeave: onNodeMouseLeave,
805
- onContextMenu: onNodeContextMenu,
806
- onDoubleClick: onNodeDoubleClick,
807
- };
808
- const position = {
809
- positionX: positionAbsolute?.x || 0,
810
- positionY: positionAbsolute?.y || 0,
811
- sourcePosition: Position.Bottom,
812
- targetPosition: Position.Top,
813
- };
814
- const booleanProps = {
815
- selected: !!selected,
816
- isSelectable,
817
- isDraggable,
818
- hidden,
819
- isParent: !!node[internalsSymbol]?.isParent,
820
- initialized: !!node.width && !!node.height,
821
- };
822
- return (jsx(NodeComponent, { ...props, ...elProps, ...position, ...events, ...booleanProps, zIndex: node[internalsSymbol]?.z ?? 0, type: nodeType, data: data, resizeObserver: resizeObserver }, id));
823
- }) }));
824
930
  }
825
- NodeRenderer.displayName = 'NodeRenderer';
826
- var NodeRenderer$1 = memo(NodeRenderer);
827
931
 
828
- const ArrowSymbol = ({ color = 'none', strokeWidth = 1 }) => (jsx("polyline", { stroke: color, strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: strokeWidth, fill: color, points: "-5,-4 0,0 -5,4 -5,-4" }));
829
- const MarkerSymbols = {
830
- [MarkerType.Arrow]: ArrowSymbol,
932
+ const selector$6 = (s) => {
933
+ const { elementsSelectable, transform, selectionBoxActive, getNodes } = s;
934
+ const selectedNodes = getNodes().filter((n) => n.selected);
935
+ return {
936
+ elementsSelectable,
937
+ selectionBoxRect: getRectOfNodes(selectedNodes, s.nodeOrigin),
938
+ transformString: `translate(${transform[0]}px,${transform[1]}px) scale(${transform[2]})`,
939
+ selectionBoxActive,
940
+ };
941
+ };
942
+ function DragSelection({ children, dragSelectionKeyPressed, }) {
943
+ const store = useStoreApi();
944
+ const dragSelection = useRef(null);
945
+ const prevSelectedNodesCount = useRef(0);
946
+ const containerBounds = useRef();
947
+ const { elementsSelectable, selectionBoxRect, transformString, selectionBoxActive, } = useStore(selector$6, shallow);
948
+ const [dragBoxStartPosition, setDragBoxStartPosition] = useState({
949
+ x: 0,
950
+ y: 0,
951
+ });
952
+ const [dragBoxRect, setDragBoxRect] = useState({
953
+ width: 0,
954
+ height: 0,
955
+ x: 0,
956
+ y: 0,
957
+ });
958
+ const [dragBoxActive, setDragBoxActive] = useState(false);
959
+ const resetDragBox = () => {
960
+ setDragBoxStartPosition({
961
+ x: 0,
962
+ y: 0,
963
+ });
964
+ setDragBoxRect({
965
+ width: 0,
966
+ height: 0,
967
+ x: 0,
968
+ y: 0,
969
+ });
970
+ setDragBoxActive(false);
971
+ };
972
+ const onClick = (e) => {
973
+ if (e.target === dragSelection.current) {
974
+ store.getState().resetSelectedElements();
975
+ store.setState({
976
+ selectionBoxActive: false,
977
+ });
978
+ setDragBoxActive(false);
979
+ }
980
+ };
981
+ const onMouseDown = (event) => {
982
+ const { resetSelectedElements, domNode } = store.getState();
983
+ containerBounds.current = domNode?.getBoundingClientRect();
984
+ if (!elementsSelectable ||
985
+ event.button !== 0 ||
986
+ event.target !== dragSelection.current ||
987
+ !containerBounds.current ||
988
+ !dragSelectionKeyPressed) {
989
+ return;
990
+ }
991
+ const { x, y } = getEventPosition(event, containerBounds.current);
992
+ resetSelectedElements();
993
+ setDragBoxRect({
994
+ width: 0,
995
+ height: 0,
996
+ x,
997
+ y,
998
+ });
999
+ setDragBoxStartPosition({
1000
+ x,
1001
+ y,
1002
+ });
1003
+ };
1004
+ const onMouseMove = (event) => {
1005
+ const { nodeInternals, transform, nodeOrigin, getNodes, onNodesChange } = store.getState();
1006
+ const hasDragBoxStartPosition = dragBoxStartPosition.x > 0 && dragBoxStartPosition.y > 0;
1007
+ if (
1008
+ // !hasDragBoxPosition ||
1009
+ !hasDragBoxStartPosition ||
1010
+ !containerBounds.current ||
1011
+ !dragSelectionKeyPressed) {
1012
+ return;
1013
+ }
1014
+ store.setState({
1015
+ selectionBoxActive: false,
1016
+ });
1017
+ setDragBoxActive(true);
1018
+ const mousePos = getEventPosition(event, containerBounds.current);
1019
+ const startX = dragBoxStartPosition.x ?? 0;
1020
+ const startY = dragBoxStartPosition.y ?? 0;
1021
+ const rect = {
1022
+ x: mousePos.x < startX ? mousePos.x : startX,
1023
+ y: mousePos.y < startY ? mousePos.y : startY,
1024
+ width: Math.abs(mousePos.x - startX),
1025
+ height: Math.abs(mousePos.y - startY),
1026
+ };
1027
+ const nodes = getNodes();
1028
+ const selectedNodes = getNodesInside(nodeInternals, rect, transform, false, true, nodeOrigin);
1029
+ const selectedNodeIds = selectedNodes.map((n) => n.id);
1030
+ if (prevSelectedNodesCount.current !== selectedNodeIds.length) {
1031
+ prevSelectedNodesCount.current = selectedNodeIds.length;
1032
+ const changes = getSelectionChanges(nodes, selectedNodeIds);
1033
+ if (changes.length) {
1034
+ onNodesChange?.(changes);
1035
+ }
1036
+ }
1037
+ setDragBoxRect(rect);
1038
+ };
1039
+ const onMouseUp = (event) => {
1040
+ if (event.button !== 0) {
1041
+ return;
1042
+ }
1043
+ store.setState({
1044
+ selectionBoxActive: prevSelectedNodesCount.current > 0,
1045
+ });
1046
+ resetDragBox();
1047
+ };
1048
+ const onMouseLeave = () => {
1049
+ store.setState({
1050
+ selectionBoxActive: prevSelectedNodesCount.current > 0,
1051
+ });
1052
+ resetDragBox();
1053
+ };
1054
+ const isPossibleDragSelection = elementsSelectable && dragSelectionKeyPressed;
1055
+ return (jsxs("div", { ref: dragSelection, className: "react-diagram__container react-diagram__drag-selection", onClick: onClick, onMouseDown: isPossibleDragSelection ? onMouseDown : undefined, onMouseMove: isPossibleDragSelection ? onMouseMove : undefined, onMouseUp: elementsSelectable && dragBoxRect ? onMouseUp : undefined, onMouseLeave: isPossibleDragSelection ? onMouseLeave : undefined, children: [children, dragBoxActive && jsx(DragBox, { rect: dragBoxRect }), selectionBoxActive && (jsx(SelectionBox$1, { rect: selectionBoxRect, transform: transformString }))] }));
1056
+ }
1057
+
1058
+ const selector$5 = (s) => {
1059
+ const { minZoom, maxZoom, translateExtent } = s;
1060
+ return {
1061
+ minZoom,
1062
+ maxZoom,
1063
+ translateExtent,
1064
+ };
1065
+ };
1066
+ function DiagramRenderer({ children, multiSelectionKeyCode, noPanClassName, panning, defaultViewport, onMove, onMoveStart, onMoveEnd, }) {
1067
+ const { minZoom, maxZoom, translateExtent } = useStore(selector$5);
1068
+ const [dragSelectionKeyPressed, setDragSelectionKeyPressed] = useState(false);
1069
+ useGlobalKeyHandler(multiSelectionKeyCode);
1070
+ const handleKeyDown = (e) => {
1071
+ if (e.key === 'Shift') {
1072
+ setDragSelectionKeyPressed(true);
1073
+ }
1074
+ };
1075
+ const handleKeyUp = () => {
1076
+ setDragSelectionKeyPressed(false);
1077
+ };
1078
+ useEffect(() => {
1079
+ document.addEventListener('keydown', handleKeyDown);
1080
+ document.addEventListener('keyup', handleKeyUp);
1081
+ return () => {
1082
+ document.removeEventListener('keydown', handleKeyDown);
1083
+ document.removeEventListener('keyup', handleKeyUp);
1084
+ };
1085
+ }, []);
1086
+ return (jsx(Pane, { noPanClassName: noPanClassName, panning: panning && !dragSelectionKeyPressed, minZoom: minZoom, maxZoom: maxZoom, translateExtent: translateExtent, defaultViewport: defaultViewport, onMove: onMove, onMoveStart: onMoveStart, onMoveEnd: onMoveEnd, children: jsx(DragSelection, { dragSelectionKeyPressed: dragSelectionKeyPressed, children: jsx(Viewport, { children: children }) }) }));
1087
+ }
1088
+ DiagramRenderer.displayName = 'DiagramRenderer';
1089
+ var DiagramRenderer$1 = memo(DiagramRenderer);
1090
+
1091
+ function useVisibleNodes() {
1092
+ const nodes = useStore(useCallback((s) => s.getNodes(), []));
1093
+ return nodes;
1094
+ }
1095
+
1096
+ var Position;
1097
+ (function (Position) {
1098
+ Position["Left"] = "left";
1099
+ Position["Top"] = "top";
1100
+ Position["Right"] = "right";
1101
+ Position["Bottom"] = "bottom";
1102
+ })(Position || (Position = {}));
1103
+
1104
+ var MarkerType;
1105
+ (function (MarkerType) {
1106
+ MarkerType["Arrow"] = "arrow";
1107
+ })(MarkerType || (MarkerType = {}));
1108
+
1109
+ const selector$4 = (s) => ({
1110
+ nodesDraggable: s.nodesDraggable,
1111
+ elementsSelectable: s.elementsSelectable,
1112
+ updateNodeDimensions: s.updateNodeDimensions,
1113
+ onError: s.onError,
1114
+ });
1115
+ function NodeRenderer({ nodeTypes, onNodeClick, onNodeMouseEnter, onNodeMouseMove, onNodeMouseLeave, onNodeContextMenu, onNodeDoubleClick, ...props }) {
1116
+ const { nodesDraggable, elementsSelectable, updateNodeDimensions, onError } = useStore(selector$4, shallow);
1117
+ const nodes = useVisibleNodes();
1118
+ const resizeObserverRef = useRef();
1119
+ const resizeObserver = useMemo(() => {
1120
+ if (typeof ResizeObserver === 'undefined') {
1121
+ return null;
1122
+ }
1123
+ const observer = new ResizeObserver((entries) => {
1124
+ const updates = entries.map((entry) => ({
1125
+ id: entry.target.getAttribute('data-id'),
1126
+ nodeElement: entry.target,
1127
+ forceUpdate: true,
1128
+ }));
1129
+ updateNodeDimensions(updates);
1130
+ });
1131
+ resizeObserverRef.current = observer;
1132
+ return observer;
1133
+ }, []);
1134
+ useEffect(() => () => {
1135
+ resizeObserverRef?.current?.disconnect();
1136
+ }, []);
1137
+ return (jsx("div", { className: "react-diagram__nodes react-diagram__container", children: nodes.map((node) => {
1138
+ const { data, type,
1139
+ // elProps
1140
+ id, className, style, ariaLabel, positionAbsolute, hidden, selected, selectable, draggable, } = node;
1141
+ let nodeType = type || 'default';
1142
+ if (!nodeTypes[nodeType]) {
1143
+ onError?.('010', nodeType);
1144
+ nodeType = 'default';
1145
+ }
1146
+ const NodeComponent = (nodeTypes[nodeType] ||
1147
+ nodeTypes.default);
1148
+ const isDraggable = !!(draggable ||
1149
+ (nodesDraggable && typeof draggable === 'undefined'));
1150
+ const isSelectable = !!(selectable ||
1151
+ (elementsSelectable && typeof selectable === 'undefined'));
1152
+ const elProps = {
1153
+ id,
1154
+ className,
1155
+ style: {
1156
+ ...style,
1157
+ width: node.width,
1158
+ height: node.height,
1159
+ },
1160
+ ariaLabel,
1161
+ };
1162
+ const events = {
1163
+ onClick: onNodeClick,
1164
+ onMouseEnter: onNodeMouseEnter,
1165
+ onMouseMove: onNodeMouseMove,
1166
+ onMouseLeave: onNodeMouseLeave,
1167
+ onContextMenu: onNodeContextMenu,
1168
+ onDoubleClick: onNodeDoubleClick,
1169
+ };
1170
+ const position = {
1171
+ positionX: positionAbsolute?.x || 0,
1172
+ positionY: positionAbsolute?.y || 0,
1173
+ sourcePosition: Position.Bottom,
1174
+ targetPosition: Position.Top,
1175
+ };
1176
+ const booleanProps = {
1177
+ selected: !!selected,
1178
+ isSelectable,
1179
+ isDraggable,
1180
+ hidden,
1181
+ isParent: !!node[internalsSymbol]?.isParent,
1182
+ initialized: !!node.width && !!node.height,
1183
+ };
1184
+ return (jsx(NodeComponent, { ...props, ...elProps, ...position, ...events, ...booleanProps, zIndex: node[internalsSymbol]?.z ?? 0, type: nodeType, data: data, resizeObserver: resizeObserver }, id));
1185
+ }) }));
1186
+ }
1187
+ NodeRenderer.displayName = 'NodeRenderer';
1188
+ var NodeRenderer$1 = memo(NodeRenderer);
1189
+
1190
+ const ArrowSymbol = ({ color = 'none', strokeWidth = 1 }) => (jsx("polyline", { stroke: color, strokeLinecap: "round", strokeLinejoin: "round", strokeWidth: strokeWidth, fill: color, points: "-5,-4 0,0 -5,4 -5,-4" }));
1191
+ const MarkerSymbols = {
1192
+ [MarkerType.Arrow]: ArrowSymbol,
831
1193
  };
832
1194
  function useMarkerSymbol(type) {
833
1195
  const store = useStoreApi();
@@ -975,1203 +1337,852 @@ const getDirection = ({ source, sourcePosition = Position.Bottom, target, }) =>
975
1337
  }
976
1338
  //when source Node position is above of a Port of target Node => y = 1
977
1339
  return source.y < target.y ? { x: 0, y: 1 } : { x: 0, y: -1 };
978
- };
979
- const distance = (a, b) => Math.sqrt(Math.pow(b.x - a.x, 2) + Math.pow(b.y - a.y, 2));
980
- function getPoints({ source, sourcePosition = Position.Bottom, target, targetPosition = Position.Top, center, offset, }) {
981
- const sourceDir = HANDLE_DIRECTIONS[sourcePosition];
982
- const targetDir = HANDLE_DIRECTIONS[targetPosition];
983
- const sourceGapped = {
984
- x: source.x + sourceDir.x * offset,
985
- y: source.y + sourceDir.y * offset,
986
- };
987
- const targetGapped = {
988
- x: target.x + targetDir.x * offset,
989
- y: target.y + targetDir.y * offset,
990
- };
991
- const direction = getDirection({
992
- source: sourceGapped,
993
- sourcePosition,
994
- target: targetGapped,
995
- });
996
- const dirAccessor = direction.x !== 0 ? 'x' : 'y';
997
- const currentDirection = direction[dirAccessor];
998
- let points = [];
999
- let centerX = 0, centerY = 0;
1000
- const [defaultCenterX, defaultCenterY, defaultOffsetX, defaultOffsetY] = getEdgeCenter({
1001
- sourceX: source.x,
1002
- sourceY: source.y,
1003
- targetX: target.x,
1004
- targetY: target.y,
1005
- });
1006
- const isSourceAndTargetPositionsParallel = sourceDir[dirAccessor] * targetDir[dirAccessor] === -1;
1007
- if (isSourceAndTargetPositionsParallel) {
1008
- centerX = center.x || defaultCenterX;
1009
- centerY = center.y || defaultCenterY;
1010
- const verticalSplit = [
1011
- { x: centerX, y: sourceGapped.y },
1012
- { x: centerX, y: targetGapped.y },
1013
- ];
1014
- const horizontalSplit = [
1015
- { x: sourceGapped.x, y: centerY },
1016
- { x: targetGapped.x, y: centerY },
1017
- ];
1018
- const centerLineIsBent = sourceDir[dirAccessor] !== currentDirection;
1019
- if (centerLineIsBent) {
1020
- points = dirAccessor === 'x' ? horizontalSplit : verticalSplit;
1021
- }
1022
- else {
1023
- points = dirAccessor === 'x' ? verticalSplit : horizontalSplit;
1024
- }
1025
- }
1026
- const pathPoints = [source, sourceGapped, ...points, targetGapped, target];
1027
- return [pathPoints, centerX, centerY, defaultOffsetX, defaultOffsetY];
1028
- }
1029
- function getBend(a, b, c, size) {
1030
- const bendSize = Math.min(distance(a, b) / 2, distance(b, c) / 2, size);
1031
- const { x, y } = b;
1032
- // no bend
1033
- if ((a.x === x && x === c.x) || (a.y === y && y === c.y)) {
1034
- return `L${x} ${y}`;
1035
- }
1036
- // first segment is horizontal
1037
- if (a.y === y) {
1038
- const xDir = a.x < c.x ? -1 : 1;
1039
- const yDir = a.y < c.y ? 1 : -1;
1040
- return `L ${x + bendSize * xDir},${y}Q ${x},${y} ${x},${y + bendSize * yDir}`;
1041
- }
1042
- const xDir = a.x < c.x ? 1 : -1;
1043
- const yDir = a.y < c.y ? -1 : 1;
1044
- return `L ${x},${y + bendSize * yDir}Q ${x},${y} ${x + bendSize * xDir},${y}`;
1045
- }
1046
- function getStepPath({ sourceX, sourceY, sourcePosition = Position.Bottom, targetX, targetY, targetPosition = Position.Top, borderRadius = 5, centerX, centerY, offset = 20, }) {
1047
- const [points, labelX, labelY, offsetX, offsetY] = getPoints({
1048
- source: { x: sourceX, y: sourceY },
1049
- sourcePosition,
1050
- target: { x: targetX, y: targetY },
1051
- targetPosition,
1052
- center: { x: centerX, y: centerY },
1053
- offset,
1054
- });
1055
- const path = points.reduce((res, p, i) => {
1056
- let segment = '';
1057
- if (i > 0 && i < points.length - 1) {
1058
- segment = getBend(points[i - 1], p, points[i + 1], borderRadius);
1059
- }
1060
- else {
1061
- segment = `${i === 0 ? 'M' : 'L'}${p.x} ${p.y}`;
1062
- }
1063
- res += segment;
1064
- return res;
1065
- }, '');
1066
- return [path, labelX, labelY, offsetX, offsetY];
1067
- }
1068
- const StepEdge = memo(({ sourceX, sourceY, targetX, targetY, label, labelStyle, labelShowBg, labelBgStyle, labelBgPadding, labelBgBorderRadius, style, sourcePosition = Position.Bottom, targetPosition = Position.Top, markerEnd, markerStart, pathOptions, }) => {
1069
- const [path, labelX, labelY] = getStepPath({
1070
- sourceX,
1071
- sourceY,
1072
- sourcePosition,
1073
- targetX,
1074
- targetY,
1075
- targetPosition,
1076
- borderRadius: pathOptions?.borderRadius,
1077
- offset: pathOptions?.offset,
1078
- });
1079
- return (jsx(BaseEdge, { path: path, labelX: labelX, labelY: labelY, label: label, labelStyle: labelStyle, labelShowBg: labelShowBg, labelBgStyle: labelBgStyle, labelBgPadding: labelBgPadding, labelBgBorderRadius: labelBgBorderRadius, style: style, markerEnd: markerEnd, markerStart: markerStart }));
1080
- });
1081
- StepEdge.displayName = 'StepEdge';
1082
-
1083
- const calculateControlOffset = (distance, curvature) => {
1084
- if (distance >= 0) {
1085
- return 0.5 * distance;
1086
- }
1087
- return curvature * 25 * Math.sqrt(-distance);
1088
- };
1089
- const getControlWithCurvature = ({ pos, x1, y1, x2, y2, c, }) => {
1090
- switch (pos) {
1091
- case Position.Left:
1092
- return [x1 - calculateControlOffset(x1 - x2, c), y1];
1093
- case Position.Right:
1094
- return [x1 + calculateControlOffset(x2 - x1, c), y1];
1095
- case Position.Top:
1096
- return [x1, y1 - calculateControlOffset(y1 - y2, c)];
1097
- case Position.Bottom:
1098
- return [x1, y1 + calculateControlOffset(y2 - y1, c)];
1099
- }
1100
- };
1101
- const getBezierPath = ({ sourceX, sourceY, sourcePosition = Position.Bottom, targetX, targetY, targetPosition = Position.Top, curvature = 0.25, }) => {
1102
- const [sourceControlX, sourceControlY] = getControlWithCurvature({
1103
- pos: sourcePosition,
1104
- x1: sourceX,
1105
- y1: sourceY,
1106
- x2: targetX,
1107
- y2: targetY,
1108
- c: curvature,
1109
- });
1110
- const [targetControlX, targetControlY] = getControlWithCurvature({
1111
- pos: targetPosition,
1112
- x1: targetX,
1113
- y1: targetY,
1114
- x2: sourceX,
1115
- y2: sourceY,
1116
- c: curvature,
1117
- });
1118
- const [labelX, labelY, offsetX, offsetY] = getBezierEdgeCenter({
1119
- sourceX,
1120
- sourceY,
1121
- targetX,
1122
- targetY,
1123
- sourceControlX,
1124
- sourceControlY,
1125
- targetControlX,
1126
- targetControlY,
1127
- });
1128
- return [
1129
- `M${sourceX},${sourceY} C${sourceControlX},${sourceControlY} ${targetControlX},${targetControlY} ${targetX},${targetY}`,
1130
- labelX,
1131
- labelY,
1132
- offsetX,
1133
- offsetY,
1134
- ];
1135
- };
1136
- const BezierEdge = memo(({ sourceX, sourceY, targetX, targetY, sourcePosition = Position.Bottom, targetPosition = Position.Top, label, labelStyle, labelShowBg, labelBgStyle, labelBgPadding, labelBgBorderRadius, style, markerEnd, markerStart, pathOptions, }) => {
1137
- const [path, labelX, labelY] = getBezierPath({
1138
- sourceX,
1139
- sourceY,
1140
- sourcePosition,
1141
- targetX,
1142
- targetY,
1143
- targetPosition,
1144
- curvature: pathOptions?.curvature,
1145
- });
1146
- return (jsx(BaseEdge, { path: path, labelX: labelX, labelY: labelY, label: label, labelStyle: labelStyle, labelShowBg: labelShowBg, labelBgStyle: labelBgStyle, labelBgPadding: labelBgPadding, labelBgBorderRadius: labelBgBorderRadius, style: style, markerEnd: markerEnd, markerStart: markerStart }));
1147
- });
1148
- BezierEdge.displayName = 'BezierEdge';
1149
-
1150
- const ARIA_NODE_DESC_KEY = 'react-diagram__node-desc';
1151
- const ARIA_EDGE_DESC_KEY = 'react-diagram__edge-desc';
1152
-
1153
- const getHostForElement = (element) => element.getRootNode?.() || window?.document;
1154
- const getPortType = (PortDomNode) => {
1155
- if (PortDomNode?.classList.contains('target')) {
1156
- return 'target';
1157
- }
1158
- else if (PortDomNode?.classList.contains('source')) {
1159
- return 'source';
1160
- }
1161
- return null;
1162
- };
1163
- const getConnection = (event, port, fromNodeId, fromType, doc) => {
1164
- const isTarget = fromType === 'target';
1165
- const result = {
1166
- isValid: false,
1167
- connection: {
1168
- source: null,
1169
- target: null,
1170
- },
1171
- };
1172
- const PortDomNode = doc.querySelector(`.react-diagram__port[data-id="${port?.nodeId}-${port?.type}"]`);
1173
- const { x, y } = getEventPosition(event);
1174
- const ElementFromPoint = doc.elementFromPoint(x, y);
1175
- const Port = ElementFromPoint?.classList.contains('react-diagram__port')
1176
- ? ElementFromPoint
1177
- : PortDomNode;
1178
- if (Port) {
1179
- const portType = getPortType(Port);
1180
- const toNodeId = Port.getAttribute('data-nodeid');
1181
- const connection = {
1182
- source: isTarget ? toNodeId : fromNodeId,
1183
- target: isTarget ? fromNodeId : toNodeId,
1184
- };
1185
- result.connection = connection;
1186
- const isValid = (isTarget && portType === 'source') ||
1187
- (!isTarget && portType === 'target');
1188
- if (isValid) {
1189
- result.isValid = true;
1190
- }
1191
- }
1192
- return result;
1193
- };
1194
- const getPorts = (node, portBounds, type, currentPort) => (portBounds[type] || []).reduce((res, h) => {
1195
- if (`${node.id}-${type}` !== currentPort) {
1196
- res.push({
1197
- type,
1198
- nodeId: node.id,
1199
- x: (node.positionAbsolute?.x ?? 0) + h.x + h.width / 2,
1200
- y: (node.positionAbsolute?.y ?? 0) + h.y + h.height / 2,
1201
- });
1202
- }
1203
- return res;
1204
- }, []);
1205
- const getAllPort = ({ nodes, nodeId, portType }) => nodes.reduce((res, node) => {
1206
- if (node[internalsSymbol]) {
1207
- const { portBounds } = node[internalsSymbol];
1208
- let sourcePorts = [];
1209
- let targetPorts = [];
1210
- if (portBounds) {
1211
- sourcePorts = getPorts(node, portBounds, 'source', `${nodeId}-${portType}`);
1212
- targetPorts = getPorts(node, portBounds, 'target', `${nodeId}-${portType}`);
1213
- }
1214
- res.push(...sourcePorts, ...targetPorts);
1215
- }
1216
- return res;
1217
- }, []);
1218
- const getClosestPort = (pos, connectionRadius, ports) => {
1219
- let closestPort = null;
1220
- let minDistance = Infinity;
1221
- ports.forEach((port) => {
1222
- const distance = Math.sqrt(Math.pow(port.x - pos.x, 2) + Math.pow(port.y - pos.y, 2));
1223
- if (distance <= connectionRadius && distance < minDistance) {
1224
- minDistance = distance;
1225
- closestPort = port;
1226
- }
1227
- });
1228
- return closestPort;
1229
- };
1230
- const handlePointerDown = ({ isAnchor = false, event, nodeId, portType, getState, setState, onConnect, onEdgeUpdateEnd, }) => {
1231
- const doc = getHostForElement(event.target);
1232
- const { domNode, autoPanOnConnect, getNodes, cancelConnection, onConnectStart, onConnectEnd, panBy, } = getState();
1233
- const containerBounds = domNode?.getBoundingClientRect();
1234
- const { x, y } = getEventPosition(event);
1235
- const clickedPort = doc?.elementFromPoint(x, y);
1236
- const clickedPortType = isAnchor ? portType : getPortType(clickedPort);
1237
- const allPort = getAllPort({
1238
- nodes: getNodes(),
1239
- nodeId,
1240
- portType,
1241
- });
1242
- let connectionPosition = getEventPosition(event, containerBounds);
1243
- let closestPort = null;
1244
- let isValid = false;
1245
- let connection = null;
1246
- let autoPanId = 0;
1247
- let autoPanStarted = false;
1248
- if (!containerBounds || !portType) {
1249
- return;
1250
- }
1251
- const autoPan = () => {
1252
- if (!autoPanOnConnect) {
1253
- return;
1254
- }
1255
- const [xMovement, yMovement] = calcAutoPanPosition(connectionPosition, containerBounds);
1256
- panBy({ x: xMovement, y: yMovement });
1257
- autoPanId = requestAnimationFrame(autoPan);
1258
- };
1259
- setState({
1260
- connectionPosition,
1261
- connectionNodeId: nodeId,
1262
- connectionPortType: clickedPortType,
1263
- });
1264
- onConnectStart?.(event, { nodeId, portType });
1265
- const onPointerMove = (event) => {
1266
- connectionPosition = getEventPosition(event, containerBounds);
1267
- closestPort = getClosestPort(connectionPosition, 20, allPort);
1268
- if (!autoPanStarted) {
1269
- autoPan();
1270
- autoPanStarted = true;
1271
- }
1272
- const result = getConnection(event, closestPort, nodeId, portType, doc);
1273
- isValid = result.isValid;
1274
- connection = result.connection;
1275
- if (closestPort && isValid) {
1276
- const { x, y } = closestPort;
1277
- setState({
1278
- connectionPosition: {
1279
- x,
1280
- y,
1281
- },
1282
- });
1283
- }
1284
- else {
1285
- setState({
1286
- connectionPosition,
1287
- });
1288
- }
1289
- };
1290
- const onPointerUp = (event) => {
1291
- if (isValid && connection)
1292
- onConnect?.(connection);
1293
- onConnectEnd?.(event);
1294
- if (portType) {
1295
- onEdgeUpdateEnd?.(event);
1296
- }
1297
- cancelConnection();
1298
- cancelAnimationFrame(autoPanId);
1299
- isValid = false;
1300
- connection = null;
1301
- autoPanStarted = false;
1302
- doc.removeEventListener('mousemove', onPointerMove);
1303
- doc.removeEventListener('mouseup', onPointerUp);
1304
- doc.removeEventListener('touchmove', onPointerMove);
1305
- doc.removeEventListener('touchend', onPointerUp);
1306
- };
1307
- doc.addEventListener('mousemove', onPointerMove);
1308
- doc.addEventListener('mouseup', onPointerUp);
1309
- doc.addEventListener('touchmove', onPointerMove);
1310
- doc.addEventListener('touchend', onPointerUp);
1311
- };
1312
-
1313
- const portPositionX = (x, shift, position) => {
1314
- if (position === Position.Left)
1315
- return x - shift;
1316
- if (position === Position.Right)
1317
- return x + shift;
1318
- return x;
1319
- };
1320
- const portPositionY = (y, shift, position) => {
1321
- if (position === Position.Top)
1322
- return y - shift;
1323
- if (position === Position.Bottom)
1324
- return y + shift;
1325
- return y;
1326
- };
1327
- const EdgeUpdaterClassName = 'react-diagram__edgeupdater';
1328
- function Anchor({ position, centerX, centerY, radius = 10, onMouseDown, onMouseEnter, onMouseOut, type, }) {
1329
- return (jsx("circle", { className: cc([
1330
- EdgeUpdaterClassName,
1331
- `${EdgeUpdaterClassName}-${type}`,
1332
- ]), cx: portPositionX(centerX, radius, position), cy: portPositionY(centerY, radius, position), r: radius, stroke: "transparent", fill: "transparent", onMouseDown: onMouseDown, onMouseEnter: onMouseEnter, onMouseOut: onMouseOut }));
1333
- }
1334
-
1335
- function getMouseHandler$1(id, getState, handler) {
1336
- return handler === undefined
1337
- ? handler
1338
- : (event) => {
1339
- const edge = getState().edges.find((e) => e.id === id);
1340
- if (edge) {
1341
- handler(event, { ...edge });
1342
- }
1343
- };
1344
- }
1345
- const wrapEdge = (EdgeComponent) => {
1346
- const EdgeWrapper = (props) => {
1347
- const { id, className, style, type, data, rfId, ariaLabel,
1348
- // sourceAndTargetIds
1349
- source, sourcePort, target, targetPort,
1350
- // marker
1351
- markerEnd, markerStart,
1352
- // labelProps
1353
- label, labelStyle, labelShowBg, labelBgStyle, labelBgPadding, labelBgBorderRadius,
1354
- // position
1355
- sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, selected, elementsSelectable, hidden, isFocusable, onClick, onDoubleClick, onContextMenu, onMouseEnter, onMouseMove, onMouseLeave, onEdgeUpdate, onEdgeUpdateStart, onEdgeUpdateEnd, } = props;
1356
- const edgeRef = useRef(null);
1357
- const [updating, setUpdating] = useState(false);
1358
- const store = useStoreApi();
1359
- const markerStartUrl = useMemo(() => `url(#${getMarkerId(markerStart, rfId)})`, [markerStart, rfId]);
1360
- const markerEndUrl = useMemo(() => `url(#${getMarkerId(markerEnd, rfId)})`, [markerEnd, rfId]);
1361
- if (hidden) {
1362
- return null;
1363
- }
1364
- const handleEdgeUpdater = (fromPortType) => (event) => {
1365
- if (event.button !== 0) {
1366
- return;
1367
- }
1368
- const { edges } = store.getState();
1369
- const nodeId = props[fromPortType];
1370
- const edge = edges.find((e) => e.id === id);
1371
- setUpdating(true);
1372
- onEdgeUpdateStart?.(event, edge, fromPortType);
1373
- const onConnectEdge = (connection) => onEdgeUpdate?.(edge, connection);
1374
- const handleEdgeUpdateEnd = (evt) => {
1375
- setUpdating(false);
1376
- onEdgeUpdateEnd?.(evt, edge, fromPortType);
1377
- };
1378
- handlePointerDown({
1379
- isAnchor: true,
1380
- event,
1381
- nodeId,
1382
- portType: fromPortType,
1383
- getState: store.getState,
1384
- setState: store.setState,
1385
- onConnect: onConnectEdge,
1386
- onEdgeUpdateEnd: handleEdgeUpdateEnd,
1387
- });
1388
- };
1389
- const onEdgeClick = (event) => {
1390
- const { edges } = store.getState();
1391
- if (onClick) {
1392
- const edge = edges.find((e) => e.id === id);
1393
- onClick(event, edge);
1394
- }
1395
- };
1396
- const onEdgeDoubleClick = getMouseHandler$1(id, store.getState, onDoubleClick);
1397
- const onEdgeContextMenu = getMouseHandler$1(id, store.getState, onContextMenu);
1398
- const onEdgeMouseEnter = getMouseHandler$1(id, store.getState, onMouseEnter);
1399
- const onEdgeMouseMove = getMouseHandler$1(id, store.getState, onMouseMove);
1400
- const onEdgeMouseLeave = getMouseHandler$1(id, store.getState, onMouseLeave);
1401
- const inactive = !elementsSelectable;
1402
- const wrapperClassName = cc([
1403
- 'react-diagram__edge',
1404
- `react-diagram__edge-${type}`,
1405
- className,
1406
- { selected, inactive },
1407
- ]);
1408
- const marker = { markerStart: markerStartUrl, markerEnd: markerEndUrl };
1409
- const sourceAndTargetIds = {
1410
- source,
1411
- sourcePort,
1412
- target,
1413
- targetPort,
1414
- };
1415
- const labelProps = {
1416
- label,
1417
- labelStyle,
1418
- labelShowBg,
1419
- labelBgStyle,
1420
- labelBgPadding,
1421
- labelBgBorderRadius,
1422
- };
1423
- const position = {
1424
- sourceX,
1425
- sourceY,
1426
- targetX,
1427
- targetY,
1428
- sourcePosition,
1429
- targetPosition,
1430
- };
1431
- const events = {
1432
- onClick: onEdgeClick,
1433
- onDoubleClick: onEdgeDoubleClick,
1434
- onContextMenu: onEdgeContextMenu,
1435
- onMouseEnter: onEdgeMouseEnter,
1436
- onMouseMove: onEdgeMouseMove,
1437
- onMouseLeave: onEdgeMouseLeave,
1438
- };
1439
- return (jsxs("g", { ...events, ref: edgeRef, className: wrapperClassName, tabIndex: isFocusable ? 0 : undefined, role: isFocusable ? 'button' : undefined, "aria-label": ariaLabel === null
1440
- ? undefined
1441
- : ariaLabel
1442
- ? ariaLabel
1443
- : `Edge from ${source} to ${target}`, "aria-describedby": isFocusable ? `${ARIA_EDGE_DESC_KEY}-${rfId}` : undefined, children: [!updating && (jsx(EdgeComponent, { ...sourceAndTargetIds, ...marker, ...labelProps, ...position, id: id, data: data, style: style, selected: selected })), jsx(Anchor, { position: sourcePosition, centerX: sourceX, centerY: sourceY, radius: 10, onMouseDown: handleEdgeUpdater('target'), onMouseEnter: console.log, onMouseOut: console.log, type: "source" }), jsx(Anchor, { position: targetPosition, centerX: targetX, centerY: targetY, radius: 10, onMouseDown: handleEdgeUpdater('source'), onMouseEnter: console.log, onMouseOut: console.log, type: "target" })] }));
1444
- };
1445
- EdgeWrapper.displayName = 'EdgeWrapper';
1446
- return memo(EdgeWrapper);
1447
- };
1448
-
1449
- const createEdgeTypes = (edgeTypes) => {
1450
- const defaultTypes = {
1451
- default: wrapEdge((edgeTypes.straight || StraightEdge)),
1452
- step: wrapEdge((edgeTypes.step || StepEdge)),
1453
- bezier: wrapEdge((edgeTypes.bezier || BezierEdge)),
1340
+ };
1341
+ const distance = (a, b) => Math.sqrt(Math.pow(b.x - a.x, 2) + Math.pow(b.y - a.y, 2));
1342
+ function getPoints({ source, sourcePosition = Position.Bottom, target, targetPosition = Position.Top, center, offset, }) {
1343
+ const sourceDir = HANDLE_DIRECTIONS[sourcePosition];
1344
+ const targetDir = HANDLE_DIRECTIONS[targetPosition];
1345
+ const sourceGapped = {
1346
+ x: source.x + sourceDir.x * offset,
1347
+ y: source.y + sourceDir.y * offset,
1454
1348
  };
1455
- const wrappedTypes = {};
1456
- const customTypes = Object.keys(edgeTypes)
1457
- .filter((k) => !Object.keys(defaultTypes).includes(k))
1458
- .reduce((res, key) => {
1459
- res[key] = wrapEdge((edgeTypes[key] || StepEdge));
1460
- return res;
1461
- }, wrappedTypes);
1462
- return {
1463
- ...defaultTypes,
1464
- ...customTypes,
1349
+ const targetGapped = {
1350
+ x: target.x + targetDir.x * offset,
1351
+ y: target.y + targetDir.y * offset,
1465
1352
  };
1466
- };
1467
- function getPortPosition(position, nodeRect, port = null) {
1468
- const x = (port?.x || 0) + nodeRect.x;
1469
- const y = (port?.y || 0) + nodeRect.y;
1470
- const width = port?.width || nodeRect.width;
1471
- const height = port?.height || nodeRect.height;
1472
- switch (position) {
1473
- case Position.Top:
1474
- return {
1475
- x: x + width / 2,
1476
- y,
1477
- };
1478
- case Position.Right:
1479
- return {
1480
- x: x + width,
1481
- y: y + height / 2,
1482
- };
1483
- case Position.Bottom:
1484
- return {
1485
- x: x + width / 2,
1486
- y: y + height,
1487
- };
1488
- case Position.Left:
1489
- return {
1490
- x,
1491
- y: y + height / 2,
1492
- };
1353
+ const direction = getDirection({
1354
+ source: sourceGapped,
1355
+ sourcePosition,
1356
+ target: targetGapped,
1357
+ });
1358
+ const dirAccessor = direction.x !== 0 ? 'x' : 'y';
1359
+ const currentDirection = direction[dirAccessor];
1360
+ let points = [];
1361
+ let centerX = 0, centerY = 0;
1362
+ const [defaultCenterX, defaultCenterY, defaultOffsetX, defaultOffsetY] = getEdgeCenter({
1363
+ sourceX: source.x,
1364
+ sourceY: source.y,
1365
+ targetX: target.x,
1366
+ targetY: target.y,
1367
+ });
1368
+ const isSourceAndTargetPositionsParallel = sourceDir[dirAccessor] * targetDir[dirAccessor] === -1;
1369
+ if (isSourceAndTargetPositionsParallel) {
1370
+ centerX = center.x || defaultCenterX;
1371
+ centerY = center.y || defaultCenterY;
1372
+ const verticalSplit = [
1373
+ { x: centerX, y: sourceGapped.y },
1374
+ { x: centerX, y: targetGapped.y },
1375
+ ];
1376
+ const horizontalSplit = [
1377
+ { x: sourceGapped.x, y: centerY },
1378
+ { x: targetGapped.x, y: centerY },
1379
+ ];
1380
+ const centerLineIsBent = sourceDir[dirAccessor] !== currentDirection;
1381
+ if (centerLineIsBent) {
1382
+ points = dirAccessor === 'x' ? horizontalSplit : verticalSplit;
1383
+ }
1384
+ else {
1385
+ points = dirAccessor === 'x' ? verticalSplit : horizontalSplit;
1386
+ }
1493
1387
  }
1388
+ const pathPoints = [source, sourceGapped, ...points, targetGapped, target];
1389
+ return [pathPoints, centerX, centerY, defaultOffsetX, defaultOffsetY];
1494
1390
  }
1495
- function getPort(bounds, portId) {
1496
- if (!bounds) {
1497
- return null;
1498
- }
1499
- if (bounds.length === 1 || !portId) {
1500
- return bounds[0];
1391
+ function getBend(a, b, c, size) {
1392
+ const bendSize = Math.min(distance(a, b) / 2, distance(b, c) / 2, size);
1393
+ const { x, y } = b;
1394
+ // no bend
1395
+ if ((a.x === x && x === c.x) || (a.y === y && y === c.y)) {
1396
+ return `L${x} ${y}`;
1501
1397
  }
1502
- else if (portId) {
1503
- return bounds.find((d) => d.id === portId) || null;
1398
+ // first segment is horizontal
1399
+ if (a.y === y) {
1400
+ const xDir = a.x < c.x ? -1 : 1;
1401
+ const yDir = a.y < c.y ? 1 : -1;
1402
+ return `L ${x + bendSize * xDir},${y}Q ${x},${y} ${x},${y + bendSize * yDir}`;
1504
1403
  }
1505
- return null;
1404
+ const xDir = a.x < c.x ? 1 : -1;
1405
+ const yDir = a.y < c.y ? -1 : 1;
1406
+ return `L ${x},${y + bendSize * yDir}Q ${x},${y} ${x + bendSize * xDir},${y}`;
1506
1407
  }
1507
- const getEdgePositions = (sourceNodeRect, sourcePort, sourcePosition, targetNodeRect, targetPort, targetPosition) => {
1508
- const sourcePortPos = getPortPosition(sourcePosition, sourceNodeRect, sourcePort);
1509
- const targetPortPos = getPortPosition(targetPosition, targetNodeRect, targetPort);
1510
- return {
1511
- sourceX: sourcePortPos.x,
1512
- sourceY: sourcePortPos.y,
1513
- targetX: targetPortPos.x,
1514
- targetY: targetPortPos.y,
1515
- };
1516
- };
1517
- function getNodeData(node) {
1518
- const portBounds = node?.[internalsSymbol]?.portBounds || null;
1519
- const isValid = portBounds &&
1520
- node?.width &&
1521
- node?.height &&
1522
- typeof node?.positionAbsolute?.x !== 'undefined' &&
1523
- typeof node?.positionAbsolute?.y !== 'undefined';
1524
- return [
1525
- {
1526
- x: node?.positionAbsolute?.x || 0,
1527
- y: node?.positionAbsolute?.y || 0,
1528
- width: node?.width || 0,
1529
- height: node?.height || 0,
1530
- },
1531
- portBounds,
1532
- !!isValid,
1533
- ];
1408
+ function getStepPath({ sourceX, sourceY, sourcePosition = Position.Bottom, targetX, targetY, targetPosition = Position.Top, borderRadius = 5, centerX, centerY, offset = 20, }) {
1409
+ const [points, labelX, labelY, offsetX, offsetY] = getPoints({
1410
+ source: { x: sourceX, y: sourceY },
1411
+ sourcePosition,
1412
+ target: { x: targetX, y: targetY },
1413
+ targetPosition,
1414
+ center: { x: centerX, y: centerY },
1415
+ offset,
1416
+ });
1417
+ const path = points.reduce((res, p, i) => {
1418
+ let segment = '';
1419
+ if (i > 0 && i < points.length - 1) {
1420
+ segment = getBend(points[i - 1], p, points[i + 1], borderRadius);
1421
+ }
1422
+ else {
1423
+ segment = `${i === 0 ? 'M' : 'L'}${p.x} ${p.y}`;
1424
+ }
1425
+ res += segment;
1426
+ return res;
1427
+ }, '');
1428
+ return [path, labelX, labelY, offsetX, offsetY];
1534
1429
  }
1535
-
1536
- const selector$2 = (s) => ({
1537
- edges: s.edges,
1538
- width: s.width,
1539
- height: s.height,
1540
- nodeInternals: s.nodeInternals,
1541
- onError: s.onError,
1430
+ const StepEdge = memo(({ sourceX, sourceY, targetX, targetY, label, labelStyle, labelShowBg, labelBgStyle, labelBgPadding, labelBgBorderRadius, style, sourcePosition = Position.Bottom, targetPosition = Position.Top, markerEnd, markerStart, pathOptions, }) => {
1431
+ const [path, labelX, labelY] = getStepPath({
1432
+ sourceX,
1433
+ sourceY,
1434
+ sourcePosition,
1435
+ targetX,
1436
+ targetY,
1437
+ targetPosition,
1438
+ borderRadius: pathOptions?.borderRadius,
1439
+ offset: pathOptions?.offset,
1440
+ });
1441
+ return (jsx(BaseEdge, { path: path, labelX: labelX, labelY: labelY, label: label, labelStyle: labelStyle, labelShowBg: labelShowBg, labelBgStyle: labelBgStyle, labelBgPadding: labelBgPadding, labelBgBorderRadius: labelBgBorderRadius, style: style, markerEnd: markerEnd, markerStart: markerStart }));
1542
1442
  });
1543
- function EdgeRenderer({ rfId, edgeTypes, noPanClassName, onEdgeClick, onEdgeDoubleClick, onEdgeContextMenu, onEdgeMouseEnter, onEdgeMouseMove, onEdgeMouseLeave, onEdgeUpdate, onEdgeUpdateStart, onEdgeUpdateEnd, }) {
1544
- const { edges, width, height, nodeInternals } = useStore(selector$2, shallow);
1545
- return (jsxs("svg", { width: width || '100vw', height: height || '100vh', className: "react-diagram__edges react-diagram__container", children: [jsx(MarkerComponent$1, { defaultColor: "#000000", rfId: rfId }), jsx("g", { children: edges.map((edge) => {
1546
- const { data, type,
1547
- // elProps
1548
- id, className, style, ariaLabel,
1549
- // sourceAndTargetIds
1550
- source, sourcePort, target, targetPort,
1551
- // marker
1552
- markerEnd, markerStart,
1553
- // labelProps
1554
- label, labelStyle, labelShowBg, labelBgStyle, labelBgPadding, labelBgBorderRadius, } = edge;
1555
- const [sourceNodeRect, sourcePortBounds, sourceIsValid] = getNodeData(nodeInternals.get(source));
1556
- const [targetNodeRect, targetPortBounds, targetIsValid] = getNodeData(nodeInternals.get(target));
1557
- if (!sourceIsValid || !targetIsValid) {
1558
- return null;
1559
- }
1560
- const edgeType = type || 'straight';
1561
- const EdgeComponent = edgeTypes[edgeType] || edgeTypes.default;
1562
- const targetNodePorts = targetPortBounds.target;
1563
- const sourcePortInfo = getPort(sourcePortBounds.source, sourcePort);
1564
- const targetPortInfo = getPort(targetNodePorts, targetPort);
1565
- const sourcePosition = sourcePortInfo?.position || Position.Bottom;
1566
- const targetPosition = targetPortInfo?.position || Position.Top;
1567
- const isFocusable = !!edge.focusable;
1568
- if (!sourcePortInfo || !targetPortInfo) {
1569
- return null;
1570
- }
1571
- const elProps = {
1572
- id,
1573
- className: cc([className, noPanClassName]),
1574
- style,
1575
- ariaLabel,
1576
- };
1577
- const sourceAndTargetIds = {
1578
- source,
1579
- sourcePort,
1580
- target,
1581
- targetPort,
1582
- };
1583
- const marker = {
1584
- markerEnd,
1585
- markerStart,
1586
- };
1587
- const labelProps = {
1588
- label,
1589
- labelStyle,
1590
- labelShowBg,
1591
- labelBgStyle,
1592
- labelBgPadding,
1593
- labelBgBorderRadius,
1594
- };
1595
- const edgePositions = getEdgePositions(sourceNodeRect, sourcePortInfo, sourcePosition, targetNodeRect, targetPortInfo, targetPosition);
1596
- const position = {
1597
- ...edgePositions,
1598
- sourcePosition,
1599
- targetPosition,
1600
- };
1601
- const events = {
1602
- onClick: onEdgeClick,
1603
- onDoubleClick: onEdgeDoubleClick,
1604
- onContextMenu: onEdgeContextMenu,
1605
- onMouseEnter: onEdgeMouseEnter,
1606
- onMouseMove: onEdgeMouseMove,
1607
- onMouseLeave: onEdgeMouseLeave,
1608
- onEdgeUpdate,
1609
- onEdgeUpdateStart,
1610
- onEdgeUpdateEnd,
1611
- };
1612
- return (jsx(EdgeComponent, { ...elProps, ...sourceAndTargetIds, ...marker, ...labelProps, ...position, ...events, rfId: rfId, type: edgeType, data: data, isFocusable: isFocusable }, id));
1613
- }) })] }));
1614
- }
1615
- EdgeRenderer.displayName = 'EdgeRenderer';
1616
- var EdgeRenderer$1 = memo(EdgeRenderer);
1443
+ StepEdge.displayName = 'StepEdge';
1617
1444
 
1618
- const oppositePosition = {
1619
- [Position.Left]: Position.Right,
1620
- [Position.Right]: Position.Left,
1621
- [Position.Top]: Position.Bottom,
1622
- [Position.Bottom]: Position.Top,
1445
+ const calculateControlOffset = (distance, curvature) => {
1446
+ if (distance >= 0) {
1447
+ return 0.5 * distance;
1448
+ }
1449
+ return curvature * 25 * Math.sqrt(-distance);
1623
1450
  };
1624
- function ConnectionPath({ style, nodeId, portType, type = ConnectionEdgeType.Straight, Component, }) {
1625
- const { fromNode, toX, toY } = useStore(useCallback((s) => ({
1626
- fromNode: s.nodeInternals.get(nodeId),
1627
- toX: (s.connectionPosition.x - s.transform[0]) / s.transform[2],
1628
- toY: (s.connectionPosition.y - s.transform[1]) / s.transform[2],
1629
- }), [nodeId]), shallow);
1630
- const fromPortBounds = fromNode?.[internalsSymbol]?.portBounds;
1631
- const portBounds = fromPortBounds?.[portType];
1632
- if (!fromNode || !portBounds) {
1633
- return null;
1451
+ const getControlWithCurvature = ({ pos, x1, y1, x2, y2, c, }) => {
1452
+ switch (pos) {
1453
+ case Position.Left:
1454
+ return [x1 - calculateControlOffset(x1 - x2, c), y1];
1455
+ case Position.Right:
1456
+ return [x1 + calculateControlOffset(x2 - x1, c), y1];
1457
+ case Position.Top:
1458
+ return [x1, y1 - calculateControlOffset(y1 - y2, c)];
1459
+ case Position.Bottom:
1460
+ return [x1, y1 + calculateControlOffset(y2 - y1, c)];
1634
1461
  }
1635
- const fromPort = portBounds[0];
1636
- const fromPortX = fromPort
1637
- ? fromPort.x + fromPort.width / 2
1638
- : (fromNode.width ?? 0) / 2;
1639
- const fromPortY = fromPort
1640
- ? fromPort.y + fromPort.height / 2
1641
- : fromNode.height ?? 0;
1642
- const fromX = (fromNode.positionAbsolute?.x ?? 0) + fromPortX;
1643
- const fromY = (fromNode.positionAbsolute?.y ?? 0) + fromPortY;
1644
- const fromPosition = fromPort?.position;
1645
- const toPosition = fromPosition ? oppositePosition[fromPosition] : null;
1646
- if (!fromPosition || !toPosition) {
1647
- return null;
1462
+ };
1463
+ const getBezierPath = ({ sourceX, sourceY, sourcePosition = Position.Bottom, targetX, targetY, targetPosition = Position.Top, curvature = 0.25, }) => {
1464
+ const [sourceControlX, sourceControlY] = getControlWithCurvature({
1465
+ pos: sourcePosition,
1466
+ x1: sourceX,
1467
+ y1: sourceY,
1468
+ x2: targetX,
1469
+ y2: targetY,
1470
+ c: curvature,
1471
+ });
1472
+ const [targetControlX, targetControlY] = getControlWithCurvature({
1473
+ pos: targetPosition,
1474
+ x1: targetX,
1475
+ y1: targetY,
1476
+ x2: sourceX,
1477
+ y2: sourceY,
1478
+ c: curvature,
1479
+ });
1480
+ const [labelX, labelY, offsetX, offsetY] = getBezierEdgeCenter({
1481
+ sourceX,
1482
+ sourceY,
1483
+ targetX,
1484
+ targetY,
1485
+ sourceControlX,
1486
+ sourceControlY,
1487
+ targetControlX,
1488
+ targetControlY,
1489
+ });
1490
+ return [
1491
+ `M${sourceX},${sourceY} C${sourceControlX},${sourceControlY} ${targetControlX},${targetControlY} ${targetX},${targetY}`,
1492
+ labelX,
1493
+ labelY,
1494
+ offsetX,
1495
+ offsetY,
1496
+ ];
1497
+ };
1498
+ const BezierEdge = memo(({ sourceX, sourceY, targetX, targetY, sourcePosition = Position.Bottom, targetPosition = Position.Top, label, labelStyle, labelShowBg, labelBgStyle, labelBgPadding, labelBgBorderRadius, style, markerEnd, markerStart, pathOptions, }) => {
1499
+ const [path, labelX, labelY] = getBezierPath({
1500
+ sourceX,
1501
+ sourceY,
1502
+ sourcePosition,
1503
+ targetX,
1504
+ targetY,
1505
+ targetPosition,
1506
+ curvature: pathOptions?.curvature,
1507
+ });
1508
+ return (jsx(BaseEdge, { path: path, labelX: labelX, labelY: labelY, label: label, labelStyle: labelStyle, labelShowBg: labelShowBg, labelBgStyle: labelBgStyle, labelBgPadding: labelBgPadding, labelBgBorderRadius: labelBgBorderRadius, style: style, markerEnd: markerEnd, markerStart: markerStart }));
1509
+ });
1510
+ BezierEdge.displayName = 'BezierEdge';
1511
+
1512
+ const ARIA_NODE_DESC_KEY = 'react-diagram__node-desc';
1513
+ const ARIA_EDGE_DESC_KEY = 'react-diagram__edge-desc';
1514
+
1515
+ const getHostForElement = (element) => element.getRootNode?.() || window?.document;
1516
+ const getPortType = (PortDomNode) => {
1517
+ if (PortDomNode?.classList.contains('target')) {
1518
+ return 'target';
1648
1519
  }
1649
- if (Component) {
1650
- return (jsx(Component, { connectionEdgeType: type, connectionEdgeStyle: style, fromNode: fromNode, fromPort: fromPort, fromX: fromX, fromY: fromY, toX: toX, toY: toY, fromPosition: fromPosition, toPosition: toPosition }));
1520
+ else if (PortDomNode?.classList.contains('source')) {
1521
+ return 'source';
1651
1522
  }
1652
- let d = '';
1653
- const pathParams = {
1654
- sourceX: fromX,
1655
- sourceY: fromY,
1656
- sourcePosition: fromPosition,
1657
- targetX: toX,
1658
- targetY: toY,
1659
- targetPosition: toPosition,
1523
+ return null;
1524
+ };
1525
+ const getConnection = (event, port, fromNodeId, fromType, doc) => {
1526
+ const isTarget = fromType === 'target';
1527
+ const result = {
1528
+ isValid: false,
1529
+ connection: {
1530
+ source: null,
1531
+ target: null,
1532
+ },
1660
1533
  };
1661
- if (type === ConnectionEdgeType.Bezier) {
1662
- [d] = getBezierPath(pathParams);
1534
+ const PortDomNode = doc.querySelector(`.react-diagram__port[data-id="${port?.nodeId}-${port?.type}"]`);
1535
+ const { x, y } = getEventPosition(event);
1536
+ const ElementFromPoint = doc.elementFromPoint(x, y);
1537
+ const Port = ElementFromPoint?.classList.contains('react-diagram__port')
1538
+ ? ElementFromPoint
1539
+ : PortDomNode;
1540
+ if (Port) {
1541
+ const portType = getPortType(Port);
1542
+ const toNodeId = Port.getAttribute('data-nodeid');
1543
+ const connection = {
1544
+ source: isTarget ? toNodeId : fromNodeId,
1545
+ target: isTarget ? fromNodeId : toNodeId,
1546
+ };
1547
+ result.connection = connection;
1548
+ const isValid = (isTarget && portType === 'source') ||
1549
+ (!isTarget && portType === 'target');
1550
+ if (isValid) {
1551
+ result.isValid = true;
1552
+ }
1663
1553
  }
1664
- else if (type === ConnectionEdgeType.Step) {
1665
- [d] = getStepPath({
1666
- ...pathParams,
1667
- borderRadius: 0,
1554
+ return result;
1555
+ };
1556
+ const getPorts = (node, portBounds, type, currentPort) => (portBounds[type] || []).reduce((res, h) => {
1557
+ if (`${node.id}-${type}` !== currentPort) {
1558
+ res.push({
1559
+ type,
1560
+ nodeId: node.id,
1561
+ x: (node.positionAbsolute?.x ?? 0) + h.x + h.width / 2,
1562
+ y: (node.positionAbsolute?.y ?? 0) + h.y + h.height / 2,
1668
1563
  });
1669
1564
  }
1670
- else {
1671
- d = `M${fromX},${fromY} ${toX},${toY}`;
1672
- }
1673
- return (jsx("path", { d: d, fill: "none", className: "react-diagram__connection-path", style: style }));
1674
- }
1675
- ConnectionPath.displayName = 'ConnectionPath';
1676
-
1677
- const selector$1 = (s) => ({
1678
- edges: s.edges,
1679
- nodeId: s.connectionNodeId,
1680
- portType: s.connectionPortType,
1681
- });
1682
- function ConnectionEdge({ containerStyle, style, type, component, }) {
1683
- const { nodeId, portType, edges } = useStore(selector$1, shallow);
1684
- const isValid = !!(nodeId && portType);
1685
- if (!isValid) {
1686
- return null;
1565
+ return res;
1566
+ }, []);
1567
+ const getAllPort = ({ nodes, nodeId, portType }) => nodes.reduce((res, node) => {
1568
+ if (node[internalsSymbol]) {
1569
+ const { portBounds } = node[internalsSymbol];
1570
+ let sourcePorts = [];
1571
+ let targetPorts = [];
1572
+ if (portBounds) {
1573
+ sourcePorts = getPorts(node, portBounds, 'source', `${nodeId}-${portType}`);
1574
+ targetPorts = getPorts(node, portBounds, 'target', `${nodeId}-${portType}`);
1575
+ }
1576
+ res.push(...sourcePorts, ...targetPorts);
1687
1577
  }
1688
- const capitalizeFirstLetter = (str) => str.charAt(0).toUpperCase() + str.slice(1);
1689
- const getConnectionEdgeType = (edgeType = '') => {
1690
- let connectionEdgeType = '';
1691
- if (type) {
1692
- connectionEdgeType = type;
1578
+ return res;
1579
+ }, []);
1580
+ const getClosestPort = (pos, connectionRadius, ports) => {
1581
+ let closestPort = null;
1582
+ let minDistance = Infinity;
1583
+ ports.forEach((port) => {
1584
+ const distance = Math.sqrt(Math.pow(port.x - pos.x, 2) + Math.pow(port.y - pos.y, 2));
1585
+ if (distance <= connectionRadius && distance < minDistance) {
1586
+ minDistance = distance;
1587
+ closestPort = port;
1693
1588
  }
1694
- else if (Object.keys(ConnectionEdgeType).includes(capitalizeFirstLetter(edgeType))) {
1695
- connectionEdgeType = edgeType;
1589
+ });
1590
+ return closestPort;
1591
+ };
1592
+ const pointToRendererPoint = ({ x, y }, [tx, ty, tScale]) => {
1593
+ const position = {
1594
+ x: (x - tx) / tScale,
1595
+ y: (y - ty) / tScale,
1596
+ };
1597
+ return position;
1598
+ };
1599
+ const rendererPointToPoint = ({ x, y }, [tx, ty, tScale]) => {
1600
+ return {
1601
+ x: x * tScale + tx,
1602
+ y: y * tScale + ty,
1603
+ };
1604
+ };
1605
+ const handlePointerDown = ({ isAnchor = false, event, nodeId, portType, getState, setState, onConnect, onEdgeUpdateEnd, }) => {
1606
+ const doc = getHostForElement(event.target);
1607
+ const { domNode, autoPanOnConnect, connectionRadius, getNodes, cancelConnection, onConnectStart, onConnectEnd, panBy, } = getState();
1608
+ const containerBounds = domNode?.getBoundingClientRect();
1609
+ const { x, y } = getEventPosition(event);
1610
+ const clickedPort = doc?.elementFromPoint(x, y);
1611
+ const clickedPortType = isAnchor ? portType : getPortType(clickedPort);
1612
+ const allPort = getAllPort({
1613
+ nodes: getNodes(),
1614
+ nodeId,
1615
+ portType,
1616
+ });
1617
+ let connectionPosition = getEventPosition(event, containerBounds);
1618
+ let closestPort = null;
1619
+ let isValid = false;
1620
+ let connection = null;
1621
+ let autoPanId = 0;
1622
+ let autoPanStarted = false;
1623
+ if (!containerBounds || !portType) {
1624
+ return;
1625
+ }
1626
+ const autoPan = () => {
1627
+ if (!autoPanOnConnect) {
1628
+ return;
1696
1629
  }
1697
- else {
1698
- connectionEdgeType = 'straight';
1630
+ const [xMovement, yMovement] = calcAutoPanPosition(connectionPosition, containerBounds);
1631
+ panBy({ x: xMovement, y: yMovement });
1632
+ autoPanId = requestAnimationFrame(autoPan);
1633
+ };
1634
+ setState({
1635
+ connectionPosition,
1636
+ connectionNodeId: nodeId,
1637
+ connectionPortType: clickedPortType,
1638
+ });
1639
+ onConnectStart?.(event, { nodeId, portType });
1640
+ const onPointerMove = (event) => {
1641
+ const { transform } = getState();
1642
+ connectionPosition = getEventPosition(event, containerBounds);
1643
+ closestPort = getClosestPort(pointToRendererPoint(connectionPosition, transform), connectionRadius, allPort);
1644
+ if (!autoPanStarted) {
1645
+ autoPan();
1646
+ autoPanStarted = true;
1699
1647
  }
1700
- return connectionEdgeType;
1648
+ const result = getConnection(event, closestPort, nodeId, portType, doc);
1649
+ isValid = result.isValid;
1650
+ connection = result.connection;
1651
+ setState({
1652
+ connectionPosition: closestPort && isValid
1653
+ ? rendererPointToPoint(closestPort, transform)
1654
+ : connectionPosition,
1655
+ });
1701
1656
  };
1702
- const currentEdgeType = edges.find((edge) => edge[portType] === nodeId)
1703
- ?.type;
1704
- const edgeType = getConnectionEdgeType(currentEdgeType);
1705
- return (jsx("svg", { style: containerStyle, className: "react-diagram__container react-diagram__edges react-diagram__connection-line", children: jsx("g", { className: "react-diagram__connection", children: jsx(ConnectionPath, { style: style, nodeId: nodeId, portType: portType, type: edgeType, Component: component }) }) }));
1706
- }
1707
-
1708
- function DiagramView({ rfId,
1709
- // DiagramRenderer props
1710
- noPanClassName, panning, defaultViewport, multiSelectionKeyCode, onMove, onMoveStart, onMoveEnd,
1711
- // NodeRenderer props
1712
- onlyRenderVisibleElements, disableKeyboardA11y, noDragClassName, nodeOrigin, nodeTypes, onNodeClick, onNodeDoubleClick, onNodeContextMenu, onNodeMouseEnter, onNodeMouseMove, onNodeMouseLeave,
1713
- // EdgeRenderer props
1714
- edgeTypes, onEdgeClick, onEdgeDoubleClick, onEdgeContextMenu, onEdgeMouseEnter, onEdgeMouseMove, onEdgeMouseLeave, onEdgeUpdate, onEdgeUpdateStart, onEdgeUpdateEnd,
1715
- // ConnectionLineWrapper
1716
- connectionEdgeContainerStyle, connectionEdgeStyle, connectionEdgeType, connectionEdgeComponent, }) {
1717
- return (jsxs(DiagramRenderer$1, { multiSelectionKeyCode: multiSelectionKeyCode, noPanClassName: noPanClassName, panning: panning, defaultViewport: defaultViewport, onMove: onMove, onMoveStart: onMoveStart, onMoveEnd: onMoveEnd, children: [jsx(NodeRenderer$1, { rfId: rfId, nodeTypes: nodeTypes, onlyRenderVisibleElements: onlyRenderVisibleElements, disableKeyboardA11y: disableKeyboardA11y, nodeOrigin: nodeOrigin, noDragClassName: noDragClassName, noPanClassName: noPanClassName, onNodeClick: onNodeClick, onNodeDoubleClick: onNodeDoubleClick, onNodeContextMenu: onNodeContextMenu, onNodeMouseEnter: onNodeMouseEnter, onNodeMouseMove: onNodeMouseMove, onNodeMouseLeave: onNodeMouseLeave }), jsx(EdgeRenderer$1, { rfId: rfId, edgeTypes: edgeTypes, noPanClassName: noPanClassName, onEdgeClick: onEdgeClick, onEdgeDoubleClick: onEdgeDoubleClick, onEdgeContextMenu: onEdgeContextMenu, onEdgeMouseEnter: onEdgeMouseEnter, onEdgeMouseMove: onEdgeMouseMove, onEdgeMouseLeave: onEdgeMouseLeave, onEdgeUpdate: onEdgeUpdate, onEdgeUpdateStart: onEdgeUpdateStart, onEdgeUpdateEnd: onEdgeUpdateEnd }), jsx(ConnectionEdge, { containerStyle: connectionEdgeContainerStyle, style: connectionEdgeStyle, type: connectionEdgeType, component: connectionEdgeComponent })] }));
1718
- }
1719
- DiagramView.displayName = 'DiagramView';
1720
- var DiagramView$1 = memo(DiagramView);
1721
-
1722
- const selector = (s) => {
1723
- const { setNodes, setEdges, setNodeExtent, setTranslateExtent, setMinZoom, setMaxZoom, } = s;
1724
- return {
1725
- setNodes,
1726
- setEdges,
1727
- setNodeExtent,
1728
- setTranslateExtent,
1729
- setMinZoom,
1730
- setMaxZoom,
1657
+ const onPointerUp = (event) => {
1658
+ if (isValid && connection)
1659
+ onConnect?.(connection);
1660
+ onConnectEnd?.(event);
1661
+ if (portType) {
1662
+ onEdgeUpdateEnd?.(event);
1663
+ }
1664
+ cancelConnection();
1665
+ cancelAnimationFrame(autoPanId);
1666
+ isValid = false;
1667
+ connection = null;
1668
+ autoPanStarted = false;
1669
+ doc.removeEventListener('mousemove', onPointerMove);
1670
+ doc.removeEventListener('mouseup', onPointerUp);
1671
+ doc.removeEventListener('touchmove', onPointerMove);
1672
+ doc.removeEventListener('touchend', onPointerUp);
1731
1673
  };
1674
+ doc.addEventListener('mousemove', onPointerMove);
1675
+ doc.addEventListener('mouseup', onPointerUp);
1676
+ doc.addEventListener('touchmove', onPointerMove);
1677
+ doc.addEventListener('touchend', onPointerUp);
1732
1678
  };
1733
- function useStoreUpdater(value, setStoreState) {
1734
- useEffect(() => {
1735
- if (typeof value !== 'undefined') {
1736
- setStoreState(value);
1737
- }
1738
- }, [value]);
1739
- }
1740
- // updates with values in store that don't have a dedicated setter function
1741
- function useDirectStoreUpdater(key, value, setState) {
1742
- useEffect(() => {
1743
- if (typeof value !== 'undefined') {
1744
- setState({ [key]: value });
1745
- }
1746
- }, [value]);
1747
- }
1748
- const StoreUpdater = ({ nodes, onNodesChange, onNodeDrag, onNodeDragStart, onNodeDragEnd, edges, onEdgesChange, gridStep, elevateNodesOnSelect, nodesDraggable, autoPanOnNodeDrag, autoPanOnConnect, onConnect, onConnectStart, onConnectEnd, onError, nodeExtent, translateExtent, minZoom, maxZoom, }) => {
1749
- const { setNodes, setEdges, setNodeExtent, setTranslateExtent, setMinZoom, setMaxZoom, } = useStore(selector, shallow);
1750
- const store = useStoreApi();
1751
- useDirectStoreUpdater('gridStep', gridStep, store.setState);
1752
- useStoreUpdater(nodes, setNodes);
1753
- useStoreUpdater(edges, setEdges);
1754
- useStoreUpdater(nodeExtent, setNodeExtent);
1755
- useStoreUpdater(translateExtent, setTranslateExtent);
1756
- useStoreUpdater(minZoom, setMinZoom);
1757
- useStoreUpdater(maxZoom, setMaxZoom);
1758
- useDirectStoreUpdater('elevateNodesOnSelect', elevateNodesOnSelect, store.setState);
1759
- useDirectStoreUpdater('nodesDraggable', nodesDraggable, store.setState);
1760
- useDirectStoreUpdater('autoPanOnNodeDrag', autoPanOnNodeDrag, store.setState);
1761
- useDirectStoreUpdater('autoPanOnConnect', autoPanOnConnect, store.setState);
1762
- useDirectStoreUpdater('onNodesChange', onNodesChange, store.setState);
1763
- useDirectStoreUpdater('onNodeDrag', onNodeDrag, store.setState);
1764
- useDirectStoreUpdater('onNodeDragStart', onNodeDragStart, store.setState);
1765
- useDirectStoreUpdater('onNodeDragEnd', onNodeDragEnd, store.setState);
1766
- useDirectStoreUpdater('onEdgesChange', onEdgesChange, store.setState);
1767
- useDirectStoreUpdater('onConnect', onConnect, store.setState);
1768
- useDirectStoreUpdater('onConnectStart', onConnectStart, store.setState);
1769
- useDirectStoreUpdater('onConnectEnd', onConnectEnd, store.setState);
1770
- useDirectStoreUpdater('onError', onErrorWrapper(onError), store.setState);
1771
- return null;
1679
+
1680
+ const portPositionX = (x, shift, position) => {
1681
+ if (position === Position.Left)
1682
+ return x - shift;
1683
+ if (position === Position.Right)
1684
+ return x + shift;
1685
+ return x;
1686
+ };
1687
+ const portPositionY = (y, shift, position) => {
1688
+ if (position === Position.Top)
1689
+ return y - shift;
1690
+ if (position === Position.Bottom)
1691
+ return y + shift;
1692
+ return y;
1772
1693
  };
1694
+ const EdgeUpdaterClassName = 'react-diagram__edge-updater';
1695
+ function Anchor({ position, centerX, centerY, radius = 10, onMouseDown,
1696
+ // onMouseEnter,
1697
+ // onMouseOut,
1698
+ type, }) {
1699
+ return (jsx("circle", { className: cc([
1700
+ EdgeUpdaterClassName,
1701
+ `${EdgeUpdaterClassName}-${type}`,
1702
+ ]), cx: portPositionX(centerX, radius, position), cy: portPositionY(centerY, radius, position), r: radius, stroke: "transparent", fill: "transparent", onMouseDown: onMouseDown }));
1703
+ }
1773
1704
 
1774
- function useNodeOrEdgeTypes(nodeOrEdgeTypes, createTypes) {
1775
- const typesKeysRef = useRef(null);
1776
- const typesParsed = useMemo(() => {
1777
- if (process.env.NODE_ENV === 'development') {
1778
- const typeKeys = Object.keys(nodeOrEdgeTypes);
1779
- if (shallow(typesKeysRef.current, typeKeys)) {
1780
- devWarn('002');
1705
+ function getMouseHandler(id, getState, handler) {
1706
+ return handler === undefined
1707
+ ? handler
1708
+ : (event) => {
1709
+ const edge = getState().edges.find((e) => e.id === id);
1710
+ if (edge) {
1711
+ handler(event, { ...edge });
1781
1712
  }
1782
- typesKeysRef.current = typeKeys;
1783
- }
1784
- return createTypes(nodeOrEdgeTypes);
1785
- }, [nodeOrEdgeTypes]);
1786
- return typesParsed;
1713
+ };
1787
1714
  }
1788
-
1789
- const NodeIdContext = createContext(null);
1790
- const Provider = NodeIdContext.Provider;
1791
- NodeIdContext.Consumer;
1792
- const useNodeId = () => {
1793
- const nodeId = useContext(NodeIdContext);
1794
- return nodeId;
1795
- };
1796
-
1797
- function Port({ type, position }) {
1798
- const store = useStoreApi();
1799
- const nodeId = useNodeId();
1800
- if (!nodeId)
1801
- return null;
1802
- const handleOnConnect = (connection) => {
1803
- const { defaultEdgeOptions, onConnect } = store.getState();
1804
- const edgeParams = {
1805
- ...defaultEdgeOptions,
1806
- ...connection,
1715
+ const wrapEdge = (EdgeComponent) => {
1716
+ const EdgeWrapper = (props) => {
1717
+ const { id, className, style, type, data, rfId, ariaLabel,
1718
+ // sourceAndTargetIds
1719
+ source, sourcePort, target, targetPort,
1720
+ // marker
1721
+ markerEnd, markerStart,
1722
+ // labelProps
1723
+ label, labelStyle, labelShowBg, labelBgStyle, labelBgPadding, labelBgBorderRadius,
1724
+ // AnchorProps
1725
+ edgeUpdaterRadius,
1726
+ // position
1727
+ sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, selected, elementsSelectable, hidden, isFocusable, onClick, onDoubleClick, onContextMenu, onMouseEnter, onMouseMove, onMouseLeave, onEdgeUpdate, onEdgeUpdateStart, onEdgeUpdateEnd, } = props;
1728
+ const position = {
1729
+ sourceX,
1730
+ sourceY,
1731
+ targetX,
1732
+ targetY,
1733
+ sourcePosition,
1734
+ targetPosition,
1807
1735
  };
1808
- onConnect?.(edgeParams);
1809
- };
1810
- const onPointerDown = (event) => {
1811
- const isMouseTriggered = isMouseEvent(event);
1812
- if ((isMouseTriggered && event.button === 0) || !isMouseTriggered) {
1736
+ const sourceAndTargetIds = {
1737
+ source,
1738
+ sourcePort,
1739
+ target,
1740
+ targetPort,
1741
+ };
1742
+ const isConnecting = className === 'react-diagram__connection';
1743
+ if (isConnecting) {
1744
+ document
1745
+ .querySelector('path')
1746
+ ?.classList.add('react-diagram__connection-path');
1747
+ return (jsx(EdgeComponent, { ...sourceAndTargetIds, ...position, id: id, data: data, style: style, selected: selected }));
1748
+ }
1749
+ const store = useStoreApi();
1750
+ const edgeRef = useRef(null);
1751
+ const [updating, setUpdating] = useState(false);
1752
+ const markerStartUrl = useMemo(() => `url(#${getMarkerId(markerStart, rfId)})`, [markerStart, rfId]);
1753
+ const markerEndUrl = useMemo(() => `url(#${getMarkerId(markerEnd, rfId)})`, [markerEnd, rfId]);
1754
+ if (hidden) {
1755
+ return null;
1756
+ }
1757
+ const handleEdgeUpdater = (fromPortType) => (event) => {
1758
+ if (event.button !== 0) {
1759
+ return;
1760
+ }
1761
+ const { edges } = store.getState();
1762
+ const nodeId = props[fromPortType];
1763
+ const edge = edges.find((e) => e.id === id);
1764
+ setUpdating(true);
1765
+ onEdgeUpdateStart?.(event, edge, fromPortType);
1766
+ const onConnectEdge = (connection) => onEdgeUpdate?.(edge, connection);
1767
+ const handleEdgeUpdateEnd = (evt) => {
1768
+ setUpdating(false);
1769
+ onEdgeUpdateEnd?.(evt, edge, fromPortType);
1770
+ };
1813
1771
  handlePointerDown({
1772
+ isAnchor: true,
1814
1773
  event,
1815
1774
  nodeId,
1816
- portType: type,
1775
+ portType: fromPortType,
1817
1776
  getState: store.getState,
1818
1777
  setState: store.setState,
1819
- onConnect: handleOnConnect,
1778
+ onConnect: onConnectEdge,
1779
+ onEdgeUpdateEnd: handleEdgeUpdateEnd,
1820
1780
  });
1821
- }
1822
- };
1823
- return (jsx("div", { "data-nodeid": nodeId, "data-id": `${nodeId}-${type}`, "data-port-position": position, className: `react-diagram__port react-diagram__port-${position} ${type} nodrag`, onMouseDown: onPointerDown, onTouchStart: onPointerDown }));
1824
- }
1825
- Port.displayName = 'Port';
1826
- var Port$1 = memo(Port);
1827
-
1828
- function Nodes({ data }) {
1829
- return (jsxs(Fragment, { children: [jsx(Port$1, { type: "target", position: Position.Top }), data.label, jsx(Port$1, { type: "source", position: Position.Bottom })] }));
1830
- }
1831
-
1832
- function useGetPointerPosition() {
1833
- const store = useStoreApi();
1834
- // returns the pointer position projected to the RF coordinate system
1835
- const getPointerPosition = useCallback(({ sourceEvent }) => {
1836
- const { transform, gridStep } = store.getState();
1837
- const x = sourceEvent.touches
1838
- ? sourceEvent.touches[0].clientX
1839
- : sourceEvent.clientX;
1840
- const y = sourceEvent.touches
1841
- ? sourceEvent.touches[0].clientY
1842
- : sourceEvent.clientY;
1843
- const pointerPos = {
1844
- x: (x - transform[0]) / transform[2],
1845
- y: (y - transform[1]) / transform[2],
1846
1781
  };
1847
- // we need the snapped position in order to be able to skip unnecessary drag events
1848
- return {
1849
- xSnapped: gridStep
1850
- ? gridStep[0] * Math.round(pointerPos.x / gridStep[0])
1851
- : pointerPos.x,
1852
- ySnapped: gridStep
1853
- ? gridStep[1] * Math.round(pointerPos.y / gridStep[1])
1854
- : pointerPos.y,
1855
- ...pointerPos,
1782
+ const onEdgeClick = (event) => {
1783
+ const { edges } = store.getState();
1784
+ if (onClick) {
1785
+ const edge = edges.find((e) => e.id === id);
1786
+ onClick(event, edge);
1787
+ }
1856
1788
  };
1857
- }, []);
1858
- return getPointerPosition;
1789
+ const onEdgeDoubleClick = getMouseHandler(id, store.getState, onDoubleClick);
1790
+ const onEdgeContextMenu = getMouseHandler(id, store.getState, onContextMenu);
1791
+ const onEdgeMouseEnter = getMouseHandler(id, store.getState, onMouseEnter);
1792
+ const onEdgeMouseMove = getMouseHandler(id, store.getState, onMouseMove);
1793
+ const onEdgeMouseLeave = getMouseHandler(id, store.getState, onMouseLeave);
1794
+ const inactive = !elementsSelectable;
1795
+ const wrapperClassName = cc([
1796
+ 'react-diagram__edge',
1797
+ `react-diagram__edge-${type}`,
1798
+ className,
1799
+ { selected, inactive },
1800
+ ]);
1801
+ const marker = { markerStart: markerStartUrl, markerEnd: markerEndUrl };
1802
+ const labelProps = {
1803
+ label,
1804
+ labelStyle,
1805
+ labelShowBg,
1806
+ labelBgStyle,
1807
+ labelBgPadding,
1808
+ labelBgBorderRadius,
1809
+ };
1810
+ const events = {
1811
+ onClick: onEdgeClick,
1812
+ onDoubleClick: onEdgeDoubleClick,
1813
+ onContextMenu: onEdgeContextMenu,
1814
+ onMouseEnter: onEdgeMouseEnter,
1815
+ onMouseMove: onEdgeMouseMove,
1816
+ onMouseLeave: onEdgeMouseLeave,
1817
+ };
1818
+ return (jsx("g", { ...events, ref: edgeRef, className: wrapperClassName, tabIndex: isFocusable ? 0 : undefined, role: isFocusable ? 'button' : undefined, "aria-label": ariaLabel === null
1819
+ ? undefined
1820
+ : ariaLabel
1821
+ ? ariaLabel
1822
+ : `Edge from ${source} to ${target}`, "aria-describedby": isFocusable ? `${ARIA_EDGE_DESC_KEY}-${rfId}` : undefined, children: !updating && (jsxs(Fragment, { children: [jsx(EdgeComponent, { ...sourceAndTargetIds, ...marker, ...labelProps, ...position, id: id, data: data, style: style, selected: selected }), jsx(Anchor, { position: sourcePosition, centerX: sourceX, centerY: sourceY, radius: edgeUpdaterRadius, onMouseDown: handleEdgeUpdater('target'),
1823
+ // onMouseEnter={console.log}
1824
+ // onMouseOut={console.log}
1825
+ type: "source" }), jsx(Anchor, { position: targetPosition, centerX: targetX, centerY: targetY, radius: edgeUpdaterRadius, onMouseDown: handleEdgeUpdater('source'),
1826
+ // onMouseEnter={console.log}
1827
+ // onMouseOut={console.log}
1828
+ type: "target" })] })) }));
1829
+ };
1830
+ EdgeWrapper.displayName = 'EdgeWrapper';
1831
+ return memo(EdgeWrapper);
1832
+ };
1833
+
1834
+ const createEdgeTypes = (edgeTypes) => {
1835
+ const defaultTypes = {
1836
+ default: wrapEdge((edgeTypes.straight || StraightEdge)),
1837
+ step: wrapEdge((edgeTypes.step || StepEdge)),
1838
+ bezier: wrapEdge((edgeTypes.bezier || BezierEdge)),
1839
+ };
1840
+ const wrappedTypes = {};
1841
+ const customTypes = Object.keys(edgeTypes)
1842
+ .filter((k) => !Object.keys(defaultTypes).includes(k))
1843
+ .reduce((res, key) => {
1844
+ res[key] = wrapEdge((edgeTypes[key] || StepEdge));
1845
+ return res;
1846
+ }, wrappedTypes);
1847
+ return {
1848
+ ...defaultTypes,
1849
+ ...customTypes,
1850
+ };
1851
+ };
1852
+ function getPortPosition(position, nodeRect, port = null) {
1853
+ const x = (port?.x || 0) + nodeRect.x;
1854
+ const y = (port?.y || 0) + nodeRect.y;
1855
+ const width = port?.width || nodeRect.width;
1856
+ const height = port?.height || nodeRect.height;
1857
+ switch (position) {
1858
+ case Position.Top:
1859
+ return {
1860
+ x: x + width / 2,
1861
+ y,
1862
+ };
1863
+ case Position.Right:
1864
+ return {
1865
+ x: x + width,
1866
+ y: y + height / 2,
1867
+ };
1868
+ case Position.Bottom:
1869
+ return {
1870
+ x: x + width / 2,
1871
+ y: y + height,
1872
+ };
1873
+ case Position.Left:
1874
+ return {
1875
+ x,
1876
+ y: y + height / 2,
1877
+ };
1878
+ }
1859
1879
  }
1860
-
1861
- const getPortBounds = (selector, nodeElement, zoom, nodeOrigin) => {
1862
- const ports = nodeElement.querySelectorAll(selector);
1863
- if (!ports || !ports.length) {
1880
+ function getPort(bounds, portId) {
1881
+ if (!bounds) {
1864
1882
  return null;
1865
1883
  }
1866
- const portsArray = Array.from(ports);
1867
- const nodeBounds = nodeElement.getBoundingClientRect();
1868
- const nodeOffset = {
1869
- x: nodeBounds.width * nodeOrigin[0],
1870
- y: nodeBounds.height * nodeOrigin[1],
1884
+ if (bounds.length === 1 || !portId) {
1885
+ return bounds[0];
1886
+ }
1887
+ else if (portId) {
1888
+ return bounds.find((d) => d.id === portId) || null;
1889
+ }
1890
+ return null;
1891
+ }
1892
+ const getEdgePositions = (sourceNodeRect, sourcePort, sourcePosition, targetNodeRect, targetPort, targetPosition) => {
1893
+ const sourcePortPos = getPortPosition(sourcePosition, sourceNodeRect, sourcePort);
1894
+ const targetPortPos = getPortPosition(targetPosition, targetNodeRect, targetPort);
1895
+ return {
1896
+ sourceX: sourcePortPos.x,
1897
+ sourceY: sourcePortPos.y,
1898
+ targetX: targetPortPos.x,
1899
+ targetY: targetPortPos.y,
1871
1900
  };
1872
- return portsArray.map((port) => {
1873
- const portBounds = port.getBoundingClientRect();
1874
- return {
1875
- id: port.getAttribute('data-portid'),
1876
- position: port.dataset.portPosition,
1877
- x: (portBounds.left - nodeBounds.left - nodeOffset.x) / zoom,
1878
- y: (portBounds.top - nodeBounds.top - nodeOffset.y) / zoom,
1879
- ...getDimensions(port),
1880
- };
1881
- });
1882
1901
  };
1883
- function getMouseHandler(id, getState, handler) {
1884
- return handler === undefined
1885
- ? handler
1886
- : (event) => {
1887
- const node = getState().nodeInternals.get(id);
1888
- handler(event, { ...node });
1889
- };
1902
+ function getNodeData(node) {
1903
+ const portBounds = node?.[internalsSymbol]?.portBounds || null;
1904
+ const isValid = portBounds &&
1905
+ node?.width &&
1906
+ node?.height &&
1907
+ typeof node?.positionAbsolute?.x !== 'undefined' &&
1908
+ typeof node?.positionAbsolute?.y !== 'undefined';
1909
+ return [
1910
+ {
1911
+ x: node?.positionAbsolute?.x || 0,
1912
+ y: node?.positionAbsolute?.y || 0,
1913
+ width: node?.width || 0,
1914
+ height: node?.height || 0,
1915
+ },
1916
+ portBounds,
1917
+ !!isValid,
1918
+ ];
1890
1919
  }
1891
- function handleNodeClick({ id, store, isSelectable, unselect = false, nodeRef, }) {
1892
- if (!isSelectable)
1893
- return;
1894
- const { addSelectedNodes, unselectNodes, multiSelectionActive, nodeInternals, } = store.getState();
1895
- const node = nodeInternals.get(id);
1896
- store.setState({ nodesSelectionActive: false });
1897
- if (!node.selected) {
1898
- addSelectedNodes([id]);
1899
- }
1900
- else if (unselect || (node.selected && multiSelectionActive)) {
1901
- unselectNodes({ nodes: [node] });
1902
- requestAnimationFrame(() => nodeRef?.current?.blur());
1903
- }
1920
+
1921
+ const selector$3 = (s) => ({
1922
+ edges: s.edges,
1923
+ width: s.width,
1924
+ height: s.height,
1925
+ nodeInternals: s.nodeInternals,
1926
+ onError: s.onError,
1927
+ });
1928
+ function EdgeRenderer({ rfId, edgeTypes, noPanClassName, edgeUpdaterRadius, onEdgeClick, onEdgeDoubleClick, onEdgeContextMenu, onEdgeMouseEnter, onEdgeMouseMove, onEdgeMouseLeave, onEdgeUpdate, onEdgeUpdateStart, onEdgeUpdateEnd, }) {
1929
+ const { edges, width, height, nodeInternals } = useStore(selector$3, shallow);
1930
+ return (jsxs("svg", { width: width || '100vw', height: height || '100vh', className: "react-diagram__edges react-diagram__container", children: [jsx(MarkerComponent$1, { defaultColor: "#000000", rfId: rfId }), jsx("g", { children: edges.map((edge) => {
1931
+ const { data, type,
1932
+ // elProps
1933
+ id, className, style, ariaLabel,
1934
+ // sourceAndTargetIds
1935
+ source, sourcePort, target, targetPort,
1936
+ // marker
1937
+ markerEnd, markerStart,
1938
+ // labelProps
1939
+ label, labelStyle, labelShowBg, labelBgStyle, labelBgPadding, labelBgBorderRadius, } = edge;
1940
+ const [sourceNodeRect, sourcePortBounds, sourceIsValid] = getNodeData(nodeInternals.get(source));
1941
+ const [targetNodeRect, targetPortBounds, targetIsValid] = getNodeData(nodeInternals.get(target));
1942
+ if (!sourceIsValid || !targetIsValid) {
1943
+ return null;
1944
+ }
1945
+ const edgeType = type || 'straight';
1946
+ const EdgeComponent = edgeTypes[edgeType] || edgeTypes.default;
1947
+ const targetNodePorts = targetPortBounds.target;
1948
+ const sourcePortInfo = getPort(sourcePortBounds.source, sourcePort);
1949
+ const targetPortInfo = getPort(targetNodePorts, targetPort);
1950
+ const sourcePosition = sourcePortInfo?.position || Position.Bottom;
1951
+ const targetPosition = targetPortInfo?.position || Position.Top;
1952
+ const isFocusable = !!edge.focusable;
1953
+ if (!sourcePortInfo || !targetPortInfo) {
1954
+ return null;
1955
+ }
1956
+ const elProps = {
1957
+ id,
1958
+ className: cc([className, noPanClassName]),
1959
+ style,
1960
+ ariaLabel,
1961
+ };
1962
+ const sourceAndTargetIds = {
1963
+ source,
1964
+ sourcePort,
1965
+ target,
1966
+ targetPort,
1967
+ };
1968
+ const marker = {
1969
+ markerEnd,
1970
+ markerStart,
1971
+ };
1972
+ const labelProps = {
1973
+ label,
1974
+ labelStyle,
1975
+ labelShowBg,
1976
+ labelBgStyle,
1977
+ labelBgPadding,
1978
+ labelBgBorderRadius,
1979
+ };
1980
+ const edgePositions = getEdgePositions(sourceNodeRect, sourcePortInfo, sourcePosition, targetNodeRect, targetPortInfo, targetPosition);
1981
+ const position = {
1982
+ ...edgePositions,
1983
+ sourcePosition,
1984
+ targetPosition,
1985
+ };
1986
+ const events = {
1987
+ onClick: onEdgeClick,
1988
+ onDoubleClick: onEdgeDoubleClick,
1989
+ onContextMenu: onEdgeContextMenu,
1990
+ onMouseEnter: onEdgeMouseEnter,
1991
+ onMouseMove: onEdgeMouseMove,
1992
+ onMouseLeave: onEdgeMouseLeave,
1993
+ onEdgeUpdate,
1994
+ onEdgeUpdateStart,
1995
+ onEdgeUpdateEnd,
1996
+ };
1997
+ return (jsx(EdgeComponent, { ...elProps, ...sourceAndTargetIds, ...marker, ...labelProps, ...position, ...events, rfId: rfId, type: edgeType, data: data, isFocusable: isFocusable, edgeUpdaterRadius: edgeUpdaterRadius }, id));
1998
+ }) })] }));
1904
1999
  }
2000
+ EdgeRenderer.displayName = 'EdgeRenderer';
2001
+ var EdgeRenderer$1 = memo(EdgeRenderer);
1905
2002
 
1906
- function isParentSelected(node, nodeInternals) {
1907
- if (!node.parentNode) {
1908
- return false;
2003
+ const oppositePosition = {
2004
+ [Position.Left]: Position.Right,
2005
+ [Position.Right]: Position.Left,
2006
+ [Position.Top]: Position.Bottom,
2007
+ [Position.Bottom]: Position.Top,
2008
+ };
2009
+ function ConnectionPath({ nodeId, portType, edge, Component, EdgeWrapper, }) {
2010
+ const { fromNode, toX, toY } = useStore(useCallback((s) => ({
2011
+ fromNode: s.nodeInternals.get(nodeId),
2012
+ toX: (s.connectionPosition.x - s.transform[0]) / s.transform[2],
2013
+ toY: (s.connectionPosition.y - s.transform[1]) / s.transform[2],
2014
+ }), [nodeId]), shallow);
2015
+ const fromPortBounds = fromNode?.[internalsSymbol]?.portBounds;
2016
+ const portBounds = fromPortBounds?.[portType];
2017
+ if (!fromNode || !portBounds) {
2018
+ return null;
1909
2019
  }
1910
- const parentNode = nodeInternals.get(node.parentNode);
1911
- if (!parentNode) {
1912
- return false;
2020
+ const fromPort = portBounds[0];
2021
+ const fromPortX = fromPort
2022
+ ? fromPort.x + fromPort.width / 2
2023
+ : (fromNode.width ?? 0) / 2;
2024
+ const fromPortY = fromPort
2025
+ ? fromPort.y + fromPort.height / 2
2026
+ : fromNode.height ?? 0;
2027
+ const fromX = (fromNode.positionAbsolute?.x ?? 0) + fromPortX;
2028
+ const fromY = (fromNode.positionAbsolute?.y ?? 0) + fromPortY;
2029
+ const fromPosition = fromPort?.position;
2030
+ const toPosition = fromPosition ? oppositePosition[fromPosition] : null;
2031
+ if (!fromPosition || !toPosition) {
2032
+ return null;
1913
2033
  }
1914
- if (parentNode.selected) {
1915
- return true;
2034
+ if (Component) {
2035
+ return (jsx(Component, { fromNode: fromNode, fromPort: fromPort, fromX: fromX, fromY: fromY, toX: toX, toY: toY, fromPosition: fromPosition, toPosition: toPosition }));
1916
2036
  }
1917
- return isParentSelected(parentNode, nodeInternals);
1918
- }
1919
- function getDragItems(nodeInternals, nodesDraggable, mousePosition, nodeId) {
1920
- return Array.from(nodeInternals.values())
1921
- .filter((n) => (n.selected || n.id === nodeId) &&
1922
- (!n.parentNode || !isParentSelected(n, nodeInternals)) &&
1923
- (n.draggable ||
1924
- (nodesDraggable && typeof n.draggable === 'undefined')))
1925
- .map((n) => ({
1926
- id: n.id,
1927
- position: n.position || { x: 0, y: 0 },
1928
- positionAbsolute: n.positionAbsolute || { x: 0, y: 0 },
1929
- distance: {
1930
- x: mousePosition.x - (n.positionAbsolute?.x ?? 0),
1931
- y: mousePosition.y - (n.positionAbsolute?.y ?? 0),
1932
- },
1933
- delta: {
1934
- x: 0,
1935
- y: 0,
1936
- },
1937
- extent: n.extent,
1938
- parentNode: n.parentNode,
1939
- width: n.width,
1940
- height: n.height,
1941
- }));
2037
+ return (jsx(EdgeWrapper, { id: edge.id, className: "react-diagram__connection", type: edge.type || 'default', source: edge.source, target: edge.target, isFocusable: false, sourceX: fromX, sourceY: fromY, targetX: toX, targetY: toY, sourcePosition: fromPosition, targetPosition: toPosition }));
1942
2038
  }
1943
- function calcNextPosition(node, nextPosition, nodeInternals, nodeExtent, nodeOrigin = [0, 0], onError) {
1944
- let currentExtent = node.extent || nodeExtent;
1945
- if (node.extent === 'parent') {
1946
- if (node.parentNode && node.width && node.height) {
1947
- const parent = nodeInternals.get(node.parentNode);
1948
- const { x: parentX, y: parentY } = getNodePositionWithOrigin(parent, nodeOrigin).positionAbsolute;
1949
- currentExtent =
1950
- parent &&
1951
- isNumeric(parentX) &&
1952
- isNumeric(parentY) &&
1953
- isNumeric(parent.width) &&
1954
- isNumeric(parent.height)
1955
- ? [
1956
- [
1957
- parentX + node.width * nodeOrigin[0],
1958
- parentY + node.height * nodeOrigin[1],
1959
- ],
1960
- [
1961
- parentX +
1962
- parent.width -
1963
- node.width +
1964
- node.width * nodeOrigin[0],
1965
- parentY +
1966
- parent.height -
1967
- node.height +
1968
- node.height * nodeOrigin[1],
1969
- ],
1970
- ]
1971
- : currentExtent;
1972
- }
1973
- else {
1974
- onError?.('011');
1975
- currentExtent = nodeExtent;
1976
- }
1977
- }
1978
- else if (node.extent && node.parentNode) {
1979
- const parent = nodeInternals.get(node.parentNode);
1980
- const { x: parentX, y: parentY } = getNodePositionWithOrigin(parent, nodeOrigin).positionAbsolute;
1981
- currentExtent = [
1982
- [node.extent[0][0] + parentX, node.extent[0][1] + parentY],
1983
- [node.extent[1][0] + parentX, node.extent[1][1] + parentY],
1984
- ];
1985
- }
1986
- let parentPosition = { x: 0, y: 0 };
1987
- if (node.parentNode) {
1988
- const parentNode = nodeInternals.get(node.parentNode);
1989
- parentPosition = getNodePositionWithOrigin(parentNode, nodeOrigin).positionAbsolute;
2039
+ ConnectionPath.displayName = 'ConnectionPath';
2040
+
2041
+ const selector$2 = (s) => ({
2042
+ edges: s.edges,
2043
+ nodeId: s.connectionNodeId,
2044
+ portType: s.connectionPortType,
2045
+ });
2046
+ function ConnectionLineRenderer({ containerStyle, edgeTypes, component, }) {
2047
+ const { nodeId, portType, edges } = useStore(selector$2, shallow);
2048
+ const isValid = !!(nodeId && portType);
2049
+ if (!isValid) {
2050
+ return null;
1990
2051
  }
1991
- const positionAbsolute = currentExtent
1992
- ? clampPosition(nextPosition, currentExtent)
1993
- : nextPosition;
2052
+ const selectedEdge = edges.find((edge) => edge[portType] === nodeId);
2053
+ if (!selectedEdge)
2054
+ return null;
2055
+ const EdgeWrapper = selectedEdge?.type
2056
+ ? edgeTypes[selectedEdge.type]
2057
+ : edgeTypes.default;
2058
+ return (jsx("svg", { style: containerStyle, className: "react-diagram__container react-diagram__connection-line", children: jsx("g", { className: "react-diagram__connection", children: jsx(ConnectionPath, { nodeId: nodeId, portType: portType, edge: selectedEdge, Component: component, EdgeWrapper: EdgeWrapper }) }) }));
2059
+ }
2060
+
2061
+ function DiagramView({ rfId,
2062
+ // DiagramRenderer props
2063
+ noPanClassName, panning, defaultViewport, multiSelectionKeyCode, onMove, onMoveStart, onMoveEnd,
2064
+ // NodeRenderer props
2065
+ onlyRenderVisibleElements, disableKeyboardA11y, noDragClassName, nodeOrigin, nodeTypes, onNodeClick, onNodeDoubleClick, onNodeContextMenu, onNodeMouseEnter, onNodeMouseMove, onNodeMouseLeave,
2066
+ // EdgeRenderer props
2067
+ edgeTypes, edgeUpdaterRadius, onEdgeClick, onEdgeDoubleClick, onEdgeContextMenu, onEdgeMouseEnter, onEdgeMouseMove, onEdgeMouseLeave, onEdgeUpdate, onEdgeUpdateStart, onEdgeUpdateEnd,
2068
+ // ConnectionLineWrapper
2069
+ ConnectionLineContainerStyle, ConnectionLineComponent, }) {
2070
+ return (jsxs(DiagramRenderer$1, { multiSelectionKeyCode: multiSelectionKeyCode, noPanClassName: noPanClassName, panning: panning, defaultViewport: defaultViewport, onMove: onMove, onMoveStart: onMoveStart, onMoveEnd: onMoveEnd, children: [jsx(NodeRenderer$1, { rfId: rfId, nodeTypes: nodeTypes, onlyRenderVisibleElements: onlyRenderVisibleElements, disableKeyboardA11y: disableKeyboardA11y, nodeOrigin: nodeOrigin, noDragClassName: noDragClassName, noPanClassName: noPanClassName, onNodeClick: onNodeClick, onNodeDoubleClick: onNodeDoubleClick, onNodeContextMenu: onNodeContextMenu, onNodeMouseEnter: onNodeMouseEnter, onNodeMouseMove: onNodeMouseMove, onNodeMouseLeave: onNodeMouseLeave }), jsx(EdgeRenderer$1, { rfId: rfId, edgeTypes: edgeTypes, noPanClassName: noPanClassName, edgeUpdaterRadius: edgeUpdaterRadius, onEdgeClick: onEdgeClick, onEdgeDoubleClick: onEdgeDoubleClick, onEdgeContextMenu: onEdgeContextMenu, onEdgeMouseEnter: onEdgeMouseEnter, onEdgeMouseMove: onEdgeMouseMove, onEdgeMouseLeave: onEdgeMouseLeave, onEdgeUpdate: onEdgeUpdate, onEdgeUpdateStart: onEdgeUpdateStart, onEdgeUpdateEnd: onEdgeUpdateEnd }), jsx(ConnectionLineRenderer, { edgeTypes: edgeTypes, containerStyle: ConnectionLineContainerStyle, component: ConnectionLineComponent })] }));
2071
+ }
2072
+ DiagramView.displayName = 'DiagramView';
2073
+ var DiagramView$1 = memo(DiagramView);
2074
+
2075
+ const selector$1 = (s) => {
2076
+ const { setNodes, setEdges, setNodeExtent, setTranslateExtent, setMinZoom, setMaxZoom, } = s;
1994
2077
  return {
1995
- position: {
1996
- x: positionAbsolute.x - parentPosition.x,
1997
- y: positionAbsolute.y - parentPosition.y,
1998
- },
1999
- positionAbsolute,
2078
+ setNodes,
2079
+ setEdges,
2080
+ setNodeExtent,
2081
+ setTranslateExtent,
2082
+ setMinZoom,
2083
+ setMaxZoom,
2000
2084
  };
2085
+ };
2086
+ function useStoreUpdater(value, setStoreState) {
2087
+ useEffect(() => {
2088
+ if (typeof value !== 'undefined') {
2089
+ setStoreState(value);
2090
+ }
2091
+ }, [value]);
2001
2092
  }
2002
- function getEventHandlerParams({ nodeId, dragItems, nodeInternals, }) {
2003
- const extentedDragItems = dragItems.map((n) => {
2004
- const node = nodeInternals.get(n.id);
2005
- return {
2006
- ...node,
2007
- position: n.position,
2008
- positionAbsolute: n.positionAbsolute,
2009
- };
2010
- });
2011
- return [
2012
- nodeId
2013
- ? extentedDragItems.find((n) => n.id === nodeId)
2014
- : extentedDragItems[0],
2015
- extentedDragItems,
2016
- ];
2093
+ // updates with values in store that don't have a dedicated setter function
2094
+ function useDirectStoreUpdater(key, value, setState) {
2095
+ useEffect(() => {
2096
+ if (typeof value !== 'undefined') {
2097
+ setState({ [key]: value });
2098
+ }
2099
+ }, [value]);
2017
2100
  }
2018
- function hasSelector(target, selector, nodeRef) {
2019
- let current = target;
2020
- do {
2021
- if (current?.matches(selector))
2022
- return true;
2023
- if (current === nodeRef.current)
2024
- return false;
2025
- current = current.parentElement;
2026
- } while (current);
2027
- return false;
2101
+ const StoreUpdater = ({ nodes, onNodesChange, onNodeDrag, onNodeDragStart, onNodeDragEnd, edges, onEdgesChange, smoothStep, centerStep, gridStep, elevateNodesOnSelect, nodesDraggable, autoPanOnNodeDrag, autoPanOnConnect, connectionRadius, onConnect, onConnectStart, onConnectEnd, onError, nodeExtent, translateExtent, minZoom, maxZoom, }) => {
2102
+ const { setNodes, setEdges, setNodeExtent, setTranslateExtent, setMinZoom, setMaxZoom, } = useStore(selector$1, shallow);
2103
+ const store = useStoreApi();
2104
+ useStoreUpdater(nodes, setNodes);
2105
+ useStoreUpdater(edges, setEdges);
2106
+ useStoreUpdater(nodeExtent, setNodeExtent);
2107
+ useStoreUpdater(translateExtent, setTranslateExtent);
2108
+ useStoreUpdater(minZoom, setMinZoom);
2109
+ useStoreUpdater(maxZoom, setMaxZoom);
2110
+ useDirectStoreUpdater('smoothStep', smoothStep, store.setState);
2111
+ useDirectStoreUpdater('centerStep', centerStep, store.setState);
2112
+ useDirectStoreUpdater('gridStep', gridStep, store.setState);
2113
+ useDirectStoreUpdater('elevateNodesOnSelect', elevateNodesOnSelect, store.setState);
2114
+ useDirectStoreUpdater('nodesDraggable', nodesDraggable, store.setState);
2115
+ useDirectStoreUpdater('autoPanOnNodeDrag', autoPanOnNodeDrag, store.setState);
2116
+ useDirectStoreUpdater('autoPanOnConnect', autoPanOnConnect, store.setState);
2117
+ useDirectStoreUpdater('connectionRadius', connectionRadius, store.setState);
2118
+ useDirectStoreUpdater('onNodesChange', onNodesChange, store.setState);
2119
+ useDirectStoreUpdater('onNodeDrag', onNodeDrag, store.setState);
2120
+ useDirectStoreUpdater('onNodeDragStart', onNodeDragStart, store.setState);
2121
+ useDirectStoreUpdater('onNodeDragEnd', onNodeDragEnd, store.setState);
2122
+ useDirectStoreUpdater('onEdgesChange', onEdgesChange, store.setState);
2123
+ useDirectStoreUpdater('onConnect', onConnect, store.setState);
2124
+ useDirectStoreUpdater('onConnectStart', onConnectStart, store.setState);
2125
+ useDirectStoreUpdater('onConnectEnd', onConnectEnd, store.setState);
2126
+ useDirectStoreUpdater('onError', onErrorWrapper(onError), store.setState);
2127
+ return null;
2128
+ };
2129
+
2130
+ function useNodeOrEdgeTypes(nodeOrEdgeTypes, createTypes) {
2131
+ const typesKeysRef = useRef(null);
2132
+ const typesParsed = useMemo(() => {
2133
+ if (process.env.NODE_ENV === 'development') {
2134
+ const typeKeys = Object.keys(nodeOrEdgeTypes);
2135
+ if (shallow(typesKeysRef.current, typeKeys)) {
2136
+ devWarn('002');
2137
+ }
2138
+ typesKeysRef.current = typeKeys;
2139
+ }
2140
+ return createTypes(nodeOrEdgeTypes);
2141
+ }, [nodeOrEdgeTypes]);
2142
+ return typesParsed;
2028
2143
  }
2029
2144
 
2030
- function useDrag({ nodeRef, nodeId, isSelectable, noDragClassName, }) {
2145
+ const NodeIdContext = createContext(null);
2146
+ const Provider = NodeIdContext.Provider;
2147
+ NodeIdContext.Consumer;
2148
+ const useNodeId = () => {
2149
+ const nodeId = useContext(NodeIdContext);
2150
+ return nodeId;
2151
+ };
2152
+
2153
+ function Port({ type, position }) {
2031
2154
  const store = useStoreApi();
2032
- const dragItems = useRef([]);
2033
- const containerBounds = useRef(null);
2034
- const mousePosition = useRef({ x: 0, y: 0 });
2035
- const lastPosition = useRef({
2036
- x: null,
2037
- y: null,
2038
- });
2039
- const dragEvent = useRef(null);
2040
- const autoPanStarted = useRef(false);
2041
- const autoPanId = useRef(0);
2042
- const [dragging, setDragging] = useState(false);
2043
- const getPointerPosition = useGetPointerPosition();
2044
- useEffect(() => {
2045
- if (nodeRef?.current) {
2046
- const selection = select(nodeRef.current);
2047
- const updateNodes = ({ x, y }) => {
2048
- const { nodeInternals, onNodeDrag, updateNodePositions, nodeExtent, nodeOrigin, gridStep, onError, } = store.getState();
2049
- lastPosition.current = { x, y };
2050
- let hasChange = false;
2051
- dragItems.current = dragItems.current.map((n) => {
2052
- const nextPosition = {
2053
- x: x - n.distance.x,
2054
- y: y - n.distance.y,
2055
- };
2056
- if (gridStep) {
2057
- nextPosition.x =
2058
- gridStep[0] * Math.round(nextPosition.x / gridStep[0]);
2059
- nextPosition.y =
2060
- gridStep[1] * Math.round(nextPosition.y / gridStep[1]);
2061
- }
2062
- const updatedPos = calcNextPosition(n, nextPosition, nodeInternals, nodeExtent, nodeOrigin, onError);
2063
- // we want to make sure that we only fire a change event when there is a changes
2064
- hasChange =
2065
- hasChange ||
2066
- n.position.x !== updatedPos.position.x ||
2067
- n.position.y !== updatedPos.position.y;
2068
- n.position = updatedPos.position;
2069
- n.positionAbsolute = updatedPos.positionAbsolute;
2070
- return n;
2071
- });
2072
- if (!hasChange) {
2073
- return;
2074
- }
2075
- updateNodePositions(dragItems.current, true, true);
2076
- setDragging(true);
2077
- if (onNodeDrag && dragEvent.current) {
2078
- const [currentNode, nodes] = getEventHandlerParams({
2079
- nodeId,
2080
- dragItems: dragItems.current,
2081
- nodeInternals,
2082
- });
2083
- onNodeDrag(dragEvent.current, currentNode, nodes);
2084
- }
2085
- };
2086
- const autoPan = () => {
2087
- if (!containerBounds.current) {
2088
- return;
2089
- }
2090
- const [xMovement, yMovement] = calcAutoPanPosition(mousePosition.current, containerBounds.current);
2091
- if (xMovement !== 0 || yMovement !== 0) {
2092
- const { transform, panBy } = store.getState();
2093
- lastPosition.current.x =
2094
- (lastPosition.current.x ?? 0) - xMovement / transform[2];
2095
- lastPosition.current.y =
2096
- (lastPosition.current.y ?? 0) - yMovement / transform[2];
2097
- updateNodes(lastPosition.current);
2098
- panBy({ x: xMovement, y: yMovement });
2099
- }
2100
- autoPanId.current = requestAnimationFrame(autoPan);
2101
- };
2102
- const dragHandle = drag()
2103
- .on('start', (e) => {
2104
- // only allow left click
2105
- if (e.sourceEvent.which !== 1)
2106
- return;
2107
- const { nodeInternals, nodesDraggable, domNode, onNodeDragStart, } = store.getState();
2108
- if (nodeId) {
2109
- handleNodeClick({
2110
- id: nodeId,
2111
- store,
2112
- nodeRef: nodeRef,
2113
- isSelectable,
2114
- });
2115
- }
2116
- const pointerPosition = getPointerPosition(e);
2117
- dragItems.current = getDragItems(nodeInternals, nodesDraggable, pointerPosition, nodeId);
2118
- if (onNodeDragStart && dragItems.current) {
2119
- const [currentNode, nodes] = getEventHandlerParams({
2120
- nodeId,
2121
- dragItems: dragItems.current,
2122
- nodeInternals,
2123
- });
2124
- onNodeDragStart(e.sourceEvent, currentNode, nodes);
2125
- }
2126
- containerBounds.current =
2127
- domNode?.getBoundingClientRect() || null;
2128
- mousePosition.current = getEventPosition(e.sourceEvent, containerBounds.current);
2129
- })
2130
- .on('drag', (e) => {
2131
- const pointerPosition = getPointerPosition(e);
2132
- const { autoPanOnNodeDrag } = store.getState();
2133
- if (!autoPanStarted.current && autoPanOnNodeDrag) {
2134
- autoPanStarted.current = true;
2135
- autoPan();
2136
- }
2137
- if ((lastPosition.current.x !== pointerPosition.xSnapped ||
2138
- lastPosition.current.y !== pointerPosition.ySnapped) &&
2139
- dragItems.current) {
2140
- dragEvent.current = e.sourceEvent;
2141
- mousePosition.current = getEventPosition(e.sourceEvent, containerBounds.current);
2142
- updateNodes(pointerPosition);
2143
- }
2144
- })
2145
- .on('end', (event) => {
2146
- setDragging(false);
2147
- autoPanStarted.current = false;
2148
- cancelAnimationFrame(autoPanId.current);
2149
- if (dragItems.current) {
2150
- const { nodeInternals, updateNodePositions, onNodeDragEnd } = store.getState();
2151
- updateNodePositions(dragItems.current, false, false);
2152
- if (onNodeDragEnd) {
2153
- const [currentNode, nodes] = getEventHandlerParams({
2154
- nodeId,
2155
- dragItems: dragItems.current,
2156
- nodeInternals,
2157
- });
2158
- onNodeDragEnd(event.sourceEvent, currentNode, nodes);
2159
- }
2160
- }
2161
- })
2162
- .filter((event) => {
2163
- const target = event.target;
2164
- const isDraggable = (!event.button && !noDragClassName) ||
2165
- !hasSelector(target, `.${noDragClassName}`, nodeRef);
2166
- return isDraggable;
2155
+ const nodeId = useNodeId();
2156
+ if (!nodeId)
2157
+ return null;
2158
+ const handleOnConnect = (connection) => {
2159
+ const { defaultEdgeOptions, onConnect } = store.getState();
2160
+ const edgeParams = {
2161
+ ...defaultEdgeOptions,
2162
+ ...connection,
2163
+ };
2164
+ onConnect?.(edgeParams);
2165
+ };
2166
+ const onPointerDown = (event) => {
2167
+ const isMouseTriggered = isMouseEvent(event);
2168
+ if ((isMouseTriggered && event.button === 0) || !isMouseTriggered) {
2169
+ handlePointerDown({
2170
+ event,
2171
+ nodeId,
2172
+ portType: type,
2173
+ getState: store.getState,
2174
+ setState: store.setState,
2175
+ onConnect: handleOnConnect,
2167
2176
  });
2168
- selection.call(dragHandle);
2169
- return () => {
2170
- selection.on('.drag', null);
2171
- };
2172
2177
  }
2173
- }, [store, nodeRef, nodeId, isSelectable, noDragClassName]);
2174
- return dragging;
2178
+ };
2179
+ return (jsx("div", { "data-nodeid": nodeId, "data-id": `${nodeId}-${type}`, "data-port-position": position, className: `react-diagram__port react-diagram__port-${position} ${type} nodrag`, onMouseDown: onPointerDown, onTouchStart: onPointerDown }));
2180
+ }
2181
+ Port.displayName = 'Port';
2182
+ var Port$1 = memo(Port);
2183
+
2184
+ function Nodes({ data }) {
2185
+ return (jsxs(Fragment, { children: [jsx(Port$1, { type: "target", position: Position.Top }), data.label, jsx(Port$1, { type: "source", position: Position.Bottom })] }));
2175
2186
  }
2176
2187
 
2177
2188
  const wrapNode = (NodeComponent) => {
@@ -2256,11 +2267,11 @@ const wrapNode = (NodeComponent) => {
2256
2267
  };
2257
2268
  const events = {
2258
2269
  onClick: onSelectNodeHandler,
2259
- onDoubleClick: getMouseHandler(id, store.getState, onDoubleClick),
2260
- onContextMenu: getMouseHandler(id, store.getState, onContextMenu),
2261
- onMouseEnter: getMouseHandler(id, store.getState, onMouseEnter),
2262
- onMouseMove: getMouseHandler(id, store.getState, onMouseMove),
2263
- onMouseLeave: getMouseHandler(id, store.getState, onMouseLeave),
2270
+ onDoubleClick: getMouseHandler$1(id, store.getState, onDoubleClick),
2271
+ onContextMenu: getMouseHandler$1(id, store.getState, onContextMenu),
2272
+ onMouseEnter: getMouseHandler$1(id, store.getState, onMouseEnter),
2273
+ onMouseMove: getMouseHandler$1(id, store.getState, onMouseMove),
2274
+ onMouseLeave: getMouseHandler$1(id, store.getState, onMouseLeave),
2264
2275
  };
2265
2276
  const position = {
2266
2277
  positionX,
@@ -2381,11 +2392,13 @@ const initialState = {
2381
2392
  onNodesChange: null,
2382
2393
  domNode: null,
2383
2394
  nodeOrigin: [0, 0],
2395
+ smoothStep: false,
2396
+ centerStep: false,
2384
2397
  gridStep: undefined,
2385
- nodesSelectionActive: false,
2386
2398
  elevateNodesOnSelect: true,
2387
2399
  nodesDraggable: true,
2388
2400
  multiSelectionActive: false,
2401
+ selectionBoxActive: false,
2389
2402
  d3Zoom: null,
2390
2403
  d3Selection: null,
2391
2404
  minZoom: 0.5,
@@ -2397,6 +2410,7 @@ const initialState = {
2397
2410
  autoPanOnConnect: true,
2398
2411
  nodeExtent: infiniteExtent,
2399
2412
  translateExtent: infiniteExtent,
2413
+ connectionRadius: 20,
2400
2414
  onError: devWarn,
2401
2415
  };
2402
2416
 
@@ -2459,17 +2473,21 @@ const createRFStore = () => createStore((set, get) => ({
2459
2473
  onNodesChange?.(changes);
2460
2474
  }
2461
2475
  },
2462
- updateNodePositions: (nodeDragItems, positionChanged = true, dragging = false) => {
2476
+ updateNodesPosition: (nodes, dragging = false, updateFunc) => {
2463
2477
  const { triggerNodeChanges } = get();
2464
- const changes = nodeDragItems.map((node) => {
2478
+ const changes = nodes.map((node) => {
2465
2479
  const change = {
2466
2480
  id: node.id,
2467
2481
  type: 'position',
2468
2482
  dragging,
2469
2483
  };
2470
- if (positionChanged) {
2471
- change.positionAbsolute = node.positionAbsolute;
2472
- change.position = node.position;
2484
+ if (updateFunc) {
2485
+ updateFunc(node);
2486
+ return {
2487
+ ...change,
2488
+ position: node.position,
2489
+ positionAbsolute: node.positionAbsolute,
2490
+ };
2473
2491
  }
2474
2492
  return change;
2475
2493
  });
@@ -2592,15 +2610,15 @@ const defaultNodeTypes = {
2592
2610
  const defaultEdgeTypes = {
2593
2611
  step: StepEdge,
2594
2612
  };
2595
- const ReactDiagram = forwardRef(({ id,
2613
+ const ReactDiagram = forwardRef(({ children, id,
2596
2614
  // DiagramView props
2597
- panning = true, minZoom, maxZoom, translateExtent, nodeExtent, defaultViewport = initViewport, multiSelectionKeyCode, onlyRenderVisibleElements = false, disableKeyboardA11y = false, noDragClassName = 'nodrag', noPanClassName = 'nopan', nodeOrigin = initNodeOrigin, nodeTypes = defaultNodeTypes, onNodeClick, onNodeDoubleClick, onNodeContextMenu, onNodeMouseEnter, onNodeMouseMove, onNodeMouseLeave, edgeTypes = defaultEdgeTypes, onEdgeClick, onEdgeDoubleClick, onEdgeContextMenu, onEdgeMouseEnter, onEdgeMouseMove, onEdgeMouseLeave, onEdgeUpdate, onEdgeUpdateStart, onEdgeUpdateEnd, onMove, onMoveStart, onMoveEnd, connectionEdgeContainerStyle, connectionEdgeStyle, connectionEdgeType, connectionEdgeComponent,
2615
+ panning = true, minZoom, maxZoom, translateExtent, nodeExtent, defaultViewport = initViewport, multiSelectionKeyCode, onlyRenderVisibleElements = false, disableKeyboardA11y = false, noDragClassName = 'nodrag', noPanClassName = 'nopan', nodeOrigin = initNodeOrigin, nodeTypes = defaultNodeTypes, onNodeClick, onNodeDoubleClick, onNodeContextMenu, onNodeMouseEnter, onNodeMouseMove, onNodeMouseLeave, edgeTypes = defaultEdgeTypes, edgeUpdaterRadius, onEdgeClick, onEdgeDoubleClick, onEdgeContextMenu, onEdgeMouseEnter, onEdgeMouseMove, onEdgeMouseLeave, onEdgeUpdate, onEdgeUpdateStart, onEdgeUpdateEnd, onMove, onMoveStart, onMoveEnd, ConnectionLineContainerStyle, ConnectionLineComponent,
2598
2616
  // StoreUpdater props
2599
- nodes, edges, nodesDraggable, elevateNodesOnSelect, autoPanOnNodeDrag, autoPanOnConnect, onNodesChange, onNodeDrag, onNodeDragStart, onNodeDragEnd, onEdgesChange, onConnect, onConnectStart, onConnectEnd, onError, }, ref) => {
2617
+ nodes, edges, nodesDraggable, elevateNodesOnSelect, autoPanOnNodeDrag, autoPanOnConnect, connectionRadius, smoothStep, centerStep, gridStep, onNodesChange, onNodeDrag, onNodeDragStart, onNodeDragEnd, onEdgesChange, onConnect, onConnectStart, onConnectEnd, onError, }, ref) => {
2600
2618
  const rfId = id || '1';
2601
2619
  const nodeTypesWrapped = useNodeOrEdgeTypes(nodeTypes, createNodeTypes);
2602
2620
  const edgeTypesWrapped = useNodeOrEdgeTypes(edgeTypes, createEdgeTypes);
2603
- return (jsx("div", { ref: ref, className: "react-diagram", children: jsxs(Wrapper, { children: [jsx(DiagramView$1, { rfId: rfId, panning: panning, defaultViewport: defaultViewport, multiSelectionKeyCode: multiSelectionKeyCode, onlyRenderVisibleElements: onlyRenderVisibleElements, disableKeyboardA11y: disableKeyboardA11y, noDragClassName: noDragClassName, noPanClassName: noPanClassName, nodeOrigin: nodeOrigin, nodeTypes: nodeTypesWrapped, edgeTypes: edgeTypesWrapped, connectionEdgeContainerStyle: connectionEdgeContainerStyle, connectionEdgeStyle: connectionEdgeStyle, connectionEdgeType: connectionEdgeType, connectionEdgeComponent: connectionEdgeComponent, onNodeClick: onNodeClick, onNodeDoubleClick: onNodeDoubleClick, onNodeContextMenu: onNodeContextMenu, onNodeMouseEnter: onNodeMouseEnter, onNodeMouseMove: onNodeMouseMove, onNodeMouseLeave: onNodeMouseLeave, onEdgeClick: onEdgeClick, onEdgeDoubleClick: onEdgeDoubleClick, onEdgeContextMenu: onEdgeContextMenu, onEdgeMouseEnter: onEdgeMouseEnter, onEdgeMouseMove: onEdgeMouseMove, onEdgeMouseLeave: onEdgeMouseLeave, onEdgeUpdate: onEdgeUpdate, onEdgeUpdateStart: onEdgeUpdateStart, onEdgeUpdateEnd: onEdgeUpdateEnd, onMove: onMove, onMoveStart: onMoveStart, onMoveEnd: onMoveEnd }), jsx(StoreUpdater, { rfId: rfId, nodes: nodes, edges: edges, nodesDraggable: nodesDraggable, elevateNodesOnSelect: elevateNodesOnSelect, autoPanOnNodeDrag: autoPanOnNodeDrag, autoPanOnConnect: autoPanOnConnect, nodeExtent: nodeExtent, translateExtent: translateExtent, minZoom: minZoom, maxZoom: maxZoom, onNodesChange: onNodesChange, onNodeDrag: onNodeDrag, onNodeDragStart: onNodeDragStart, onNodeDragEnd: onNodeDragEnd, onEdgesChange: onEdgesChange, onConnect: onConnect, onConnectStart: onConnectStart, onConnectEnd: onConnectEnd, onError: onError })] }) }));
2621
+ return (jsx("div", { ref: ref, className: "react-diagram", children: jsxs(Wrapper, { children: [jsx(DiagramView$1, { rfId: rfId, panning: panning, defaultViewport: defaultViewport, multiSelectionKeyCode: multiSelectionKeyCode, onlyRenderVisibleElements: onlyRenderVisibleElements, disableKeyboardA11y: disableKeyboardA11y, noDragClassName: noDragClassName, noPanClassName: noPanClassName, nodeOrigin: nodeOrigin, nodeTypes: nodeTypesWrapped, edgeTypes: edgeTypesWrapped, edgeUpdaterRadius: edgeUpdaterRadius, ConnectionLineContainerStyle: ConnectionLineContainerStyle, ConnectionLineComponent: ConnectionLineComponent, onNodeClick: onNodeClick, onNodeDoubleClick: onNodeDoubleClick, onNodeContextMenu: onNodeContextMenu, onNodeMouseEnter: onNodeMouseEnter, onNodeMouseMove: onNodeMouseMove, onNodeMouseLeave: onNodeMouseLeave, onEdgeClick: onEdgeClick, onEdgeDoubleClick: onEdgeDoubleClick, onEdgeContextMenu: onEdgeContextMenu, onEdgeMouseEnter: onEdgeMouseEnter, onEdgeMouseMove: onEdgeMouseMove, onEdgeMouseLeave: onEdgeMouseLeave, onEdgeUpdate: onEdgeUpdate, onEdgeUpdateStart: onEdgeUpdateStart, onEdgeUpdateEnd: onEdgeUpdateEnd, onMove: onMove, onMoveStart: onMoveStart, onMoveEnd: onMoveEnd }), jsx(StoreUpdater, { rfId: rfId, nodes: nodes, edges: edges, nodesDraggable: nodesDraggable, elevateNodesOnSelect: elevateNodesOnSelect, autoPanOnNodeDrag: autoPanOnNodeDrag, autoPanOnConnect: autoPanOnConnect, connectionRadius: connectionRadius, nodeExtent: nodeExtent, translateExtent: translateExtent, minZoom: minZoom, maxZoom: maxZoom, smoothStep: smoothStep, centerStep: centerStep, gridStep: gridStep, onNodesChange: onNodesChange, onNodeDrag: onNodeDrag, onNodeDragStart: onNodeDragStart, onNodeDragEnd: onNodeDragEnd, onEdgesChange: onEdgesChange, onConnect: onConnect, onConnectStart: onConnectStart, onConnectEnd: onConnectEnd, onError: onError }), children] }) }));
2604
2622
  });
2605
2623
  ReactDiagram.displayName = 'ReactDiagram';
2606
2624
 
@@ -2614,4 +2632,35 @@ function createUseItemsState(applyChanges) {
2614
2632
  const useNodesState = createUseItemsState(applyNodeChanges);
2615
2633
  const useEdgesState = createUseItemsState(applyEdgeChanges);
2616
2634
 
2617
- export { BaseEdge, BezierEdge, ConnectionEdgeType, MarkerType, Port$1 as Port, Position, ReactDiagramProvider, StepEdge, addEdge, boxToRect, clamp, ReactDiagram as default, getBezierPath, getStepPath, internalsSymbol, isEdge, isNode, rectToBox, updateEdge, useEdgesState, useNodesState };
2635
+ function LinePath({ color, scaledGap, lineWidth }) {
2636
+ const m1 = `M${scaledGap[0] / 2} 0`;
2637
+ const v = `V${scaledGap[1]}`;
2638
+ const m2 = `M0 ${scaledGap[1] / 2}`;
2639
+ const h = `H${scaledGap[0]}`;
2640
+ const path = `${m1} ${v} ${m2} ${h}`;
2641
+ return jsx("path", { stroke: color, strokeWidth: lineWidth, d: path });
2642
+ }
2643
+
2644
+ const selector = (s) => ({
2645
+ transform: s.transform,
2646
+ rfId: s.rfId,
2647
+ gridStepGap: s.gridStep,
2648
+ });
2649
+ function Background({ gap, lineWidth = 1, color = '#000000', }) {
2650
+ const ref = useRef(null);
2651
+ const { transform, rfId, gridStepGap } = useStore(selector, shallow);
2652
+ const defaultGap = gap ? gap : gridStepGap ? gridStepGap : 50;
2653
+ const gapXY = Array.isArray(defaultGap)
2654
+ ? defaultGap
2655
+ : [defaultGap, defaultGap];
2656
+ const scaledGap = [
2657
+ gapXY[0] * transform[2] || 1,
2658
+ gapXY[1] * transform[2] || 1,
2659
+ ];
2660
+ const patternOffset = [scaledGap[0] / 2, scaledGap[1] / 2];
2661
+ return (jsxs("svg", { className: "react-diagram__container react-diagram__background", ref: ref, children: [jsx("pattern", { id: `background-${rfId}`, x: transform[0] % scaledGap[0], y: transform[1] % scaledGap[1], width: scaledGap[0], height: scaledGap[1], patternUnits: "userSpaceOnUse", patternTransform: `translate(-${patternOffset[0]},-${patternOffset[1]})`, children: jsx(LinePath, { scaledGap: scaledGap, color: color, lineWidth: lineWidth }) }), jsx("rect", { x: "0", y: "0", width: "100%", height: "100%", fill: `url(#${`background-${rfId}`})` })] }));
2662
+ }
2663
+ Background.displayName = 'Background';
2664
+ var index = memo(Background);
2665
+
2666
+ export { index as Background, BaseEdge, BezierEdge, MarkerType, Port$1 as Port, Position, ReactDiagramProvider, StepEdge, addEdge, boxToRect, clamp, ReactDiagram as default, getBezierPath, getStepPath, internalsSymbol, isEdge, isNode, rectToBox, updateEdge, useEdgesState, useNodesState };