@excalidraw/element 0.18.0-54a9826 → 0.18.0-60b2758

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 (72) hide show
  1. package/dist/dev/index.js +393 -177
  2. package/dist/dev/index.js.map +3 -3
  3. package/dist/prod/index.js +12 -12
  4. package/dist/types/common/debug.d.ts +21 -0
  5. package/dist/types/common/src/colors.d.ts +1 -1
  6. package/dist/types/common/src/constants.d.ts +1 -0
  7. package/dist/types/common/src/index.d.ts +1 -0
  8. package/dist/types/common/src/utils.d.ts +3 -4
  9. package/dist/types/element/src/arrows/focus.d.ts +1 -1
  10. package/dist/types/element/src/binding.d.ts +6 -5
  11. package/dist/types/element/src/types.d.ts +1 -1
  12. package/dist/types/element/src/utils.d.ts +5 -3
  13. package/dist/types/excalidraw/actions/actionAddToLibrary.d.ts +24 -27
  14. package/dist/types/excalidraw/actions/actionBoundText.d.ts +16 -18
  15. package/dist/types/excalidraw/actions/actionCanvas.d.ts +97 -109
  16. package/dist/types/excalidraw/actions/actionClipboard.d.ts +16 -18
  17. package/dist/types/excalidraw/actions/actionCropEditor.d.ts +8 -9
  18. package/dist/types/excalidraw/actions/actionDeleteSelected.d.ts +24 -27
  19. package/dist/types/excalidraw/actions/actionElementLink.d.ts +4 -9
  20. package/dist/types/excalidraw/actions/actionElementLock.d.ts +16 -18
  21. package/dist/types/excalidraw/actions/actionEmbeddable.d.ts +8 -9
  22. package/dist/types/excalidraw/actions/actionExport.d.ts +34 -42
  23. package/dist/types/excalidraw/actions/actionFrame.d.ts +32 -36
  24. package/dist/types/excalidraw/actions/actionGroup.d.ts +16 -18
  25. package/dist/types/excalidraw/actions/actionLinearEditor.d.ts +8 -9
  26. package/dist/types/excalidraw/actions/actionLink.d.ts +8 -9
  27. package/dist/types/excalidraw/actions/actionMenu.d.ts +4 -9
  28. package/dist/types/excalidraw/actions/actionProperties.d.ts +16 -18
  29. package/dist/types/excalidraw/actions/actionSelectAll.d.ts +8 -9
  30. package/dist/types/excalidraw/actions/actionStyles.d.ts +8 -9
  31. package/dist/types/excalidraw/actions/actionToggleGridMode.d.ts +8 -9
  32. package/dist/types/excalidraw/actions/actionToggleObjectsSnapMode.d.ts +8 -9
  33. package/dist/types/excalidraw/actions/actionToggleSearchMenu.d.ts +4 -9
  34. package/dist/types/excalidraw/actions/actionToggleStats.d.ts +8 -9
  35. package/dist/types/excalidraw/actions/actionToggleViewMode.d.ts +8 -9
  36. package/dist/types/excalidraw/actions/actionToggleZenMode.d.ts +8 -9
  37. package/dist/types/excalidraw/actions/shortcuts.d.ts +1 -1
  38. package/dist/types/excalidraw/appState.d.ts +6 -7
  39. package/dist/types/excalidraw/charts/charts.bar.d.ts +2 -0
  40. package/dist/types/excalidraw/charts/charts.constants.d.ts +48 -0
  41. package/dist/types/excalidraw/charts/charts.helpers.d.ts +32 -0
  42. package/dist/types/excalidraw/charts/charts.line.d.ts +2 -0
  43. package/dist/types/excalidraw/charts/charts.parse.d.ts +10 -0
  44. package/dist/types/excalidraw/charts/charts.radar.d.ts +2 -0
  45. package/dist/types/excalidraw/charts/charts.types.d.ts +18 -0
  46. package/dist/types/excalidraw/charts/index.d.ts +7 -0
  47. package/dist/types/excalidraw/clipboard.d.ts +0 -2
  48. package/dist/types/excalidraw/components/App.d.ts +4 -2
  49. package/dist/types/excalidraw/components/CommandPalette/types.d.ts +1 -1
  50. package/dist/types/excalidraw/components/PasteChartDialog.d.ts +4 -5
  51. package/dist/types/excalidraw/components/PropertiesPopover.d.ts +1 -1
  52. package/dist/types/excalidraw/components/dropdownMenu/DropdownMenu.d.ts +30 -17
  53. package/dist/types/excalidraw/components/dropdownMenu/DropdownMenuContent.d.ts +3 -2
  54. package/dist/types/excalidraw/components/dropdownMenu/DropdownMenuItem.d.ts +11 -13
  55. package/dist/types/excalidraw/components/dropdownMenu/DropdownMenuItemCheckbox.d.ts +5 -0
  56. package/dist/types/excalidraw/components/dropdownMenu/DropdownMenuSub.d.ts +23 -0
  57. package/dist/types/excalidraw/components/dropdownMenu/DropdownMenuSubContent.d.ts +8 -0
  58. package/dist/types/excalidraw/components/dropdownMenu/DropdownMenuSubTrigger.d.ts +12 -0
  59. package/dist/types/excalidraw/components/dropdownMenu/common.d.ts +1 -1
  60. package/dist/types/excalidraw/components/dropdownMenu/dropdownMenuUtils.d.ts +2 -0
  61. package/dist/types/excalidraw/components/icons.d.ts +6 -1
  62. package/dist/types/excalidraw/components/main-menu/DefaultItems.d.ts +15 -0
  63. package/dist/types/excalidraw/components/main-menu/MainMenu.d.ts +23 -13
  64. package/dist/types/excalidraw/components/shapes.d.ts +74 -1
  65. package/dist/types/excalidraw/data/blob.d.ts +28 -30
  66. package/dist/types/excalidraw/data/json.d.ts +14 -15
  67. package/dist/types/excalidraw/index.d.ts +1 -0
  68. package/dist/types/excalidraw/types.d.ts +13 -10
  69. package/dist/types/math/src/point.d.ts +6 -1
  70. package/dist/types/math/src/types.d.ts +25 -1
  71. package/package.json +3 -3
  72. package/dist/types/excalidraw/charts.d.ts +0 -27
package/dist/dev/index.js CHANGED
@@ -2267,7 +2267,7 @@ import {
2267
2267
  } from "@excalidraw/common";
2268
2268
  import {
2269
2269
  degreesToRadians,
2270
- lineSegment as lineSegment7,
2270
+ lineSegment as lineSegment6,
2271
2271
  pointDistance as pointDistance7,
2272
2272
  pointFrom as pointFrom14,
2273
2273
  pointFromArray as pointFromArray3,
@@ -2631,7 +2631,7 @@ import {
2631
2631
  init_define_import_meta_env();
2632
2632
  import {
2633
2633
  isRightAngleRads,
2634
- lineSegment as lineSegment6,
2634
+ lineSegment as lineSegment5,
2635
2635
  pointFrom as pointFrom12,
2636
2636
  pointRotateRads as pointRotateRads11
2637
2637
  } from "@excalidraw/math";
@@ -3120,8 +3120,7 @@ import {
3120
3120
  pointDistance as pointDistance5,
3121
3121
  vectorFromPoint as vectorFromPoint8,
3122
3122
  curveLength,
3123
- curvePointAtLength,
3124
- lineSegment as lineSegment5
3123
+ curvePointAtLength
3125
3124
  } from "@excalidraw/math";
3126
3125
  import {
3127
3126
  DRAGGING_THRESHOLD,
@@ -3134,6 +3133,7 @@ import {
3134
3133
  } from "@excalidraw/common";
3135
3134
  import {
3136
3135
  deconstructLinearOrFreeDrawElement as deconstructLinearOrFreeDrawElement2,
3136
+ getSnapOutlineMidPoint as getSnapOutlineMidPoint2,
3137
3137
  isPathALoop as isPathALoop2,
3138
3138
  moveArrowAboveBindable,
3139
3139
  projectFixedPointOntoDiagonal as projectFixedPointOntoDiagonal2
@@ -3194,6 +3194,7 @@ import {
3194
3194
  ROUNDNESS as ROUNDNESS2
3195
3195
  } from "@excalidraw/common";
3196
3196
  import {
3197
+ bezierEquation,
3197
3198
  curve as curve3,
3198
3199
  curveCatmullRomCubicApproxPoints,
3199
3200
  curveOffsetPoints,
@@ -3591,11 +3592,7 @@ function deconstructRectanguloidElement(element, offset = 0) {
3591
3592
  setElementShapesCacheEntry(element, shape, offset);
3592
3593
  return shape;
3593
3594
  }
3594
- function deconstructDiamondElement(element, offset = 0) {
3595
- const cachedShape = getElementShapesCacheEntry(element, offset);
3596
- if (cachedShape) {
3597
- return cachedShape;
3598
- }
3595
+ function getDiamondBaseCorners(element, offset = 0) {
3599
3596
  const [topX, topY, rightX, rightY, bottomX, bottomY, leftX, leftY] = getDiamondPoints(element);
3600
3597
  const verticalRadius = element.roundness ? getCornerRadius(Math.abs(topX - leftX), element) : (topX - leftX) * 0.01;
3601
3598
  const horizontalRadius = element.roundness ? getCornerRadius(Math.abs(rightY - topY), element) : (rightY - topY) * 0.01;
@@ -3605,7 +3602,7 @@ function deconstructDiamondElement(element, offset = 0) {
3605
3602
  pointFrom3(element.x + bottomX, element.y + bottomY),
3606
3603
  pointFrom3(element.x + leftX, element.y + leftY)
3607
3604
  ];
3608
- const baseCorners = [
3605
+ return [
3609
3606
  curve3(
3610
3607
  pointFrom3(
3611
3608
  right[0] - verticalRadius,
@@ -3659,6 +3656,13 @@ function deconstructDiamondElement(element, offset = 0) {
3659
3656
  )
3660
3657
  // TOP
3661
3658
  ];
3659
+ }
3660
+ function deconstructDiamondElement(element, offset = 0) {
3661
+ const cachedShape = getElementShapesCacheEntry(element, offset);
3662
+ if (cachedShape) {
3663
+ return cachedShape;
3664
+ }
3665
+ const baseCorners = getDiamondBaseCorners(element, offset);
3662
3666
  const corners = baseCorners.map(
3663
3667
  (corner) => curveCatmullRomCubicApproxPoints(curveOffsetPoints(corner, offset))
3664
3668
  );
@@ -3778,20 +3782,90 @@ var getDiagonalsForBindableElement = (element, elementsMap) => {
3778
3782
  );
3779
3783
  return [diagonalOne, diagonalTwo];
3780
3784
  };
3781
- var projectFixedPointOntoDiagonal = (arrow, point, element, startOrEnd, elementsMap) => {
3785
+ var getSnapOutlineMidPoint = (point, element, elementsMap, zoom) => {
3786
+ const center = elementCenterPoint(element, elementsMap);
3787
+ const sideMidpoints = element.type === "diamond" ? getDiamondBaseCorners(element).map((curve4) => {
3788
+ const point2 = bezierEquation(curve4, 0.5);
3789
+ const rotatedPoint = pointRotateRads3(point2, center, element.angle);
3790
+ return pointFrom3(rotatedPoint[0], rotatedPoint[1]);
3791
+ }) : [
3792
+ // RIGHT midpoint
3793
+ pointRotateRads3(
3794
+ pointFrom3(
3795
+ element.x + element.width,
3796
+ element.y + element.height / 2
3797
+ ),
3798
+ center,
3799
+ element.angle
3800
+ ),
3801
+ // BOTTOM midpoint
3802
+ pointRotateRads3(
3803
+ pointFrom3(
3804
+ element.x + element.width / 2,
3805
+ element.y + element.height
3806
+ ),
3807
+ center,
3808
+ element.angle
3809
+ ),
3810
+ // LEFT midpoint
3811
+ pointRotateRads3(
3812
+ pointFrom3(element.x, element.y + element.height / 2),
3813
+ center,
3814
+ element.angle
3815
+ ),
3816
+ // TOP midpoint
3817
+ pointRotateRads3(
3818
+ pointFrom3(element.x + element.width / 2, element.y),
3819
+ center,
3820
+ element.angle
3821
+ )
3822
+ ];
3823
+ const candidate = sideMidpoints.find(
3824
+ (midpoint2) => pointDistance2(point, midpoint2) <= maxBindingDistance_simple(zoom) + element.strokeWidth / 2 && !hitElementItself({
3825
+ point,
3826
+ element,
3827
+ threshold: 0,
3828
+ elementsMap,
3829
+ overrideShouldTestInside: true
3830
+ })
3831
+ );
3832
+ return candidate;
3833
+ };
3834
+ var projectFixedPointOntoDiagonal = (arrow, point, element, startOrEnd, elementsMap, zoom) => {
3782
3835
  invariant2(arrow.points.length >= 2, "Arrow must have at least two points");
3783
3836
  if (arrow.width < 3 && arrow.height < 3) {
3784
3837
  return null;
3785
3838
  }
3839
+ const sideMidPoint = getSnapOutlineMidPoint(
3840
+ point,
3841
+ element,
3842
+ elementsMap,
3843
+ zoom
3844
+ );
3845
+ if (sideMidPoint) {
3846
+ return sideMidPoint;
3847
+ }
3786
3848
  const [diagonalOne, diagonalTwo] = getDiagonalsForBindableElement(
3787
3849
  element,
3788
3850
  elementsMap
3789
3851
  );
3790
- const a2 = LinearElementEditor.getPointAtIndexGlobalCoordinates(
3852
+ let a2 = LinearElementEditor.getPointAtIndexGlobalCoordinates(
3791
3853
  arrow,
3792
3854
  startOrEnd === "start" ? 1 : arrow.points.length - 2,
3793
3855
  elementsMap
3794
3856
  );
3857
+ if (arrow.points.length === 2) {
3858
+ const otherBinding = startOrEnd === "start" ? arrow.endBinding : arrow.startBinding;
3859
+ const otherBindable = otherBinding && elementsMap.get(otherBinding.elementId);
3860
+ const otherFocusPoint = otherBinding && otherBindable && getGlobalFixedPointForBindableElement(
3861
+ normalizeFixedPoint(otherBinding.fixedPoint),
3862
+ otherBindable,
3863
+ elementsMap
3864
+ );
3865
+ if (otherFocusPoint) {
3866
+ a2 = otherFocusPoint;
3867
+ }
3868
+ }
3795
3869
  const b2 = pointFromVector3(
3796
3870
  vectorScale3(
3797
3871
  vectorFromPoint3(point, a2),
@@ -3802,18 +3876,21 @@ var projectFixedPointOntoDiagonal = (arrow, point, element, startOrEnd, elements
3802
3876
  ),
3803
3877
  a2
3804
3878
  );
3805
- const intersector = lineSegment2(point, b2);
3879
+ const intersector = lineSegment2(b2, a2);
3806
3880
  const p1 = lineSegmentIntersectionPoints(diagonalOne, intersector);
3807
3881
  const p2 = lineSegmentIntersectionPoints(diagonalTwo, intersector);
3808
3882
  const d1 = p1 && pointDistance2(a2, p1);
3809
3883
  const d2 = p2 && pointDistance2(a2, p2);
3810
- let p = null;
3884
+ let projection = null;
3811
3885
  if (d1 != null && d2 != null) {
3812
- p = d1 < d2 ? p1 : p2;
3886
+ projection = d1 < d2 ? p1 : p2;
3813
3887
  } else {
3814
- p = p1 || p2 || null;
3888
+ projection = p1 || p2 || null;
3889
+ }
3890
+ if (projection && isPointInElement(projection, element, elementsMap)) {
3891
+ return projection;
3815
3892
  }
3816
- return p && isPointInElement(p, element, elementsMap) ? p : null;
3893
+ return null;
3817
3894
  };
3818
3895
 
3819
3896
  // src/textElement.ts
@@ -6984,8 +7061,9 @@ var bumpVersion = (element, version) => {
6984
7061
  };
6985
7062
 
6986
7063
  // src/binding.ts
6987
- var BASE_BINDING_GAP = 10;
7064
+ var BASE_BINDING_GAP = 5;
6988
7065
  var BASE_BINDING_GAP_ELBOW = 5;
7066
+ var BASE_ARROW_MIN_LENGTH = 10;
6989
7067
  var FOCUS_POINT_SIZE = 10 / 1.5;
6990
7068
  var getBindingGap = (bindTarget, opts) => {
6991
7069
  return (opts.elbowed ? BASE_BINDING_GAP_ELBOW : BASE_BINDING_GAP) + bindTarget.strokeWidth / 2;
@@ -7408,7 +7486,8 @@ var getBindingStrategyForDraggingBindingElementEndpoints_simple = (arrow, draggi
7408
7486
  globalPoint,
7409
7487
  hit,
7410
7488
  startDragged ? "start" : "end",
7411
- elementsMap
7489
+ elementsMap,
7490
+ appState.zoom
7412
7491
  ) || globalPoint
7413
7492
  } : { mode: null };
7414
7493
  const otherEndpoint = LinearElementEditor.getPointAtIndexGlobalCoordinates(
@@ -7416,7 +7495,15 @@ var getBindingStrategyForDraggingBindingElementEndpoints_simple = (arrow, draggi
7416
7495
  startDragged ? -1 : 0,
7417
7496
  elementsMap
7418
7497
  );
7419
- const other = otherBindableElement && !otherFocusPointIsInElement && appState.selectedLinearElement?.initialState.altFocusPoint ? {
7498
+ const pointIsCloseToOtherElement = otherFocusPoint && otherBindableElement && hitElementItself({
7499
+ point: globalPoint,
7500
+ element: otherBindableElement,
7501
+ elementsMap,
7502
+ threshold: maxBindingDistance_simple(appState.zoom),
7503
+ overrideShouldTestInside: true
7504
+ });
7505
+ const otherNeverOverride = opts?.newArrow ? appState.selectedLinearElement?.initialState.arrowStartIsInside : otherBinding?.mode === "inside";
7506
+ const other = !otherNeverOverride ? otherBindableElement && !otherFocusPointIsInElement && !pointIsCloseToOtherElement && appState.selectedLinearElement?.initialState.altFocusPoint ? {
7420
7507
  mode: "orbit",
7421
7508
  element: otherBindableElement,
7422
7509
  focusPoint: appState.selectedLinearElement.initialState.altFocusPoint
@@ -7428,9 +7515,10 @@ var getBindingStrategyForDraggingBindingElementEndpoints_simple = (arrow, draggi
7428
7515
  otherEndpoint,
7429
7516
  otherBindableElement,
7430
7517
  startDragged ? "end" : "start",
7431
- elementsMap
7518
+ elementsMap,
7519
+ appState.zoom
7432
7520
  ) || otherEndpoint
7433
- } : { mode: void 0 };
7521
+ } : { mode: void 0 } : { mode: void 0 };
7434
7522
  return {
7435
7523
  start: startDragged ? current : other,
7436
7524
  end: endDragged ? current : other
@@ -7611,7 +7699,7 @@ var updateBoundElements = (changedElement, scene, options) => {
7611
7699
  elementsMap.set(element.id, element);
7612
7700
  });
7613
7701
  }
7614
- boundElementsVisitor(elementsMap, changedElement, (element) => {
7702
+ const visitor = (element) => {
7615
7703
  if (!isArrowElement(element) || element.isDeleted) {
7616
7704
  return;
7617
7705
  }
@@ -7657,7 +7745,8 @@ var updateBoundElements = (changedElement, scene, options) => {
7657
7745
  if (boundText && !boundText.isDeleted) {
7658
7746
  handleBindTextResize(element, scene, false);
7659
7747
  }
7660
- });
7748
+ };
7749
+ boundElementsVisitor(elementsMap, changedElement, visitor);
7661
7750
  };
7662
7751
  var updateArrowBindings = (latestElement, startOrEnd, elementsMap, scene, appState) => {
7663
7752
  invariant7(
@@ -7790,20 +7879,22 @@ var bindPointToSnapToElementOutline = (arrowElement, bindableElement, startOrEnd
7790
7879
  headingForPointFromElement(bindableElement, aabb, point)
7791
7880
  );
7792
7881
  const snapPoint = snapToMid(
7793
- arrowElement,
7794
7882
  bindableElement,
7795
7883
  elementsMap,
7796
- edgePoint
7884
+ edgePoint,
7885
+ 0.05,
7886
+ arrowElement
7797
7887
  );
7888
+ const resolved = snapPoint || point;
7798
7889
  const otherPoint = pointFrom8(
7799
- isHorizontal ? bindableCenter[0] : snapPoint[0],
7800
- !isHorizontal ? bindableCenter[1] : snapPoint[1]
7890
+ isHorizontal ? bindableCenter[0] : resolved[0],
7891
+ !isHorizontal ? bindableCenter[1] : resolved[1]
7801
7892
  );
7802
7893
  const intersector = customIntersector ?? lineSegment4(
7803
7894
  otherPoint,
7804
7895
  pointFromVector6(
7805
7896
  vectorScale7(
7806
- vectorNormalize4(vectorFromPoint7(snapPoint, otherPoint)),
7897
+ vectorNormalize4(vectorFromPoint7(resolved, otherPoint)),
7807
7898
  Math.max(bindableElement.width, bindableElement.height) * 2
7808
7899
  ),
7809
7900
  otherPoint
@@ -7817,14 +7908,14 @@ var bindPointToSnapToElementOutline = (arrowElement, bindableElement, startOrEnd
7817
7908
  ).sort(pointDistanceSq)[0];
7818
7909
  if (!intersection) {
7819
7910
  const anotherPoint = pointFrom8(
7820
- !isHorizontal ? bindableCenter[0] : snapPoint[0],
7821
- isHorizontal ? bindableCenter[1] : snapPoint[1]
7911
+ !isHorizontal ? bindableCenter[0] : resolved[0],
7912
+ isHorizontal ? bindableCenter[1] : resolved[1]
7822
7913
  );
7823
7914
  const anotherIntersector = lineSegment4(
7824
7915
  anotherPoint,
7825
7916
  pointFromVector6(
7826
7917
  vectorScale7(
7827
- vectorNormalize4(vectorFromPoint7(snapPoint, anotherPoint)),
7918
+ vectorNormalize4(vectorFromPoint7(resolved, anotherPoint)),
7828
7919
  Math.max(bindableElement.width, bindableElement.height) * 2
7829
7920
  ),
7830
7921
  anotherPoint
@@ -7933,15 +8024,15 @@ var avoidRectangularCorner = (arrowElement, bindTarget, elementsMap, p) => {
7933
8024
  }
7934
8025
  return p;
7935
8026
  };
7936
- var snapToMid = (arrowElement, bindTarget, elementsMap, p, tolerance = 0.05) => {
8027
+ var snapToMid = (bindTarget, elementsMap, p, tolerance = 0.05, arrowElement) => {
7937
8028
  const { x, y, width, height, angle } = bindTarget;
7938
8029
  const center = elementCenterPoint(bindTarget, elementsMap, -0.1, -0.1);
7939
8030
  const nonRotated = pointRotateRads8(p, center, -angle);
7940
- const bindingGap = getBindingGap(bindTarget, arrowElement);
8031
+ const bindingGap = arrowElement ? getBindingGap(bindTarget, arrowElement) : 0;
7941
8032
  const verticalThreshold = clamp3(tolerance * height, 5, 80);
7942
8033
  const horizontalThreshold = clamp3(tolerance * width, 5, 80);
7943
8034
  if (pointDistance4(center, nonRotated) < bindingGap) {
7944
- return p;
8035
+ return void 0;
7945
8036
  }
7946
8037
  if (nonRotated[0] <= x + width / 2 && nonRotated[1] > center[1] - verticalThreshold && nonRotated[1] < center[1] + verticalThreshold) {
7947
8038
  return pointRotateRads8(
@@ -7950,7 +8041,11 @@ var snapToMid = (arrowElement, bindTarget, elementsMap, p, tolerance = 0.05) =>
7950
8041
  angle
7951
8042
  );
7952
8043
  } else if (nonRotated[1] <= y + height / 2 && nonRotated[0] > center[0] - horizontalThreshold && nonRotated[0] < center[0] + horizontalThreshold) {
7953
- return pointRotateRads8(pointFrom8(center[0], y - bindingGap), center, angle);
8044
+ return pointRotateRads8(
8045
+ pointFrom8(center[0], y - bindingGap),
8046
+ center,
8047
+ angle
8048
+ );
7954
8049
  } else if (nonRotated[0] >= x + width / 2 && nonRotated[1] > center[1] - verticalThreshold && nonRotated[1] < center[1] + verticalThreshold) {
7955
8050
  return pointRotateRads8(
7956
8051
  pointFrom8(x + width + bindingGap, center[1]),
@@ -7994,10 +8089,36 @@ var snapToMid = (arrowElement, bindTarget, elementsMap, p, tolerance = 0.05) =>
7994
8089
  return pointRotateRads8(bottomRight, center, angle);
7995
8090
  }
7996
8091
  }
7997
- return p;
8092
+ return void 0;
8093
+ };
8094
+ var extractBinding = (arrow, startOrEnd, elementsMap) => {
8095
+ const binding = arrow[startOrEnd];
8096
+ if (!binding) {
8097
+ return {
8098
+ element: null,
8099
+ fixedPoint: null,
8100
+ focusPoint: null,
8101
+ binding,
8102
+ mode: null
8103
+ };
8104
+ }
8105
+ const element = elementsMap.get(
8106
+ binding.elementId
8107
+ );
8108
+ return {
8109
+ element,
8110
+ fixedPoint: binding.fixedPoint,
8111
+ focusPoint: getGlobalFixedPointForBindableElement(
8112
+ normalizeFixedPoint(binding.fixedPoint),
8113
+ element,
8114
+ elementsMap
8115
+ ),
8116
+ binding,
8117
+ mode: binding.mode
8118
+ };
7998
8119
  };
7999
- var compareElementArea = (a2, b2) => b2.width ** 2 + b2.height ** 2 - (a2.width ** 2 + a2.height ** 2);
8000
- var updateBoundPoint = (arrow, startOrEnd, binding, bindableElement, elementsMap, opts) => {
8120
+ var elementArea = (element) => element.width * element.height;
8121
+ var updateBoundPoint = (arrow, startOrEnd, binding, bindableElement, elementsMap, dragging) => {
8001
8122
  if (binding == null || // We only need to update the other end if this is a 2 point line element
8002
8123
  binding.elementId !== bindableElement.id && arrow.points.length > 2 || // Initial arrow created on pointer down needs to not update the points
8003
8124
  pointsEqual5(
@@ -8006,110 +8127,92 @@ var updateBoundPoint = (arrow, startOrEnd, binding, bindableElement, elementsMap
8006
8127
  )) {
8007
8128
  return null;
8008
8129
  }
8009
- const global2 = getGlobalFixedPointForBindableElement(
8130
+ const focusPoint = getGlobalFixedPointForBindableElement(
8010
8131
  normalizeFixedPoint(binding.fixedPoint),
8011
8132
  bindableElement,
8012
8133
  elementsMap
8013
8134
  );
8014
- const pointIndex = startOrEnd === "startBinding" ? 0 : arrow.points.length - 1;
8015
- const elbowed = isElbowArrow(arrow);
8016
- const otherBinding = startOrEnd === "startBinding" ? arrow.endBinding : arrow.startBinding;
8017
- const otherBindableElement = otherBinding && elementsMap.get(otherBinding.elementId);
8018
- const bounds = getElementBounds(bindableElement, elementsMap);
8019
- const otherBounds = otherBindableElement && getElementBounds(otherBindableElement, elementsMap);
8020
- const isLargerThanOther = otherBindableElement && compareElementArea(bindableElement, otherBindableElement) < // if both shapes the same size, pretend the other is larger
8021
- (startOrEnd === "endBinding" ? 1 : 0);
8022
- const isOverlapping = otherBounds && doBoundsIntersect(bounds, otherBounds);
8023
- let arrowTooShort = false;
8024
- if (!isOverlapping && !elbowed && arrow.startBinding && arrow.endBinding && otherBindableElement && arrow.points.length === 2) {
8025
- const startFocusPoint = getGlobalFixedPointForBindableElement(
8026
- arrow.startBinding.fixedPoint,
8027
- startOrEnd === "startBinding" ? bindableElement : otherBindableElement,
8028
- elementsMap
8029
- );
8030
- const endFocusPoint = getGlobalFixedPointForBindableElement(
8031
- arrow.endBinding.fixedPoint,
8032
- startOrEnd === "endBinding" ? bindableElement : otherBindableElement,
8033
- elementsMap
8034
- );
8035
- const segment = lineSegment4(startFocusPoint, endFocusPoint);
8036
- const startIntersection = intersectElementWithLineSegment(
8037
- startOrEnd === "endBinding" ? bindableElement : otherBindableElement,
8135
+ if (binding.mode === "inside") {
8136
+ return LinearElementEditor.createPointAt(
8137
+ arrow,
8038
8138
  elementsMap,
8039
- segment,
8040
- 0,
8041
- true
8139
+ focusPoint[0],
8140
+ focusPoint[1],
8141
+ null
8042
8142
  );
8043
- const endIntersection = intersectElementWithLineSegment(
8044
- startOrEnd === "startBinding" ? bindableElement : otherBindableElement,
8143
+ }
8144
+ const { element: otherBindable, focusPoint: otherFocusPoint } = extractBinding(
8145
+ arrow,
8146
+ startOrEnd === "startBinding" ? "endBinding" : "startBinding",
8147
+ elementsMap
8148
+ );
8149
+ const otherArrowPoint = LinearElementEditor.getPointAtIndexGlobalCoordinates(
8150
+ arrow,
8151
+ startOrEnd === "startBinding" ? 1 : -2,
8152
+ elementsMap
8153
+ );
8154
+ const otherFocusPointOrArrowPoint = arrow.points.length === 2 ? otherFocusPoint || otherArrowPoint : otherArrowPoint;
8155
+ const intersector = otherFocusPointOrArrowPoint && lineSegment4(focusPoint, otherFocusPointOrArrowPoint);
8156
+ const otherOutlinePoint = otherBindable && intersector && intersectElementWithLineSegment(
8157
+ otherBindable,
8158
+ elementsMap,
8159
+ intersector,
8160
+ getBindingGap(otherBindable, arrow)
8161
+ ).sort(
8162
+ (a2, b2) => pointDistanceSq(a2, focusPoint) - pointDistanceSq(b2, focusPoint)
8163
+ )[0];
8164
+ const outlinePoint = intersector && intersectElementWithLineSegment(
8165
+ bindableElement,
8166
+ elementsMap,
8167
+ intersector,
8168
+ getBindingGap(bindableElement, arrow)
8169
+ ).sort(
8170
+ (a2, b2) => pointDistanceSq(a2, otherFocusPointOrArrowPoint) - pointDistanceSq(b2, otherFocusPointOrArrowPoint)
8171
+ )[0];
8172
+ const startHasArrowhead = arrow.startArrowhead !== null;
8173
+ const endHasArrowhead = arrow.endArrowhead !== null;
8174
+ const resolvedTarget = !startHasArrowhead && !endHasArrowhead || startOrEnd === "startBinding" && startHasArrowhead || startOrEnd === "endBinding" && endHasArrowhead ? focusPoint : outlinePoint || focusPoint;
8175
+ if (otherBindable && outlinePoint && !dragging && // Arbitrary threshold to handle wireframing use cases
8176
+ elementArea(otherBindable) < elementArea(bindableElement) * 2 && hitElementItself({
8177
+ element: otherBindable,
8178
+ point: outlinePoint,
8179
+ elementsMap,
8180
+ threshold: getBindingGap(otherBindable, arrow),
8181
+ overrideShouldTestInside: true
8182
+ })) {
8183
+ return LinearElementEditor.createPointAt(
8184
+ arrow,
8045
8185
  elementsMap,
8046
- segment,
8047
- 0,
8048
- true
8186
+ resolvedTarget[0],
8187
+ resolvedTarget[1],
8188
+ null
8049
8189
  );
8050
- if (startIntersection.length > 0 && endIntersection.length > 0) {
8051
- const len = pointDistance4(startIntersection[0], endIntersection[0]);
8052
- arrowTooShort = len < 40;
8053
- }
8054
8190
  }
8055
- const isNested = (arrowTooShort || isOverlapping) && isLargerThanOther;
8056
- let _customIntersector = opts?.customIntersector;
8057
- if (!elbowed && !_customIntersector) {
8058
- const [x1, y1, x2, y2] = LinearElementEditor.getElementAbsoluteCoords(
8191
+ const otherTargetPoint = otherBindable ? otherOutlinePoint || otherFocusPoint || otherArrowPoint : otherArrowPoint;
8192
+ const arrowTooShort = pointDistance4(otherTargetPoint, outlinePoint || focusPoint) <= BASE_ARROW_MIN_LENGTH;
8193
+ if (!otherBindable) {
8194
+ return LinearElementEditor.createPointAt(
8059
8195
  arrow,
8060
- elementsMap
8061
- );
8062
- const center = pointFrom8((x1 + x2) / 2, (y1 + y2) / 2);
8063
- const edgePoint = global2;
8064
- const adjacentPoint = pointRotateRads8(
8065
- pointFrom8(
8066
- arrow.x + arrow.points[pointIndex === 0 ? 1 : arrow.points.length - 2][0],
8067
- arrow.y + arrow.points[pointIndex === 0 ? 1 : arrow.points.length - 2][1]
8068
- ),
8069
- center,
8070
- arrow.angle
8071
- );
8072
- const bindingGap = getBindingGap(bindableElement, arrow);
8073
- const halfVector = vectorScale7(
8074
- vectorNormalize4(vectorFromPoint7(edgePoint, adjacentPoint)),
8075
- pointDistance4(edgePoint, adjacentPoint) + Math.max(bindableElement.width, bindableElement.height) + bindingGap * 2
8196
+ elementsMap,
8197
+ arrowTooShort ? focusPoint[0] : outlinePoint?.[0] ?? focusPoint[0],
8198
+ arrowTooShort ? focusPoint[1] : outlinePoint?.[1] ?? focusPoint[1],
8199
+ null
8076
8200
  );
8077
- _customIntersector = lineSegment4(
8078
- pointFromVector6(halfVector, adjacentPoint),
8079
- pointFromVector6(vectorScale7(halfVector, -1), adjacentPoint)
8201
+ }
8202
+ if (arrowTooShort) {
8203
+ return LinearElementEditor.createPointAt(
8204
+ arrow,
8205
+ elementsMap,
8206
+ resolvedTarget?.[0] || focusPoint[0],
8207
+ resolvedTarget?.[1] || focusPoint[1],
8208
+ null
8080
8209
  );
8081
8210
  }
8082
- const maybeOutlineGlobal = binding.mode === "orbit" && bindableElement ? isNested ? global2 : bindPointToSnapToElementOutline(
8083
- {
8084
- ...arrow,
8085
- points: [
8086
- pointIndex === 0 ? LinearElementEditor.createPointAt(
8087
- arrow,
8088
- elementsMap,
8089
- global2[0],
8090
- global2[1],
8091
- null
8092
- ) : arrow.points[0],
8093
- ...arrow.points.slice(1, -1),
8094
- pointIndex === arrow.points.length - 1 ? LinearElementEditor.createPointAt(
8095
- arrow,
8096
- elementsMap,
8097
- global2[0],
8098
- global2[1],
8099
- null
8100
- ) : arrow.points[arrow.points.length - 1]
8101
- ]
8102
- },
8103
- bindableElement,
8104
- pointIndex === 0 ? "start" : "end",
8105
- elementsMap,
8106
- _customIntersector
8107
- ) : global2;
8108
8211
  return LinearElementEditor.createPointAt(
8109
8212
  arrow,
8110
8213
  elementsMap,
8111
- maybeOutlineGlobal[0],
8112
- maybeOutlineGlobal[1],
8214
+ outlinePoint?.[0] || focusPoint[0],
8215
+ outlinePoint?.[1] || focusPoint[1],
8113
8216
  null
8114
8217
  );
8115
8218
  };
@@ -8477,10 +8580,17 @@ var getArrowLocalFixedPoints = (arrow, elementsMap) => {
8477
8580
  LinearElementEditor.pointFromAbsoluteCoords(arrow, endPoint, elementsMap)
8478
8581
  ];
8479
8582
  };
8583
+ var isFixedPoint = (fixedPoint) => {
8584
+ return Array.isArray(fixedPoint) && fixedPoint.length === 2 && fixedPoint.every((coord) => Number.isFinite(coord));
8585
+ };
8480
8586
  var normalizeFixedPoint = (fixedPoint) => {
8481
- if (fixedPoint && (Math.abs(fixedPoint[0] - 0.5) < 1e-4 || Math.abs(fixedPoint[1] - 0.5) < 1e-4)) {
8587
+ if (!isFixedPoint(fixedPoint)) {
8588
+ return [0.5001, 0.5001];
8589
+ }
8590
+ const EPSILON2 = 1e-4;
8591
+ if (Math.abs(fixedPoint[0] - 0.5) < EPSILON2 || Math.abs(fixedPoint[1] - 0.5) < EPSILON2) {
8482
8592
  return fixedPoint.map(
8483
- (ratio) => Math.abs(ratio - 0.5) < 1e-4 ? 0.5001 : ratio
8593
+ (ratio) => Math.abs(ratio - 0.5) < EPSILON2 ? 0.5001 : ratio
8484
8594
  );
8485
8595
  }
8486
8596
  return fixedPoint;
@@ -9005,7 +9115,8 @@ var LinearElementEditor = class _LinearElementEditor {
9005
9115
  elements,
9006
9116
  app,
9007
9117
  shouldRotateWithDiscreteAngle(event),
9008
- event.altKey
9118
+ event.altKey,
9119
+ linearElementEditor
9009
9120
  );
9010
9121
  _LinearElementEditor.movePoints(element, app.scene, positions, {
9011
9122
  startBinding: updates?.startBinding,
@@ -9041,12 +9152,13 @@ var LinearElementEditor = class _LinearElementEditor {
9041
9152
  customLineAngle,
9042
9153
  initialState: {
9043
9154
  ...linearElementEditor.initialState,
9044
- altFocusPoint: !linearElementEditor.initialState.altFocusPoint && startBindingElement && updates?.suggestedBinding?.id !== startBindingElement.id ? projectFixedPointOntoDiagonal2(
9155
+ altFocusPoint: !linearElementEditor.initialState.altFocusPoint && startBindingElement && updates?.suggestedBinding?.element.id !== startBindingElement.id ? projectFixedPointOntoDiagonal2(
9045
9156
  element,
9046
9157
  pointFrom9(element.x, element.y),
9047
9158
  startBindingElement,
9048
9159
  "start",
9049
- elementsMap
9160
+ elementsMap,
9161
+ app.state.zoom
9050
9162
  ) : linearElementEditor.initialState.altFocusPoint
9051
9163
  }
9052
9164
  };
@@ -9134,7 +9246,8 @@ var LinearElementEditor = class _LinearElementEditor {
9134
9246
  elements,
9135
9247
  app,
9136
9248
  shouldRotateWithDiscreteAngle(event) && singlePointDragged,
9137
- event.altKey
9249
+ event.altKey,
9250
+ linearElementEditor
9138
9251
  );
9139
9252
  _LinearElementEditor.movePoints(element, app.scene, positions, {
9140
9253
  startBinding: updates?.startBinding,
@@ -9178,8 +9291,8 @@ var LinearElementEditor = class _LinearElementEditor {
9178
9291
  element.endBinding.elementId
9179
9292
  );
9180
9293
  const altFocusPointBindableElement = endIsSelected && // The "other" end (i.e. "end") is dragged
9181
- startBindingElement && updates?.suggestedBinding?.id !== startBindingElement.id ? startBindingElement : startIsSelected && // The "other" end (i.e. "start") is dragged
9182
- endBindingElement && updates?.suggestedBinding?.id !== endBindingElement.id ? endBindingElement : null;
9294
+ startBindingElement && updates?.suggestedBinding?.element.id !== startBindingElement.id ? startBindingElement : startIsSelected && // The "other" end (i.e. "start") is dragged
9295
+ endBindingElement && updates?.suggestedBinding?.element.id !== endBindingElement.id ? endBindingElement : null;
9183
9296
  const newLinearElementEditor = {
9184
9297
  ...linearElementEditor,
9185
9298
  selectedPointsIndices: newSelectedPointsIndices,
@@ -9192,7 +9305,8 @@ var LinearElementEditor = class _LinearElementEditor {
9192
9305
  pointFrom9(element.x, element.y),
9193
9306
  altFocusPointBindableElement,
9194
9307
  "start",
9195
- elementsMap
9308
+ elementsMap,
9309
+ app.state.zoom
9196
9310
  ) : linearElementEditor.initialState.altFocusPoint
9197
9311
  },
9198
9312
  segmentMidPointHoveredCoords: newSelectedMidPointHoveredCoords,
@@ -10206,7 +10320,7 @@ var normalizeSelectedPoints = (points) => {
10206
10320
  nextPoints = nextPoints.sort((a2, b2) => a2 - b2);
10207
10321
  return nextPoints.length ? nextPoints : null;
10208
10322
  };
10209
- var pointDraggingUpdates = (selectedPointsIndices, deltaX, deltaY, scenePointerX, scenePointerY, elementsMap, element, elements, app, angleLocked, altKey) => {
10323
+ var pointDraggingUpdates = (selectedPointsIndices, deltaX, deltaY, scenePointerX, scenePointerY, elementsMap, element, elements, app, angleLocked, altKey, linearElementEditor) => {
10210
10324
  const naiveDraggingPoints = new Map(
10211
10325
  selectedPointsIndices.map((pointIndex) => {
10212
10326
  return [
@@ -10245,10 +10359,21 @@ var pointDraggingUpdates = (selectedPointsIndices, deltaX, deltaY, scenePointerX
10245
10359
  }
10246
10360
  );
10247
10361
  if (isElbowArrow(element)) {
10362
+ const suggestedBindingElement = startIsDragged ? start.element : endIsDragged ? end.element : null;
10248
10363
  return {
10249
10364
  positions: naiveDraggingPoints,
10250
10365
  updates: {
10251
- suggestedBinding: startIsDragged ? start.element : endIsDragged ? end.element : null
10366
+ suggestedBinding: suggestedBindingElement ? {
10367
+ element: suggestedBindingElement,
10368
+ midPoint: snapToMid(
10369
+ suggestedBindingElement,
10370
+ elementsMap,
10371
+ pointFrom9(
10372
+ scenePointerX - linearElementEditor.pointerOffset.x,
10373
+ scenePointerY - linearElementEditor.pointerOffset.y
10374
+ )
10375
+ )
10376
+ } : null
10252
10377
  }
10253
10378
  };
10254
10379
  }
@@ -10320,7 +10445,18 @@ var pointDraggingUpdates = (selectedPointsIndices, deltaX, deltaY, scenePointerX
10320
10445
  )
10321
10446
  };
10322
10447
  if (startIsDragged && (updates.startBinding.mode === "orbit" || !getFeatureFlag2("COMPLEX_BINDINGS"))) {
10323
- updates.suggestedBinding = start.element;
10448
+ updates.suggestedBinding = start.element ? {
10449
+ element: start.element,
10450
+ midPoint: getSnapOutlineMidPoint2(
10451
+ pointFrom9(
10452
+ scenePointerX - linearElementEditor.pointerOffset.x,
10453
+ scenePointerY - linearElementEditor.pointerOffset.y
10454
+ ),
10455
+ start.element,
10456
+ elementsMap,
10457
+ app.state.zoom
10458
+ )
10459
+ } : null;
10324
10460
  }
10325
10461
  } else if (startIsDragged) {
10326
10462
  updates.suggestedBinding = app.state.suggestedBinding;
@@ -10340,7 +10476,18 @@ var pointDraggingUpdates = (selectedPointsIndices, deltaX, deltaY, scenePointerX
10340
10476
  )
10341
10477
  };
10342
10478
  if (endIsDragged && (updates.endBinding.mode === "orbit" || !getFeatureFlag2("COMPLEX_BINDINGS"))) {
10343
- updates.suggestedBinding = end.element;
10479
+ updates.suggestedBinding = end.element ? {
10480
+ element: end.element,
10481
+ midPoint: getSnapOutlineMidPoint2(
10482
+ pointFrom9(
10483
+ scenePointerX - linearElementEditor.pointerOffset.x,
10484
+ scenePointerY - linearElementEditor.pointerOffset.y
10485
+ ),
10486
+ end.element,
10487
+ elementsMap,
10488
+ app.state.zoom
10489
+ )
10490
+ } : null;
10344
10491
  }
10345
10492
  } else if (endIsDragged) {
10346
10493
  updates.suggestedBinding = app.state.suggestedBinding;
@@ -10363,8 +10510,6 @@ var pointDraggingUpdates = (selectedPointsIndices, deltaX, deltaY, scenePointerX
10363
10510
  startBinding: updates.startBinding === void 0 ? element.startBinding : updates.startBinding === null ? null : updates.startBinding,
10364
10511
  endBinding: updates.endBinding === void 0 ? element.endBinding : updates.endBinding === null ? null : updates.endBinding
10365
10512
  };
10366
- const startCustomIntersector = start.focusPoint && end.focusPoint ? lineSegment5(start.focusPoint, end.focusPoint) : void 0;
10367
- const endCustomIntersector = start.focusPoint && end.focusPoint ? lineSegment5(end.focusPoint, start.focusPoint) : void 0;
10368
10513
  const startIsDraggingOverEndElement = element.endBinding && nextArrow.startBinding && startIsDragged && nextArrow.startBinding.elementId === element.endBinding.elementId;
10369
10514
  const endIsDraggingOverStartElement = element.startBinding && nextArrow.endBinding && endIsDragged && element.startBinding.elementId === nextArrow.endBinding.elementId;
10370
10515
  const endBindable = nextArrow.endBinding ? end.element ?? elementsMap.get(
@@ -10376,9 +10521,7 @@ var pointDraggingUpdates = (selectedPointsIndices, deltaX, deltaY, scenePointerX
10376
10521
  nextArrow.endBinding,
10377
10522
  endBindable,
10378
10523
  elementsMap,
10379
- {
10380
- customIntersector: endCustomIntersector
10381
- }
10524
+ endIsDragged
10382
10525
  ) || nextArrow.points[nextArrow.points.length - 1] : nextArrow.points[nextArrow.points.length - 1];
10383
10526
  nextArrow.points[nextArrow.points.length - 1] = endLocalPoint;
10384
10527
  const startBindable = nextArrow.startBinding ? start.element ?? elementsMap.get(
@@ -10390,7 +10533,7 @@ var pointDraggingUpdates = (selectedPointsIndices, deltaX, deltaY, scenePointerX
10390
10533
  nextArrow.startBinding,
10391
10534
  startBindable,
10392
10535
  elementsMap,
10393
- { customIntersector: startCustomIntersector }
10536
+ startIsDragged
10394
10537
  ) || nextArrow.points[0] : nextArrow.points[0];
10395
10538
  const endChanged = !startIsDraggingOverEndElement && !(endIsDraggingOverStartElement && app.state.bindMode !== "inside" && getFeatureFlag2("COMPLEX_BINDINGS")) && !!endBindable;
10396
10539
  const startChanged = pointDistance5(startLocalPoint, nextArrow.points[0]) !== 0;
@@ -12202,7 +12345,7 @@ function getFreedrawOutlineAsSegments(element, points, elementsMap) {
12202
12345
  return points.slice(2).reduce(
12203
12346
  (acc, curr) => {
12204
12347
  acc.push(
12205
- lineSegment6(
12348
+ lineSegment5(
12206
12349
  acc[acc.length - 1][1],
12207
12350
  pointRotateRads11(
12208
12351
  pointFrom12(curr[0] + element.x, curr[1] + element.y),
@@ -12214,7 +12357,7 @@ function getFreedrawOutlineAsSegments(element, points, elementsMap) {
12214
12357
  return acc;
12215
12358
  },
12216
12359
  [
12217
- lineSegment6(
12360
+ lineSegment5(
12218
12361
  pointRotateRads11(
12219
12362
  pointFrom12(
12220
12363
  points[0][0] + element.x,
@@ -13149,7 +13292,7 @@ var getElementLineSegments = (element, elementsMap) => {
13149
13292
  let i = 0;
13150
13293
  while (i < points.length - 1) {
13151
13294
  segments.push(
13152
- lineSegment7(
13295
+ lineSegment6(
13153
13296
  pointFrom14(points[i][0], points[i][1]),
13154
13297
  pointFrom14(points[i + 1][0], points[i + 1][1])
13155
13298
  )
@@ -13162,7 +13305,7 @@ var getElementLineSegments = (element, elementsMap) => {
13162
13305
  let i = 0;
13163
13306
  while (i < points.length - 1) {
13164
13307
  segments.push(
13165
- lineSegment7(
13308
+ lineSegment6(
13166
13309
  pointFrom14(points[i][0], points[i][1]),
13167
13310
  pointFrom14(points[i + 1][0], points[i + 1][1])
13168
13311
  )
@@ -13188,10 +13331,10 @@ var getElementLineSegments = (element, elementsMap) => {
13188
13331
  const container = getContainerElement(element, elementsMap);
13189
13332
  if (container && isLinearElement(container)) {
13190
13333
  const segments2 = [
13191
- lineSegment7(pointFrom14(x1, y1), pointFrom14(x2, y1)),
13192
- lineSegment7(pointFrom14(x2, y1), pointFrom14(x2, y2)),
13193
- lineSegment7(pointFrom14(x2, y2), pointFrom14(x1, y2)),
13194
- lineSegment7(pointFrom14(x1, y2), pointFrom14(x1, y1))
13334
+ lineSegment6(pointFrom14(x1, y1), pointFrom14(x2, y1)),
13335
+ lineSegment6(pointFrom14(x2, y1), pointFrom14(x2, y2)),
13336
+ lineSegment6(pointFrom14(x2, y2), pointFrom14(x1, y2)),
13337
+ lineSegment6(pointFrom14(x1, y2), pointFrom14(x1, y1))
13195
13338
  ];
13196
13339
  return segments2;
13197
13340
  }
@@ -13199,7 +13342,7 @@ var getElementLineSegments = (element, elementsMap) => {
13199
13342
  const points = shape.data;
13200
13343
  const segments = [];
13201
13344
  for (let i = 0; i < points.length - 1; i++) {
13202
- segments.push(lineSegment7(points[i], points[i + 1]));
13345
+ segments.push(lineSegment6(points[i], points[i + 1]));
13203
13346
  }
13204
13347
  return segments;
13205
13348
  } else if (shape.type === "ellipse") {
@@ -13216,14 +13359,14 @@ var getElementLineSegments = (element, elementsMap) => {
13216
13359
  [x2, cy]
13217
13360
  ].map((point) => pointRotateRads13(point, center, element.angle));
13218
13361
  return [
13219
- lineSegment7(nw, ne),
13220
- lineSegment7(sw, se2),
13221
- lineSegment7(nw, sw),
13222
- lineSegment7(ne, se2),
13223
- lineSegment7(nw, e),
13224
- lineSegment7(sw, e),
13225
- lineSegment7(ne, w),
13226
- lineSegment7(se2, w)
13362
+ lineSegment6(nw, ne),
13363
+ lineSegment6(sw, se2),
13364
+ lineSegment6(nw, sw),
13365
+ lineSegment6(ne, se2),
13366
+ lineSegment6(nw, e),
13367
+ lineSegment6(sw, e),
13368
+ lineSegment6(ne, w),
13369
+ lineSegment6(se2, w)
13227
13370
  ];
13228
13371
  };
13229
13372
  var _isRectanguloidElement = (element) => {
@@ -13231,7 +13374,7 @@ var _isRectanguloidElement = (element) => {
13231
13374
  };
13232
13375
  var getRotatedSides = (sides, center, angle) => {
13233
13376
  return sides.map((side) => {
13234
- return lineSegment7(
13377
+ return lineSegment6(
13235
13378
  pointRotateRads13(side[0], center, angle),
13236
13379
  pointRotateRads13(side[1], center, angle)
13237
13380
  );
@@ -13243,7 +13386,7 @@ var getSegmentsOnCurve = (curve4, center, angle) => {
13243
13386
  const segments = [];
13244
13387
  while (i < points.length - 1) {
13245
13388
  segments.push(
13246
- lineSegment7(
13389
+ lineSegment6(
13247
13390
  pointRotateRads13(
13248
13391
  pointFrom14(points[i][0], points[i][1]),
13249
13392
  center,
@@ -13278,9 +13421,9 @@ var getSegmentsOnEllipse = (ellipse4) => {
13278
13421
  points.push(pointRotateRads13(pointFrom14(x, y), center, ellipse4.angle));
13279
13422
  }
13280
13423
  for (let i = 0; i < points.length - 1; i++) {
13281
- segments.push(lineSegment7(points[i], points[i + 1]));
13424
+ segments.push(lineSegment6(points[i], points[i + 1]));
13282
13425
  }
13283
- segments.push(lineSegment7(points[points.length - 1], points[0]));
13426
+ segments.push(lineSegment6(points[points.length - 1], points[0]));
13284
13427
  return segments;
13285
13428
  };
13286
13429
  var getRectangleBoxAbsoluteCoords = (boxSceneCoords) => {
@@ -17715,7 +17858,7 @@ var RE_GENERIC_EMBED = /^<(?:iframe|blockquote)[\s\S]*?\s(?:src|href)=["']([^"']
17715
17858
  var RE_GIPHY = /giphy.com\/(?:clips|embed|gifs)\/[a-zA-Z0-9]*?-?([a-zA-Z0-9]+)(?:[^a-zA-Z0-9]|$)/;
17716
17859
  var RE_REDDIT = /^(?:http(?:s)?:\/\/)?(?:www\.)?reddit\.com\/r\/([a-zA-Z0-9_]+)\/comments\/([a-zA-Z0-9_]+)\/([a-zA-Z0-9_]+)\/?(?:\?[^#\s]*)?(?:#[^\s]*)?$/;
17717
17860
  var RE_REDDIT_EMBED = /^<blockquote[\s\S]*?\shref=["'](https?:\/\/(?:www\.)?reddit\.com\/[^"']*)/i;
17718
- var parseYouTubeTimestamp = (url) => {
17861
+ var parseYouTubeLikeTimestamp = (url) => {
17719
17862
  let timeParam;
17720
17863
  try {
17721
17864
  const urlObj = new URL(url.startsWith("http") ? url : `https://${url}`);
@@ -17737,11 +17880,42 @@ var parseYouTubeTimestamp = (url) => {
17737
17880
  const [, hours = "0", minutes = "0", seconds = "0"] = timeMatch;
17738
17881
  return parseInt(hours) * 3600 + parseInt(minutes) * 60 + parseInt(seconds);
17739
17882
  };
17883
+ var parseGoogleDriveVideoLink = (url) => {
17884
+ try {
17885
+ const urlObj = new URL(url.startsWith("http") ? url : `https://${url}`);
17886
+ const hostname = urlObj.hostname.replace(/^www\./, "");
17887
+ if (hostname !== "drive.google.com") {
17888
+ return null;
17889
+ }
17890
+ let fileId = null;
17891
+ const pathMatch = urlObj.pathname.match(/^\/file\/d\/([^/]+)(?:\/|$)/);
17892
+ if (pathMatch?.[1]) {
17893
+ fileId = pathMatch[1];
17894
+ } else if (urlObj.pathname === "/open" || urlObj.pathname === "/uc") {
17895
+ fileId = urlObj.searchParams.get("id");
17896
+ }
17897
+ if (!fileId || !/^[a-zA-Z0-9_-]+$/.test(fileId)) {
17898
+ return null;
17899
+ }
17900
+ const resourceKey = urlObj.searchParams.get("resourcekey");
17901
+ const timestamp = parseYouTubeLikeTimestamp(urlObj.toString());
17902
+ return {
17903
+ fileId,
17904
+ resourceKey: resourceKey && /^[a-zA-Z0-9_-]+$/.test(resourceKey) ? resourceKey : void 0,
17905
+ // Drive accepts YouTube-like `t` formats (e.g. `t=90`, `t=1m30s`);
17906
+ // normalize to seconds for a stable preview URL.
17907
+ timestamp: timestamp > 0 ? timestamp : void 0
17908
+ };
17909
+ } catch (error) {
17910
+ return null;
17911
+ }
17912
+ };
17740
17913
  var ALLOWED_DOMAINS = /* @__PURE__ */ new Set([
17741
17914
  "youtube.com",
17742
17915
  "youtu.be",
17743
17916
  "vimeo.com",
17744
17917
  "player.vimeo.com",
17918
+ "drive.google.com",
17745
17919
  "figma.com",
17746
17920
  "link.excalidraw.com",
17747
17921
  "gist.github.com",
@@ -17759,6 +17933,7 @@ var ALLOW_SAME_ORIGIN = /* @__PURE__ */ new Set([
17759
17933
  "youtu.be",
17760
17934
  "vimeo.com",
17761
17935
  "player.vimeo.com",
17936
+ "drive.google.com",
17762
17937
  "figma.com",
17763
17938
  "twitter.com",
17764
17939
  "x.com",
@@ -17785,7 +17960,7 @@ var getEmbedLink = (link) => {
17785
17960
  let aspectRatio = { w: 560, h: 840 };
17786
17961
  const ytLink = link.match(RE_YOUTUBE);
17787
17962
  if (ytLink?.[2]) {
17788
- const startTime = parseYouTubeTimestamp(originalLink);
17963
+ const startTime = parseYouTubeLikeTimestamp(originalLink);
17789
17964
  const time = startTime > 0 ? `&start=${startTime}` : ``;
17790
17965
  const isPortrait = link.includes("shorts");
17791
17966
  type = "video";
@@ -17838,6 +18013,32 @@ var getEmbedLink = (link) => {
17838
18013
  sandbox: { allowSameOrigin }
17839
18014
  };
17840
18015
  }
18016
+ const googleDriveVideo = parseGoogleDriveVideoLink(link);
18017
+ if (googleDriveVideo) {
18018
+ type = "video";
18019
+ const searchParams = new URLSearchParams();
18020
+ if (googleDriveVideo.resourceKey) {
18021
+ searchParams.set("resourcekey", googleDriveVideo.resourceKey);
18022
+ }
18023
+ if (googleDriveVideo.timestamp) {
18024
+ searchParams.set("t", `${googleDriveVideo.timestamp}`);
18025
+ }
18026
+ const search = searchParams.toString();
18027
+ link = `https://drive.google.com/file/d/${googleDriveVideo.fileId}/preview${search ? `?${search}` : ""}`;
18028
+ aspectRatio = { w: 560, h: 315 };
18029
+ embeddedLinkCache.set(originalLink, {
18030
+ link,
18031
+ intrinsicSize: aspectRatio,
18032
+ type,
18033
+ sandbox: { allowSameOrigin }
18034
+ });
18035
+ return {
18036
+ link,
18037
+ intrinsicSize: aspectRatio,
18038
+ type,
18039
+ sandbox: { allowSameOrigin }
18040
+ };
18041
+ }
17841
18042
  const figmaLink = link.match(RE_FIGMA);
17842
18043
  if (figmaLink) {
17843
18044
  type = "generic";
@@ -18900,7 +19101,7 @@ var moveAllRight = (allElements, appState) => {
18900
19101
  };
18901
19102
 
18902
19103
  // src/arrows/focus.ts
18903
- var isFocusPointVisible = (focusPoint, arrow, bindableElement, elementsMap, appState, ignoreOverlap = false) => {
19104
+ var isFocusPointVisible = (focusPoint, arrow, bindableElement, elementsMap, appState, startOrEnd, ignoreOverlap = false) => {
18904
19105
  if (isElbowArrow(arrow) || !isBindingEnabled(appState) || arrow.points.length !== 2) {
18905
19106
  return false;
18906
19107
  }
@@ -18915,7 +19116,12 @@ var isFocusPointVisible = (focusPoint, arrow, bindableElement, elementsMap, appS
18915
19116
  return false;
18916
19117
  }
18917
19118
  }
18918
- return hitElementItself({
19119
+ const arrowPoint = LinearElementEditor.getPointAtIndexGlobalCoordinates(
19120
+ arrow,
19121
+ startOrEnd === "end" ? arrow.points.length - 1 : 0,
19122
+ elementsMap
19123
+ );
19124
+ return pointDistance8(focusPoint, arrowPoint) >= FOCUS_POINT_SIZE * 1.5 / appState.zoom.value && hitElementItself({
18919
19125
  element: bindableElement,
18920
19126
  elementsMap,
18921
19127
  point: focusPoint,
@@ -18948,13 +19154,14 @@ var focusPointUpdate = (arrow, bindableElement, isStartBinding, elementsMap, sce
18948
19154
  bindingField,
18949
19155
  currentBinding,
18950
19156
  bindableElement,
18951
- elementsMap
19157
+ elementsMap,
19158
+ true
18952
19159
  );
18953
19160
  if (newPoint) {
18954
19161
  pointUpdates.set(pointIndex, { point: newPoint });
18955
19162
  }
18956
19163
  }
18957
- if (adjacentBinding) {
19164
+ if (adjacentBinding && adjacentBinding.mode === "orbit") {
18958
19165
  const adjacentBindableElement = elementsMap.get(
18959
19166
  adjacentBinding.elementId
18960
19167
  );
@@ -19105,7 +19312,8 @@ var handleFocusPointPointerDown = (arrow, pointerDownState, elementsMap, appStat
19105
19312
  arrow,
19106
19313
  bindableElement,
19107
19314
  elementsMap,
19108
- appState
19315
+ appState,
19316
+ "start"
19109
19317
  ) && pointDistance8(pointerPos, focusPoint) <= hitThreshold) {
19110
19318
  return {
19111
19319
  hitFocusPoint: "start",
@@ -19130,7 +19338,8 @@ var handleFocusPointPointerDown = (arrow, pointerDownState, elementsMap, appStat
19130
19338
  arrow,
19131
19339
  bindableElement,
19132
19340
  elementsMap,
19133
- appState
19341
+ appState,
19342
+ "end"
19134
19343
  ) && pointDistance8(pointerPos, focusPoint) <= hitThreshold) {
19135
19344
  return {
19136
19345
  hitFocusPoint: "end",
@@ -19203,7 +19412,8 @@ var handleFocusPointHover = (arrow, scenePointerX, scenePointerY, scene, appStat
19203
19412
  arrow,
19204
19413
  bindableElement,
19205
19414
  elementsMap,
19206
- appState
19415
+ appState,
19416
+ "start"
19207
19417
  ) && pointDistance8(pointerPos, focusPoint) <= hitThreshold) {
19208
19418
  return "start";
19209
19419
  }
@@ -19222,7 +19432,8 @@ var handleFocusPointHover = (arrow, scenePointerX, scenePointerY, scene, appStat
19222
19432
  arrow,
19223
19433
  bindableElement,
19224
19434
  elementsMap,
19225
- appState
19435
+ appState,
19436
+ "end"
19226
19437
  ) && pointDistance8(pointerPos, focusPoint) <= hitThreshold) {
19227
19438
  return "end";
19228
19439
  }
@@ -21372,6 +21583,7 @@ var getNonDeletedElements2 = (elements) => elements.filter((element) => !element
21372
21583
  var isNonDeletedElement2 = (element) => !element.isDeleted;
21373
21584
  export {
21374
21585
  AppStateDelta,
21586
+ BASE_ARROW_MIN_LENGTH,
21375
21587
  BASE_BINDING_GAP,
21376
21588
  BASE_BINDING_GAP_ELBOW,
21377
21589
  BASE_PADDING,
@@ -21492,6 +21704,7 @@ export {
21492
21704
  getCursorForResizingElement,
21493
21705
  getDefaultFrameName,
21494
21706
  getDefaultRoundnessTypeForElement,
21707
+ getDiamondBaseCorners,
21495
21708
  getDiamondPoints,
21496
21709
  getDragOffsetXY,
21497
21710
  getDraggedElementsBounds,
@@ -21554,6 +21767,7 @@ export {
21554
21767
  getSelectedGroupIdForElement,
21555
21768
  getSelectedGroupIds,
21556
21769
  getSelectionStateForElements,
21770
+ getSnapOutlineMidPoint,
21557
21771
  getTargetElements,
21558
21772
  getTargetFrame,
21559
21773
  getTextElementAngle,
@@ -21614,6 +21828,7 @@ export {
21614
21828
  isElementLink,
21615
21829
  isEmbeddableElement,
21616
21830
  isExcalidrawElement,
21831
+ isFixedPoint,
21617
21832
  isFlowchartNodeElement,
21618
21833
  isFocusPointVisible,
21619
21834
  isFrameElement,
@@ -21708,6 +21923,7 @@ export {
21708
21923
  shouldEnableBindingForPointerEvent,
21709
21924
  shouldTestInside,
21710
21925
  showSelectedShapeActions,
21926
+ snapToMid,
21711
21927
  suppportsHorizontalAlign,
21712
21928
  syncInvalidIndices,
21713
21929
  syncInvalidIndicesImmutable,