react-cosmos-diagram 0.3.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 (67) 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/ReactDiagramProvider/type.d.ts +4 -2
  8. package/dist/esm/components/ReactDiagramProvider/type.d.ts.map +1 -1
  9. package/dist/esm/components/SelectionBox/index.d.ts.map +1 -1
  10. package/dist/esm/components/StoreUpdater/index.d.ts +2 -2
  11. package/dist/esm/components/StoreUpdater/index.d.ts.map +1 -1
  12. package/dist/esm/container/DragSelection/index.d.ts +0 -3
  13. package/dist/esm/container/DragSelection/index.d.ts.map +1 -1
  14. package/dist/esm/container/NodeRenderer/index.d.ts.map +1 -1
  15. package/dist/esm/container/Pane/index.d.ts.map +1 -1
  16. package/dist/esm/container/ReactDiagram/index.d.ts +2 -0
  17. package/dist/esm/container/ReactDiagram/index.d.ts.map +1 -1
  18. package/dist/esm/hooks/useDrag/index.d.ts.map +1 -1
  19. package/dist/esm/hooks/useDrag/type.d.ts +3 -10
  20. package/dist/esm/hooks/useDrag/type.d.ts.map +1 -1
  21. package/dist/esm/hooks/useDrag/utils.d.ts +7 -6
  22. package/dist/esm/hooks/useDrag/utils.d.ts.map +1 -1
  23. package/dist/esm/hooks/useGetPointerPosition.d.ts +14 -2
  24. package/dist/esm/hooks/useGetPointerPosition.d.ts.map +1 -1
  25. package/dist/esm/index.d.ts +1 -0
  26. package/dist/esm/index.d.ts.map +1 -1
  27. package/dist/esm/index.js +1281 -1218
  28. package/dist/esm/store/index.d.ts.map +1 -1
  29. package/dist/esm/store/initialState.d.ts.map +1 -1
  30. package/dist/esm/types/core.d.ts +2 -0
  31. package/dist/esm/types/core.d.ts.map +1 -1
  32. package/dist/esm/types/index.d.ts +1 -0
  33. package/dist/esm/types/index.d.ts.map +1 -1
  34. package/dist/umd/components/Background/LinePath.d.ts +8 -0
  35. package/dist/umd/components/Background/LinePath.d.ts.map +1 -0
  36. package/dist/umd/components/Background/index.d.ts +9 -0
  37. package/dist/umd/components/Background/index.d.ts.map +1 -0
  38. package/dist/umd/components/Background/type.d.ts +6 -0
  39. package/dist/umd/components/Background/type.d.ts.map +1 -0
  40. package/dist/umd/components/ReactDiagramProvider/type.d.ts +4 -2
  41. package/dist/umd/components/ReactDiagramProvider/type.d.ts.map +1 -1
  42. package/dist/umd/components/SelectionBox/index.d.ts.map +1 -1
  43. package/dist/umd/components/StoreUpdater/index.d.ts +2 -2
  44. package/dist/umd/components/StoreUpdater/index.d.ts.map +1 -1
  45. package/dist/umd/container/DragSelection/index.d.ts +0 -3
  46. package/dist/umd/container/DragSelection/index.d.ts.map +1 -1
  47. package/dist/umd/container/NodeRenderer/index.d.ts.map +1 -1
  48. package/dist/umd/container/Pane/index.d.ts.map +1 -1
  49. package/dist/umd/container/ReactDiagram/index.d.ts +2 -0
  50. package/dist/umd/container/ReactDiagram/index.d.ts.map +1 -1
  51. package/dist/umd/hooks/useDrag/index.d.ts.map +1 -1
  52. package/dist/umd/hooks/useDrag/type.d.ts +3 -10
  53. package/dist/umd/hooks/useDrag/type.d.ts.map +1 -1
  54. package/dist/umd/hooks/useDrag/utils.d.ts +7 -6
  55. package/dist/umd/hooks/useDrag/utils.d.ts.map +1 -1
  56. package/dist/umd/hooks/useGetPointerPosition.d.ts +14 -2
  57. package/dist/umd/hooks/useGetPointerPosition.d.ts.map +1 -1
  58. package/dist/umd/index.d.ts +1 -0
  59. package/dist/umd/index.d.ts.map +1 -1
  60. package/dist/umd/index.js +1 -1
  61. package/dist/umd/store/index.d.ts.map +1 -1
  62. package/dist/umd/store/initialState.d.ts.map +1 -1
  63. package/dist/umd/types/core.d.ts +2 -0
  64. package/dist/umd/types/core.d.ts.map +1 -1
  65. package/dist/umd/types/index.d.ts +1 -0
  66. package/dist/umd/types/index.d.ts.map +1 -1
  67. package/package.json +1 -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;
@@ -433,396 +502,696 @@ 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
- const selector$3 = (s) => ({
741
- nodesDraggable: s.nodesDraggable,
742
- elementsSelectable: s.elementsSelectable,
743
- updateNodeDimensions: s.updateNodeDimensions,
744
- onError: s.onError,
912
+ const createSelectionChange = (id, selected) => ({
913
+ id,
914
+ type: 'select',
915
+ selected,
745
916
  });
746
- function NodeRenderer({ nodeTypes, onNodeClick, onNodeMouseEnter, onNodeMouseMove, onNodeMouseLeave, onNodeContextMenu, onNodeDoubleClick, ...props }) {
747
- const { nodesDraggable, elementsSelectable, updateNodeDimensions, onError } = useStore(selector$3, shallow);
748
- const nodes = useVisibleNodes();
749
- const resizeObserverRef = useRef();
750
- const resizeObserver = useMemo(() => {
751
- if (typeof ResizeObserver === 'undefined') {
752
- 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));
753
923
  }
754
- const observer = new ResizeObserver((entries) => {
755
- const updates = entries.map((entry) => ({
756
- id: entry.target.getAttribute('data-id'),
757
- nodeElement: entry.target,
758
- forceUpdate: true,
759
- }));
760
- updateNodeDimensions(updates);
761
- });
762
- resizeObserverRef.current = observer;
763
- return observer;
764
- }, []);
765
- useEffect(() => () => {
766
- resizeObserverRef?.current?.disconnect();
924
+ else if (item.selected && !willBeSelected) {
925
+ item.selected = false;
926
+ res.push(createSelectionChange(item.id, false));
927
+ }
928
+ return res;
767
929
  }, []);
768
- return (jsx("div", { className: "react-diagram__nodes react-diagram__container", children: nodes.map((node) => {
769
- const { data, type,
770
- // elProps
771
- id, className, style, ariaLabel, positionAbsolute, hidden, selected, selectable, draggable, } = node;
772
- let nodeType = type || 'default';
773
- if (!nodeTypes[nodeType]) {
774
- onError?.('010', nodeType);
775
- nodeType = 'default';
776
- }
777
- const NodeComponent = (nodeTypes[nodeType] ||
778
- nodeTypes.default);
779
- const isDraggable = !!(draggable ||
780
- (nodesDraggable && typeof draggable === 'undefined'));
781
- const isSelectable = !!(selectable ||
782
- (elementsSelectable && typeof selectable === 'undefined'));
783
- const elProps = {
784
- id,
785
- className,
786
- style: {
787
- ...style,
788
- width: node.width,
789
- height: node.height,
790
- },
791
- ariaLabel,
792
- };
793
- const events = {
794
- onClick: onNodeClick,
795
- onMouseEnter: onNodeMouseEnter,
796
- onMouseMove: onNodeMouseMove,
797
- onMouseLeave: onNodeMouseLeave,
798
- onContextMenu: onNodeContextMenu,
799
- onDoubleClick: onNodeDoubleClick,
800
- };
801
- const position = {
802
- positionX: positionAbsolute?.x || 0,
803
- positionY: positionAbsolute?.y || 0,
804
- sourcePosition: Position.Bottom,
805
- targetPosition: Position.Top,
806
- };
807
- const booleanProps = {
808
- selected: !!selected,
809
- isSelectable,
810
- isDraggable,
811
- hidden,
812
- isParent: !!node[internalsSymbol]?.isParent,
813
- initialized: !!node.width && !!node.height,
814
- };
815
- return (jsx(NodeComponent, { ...props, ...elProps, ...position, ...events, ...booleanProps, zIndex: node[internalsSymbol]?.z ?? 0, type: nodeType, data: data, resizeObserver: resizeObserver }, id));
816
- }) }));
817
930
  }
818
- NodeRenderer.displayName = 'NodeRenderer';
819
- var NodeRenderer$1 = memo(NodeRenderer);
820
931
 
821
- 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" }));
822
- const MarkerSymbols = {
823
- [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
+ };
824
941
  };
825
- function useMarkerSymbol(type) {
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,
1193
+ };
1194
+ function useMarkerSymbol(type) {
826
1195
  const store = useStoreApi();
827
1196
  const symbol = useMemo(() => {
828
1197
  const symbolExists = Object.prototype.hasOwnProperty.call(MarkerSymbols, type);
@@ -1308,855 +1677,512 @@ const handlePointerDown = ({ isAnchor = false, event, nodeId, portType, getState
1308
1677
  doc.addEventListener('touchend', onPointerUp);
1309
1678
  };
1310
1679
 
1311
- const portPositionX = (x, shift, position) => {
1312
- if (position === Position.Left)
1313
- return x - shift;
1314
- if (position === Position.Right)
1315
- return x + shift;
1316
- return x;
1317
- };
1318
- const portPositionY = (y, shift, position) => {
1319
- if (position === Position.Top)
1320
- return y - shift;
1321
- if (position === Position.Bottom)
1322
- return y + shift;
1323
- return y;
1324
- };
1325
- const EdgeUpdaterClassName = 'react-diagram__edge-updater';
1326
- function Anchor({ position, centerX, centerY, radius = 10, onMouseDown,
1327
- // onMouseEnter,
1328
- // onMouseOut,
1329
- type, }) {
1330
- return (jsx("circle", { className: cc([
1331
- EdgeUpdaterClassName,
1332
- `${EdgeUpdaterClassName}-${type}`,
1333
- ]), cx: portPositionX(centerX, radius, position), cy: portPositionY(centerY, radius, position), r: radius, stroke: "transparent", fill: "transparent", onMouseDown: onMouseDown }));
1334
- }
1335
-
1336
- function getMouseHandler$1(id, getState, handler) {
1337
- return handler === undefined
1338
- ? handler
1339
- : (event) => {
1340
- const edge = getState().edges.find((e) => e.id === id);
1341
- if (edge) {
1342
- handler(event, { ...edge });
1343
- }
1344
- };
1345
- }
1346
- const wrapEdge = (EdgeComponent) => {
1347
- const EdgeWrapper = (props) => {
1348
- const { id, className, style, type, data, rfId, ariaLabel,
1349
- // sourceAndTargetIds
1350
- source, sourcePort, target, targetPort,
1351
- // marker
1352
- markerEnd, markerStart,
1353
- // labelProps
1354
- label, labelStyle, labelShowBg, labelBgStyle, labelBgPadding, labelBgBorderRadius,
1355
- // AnchorProps
1356
- edgeUpdaterRadius,
1357
- // position
1358
- sourceX, sourceY, targetX, targetY, sourcePosition, targetPosition, selected, elementsSelectable, hidden, isFocusable, onClick, onDoubleClick, onContextMenu, onMouseEnter, onMouseMove, onMouseLeave, onEdgeUpdate, onEdgeUpdateStart, onEdgeUpdateEnd, } = props;
1359
- const position = {
1360
- sourceX,
1361
- sourceY,
1362
- targetX,
1363
- targetY,
1364
- sourcePosition,
1365
- targetPosition,
1366
- };
1367
- const sourceAndTargetIds = {
1368
- source,
1369
- sourcePort,
1370
- target,
1371
- targetPort,
1372
- };
1373
- const isConnecting = className === 'react-diagram__connection';
1374
- if (isConnecting) {
1375
- document
1376
- .querySelector('path')
1377
- ?.classList.add('react-diagram__connection-path');
1378
- return (jsx(EdgeComponent, { ...sourceAndTargetIds, ...position, id: id, data: data, style: style, selected: selected }));
1379
- }
1380
- const store = useStoreApi();
1381
- const edgeRef = useRef(null);
1382
- const [updating, setUpdating] = useState(false);
1383
- const markerStartUrl = useMemo(() => `url(#${getMarkerId(markerStart, rfId)})`, [markerStart, rfId]);
1384
- const markerEndUrl = useMemo(() => `url(#${getMarkerId(markerEnd, rfId)})`, [markerEnd, rfId]);
1385
- if (hidden) {
1386
- return null;
1387
- }
1388
- const handleEdgeUpdater = (fromPortType) => (event) => {
1389
- if (event.button !== 0) {
1390
- return;
1391
- }
1392
- const { edges } = store.getState();
1393
- const nodeId = props[fromPortType];
1394
- const edge = edges.find((e) => e.id === id);
1395
- setUpdating(true);
1396
- onEdgeUpdateStart?.(event, edge, fromPortType);
1397
- const onConnectEdge = (connection) => onEdgeUpdate?.(edge, connection);
1398
- const handleEdgeUpdateEnd = (evt) => {
1399
- setUpdating(false);
1400
- onEdgeUpdateEnd?.(evt, edge, fromPortType);
1401
- };
1402
- handlePointerDown({
1403
- isAnchor: true,
1404
- event,
1405
- nodeId,
1406
- portType: fromPortType,
1407
- getState: store.getState,
1408
- setState: store.setState,
1409
- onConnect: onConnectEdge,
1410
- onEdgeUpdateEnd: handleEdgeUpdateEnd,
1411
- });
1412
- };
1413
- const onEdgeClick = (event) => {
1414
- const { edges } = store.getState();
1415
- if (onClick) {
1416
- const edge = edges.find((e) => e.id === id);
1417
- onClick(event, edge);
1418
- }
1419
- };
1420
- const onEdgeDoubleClick = getMouseHandler$1(id, store.getState, onDoubleClick);
1421
- const onEdgeContextMenu = getMouseHandler$1(id, store.getState, onContextMenu);
1422
- const onEdgeMouseEnter = getMouseHandler$1(id, store.getState, onMouseEnter);
1423
- const onEdgeMouseMove = getMouseHandler$1(id, store.getState, onMouseMove);
1424
- const onEdgeMouseLeave = getMouseHandler$1(id, store.getState, onMouseLeave);
1425
- const inactive = !elementsSelectable;
1426
- const wrapperClassName = cc([
1427
- 'react-diagram__edge',
1428
- `react-diagram__edge-${type}`,
1429
- className,
1430
- { selected, inactive },
1431
- ]);
1432
- const marker = { markerStart: markerStartUrl, markerEnd: markerEndUrl };
1433
- const labelProps = {
1434
- label,
1435
- labelStyle,
1436
- labelShowBg,
1437
- labelBgStyle,
1438
- labelBgPadding,
1439
- labelBgBorderRadius,
1440
- };
1441
- const events = {
1442
- onClick: onEdgeClick,
1443
- onDoubleClick: onEdgeDoubleClick,
1444
- onContextMenu: onEdgeContextMenu,
1445
- onMouseEnter: onEdgeMouseEnter,
1446
- onMouseMove: onEdgeMouseMove,
1447
- onMouseLeave: onEdgeMouseLeave,
1448
- };
1449
- return (jsx("g", { ...events, ref: edgeRef, className: wrapperClassName, tabIndex: isFocusable ? 0 : undefined, role: isFocusable ? 'button' : undefined, "aria-label": ariaLabel === null
1450
- ? undefined
1451
- : ariaLabel
1452
- ? ariaLabel
1453
- : `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'),
1454
- // onMouseEnter={console.log}
1455
- // onMouseOut={console.log}
1456
- type: "source" }), jsx(Anchor, { position: targetPosition, centerX: targetX, centerY: targetY, radius: edgeUpdaterRadius, onMouseDown: handleEdgeUpdater('source'),
1457
- // onMouseEnter={console.log}
1458
- // onMouseOut={console.log}
1459
- type: "target" })] })) }));
1460
- };
1461
- EdgeWrapper.displayName = 'EdgeWrapper';
1462
- return memo(EdgeWrapper);
1463
- };
1464
-
1465
- const createEdgeTypes = (edgeTypes) => {
1466
- const defaultTypes = {
1467
- default: wrapEdge((edgeTypes.straight || StraightEdge)),
1468
- step: wrapEdge((edgeTypes.step || StepEdge)),
1469
- bezier: wrapEdge((edgeTypes.bezier || BezierEdge)),
1470
- };
1471
- const wrappedTypes = {};
1472
- const customTypes = Object.keys(edgeTypes)
1473
- .filter((k) => !Object.keys(defaultTypes).includes(k))
1474
- .reduce((res, key) => {
1475
- res[key] = wrapEdge((edgeTypes[key] || StepEdge));
1476
- return res;
1477
- }, wrappedTypes);
1478
- return {
1479
- ...defaultTypes,
1480
- ...customTypes,
1481
- };
1482
- };
1483
- function getPortPosition(position, nodeRect, port = null) {
1484
- const x = (port?.x || 0) + nodeRect.x;
1485
- const y = (port?.y || 0) + nodeRect.y;
1486
- const width = port?.width || nodeRect.width;
1487
- const height = port?.height || nodeRect.height;
1488
- switch (position) {
1489
- case Position.Top:
1490
- return {
1491
- x: x + width / 2,
1492
- y,
1493
- };
1494
- case Position.Right:
1495
- return {
1496
- x: x + width,
1497
- y: y + height / 2,
1498
- };
1499
- case Position.Bottom:
1500
- return {
1501
- x: x + width / 2,
1502
- y: y + height,
1503
- };
1504
- case Position.Left:
1505
- return {
1506
- x,
1507
- y: y + height / 2,
1508
- };
1509
- }
1510
- }
1511
- function getPort(bounds, portId) {
1512
- if (!bounds) {
1513
- return null;
1514
- }
1515
- if (bounds.length === 1 || !portId) {
1516
- return bounds[0];
1517
- }
1518
- else if (portId) {
1519
- return bounds.find((d) => d.id === portId) || null;
1520
- }
1521
- return null;
1522
- }
1523
- const getEdgePositions = (sourceNodeRect, sourcePort, sourcePosition, targetNodeRect, targetPort, targetPosition) => {
1524
- const sourcePortPos = getPortPosition(sourcePosition, sourceNodeRect, sourcePort);
1525
- const targetPortPos = getPortPosition(targetPosition, targetNodeRect, targetPort);
1526
- return {
1527
- sourceX: sourcePortPos.x,
1528
- sourceY: sourcePortPos.y,
1529
- targetX: targetPortPos.x,
1530
- targetY: targetPortPos.y,
1531
- };
1532
- };
1533
- function getNodeData(node) {
1534
- const portBounds = node?.[internalsSymbol]?.portBounds || null;
1535
- const isValid = portBounds &&
1536
- node?.width &&
1537
- node?.height &&
1538
- typeof node?.positionAbsolute?.x !== 'undefined' &&
1539
- typeof node?.positionAbsolute?.y !== 'undefined';
1540
- return [
1541
- {
1542
- x: node?.positionAbsolute?.x || 0,
1543
- y: node?.positionAbsolute?.y || 0,
1544
- width: node?.width || 0,
1545
- height: node?.height || 0,
1546
- },
1547
- portBounds,
1548
- !!isValid,
1549
- ];
1550
- }
1551
-
1552
- const selector$2 = (s) => ({
1553
- edges: s.edges,
1554
- width: s.width,
1555
- height: s.height,
1556
- nodeInternals: s.nodeInternals,
1557
- onError: s.onError,
1558
- });
1559
- function EdgeRenderer({ rfId, edgeTypes, noPanClassName, edgeUpdaterRadius, onEdgeClick, onEdgeDoubleClick, onEdgeContextMenu, onEdgeMouseEnter, onEdgeMouseMove, onEdgeMouseLeave, onEdgeUpdate, onEdgeUpdateStart, onEdgeUpdateEnd, }) {
1560
- const { edges, width, height, nodeInternals } = useStore(selector$2, shallow);
1561
- 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) => {
1562
- const { data, type,
1563
- // elProps
1564
- id, className, style, ariaLabel,
1565
- // sourceAndTargetIds
1566
- source, sourcePort, target, targetPort,
1567
- // marker
1568
- markerEnd, markerStart,
1569
- // labelProps
1570
- label, labelStyle, labelShowBg, labelBgStyle, labelBgPadding, labelBgBorderRadius, } = edge;
1571
- const [sourceNodeRect, sourcePortBounds, sourceIsValid] = getNodeData(nodeInternals.get(source));
1572
- const [targetNodeRect, targetPortBounds, targetIsValid] = getNodeData(nodeInternals.get(target));
1573
- if (!sourceIsValid || !targetIsValid) {
1574
- return null;
1575
- }
1576
- const edgeType = type || 'straight';
1577
- const EdgeComponent = edgeTypes[edgeType] || edgeTypes.default;
1578
- const targetNodePorts = targetPortBounds.target;
1579
- const sourcePortInfo = getPort(sourcePortBounds.source, sourcePort);
1580
- const targetPortInfo = getPort(targetNodePorts, targetPort);
1581
- const sourcePosition = sourcePortInfo?.position || Position.Bottom;
1582
- const targetPosition = targetPortInfo?.position || Position.Top;
1583
- const isFocusable = !!edge.focusable;
1584
- if (!sourcePortInfo || !targetPortInfo) {
1585
- return null;
1586
- }
1587
- const elProps = {
1588
- id,
1589
- className: cc([className, noPanClassName]),
1590
- style,
1591
- ariaLabel,
1592
- };
1593
- const sourceAndTargetIds = {
1594
- source,
1595
- sourcePort,
1596
- target,
1597
- targetPort,
1598
- };
1599
- const marker = {
1600
- markerEnd,
1601
- markerStart,
1602
- };
1603
- const labelProps = {
1604
- label,
1605
- labelStyle,
1606
- labelShowBg,
1607
- labelBgStyle,
1608
- labelBgPadding,
1609
- labelBgBorderRadius,
1610
- };
1611
- const edgePositions = getEdgePositions(sourceNodeRect, sourcePortInfo, sourcePosition, targetNodeRect, targetPortInfo, targetPosition);
1612
- const position = {
1613
- ...edgePositions,
1614
- sourcePosition,
1615
- targetPosition,
1616
- };
1617
- const events = {
1618
- onClick: onEdgeClick,
1619
- onDoubleClick: onEdgeDoubleClick,
1620
- onContextMenu: onEdgeContextMenu,
1621
- onMouseEnter: onEdgeMouseEnter,
1622
- onMouseMove: onEdgeMouseMove,
1623
- onMouseLeave: onEdgeMouseLeave,
1624
- onEdgeUpdate,
1625
- onEdgeUpdateStart,
1626
- onEdgeUpdateEnd,
1627
- };
1628
- return (jsx(EdgeComponent, { ...elProps, ...sourceAndTargetIds, ...marker, ...labelProps, ...position, ...events, rfId: rfId, type: edgeType, data: data, isFocusable: isFocusable, edgeUpdaterRadius: edgeUpdaterRadius }, id));
1629
- }) })] }));
1630
- }
1631
- EdgeRenderer.displayName = 'EdgeRenderer';
1632
- var EdgeRenderer$1 = memo(EdgeRenderer);
1633
-
1634
- const oppositePosition = {
1635
- [Position.Left]: Position.Right,
1636
- [Position.Right]: Position.Left,
1637
- [Position.Top]: Position.Bottom,
1638
- [Position.Bottom]: Position.Top,
1639
- };
1640
- function ConnectionPath({ nodeId, portType, edge, Component, EdgeWrapper, }) {
1641
- const { fromNode, toX, toY } = useStore(useCallback((s) => ({
1642
- fromNode: s.nodeInternals.get(nodeId),
1643
- toX: (s.connectionPosition.x - s.transform[0]) / s.transform[2],
1644
- toY: (s.connectionPosition.y - s.transform[1]) / s.transform[2],
1645
- }), [nodeId]), shallow);
1646
- const fromPortBounds = fromNode?.[internalsSymbol]?.portBounds;
1647
- const portBounds = fromPortBounds?.[portType];
1648
- if (!fromNode || !portBounds) {
1649
- return null;
1650
- }
1651
- const fromPort = portBounds[0];
1652
- const fromPortX = fromPort
1653
- ? fromPort.x + fromPort.width / 2
1654
- : (fromNode.width ?? 0) / 2;
1655
- const fromPortY = fromPort
1656
- ? fromPort.y + fromPort.height / 2
1657
- : fromNode.height ?? 0;
1658
- const fromX = (fromNode.positionAbsolute?.x ?? 0) + fromPortX;
1659
- const fromY = (fromNode.positionAbsolute?.y ?? 0) + fromPortY;
1660
- const fromPosition = fromPort?.position;
1661
- const toPosition = fromPosition ? oppositePosition[fromPosition] : null;
1662
- if (!fromPosition || !toPosition) {
1663
- return null;
1664
- }
1665
- if (Component) {
1666
- return (jsx(Component, { fromNode: fromNode, fromPort: fromPort, fromX: fromX, fromY: fromY, toX: toX, toY: toY, fromPosition: fromPosition, toPosition: toPosition }));
1667
- }
1668
- 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 }));
1669
- }
1670
- ConnectionPath.displayName = 'ConnectionPath';
1671
-
1672
- const selector$1 = (s) => ({
1673
- edges: s.edges,
1674
- nodeId: s.connectionNodeId,
1675
- portType: s.connectionPortType,
1676
- });
1677
- function ConnectionLineRenderer({ containerStyle, edgeTypes, component, }) {
1678
- const { nodeId, portType, edges } = useStore(selector$1, shallow);
1679
- const isValid = !!(nodeId && portType);
1680
- if (!isValid) {
1681
- return null;
1682
- }
1683
- const selectedEdge = edges.find((edge) => edge[portType] === nodeId);
1684
- if (!selectedEdge)
1685
- return null;
1686
- const EdgeWrapper = selectedEdge?.type
1687
- ? edgeTypes[selectedEdge.type]
1688
- : edgeTypes.default;
1689
- 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 }) }) }));
1690
- }
1691
-
1692
- function DiagramView({ rfId,
1693
- // DiagramRenderer props
1694
- noPanClassName, panning, defaultViewport, multiSelectionKeyCode, onMove, onMoveStart, onMoveEnd,
1695
- // NodeRenderer props
1696
- onlyRenderVisibleElements, disableKeyboardA11y, noDragClassName, nodeOrigin, nodeTypes, onNodeClick, onNodeDoubleClick, onNodeContextMenu, onNodeMouseEnter, onNodeMouseMove, onNodeMouseLeave,
1697
- // EdgeRenderer props
1698
- edgeTypes, edgeUpdaterRadius, onEdgeClick, onEdgeDoubleClick, onEdgeContextMenu, onEdgeMouseEnter, onEdgeMouseMove, onEdgeMouseLeave, onEdgeUpdate, onEdgeUpdateStart, onEdgeUpdateEnd,
1699
- // ConnectionLineWrapper
1700
- ConnectionLineContainerStyle, ConnectionLineComponent, }) {
1701
- 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 })] }));
1702
- }
1703
- DiagramView.displayName = 'DiagramView';
1704
- var DiagramView$1 = memo(DiagramView);
1705
-
1706
- const selector = (s) => {
1707
- const { setNodes, setEdges, setNodeExtent, setTranslateExtent, setMinZoom, setMaxZoom, } = s;
1708
- return {
1709
- setNodes,
1710
- setEdges,
1711
- setNodeExtent,
1712
- setTranslateExtent,
1713
- setMinZoom,
1714
- setMaxZoom,
1715
- };
1716
- };
1717
- function useStoreUpdater(value, setStoreState) {
1718
- useEffect(() => {
1719
- if (typeof value !== 'undefined') {
1720
- setStoreState(value);
1721
- }
1722
- }, [value]);
1723
- }
1724
- // updates with values in store that don't have a dedicated setter function
1725
- function useDirectStoreUpdater(key, value, setState) {
1726
- useEffect(() => {
1727
- if (typeof value !== 'undefined') {
1728
- setState({ [key]: value });
1729
- }
1730
- }, [value]);
1731
- }
1732
- const StoreUpdater = ({ nodes, onNodesChange, onNodeDrag, onNodeDragStart, onNodeDragEnd, edges, onEdgesChange, gridStep, elevateNodesOnSelect, nodesDraggable, autoPanOnNodeDrag, autoPanOnConnect, connectionRadius, onConnect, onConnectStart, onConnectEnd, onError, nodeExtent, translateExtent, minZoom, maxZoom, }) => {
1733
- const { setNodes, setEdges, setNodeExtent, setTranslateExtent, setMinZoom, setMaxZoom, } = useStore(selector, shallow);
1734
- const store = useStoreApi();
1735
- useDirectStoreUpdater('gridStep', gridStep, store.setState);
1736
- useStoreUpdater(nodes, setNodes);
1737
- useStoreUpdater(edges, setEdges);
1738
- useStoreUpdater(nodeExtent, setNodeExtent);
1739
- useStoreUpdater(translateExtent, setTranslateExtent);
1740
- useStoreUpdater(minZoom, setMinZoom);
1741
- useStoreUpdater(maxZoom, setMaxZoom);
1742
- useDirectStoreUpdater('elevateNodesOnSelect', elevateNodesOnSelect, store.setState);
1743
- useDirectStoreUpdater('nodesDraggable', nodesDraggable, store.setState);
1744
- useDirectStoreUpdater('autoPanOnNodeDrag', autoPanOnNodeDrag, store.setState);
1745
- useDirectStoreUpdater('autoPanOnConnect', autoPanOnConnect, store.setState);
1746
- useDirectStoreUpdater('connectionRadius', connectionRadius, store.setState);
1747
- useDirectStoreUpdater('onNodesChange', onNodesChange, store.setState);
1748
- useDirectStoreUpdater('onNodeDrag', onNodeDrag, store.setState);
1749
- useDirectStoreUpdater('onNodeDragStart', onNodeDragStart, store.setState);
1750
- useDirectStoreUpdater('onNodeDragEnd', onNodeDragEnd, store.setState);
1751
- useDirectStoreUpdater('onEdgesChange', onEdgesChange, store.setState);
1752
- useDirectStoreUpdater('onConnect', onConnect, store.setState);
1753
- useDirectStoreUpdater('onConnectStart', onConnectStart, store.setState);
1754
- useDirectStoreUpdater('onConnectEnd', onConnectEnd, store.setState);
1755
- useDirectStoreUpdater('onError', onErrorWrapper(onError), store.setState);
1756
- return null;
1757
- };
1758
-
1759
- function useNodeOrEdgeTypes(nodeOrEdgeTypes, createTypes) {
1760
- const typesKeysRef = useRef(null);
1761
- const typesParsed = useMemo(() => {
1762
- if (process.env.NODE_ENV === 'development') {
1763
- const typeKeys = Object.keys(nodeOrEdgeTypes);
1764
- if (shallow(typesKeysRef.current, typeKeys)) {
1765
- devWarn('002');
1766
- }
1767
- typesKeysRef.current = typeKeys;
1768
- }
1769
- return createTypes(nodeOrEdgeTypes);
1770
- }, [nodeOrEdgeTypes]);
1771
- return typesParsed;
1772
- }
1773
-
1774
- const NodeIdContext = createContext(null);
1775
- const Provider = NodeIdContext.Provider;
1776
- NodeIdContext.Consumer;
1777
- const useNodeId = () => {
1778
- const nodeId = useContext(NodeIdContext);
1779
- return nodeId;
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;
1780
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
+ }
1781
1704
 
1782
- function Port({ type, position }) {
1783
- const store = useStoreApi();
1784
- const nodeId = useNodeId();
1785
- if (!nodeId)
1786
- return null;
1787
- const handleOnConnect = (connection) => {
1788
- const { defaultEdgeOptions, onConnect } = store.getState();
1789
- const edgeParams = {
1790
- ...defaultEdgeOptions,
1791
- ...connection,
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 });
1712
+ }
1792
1713
  };
1793
- onConnect?.(edgeParams);
1794
- };
1795
- const onPointerDown = (event) => {
1796
- const isMouseTriggered = isMouseEvent(event);
1797
- if ((isMouseTriggered && event.button === 0) || !isMouseTriggered) {
1714
+ }
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,
1735
+ };
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
+ };
1798
1771
  handlePointerDown({
1772
+ isAnchor: true,
1799
1773
  event,
1800
1774
  nodeId,
1801
- portType: type,
1775
+ portType: fromPortType,
1802
1776
  getState: store.getState,
1803
1777
  setState: store.setState,
1804
- onConnect: handleOnConnect,
1778
+ onConnect: onConnectEdge,
1779
+ onEdgeUpdateEnd: handleEdgeUpdateEnd,
1805
1780
  });
1806
- }
1807
- };
1808
- 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 }));
1809
- }
1810
- Port.displayName = 'Port';
1811
- var Port$1 = memo(Port);
1812
-
1813
- function Nodes({ data }) {
1814
- return (jsxs(Fragment, { children: [jsx(Port$1, { type: "target", position: Position.Top }), data.label, jsx(Port$1, { type: "source", position: Position.Bottom })] }));
1815
- }
1816
-
1817
- function useGetPointerPosition() {
1818
- const store = useStoreApi();
1819
- // returns the pointer position projected to the RF coordinate system
1820
- const getPointerPosition = useCallback(({ sourceEvent }) => {
1821
- const { transform, gridStep } = store.getState();
1822
- const x = sourceEvent.touches
1823
- ? sourceEvent.touches[0].clientX
1824
- : sourceEvent.clientX;
1825
- const y = sourceEvent.touches
1826
- ? sourceEvent.touches[0].clientY
1827
- : sourceEvent.clientY;
1828
- const pointerPos = {
1829
- x: (x - transform[0]) / transform[2],
1830
- y: (y - transform[1]) / transform[2],
1831
1781
  };
1832
- // we need the snapped position in order to be able to skip unnecessary drag events
1833
- return {
1834
- xSnapped: gridStep
1835
- ? gridStep[0] * Math.round(pointerPos.x / gridStep[0])
1836
- : pointerPos.x,
1837
- ySnapped: gridStep
1838
- ? gridStep[1] * Math.round(pointerPos.y / gridStep[1])
1839
- : pointerPos.y,
1840
- ...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
+ }
1841
1788
  };
1842
- }, []);
1843
- return getPointerPosition;
1844
- }
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
+ };
1845
1833
 
1846
- const getPortBounds = (selector, nodeElement, zoom, nodeOrigin) => {
1847
- const ports = nodeElement.querySelectorAll(selector);
1848
- if (!ports || !ports.length) {
1849
- return null;
1850
- }
1851
- const portsArray = Array.from(ports);
1852
- const nodeBounds = nodeElement.getBoundingClientRect();
1853
- const nodeOffset = {
1854
- x: nodeBounds.width * nodeOrigin[0],
1855
- y: nodeBounds.height * nodeOrigin[1],
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,
1856
1850
  };
1857
- return portsArray.map((port) => {
1858
- const portBounds = port.getBoundingClientRect();
1859
- return {
1860
- id: port.getAttribute('data-portid'),
1861
- position: port.dataset.portPosition,
1862
- x: (portBounds.left - nodeBounds.left - nodeOffset.x) / zoom,
1863
- y: (portBounds.top - nodeBounds.top - nodeOffset.y) / zoom,
1864
- ...getDimensions(port),
1865
- };
1866
- });
1867
1851
  };
1868
- function getMouseHandler(id, getState, handler) {
1869
- return handler === undefined
1870
- ? handler
1871
- : (event) => {
1872
- const node = getState().nodeInternals.get(id);
1873
- handler(event, { ...node });
1874
- };
1875
- }
1876
- function handleNodeClick({ id, store, isSelectable, unselect = false, nodeRef, }) {
1877
- if (!isSelectable)
1878
- return;
1879
- const { addSelectedNodes, unselectNodes, multiSelectionActive, nodeInternals, } = store.getState();
1880
- const node = nodeInternals.get(id);
1881
- store.setState({ nodesSelectionActive: false });
1882
- if (!node.selected) {
1883
- addSelectedNodes([id]);
1884
- }
1885
- else if (unselect || (node.selected && multiSelectionActive)) {
1886
- unselectNodes({ nodes: [node] });
1887
- requestAnimationFrame(() => nodeRef?.current?.blur());
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
+ };
1888
1878
  }
1889
1879
  }
1890
-
1891
- function isParentSelected(node, nodeInternals) {
1892
- if (!node.parentNode) {
1893
- return false;
1880
+ function getPort(bounds, portId) {
1881
+ if (!bounds) {
1882
+ return null;
1894
1883
  }
1895
- const parentNode = nodeInternals.get(node.parentNode);
1896
- if (!parentNode) {
1897
- return false;
1884
+ if (bounds.length === 1 || !portId) {
1885
+ return bounds[0];
1898
1886
  }
1899
- if (parentNode.selected) {
1900
- return true;
1887
+ else if (portId) {
1888
+ return bounds.find((d) => d.id === portId) || null;
1901
1889
  }
1902
- return isParentSelected(parentNode, nodeInternals);
1890
+ return null;
1903
1891
  }
1904
- function getDragItems(nodeInternals, nodesDraggable, mousePosition, nodeId) {
1905
- return Array.from(nodeInternals.values())
1906
- .filter((n) => (n.selected || n.id === nodeId) &&
1907
- (!n.parentNode || !isParentSelected(n, nodeInternals)) &&
1908
- (n.draggable ||
1909
- (nodesDraggable && typeof n.draggable === 'undefined')))
1910
- .map((n) => ({
1911
- id: n.id,
1912
- position: n.position || { x: 0, y: 0 },
1913
- positionAbsolute: n.positionAbsolute || { x: 0, y: 0 },
1914
- distance: {
1915
- x: mousePosition.x - (n.positionAbsolute?.x ?? 0),
1916
- y: mousePosition.y - (n.positionAbsolute?.y ?? 0),
1917
- },
1918
- delta: {
1919
- x: 0,
1920
- y: 0,
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,
1900
+ };
1901
+ };
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,
1921
1915
  },
1922
- extent: n.extent,
1923
- parentNode: n.parentNode,
1924
- width: n.width,
1925
- height: n.height,
1926
- }));
1916
+ portBounds,
1917
+ !!isValid,
1918
+ ];
1927
1919
  }
1928
- function calcNextPosition(node, nextPosition, nodeInternals, nodeExtent, nodeOrigin = [0, 0], onError) {
1929
- let currentExtent = node.extent || nodeExtent;
1930
- if (node.extent === 'parent') {
1931
- if (node.parentNode && node.width && node.height) {
1932
- const parent = nodeInternals.get(node.parentNode);
1933
- const { x: parentX, y: parentY } = getNodePositionWithOrigin(parent, nodeOrigin).positionAbsolute;
1934
- currentExtent =
1935
- parent &&
1936
- isNumeric(parentX) &&
1937
- isNumeric(parentY) &&
1938
- isNumeric(parent.width) &&
1939
- isNumeric(parent.height)
1940
- ? [
1941
- [
1942
- parentX + node.width * nodeOrigin[0],
1943
- parentY + node.height * nodeOrigin[1],
1944
- ],
1945
- [
1946
- parentX +
1947
- parent.width -
1948
- node.width +
1949
- node.width * nodeOrigin[0],
1950
- parentY +
1951
- parent.height -
1952
- node.height +
1953
- node.height * nodeOrigin[1],
1954
- ],
1955
- ]
1956
- : currentExtent;
1957
- }
1958
- else {
1959
- onError?.('011');
1960
- currentExtent = nodeExtent;
1961
- }
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
+ }) })] }));
1999
+ }
2000
+ EdgeRenderer.displayName = 'EdgeRenderer';
2001
+ var EdgeRenderer$1 = memo(EdgeRenderer);
2002
+
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;
1962
2019
  }
1963
- else if (node.extent && node.parentNode) {
1964
- const parent = nodeInternals.get(node.parentNode);
1965
- const { x: parentX, y: parentY } = getNodePositionWithOrigin(parent, nodeOrigin).positionAbsolute;
1966
- currentExtent = [
1967
- [node.extent[0][0] + parentX, node.extent[0][1] + parentY],
1968
- [node.extent[1][0] + parentX, node.extent[1][1] + parentY],
1969
- ];
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;
1970
2033
  }
1971
- let parentPosition = { x: 0, y: 0 };
1972
- if (node.parentNode) {
1973
- const parentNode = nodeInternals.get(node.parentNode);
1974
- parentPosition = getNodePositionWithOrigin(parentNode, nodeOrigin).positionAbsolute;
2034
+ if (Component) {
2035
+ return (jsx(Component, { fromNode: fromNode, fromPort: fromPort, fromX: fromX, fromY: fromY, toX: toX, toY: toY, fromPosition: fromPosition, toPosition: toPosition }));
1975
2036
  }
1976
- const positionAbsolute = currentExtent
1977
- ? clampPosition(nextPosition, currentExtent)
1978
- : nextPosition;
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 }));
2038
+ }
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;
2051
+ }
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;
1979
2077
  return {
1980
- position: {
1981
- x: positionAbsolute.x - parentPosition.x,
1982
- y: positionAbsolute.y - parentPosition.y,
1983
- },
1984
- positionAbsolute,
2078
+ setNodes,
2079
+ setEdges,
2080
+ setNodeExtent,
2081
+ setTranslateExtent,
2082
+ setMinZoom,
2083
+ setMaxZoom,
1985
2084
  };
2085
+ };
2086
+ function useStoreUpdater(value, setStoreState) {
2087
+ useEffect(() => {
2088
+ if (typeof value !== 'undefined') {
2089
+ setStoreState(value);
2090
+ }
2091
+ }, [value]);
1986
2092
  }
1987
- function getEventHandlerParams({ nodeId, dragItems, nodeInternals, }) {
1988
- const extentedDragItems = dragItems.map((n) => {
1989
- const node = nodeInternals.get(n.id);
1990
- return {
1991
- ...node,
1992
- position: n.position,
1993
- positionAbsolute: n.positionAbsolute,
1994
- };
1995
- });
1996
- return [
1997
- nodeId
1998
- ? extentedDragItems.find((n) => n.id === nodeId)
1999
- : extentedDragItems[0],
2000
- extentedDragItems,
2001
- ];
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]);
2002
2100
  }
2003
- function hasSelector(target, selector, nodeRef) {
2004
- let current = target;
2005
- do {
2006
- if (current?.matches(selector))
2007
- return true;
2008
- if (current === nodeRef.current)
2009
- return false;
2010
- current = current.parentElement;
2011
- } while (current);
2012
- 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;
2013
2143
  }
2014
2144
 
2015
- 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 }) {
2016
2154
  const store = useStoreApi();
2017
- const dragItems = useRef([]);
2018
- const containerBounds = useRef(null);
2019
- const mousePosition = useRef({ x: 0, y: 0 });
2020
- const lastPosition = useRef({
2021
- x: null,
2022
- y: null,
2023
- });
2024
- const dragEvent = useRef(null);
2025
- const autoPanStarted = useRef(false);
2026
- const autoPanId = useRef(0);
2027
- const [dragging, setDragging] = useState(false);
2028
- const getPointerPosition = useGetPointerPosition();
2029
- useEffect(() => {
2030
- if (nodeRef?.current) {
2031
- const selection = select(nodeRef.current);
2032
- const updateNodes = ({ x, y }) => {
2033
- const { nodeInternals, onNodeDrag, updateNodePositions, nodeExtent, nodeOrigin, gridStep, onError, } = store.getState();
2034
- lastPosition.current = { x, y };
2035
- let hasChange = false;
2036
- dragItems.current = dragItems.current.map((n) => {
2037
- const nextPosition = {
2038
- x: x - n.distance.x,
2039
- y: y - n.distance.y,
2040
- };
2041
- if (gridStep) {
2042
- nextPosition.x =
2043
- gridStep[0] * Math.round(nextPosition.x / gridStep[0]);
2044
- nextPosition.y =
2045
- gridStep[1] * Math.round(nextPosition.y / gridStep[1]);
2046
- }
2047
- const updatedPos = calcNextPosition(n, nextPosition, nodeInternals, nodeExtent, nodeOrigin, onError);
2048
- // we want to make sure that we only fire a change event when there is a changes
2049
- hasChange =
2050
- hasChange ||
2051
- n.position.x !== updatedPos.position.x ||
2052
- n.position.y !== updatedPos.position.y;
2053
- n.position = updatedPos.position;
2054
- n.positionAbsolute = updatedPos.positionAbsolute;
2055
- return n;
2056
- });
2057
- if (!hasChange) {
2058
- return;
2059
- }
2060
- updateNodePositions(dragItems.current, true, true);
2061
- setDragging(true);
2062
- if (onNodeDrag && dragEvent.current) {
2063
- const [currentNode, nodes] = getEventHandlerParams({
2064
- nodeId,
2065
- dragItems: dragItems.current,
2066
- nodeInternals,
2067
- });
2068
- onNodeDrag(dragEvent.current, currentNode, nodes);
2069
- }
2070
- };
2071
- const autoPan = () => {
2072
- if (!containerBounds.current) {
2073
- return;
2074
- }
2075
- const [xMovement, yMovement] = calcAutoPanPosition(mousePosition.current, containerBounds.current);
2076
- if (xMovement !== 0 || yMovement !== 0) {
2077
- const { transform, panBy } = store.getState();
2078
- lastPosition.current.x =
2079
- (lastPosition.current.x ?? 0) - xMovement / transform[2];
2080
- lastPosition.current.y =
2081
- (lastPosition.current.y ?? 0) - yMovement / transform[2];
2082
- updateNodes(lastPosition.current);
2083
- panBy({ x: xMovement, y: yMovement });
2084
- }
2085
- autoPanId.current = requestAnimationFrame(autoPan);
2086
- };
2087
- const dragHandle = drag()
2088
- .on('start', (e) => {
2089
- // only allow left click
2090
- if (e.sourceEvent.which !== 1)
2091
- return;
2092
- const { nodeInternals, nodesDraggable, domNode, onNodeDragStart, } = store.getState();
2093
- if (nodeId) {
2094
- handleNodeClick({
2095
- id: nodeId,
2096
- store,
2097
- nodeRef: nodeRef,
2098
- isSelectable,
2099
- });
2100
- }
2101
- const pointerPosition = getPointerPosition(e);
2102
- dragItems.current = getDragItems(nodeInternals, nodesDraggable, pointerPosition, nodeId);
2103
- if (onNodeDragStart && dragItems.current) {
2104
- const [currentNode, nodes] = getEventHandlerParams({
2105
- nodeId,
2106
- dragItems: dragItems.current,
2107
- nodeInternals,
2108
- });
2109
- onNodeDragStart(e.sourceEvent, currentNode, nodes);
2110
- }
2111
- containerBounds.current =
2112
- domNode?.getBoundingClientRect() || null;
2113
- mousePosition.current = getEventPosition(e.sourceEvent, containerBounds.current);
2114
- })
2115
- .on('drag', (e) => {
2116
- const pointerPosition = getPointerPosition(e);
2117
- const { autoPanOnNodeDrag } = store.getState();
2118
- if (!autoPanStarted.current && autoPanOnNodeDrag) {
2119
- autoPanStarted.current = true;
2120
- autoPan();
2121
- }
2122
- if ((lastPosition.current.x !== pointerPosition.xSnapped ||
2123
- lastPosition.current.y !== pointerPosition.ySnapped) &&
2124
- dragItems.current) {
2125
- dragEvent.current = e.sourceEvent;
2126
- mousePosition.current = getEventPosition(e.sourceEvent, containerBounds.current);
2127
- updateNodes(pointerPosition);
2128
- }
2129
- })
2130
- .on('end', (event) => {
2131
- setDragging(false);
2132
- autoPanStarted.current = false;
2133
- cancelAnimationFrame(autoPanId.current);
2134
- if (dragItems.current) {
2135
- const { nodeInternals, updateNodePositions, onNodeDragEnd } = store.getState();
2136
- updateNodePositions(dragItems.current, false, false);
2137
- if (onNodeDragEnd) {
2138
- const [currentNode, nodes] = getEventHandlerParams({
2139
- nodeId,
2140
- dragItems: dragItems.current,
2141
- nodeInternals,
2142
- });
2143
- onNodeDragEnd(event.sourceEvent, currentNode, nodes);
2144
- }
2145
- }
2146
- })
2147
- .filter((event) => {
2148
- const target = event.target;
2149
- const isDraggable = (!event.button && !noDragClassName) ||
2150
- !hasSelector(target, `.${noDragClassName}`, nodeRef);
2151
- 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,
2152
2176
  });
2153
- selection.call(dragHandle);
2154
- return () => {
2155
- selection.on('.drag', null);
2156
- };
2157
2177
  }
2158
- }, [store, nodeRef, nodeId, isSelectable, noDragClassName]);
2159
- 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 })] }));
2160
2186
  }
2161
2187
 
2162
2188
  const wrapNode = (NodeComponent) => {
@@ -2241,11 +2267,11 @@ const wrapNode = (NodeComponent) => {
2241
2267
  };
2242
2268
  const events = {
2243
2269
  onClick: onSelectNodeHandler,
2244
- onDoubleClick: getMouseHandler(id, store.getState, onDoubleClick),
2245
- onContextMenu: getMouseHandler(id, store.getState, onContextMenu),
2246
- onMouseEnter: getMouseHandler(id, store.getState, onMouseEnter),
2247
- onMouseMove: getMouseHandler(id, store.getState, onMouseMove),
2248
- 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),
2249
2275
  };
2250
2276
  const position = {
2251
2277
  positionX,
@@ -2366,11 +2392,13 @@ const initialState = {
2366
2392
  onNodesChange: null,
2367
2393
  domNode: null,
2368
2394
  nodeOrigin: [0, 0],
2395
+ smoothStep: false,
2396
+ centerStep: false,
2369
2397
  gridStep: undefined,
2370
- nodesSelectionActive: false,
2371
2398
  elevateNodesOnSelect: true,
2372
2399
  nodesDraggable: true,
2373
2400
  multiSelectionActive: false,
2401
+ selectionBoxActive: false,
2374
2402
  d3Zoom: null,
2375
2403
  d3Selection: null,
2376
2404
  minZoom: 0.5,
@@ -2445,17 +2473,21 @@ const createRFStore = () => createStore((set, get) => ({
2445
2473
  onNodesChange?.(changes);
2446
2474
  }
2447
2475
  },
2448
- updateNodePositions: (nodeDragItems, positionChanged = true, dragging = false) => {
2476
+ updateNodesPosition: (nodes, dragging = false, updateFunc) => {
2449
2477
  const { triggerNodeChanges } = get();
2450
- const changes = nodeDragItems.map((node) => {
2478
+ const changes = nodes.map((node) => {
2451
2479
  const change = {
2452
2480
  id: node.id,
2453
2481
  type: 'position',
2454
2482
  dragging,
2455
2483
  };
2456
- if (positionChanged) {
2457
- change.positionAbsolute = node.positionAbsolute;
2458
- change.position = node.position;
2484
+ if (updateFunc) {
2485
+ updateFunc(node);
2486
+ return {
2487
+ ...change,
2488
+ position: node.position,
2489
+ positionAbsolute: node.positionAbsolute,
2490
+ };
2459
2491
  }
2460
2492
  return change;
2461
2493
  });
@@ -2578,15 +2610,15 @@ const defaultNodeTypes = {
2578
2610
  const defaultEdgeTypes = {
2579
2611
  step: StepEdge,
2580
2612
  };
2581
- const ReactDiagram = forwardRef(({ id,
2613
+ const ReactDiagram = forwardRef(({ children, id,
2582
2614
  // DiagramView props
2583
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,
2584
2616
  // StoreUpdater props
2585
- nodes, edges, nodesDraggable, elevateNodesOnSelect, autoPanOnNodeDrag, autoPanOnConnect, connectionRadius, 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) => {
2586
2618
  const rfId = id || '1';
2587
2619
  const nodeTypesWrapped = useNodeOrEdgeTypes(nodeTypes, createNodeTypes);
2588
2620
  const edgeTypesWrapped = useNodeOrEdgeTypes(edgeTypes, createEdgeTypes);
2589
- 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, 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] }) }));
2590
2622
  });
2591
2623
  ReactDiagram.displayName = 'ReactDiagram';
2592
2624
 
@@ -2600,4 +2632,35 @@ function createUseItemsState(applyChanges) {
2600
2632
  const useNodesState = createUseItemsState(applyNodeChanges);
2601
2633
  const useEdgesState = createUseItemsState(applyEdgeChanges);
2602
2634
 
2603
- export { 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 };
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 };