@dwelle/excalidraw 0.5.0-e05a141 → 0.5.0-e2a82c4d8

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 (138) hide show
  1. package/dist/dev/{chunk-JCMFCSXV.js → chunk-7M7SVUYU.js} +121 -7
  2. package/dist/dev/chunk-7M7SVUYU.js.map +7 -0
  3. package/dist/dev/{chunk-P7XQCHXR.js → chunk-HJWER26G.js} +901 -439
  4. package/dist/dev/chunk-HJWER26G.js.map +7 -0
  5. package/dist/dev/{chunk-B7UQ5W6R.js → chunk-Q5BO7QEK.js} +2 -2
  6. package/dist/dev/{chunk-B7UQ5W6R.js.map → chunk-Q5BO7QEK.js.map} +1 -1
  7. package/dist/dev/components/TTDDialog/CodeMirrorEditor-4GD6MAJW.js +259 -0
  8. package/dist/dev/components/TTDDialog/CodeMirrorEditor-4GD6MAJW.js.map +7 -0
  9. package/dist/dev/data/{image-BUI6GQJR.js → image-UQK7BQY4.js} +3 -3
  10. package/dist/dev/index.css +2444 -173
  11. package/dist/dev/index.css.map +3 -3
  12. package/dist/dev/index.js +6875 -1415
  13. package/dist/dev/index.js.map +4 -4
  14. package/dist/dev/locales/{en-SEGQGVZN.js → en-IHKMFGHF.js} +6 -2
  15. package/dist/dev/subset-shared.chunk.js +1 -1
  16. package/dist/dev/subset-worker.chunk.js +1 -1
  17. package/dist/prod/chunk-QHCRJDAB.js +12 -0
  18. package/dist/prod/chunk-R2CZDOAE.js +34 -0
  19. package/dist/prod/{chunk-KDBB3MAO.js → chunk-XXRJJHWR.js} +1 -1
  20. package/dist/prod/components/TTDDialog/CodeMirrorEditor-P2CDXXOC.js +1 -0
  21. package/dist/prod/data/image-WAWRV65K.js +1 -0
  22. package/dist/prod/index.css +1 -1
  23. package/dist/prod/index.js +34 -25
  24. package/dist/prod/locales/en-QQWGF6XN.js +1 -0
  25. package/dist/prod/subset-shared.chunk.js +1 -1
  26. package/dist/prod/subset-worker.chunk.js +1 -1
  27. package/dist/types/common/src/utils.d.ts +5 -3
  28. package/dist/types/element/src/Scene.d.ts +2 -0
  29. package/dist/types/element/src/arrowheads.d.ts +3 -0
  30. package/dist/types/element/src/binding.d.ts +5 -4
  31. package/dist/types/element/src/bounds.d.ts +5 -3
  32. package/dist/types/element/src/elbowArrow.d.ts +2 -0
  33. package/dist/types/element/src/frame.d.ts +1 -1
  34. package/dist/types/element/src/index.d.ts +1 -0
  35. package/dist/types/element/src/linearElementEditor.d.ts +5 -2
  36. package/dist/types/element/src/mutateElement.d.ts +2 -0
  37. package/dist/types/element/src/selection.d.ts +7 -3
  38. package/dist/types/element/src/shape.d.ts +1 -1
  39. package/dist/types/element/src/textElement.d.ts +1 -1
  40. package/dist/types/element/src/textWrapping.d.ts +26 -0
  41. package/dist/types/element/src/types.d.ts +4 -1
  42. package/dist/types/element/src/utils.d.ts +2 -2
  43. package/dist/types/excalidraw/TTA/TTAChatEmptyState.d.ts +7 -0
  44. package/dist/types/excalidraw/TTA/TTAChatMessage.d.ts +15 -0
  45. package/dist/types/excalidraw/TTA/TTAComposer.d.ts +24 -0
  46. package/dist/types/excalidraw/TTA/TTADialog.d.ts +19 -0
  47. package/dist/types/excalidraw/TTA/TTADialogPanel.d.ts +46 -0
  48. package/dist/types/excalidraw/TTA/TTADialogTrigger.d.ts +10 -0
  49. package/dist/types/excalidraw/TTA/TTAHistory.d.ts +11 -0
  50. package/dist/types/excalidraw/TTA/TTAWarningMessage.d.ts +5 -0
  51. package/dist/types/excalidraw/TTA/chatErrors.d.ts +13 -0
  52. package/dist/types/excalidraw/TTA/chatHelpers.d.ts +26 -0
  53. package/dist/types/excalidraw/TTA/client.d.ts +74 -0
  54. package/dist/types/excalidraw/TTA/history.d.ts +2 -0
  55. package/dist/types/excalidraw/TTA/insertAISkeletons.d.ts +20 -0
  56. package/dist/types/excalidraw/TTA/types.d.ts +167 -0
  57. package/dist/types/excalidraw/TTA/useAIAssistantPreview.d.ts +18 -0
  58. package/dist/types/excalidraw/TTA/useAIStreamingCanvasPreview.d.ts +21 -0
  59. package/dist/types/excalidraw/TTA/useAIStreamingLifecycle.d.ts +34 -0
  60. package/dist/types/excalidraw/TTA/useTTAChatHistory.d.ts +18 -0
  61. package/dist/types/excalidraw/TTA/utils.d.ts +14 -0
  62. package/dist/types/excalidraw/actions/actionAddToLibrary.d.ts +15 -6
  63. package/dist/types/excalidraw/actions/actionBoundText.d.ts +11 -5
  64. package/dist/types/excalidraw/actions/actionCanvas.d.ts +50 -20
  65. package/dist/types/excalidraw/actions/actionClipboard.d.ts +10 -4
  66. package/dist/types/excalidraw/actions/actionCropEditor.d.ts +5 -2
  67. package/dist/types/excalidraw/actions/actionDeleteSelected.d.ts +15 -6
  68. package/dist/types/excalidraw/actions/actionDeselect.d.ts +161 -0
  69. package/dist/types/excalidraw/actions/actionElementLink.d.ts +5 -2
  70. package/dist/types/excalidraw/actions/actionElementLock.d.ts +10 -4
  71. package/dist/types/excalidraw/actions/actionEmbeddable.d.ts +5 -2
  72. package/dist/types/excalidraw/actions/actionExport.d.ts +21 -8
  73. package/dist/types/excalidraw/actions/actionFrame.d.ts +20 -8
  74. package/dist/types/excalidraw/actions/actionGroup.d.ts +11 -5
  75. package/dist/types/excalidraw/actions/actionLinearEditor.d.ts +5 -2
  76. package/dist/types/excalidraw/actions/actionLink.d.ts +5 -2
  77. package/dist/types/excalidraw/actions/actionMenu.d.ts +5 -2
  78. package/dist/types/excalidraw/actions/actionProperties.d.ts +12 -6
  79. package/dist/types/excalidraw/actions/actionSelectAll.d.ts +5 -2
  80. package/dist/types/excalidraw/actions/actionStyles.d.ts +6 -2
  81. package/dist/types/excalidraw/actions/actionTextAutoResize.d.ts +3 -3
  82. package/dist/types/excalidraw/actions/actionToggleArrowBinding.d.ts +174 -0
  83. package/dist/types/excalidraw/actions/actionToggleGridMode.d.ts +5 -2
  84. package/dist/types/excalidraw/actions/actionToggleMidpointSnapping.d.ts +174 -0
  85. package/dist/types/excalidraw/actions/actionToggleObjectsSnapMode.d.ts +5 -2
  86. package/dist/types/excalidraw/actions/actionToggleSearchMenu.d.ts +5 -2
  87. package/dist/types/excalidraw/actions/actionToggleStats.d.ts +5 -2
  88. package/dist/types/excalidraw/actions/actionToggleViewMode.d.ts +5 -2
  89. package/dist/types/excalidraw/actions/actionToggleZenMode.d.ts +5 -2
  90. package/dist/types/excalidraw/actions/index.d.ts +3 -0
  91. package/dist/types/excalidraw/actions/types.d.ts +1 -1
  92. package/dist/types/excalidraw/aiWarnings.d.ts +7 -0
  93. package/dist/types/excalidraw/appState.d.ts +4 -0
  94. package/dist/types/excalidraw/components/AI/ChatMessage.d.ts +33 -0
  95. package/dist/types/excalidraw/components/AI/index.d.ts +2 -0
  96. package/dist/types/excalidraw/components/App.d.ts +11 -1
  97. package/dist/types/excalidraw/components/FilledButton.d.ts +1 -1
  98. package/dist/types/excalidraw/components/IconPicker.d.ts +14 -9
  99. package/dist/types/excalidraw/components/Range.d.ts +10 -4
  100. package/dist/types/excalidraw/components/TTDDialog/Chat/TTDRateLimitWarningContent.d.ts +5 -0
  101. package/dist/types/excalidraw/components/TTDDialog/CodeMirrorEditor.d.ts +11 -0
  102. package/dist/types/excalidraw/components/TTDDialog/TTDDialog.d.ts +2 -2
  103. package/dist/types/excalidraw/components/TTDDialog/TTDDialogInput.d.ts +3 -3
  104. package/dist/types/excalidraw/components/TTDDialog/TTDDialogOutput.d.ts +4 -1
  105. package/dist/types/excalidraw/components/TTDDialog/mermaid-lang-lite.d.ts +2 -0
  106. package/dist/types/excalidraw/components/TTDDialog/types.d.ts +5 -1
  107. package/dist/types/excalidraw/components/TTDDialog/utils/TTDStreamFetch.d.ts +24 -6
  108. package/dist/types/excalidraw/components/TTDDialog/utils/mermaidAutoFix.d.ts +1 -0
  109. package/dist/types/excalidraw/components/TTDDialog/utils/mermaidError.d.ts +10 -0
  110. package/dist/types/excalidraw/components/canvases/InteractiveCanvas.d.ts +1 -0
  111. package/dist/types/excalidraw/components/dropdownMenu/DropdownMenuItemContentRadio.d.ts +2 -1
  112. package/dist/types/excalidraw/components/icons.d.ts +18 -8
  113. package/dist/types/excalidraw/components/main-menu/DefaultItems.d.ts +3 -0
  114. package/dist/types/excalidraw/context/tunnels.d.ts +1 -0
  115. package/dist/types/excalidraw/data/blob.d.ts +9 -3
  116. package/dist/types/excalidraw/data/filesystem.d.ts +3 -3
  117. package/dist/types/excalidraw/data/index.d.ts +1 -1
  118. package/dist/types/excalidraw/data/json.d.ts +6 -3
  119. package/dist/types/excalidraw/data/resave.d.ts +1 -1
  120. package/dist/types/excalidraw/data/sse.d.ts +15 -0
  121. package/dist/types/excalidraw/index.d.ts +15 -2
  122. package/dist/types/excalidraw/textAutoResizeHandle.d.ts +15 -0
  123. package/dist/types/excalidraw/types.d.ts +15 -2
  124. package/dist/types/excalidraw/wysiwyg/textWysiwyg.d.ts +5 -1
  125. package/dist/types/math/src/curve.d.ts +4 -1
  126. package/dist/types/math/src/point.d.ts +1 -1
  127. package/package.json +11 -5
  128. package/CHANGELOG.md +0 -2385
  129. package/dist/dev/chunk-JCMFCSXV.js.map +0 -7
  130. package/dist/dev/chunk-P7XQCHXR.js.map +0 -7
  131. package/dist/prod/chunk-FVPDTNSG.js +0 -12
  132. package/dist/prod/chunk-LRBVLW2I.js +0 -33
  133. package/dist/prod/data/image-KI7JN73E.js +0 -1
  134. package/dist/prod/locales/en-6237XDE7.js +0 -1
  135. package/dist/types/excalidraw/data/ai/types.d.ts +0 -242
  136. package/history.ts +0 -249
  137. /package/dist/dev/data/{image-BUI6GQJR.js.map → image-UQK7BQY4.js.map} +0 -0
  138. /package/dist/dev/locales/{en-SEGQGVZN.js.map → en-IHKMFGHF.js.map} +0 -0
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  define_import_meta_env_default
3
- } from "./chunk-B7UQ5W6R.js";
3
+ } from "./chunk-Q5BO7QEK.js";
4
4
  import {
5
5
  __publicField
6
6
  } from "./chunk-XDFCUUT6.js";
@@ -212,7 +212,12 @@ function pointsEqual(a, b, tolerance = PRECISION) {
212
212
  const abs = Math.abs;
213
213
  return abs(a[0] - b[0]) < tolerance && abs(a[1] - b[1]) < tolerance;
214
214
  }
215
- function pointRotateRads([x, y], [cx, cy], angle) {
215
+ function pointRotateRads(point, center, angle) {
216
+ if (!angle) {
217
+ return point;
218
+ }
219
+ const [x, y] = point;
220
+ const [cx, cy] = center;
216
221
  return pointFrom(
217
222
  (x - cx) * Math.cos(angle) - (y - cy) * Math.sin(angle) + cx,
218
223
  (x - cx) * Math.sin(angle) + (y - cy) * Math.cos(angle) + cy
@@ -343,8 +348,15 @@ var initial_guesses = [
343
348
  [0.2, 0],
344
349
  [0.8, 0]
345
350
  ];
346
- var calculate = ([t0, s0], l, c) => {
347
- const solution = solveWithAnalyticalJacobian(c, l, t0, s0, 0.01, 4);
351
+ var calculate = ([t0, s0], l, c, tolerance = 0.01, iterLimit = 4) => {
352
+ const solution = solveWithAnalyticalJacobian(
353
+ c,
354
+ l,
355
+ t0,
356
+ s0,
357
+ tolerance,
358
+ iterLimit
359
+ );
348
360
  if (!solution) {
349
361
  return null;
350
362
  }
@@ -354,16 +366,34 @@ var calculate = ([t0, s0], l, c) => {
354
366
  }
355
367
  return bezierEquation(c, t);
356
368
  };
357
- function curveIntersectLineSegment(c, l) {
358
- let solution = calculate(initial_guesses[0], l, c);
369
+ function curveIntersectLineSegment(c, l, opts) {
370
+ let solution = calculate(
371
+ initial_guesses[0],
372
+ l,
373
+ c,
374
+ opts?.tolerance,
375
+ opts?.iterLimit
376
+ );
359
377
  if (solution) {
360
378
  return [solution];
361
379
  }
362
- solution = calculate(initial_guesses[1], l, c);
380
+ solution = calculate(
381
+ initial_guesses[1],
382
+ l,
383
+ c,
384
+ opts?.tolerance,
385
+ opts?.iterLimit
386
+ );
363
387
  if (solution) {
364
388
  return [solution];
365
389
  }
366
- solution = calculate(initial_guesses[2], l, c);
390
+ solution = calculate(
391
+ initial_guesses[2],
392
+ l,
393
+ c,
394
+ opts?.tolerance,
395
+ opts?.iterLimit
396
+ );
367
397
  if (solution) {
368
398
  return [solution];
369
399
  }
@@ -1789,6 +1819,17 @@ var getDateTime = () => {
1789
1819
  return `${year}-${month}-${day}-${hr}${min}`;
1790
1820
  };
1791
1821
  var capitalizeString = (str) => str.charAt(0).toUpperCase() + str.slice(1);
1822
+ var formatTimeToHourMinute = (value, opts) => {
1823
+ const date = value instanceof Date ? value : new Date(value);
1824
+ if (Number.isNaN(date.getTime())) {
1825
+ return "";
1826
+ }
1827
+ return date.toLocaleTimeString(opts?.locale, {
1828
+ hour: "2-digit",
1829
+ minute: "2-digit",
1830
+ ...opts?.hour12 === void 0 ? {} : { hour12: opts.hour12 }
1831
+ });
1832
+ };
1792
1833
  var isToolIcon = (target) => target instanceof HTMLElement && target.className.includes("ToolIcon");
1793
1834
  var isInputLike = (target) => target instanceof HTMLElement && target.dataset.type === "wysiwyg" || target instanceof HTMLBRElement || // newline in wysiwyg
1794
1835
  target instanceof HTMLInputElement || target instanceof HTMLTextAreaElement || target instanceof HTMLSelectElement;
@@ -1796,7 +1837,7 @@ var isInteractive = (target) => {
1796
1837
  return isInputLike(target) || target instanceof Element && !!target.closest("label, button");
1797
1838
  };
1798
1839
  var isWritableElement = (target) => target instanceof HTMLElement && target.dataset.type === "wysiwyg" || target instanceof HTMLBRElement || // newline in wysiwyg
1799
- target instanceof HTMLTextAreaElement || target instanceof HTMLInputElement && (target.type === "text" || target.type === "number" || target.type === "password" || target.type === "search");
1840
+ target instanceof HTMLTextAreaElement || target instanceof HTMLInputElement && (target.type === "text" || target.type === "number" || target.type === "password" || target.type === "search") || target instanceof HTMLElement && target.closest(".cm-editor") !== null;
1800
1841
  var getFontFamilyString = ({
1801
1842
  fontFamily
1802
1843
  }) => {
@@ -1841,32 +1882,23 @@ var debounce = (fn, timeout) => {
1841
1882
  };
1842
1883
  return ret;
1843
1884
  };
1844
- var throttleRAF = (fn, opts) => {
1885
+ var throttleRAF = (fn) => {
1845
1886
  let timerId = null;
1846
1887
  let lastArgs = null;
1847
- let lastArgsTrailing = null;
1848
- const scheduleFunc = (args) => {
1888
+ const scheduleFunc = () => {
1849
1889
  timerId = window.requestAnimationFrame(() => {
1850
1890
  timerId = null;
1851
- fn(...args);
1891
+ const args = lastArgs;
1852
1892
  lastArgs = null;
1853
- if (lastArgsTrailing) {
1854
- lastArgs = lastArgsTrailing;
1855
- lastArgsTrailing = null;
1856
- scheduleFunc(lastArgs);
1893
+ if (args) {
1894
+ fn(...args);
1857
1895
  }
1858
1896
  });
1859
1897
  };
1860
1898
  const ret = (...args) => {
1861
- if (isTestEnv()) {
1862
- fn(...args);
1863
- return;
1864
- }
1865
1899
  lastArgs = args;
1866
1900
  if (timerId === null) {
1867
- scheduleFunc(lastArgs);
1868
- } else if (opts?.trailing) {
1869
- lastArgsTrailing = args;
1901
+ scheduleFunc();
1870
1902
  }
1871
1903
  };
1872
1904
  ret.flush = () => {
@@ -1875,12 +1907,12 @@ var throttleRAF = (fn, opts) => {
1875
1907
  timerId = null;
1876
1908
  }
1877
1909
  if (lastArgs) {
1878
- fn(...lastArgsTrailing || lastArgs);
1879
- lastArgs = lastArgsTrailing = null;
1910
+ fn(...lastArgs);
1911
+ lastArgs = null;
1880
1912
  }
1881
1913
  };
1882
1914
  ret.cancel = () => {
1883
- lastArgs = lastArgsTrailing = null;
1915
+ lastArgs = null;
1884
1916
  if (timerId !== null) {
1885
1917
  cancelAnimationFrame(timerId);
1886
1918
  timerId = null;
@@ -2688,6 +2720,8 @@ var getDefaultAppState = () => {
2688
2720
  gridStep: DEFAULT_GRID_STEP,
2689
2721
  gridModeEnabled: false,
2690
2722
  isBindingEnabled: true,
2723
+ bindingPreference: "enabled",
2724
+ isMidpointSnappingEnabled: true,
2691
2725
  defaultSidebarDockedPreference: false,
2692
2726
  isLoading: false,
2693
2727
  isResizing: false,
@@ -2743,7 +2777,8 @@ var getDefaultAppState = () => {
2743
2777
  searchMatches: null,
2744
2778
  lockedMultiSelections: {},
2745
2779
  activeLockedId: null,
2746
- bindMode: "orbit"
2780
+ bindMode: "orbit",
2781
+ boxSelectionMode: "contain"
2747
2782
  };
2748
2783
  };
2749
2784
  var APP_STATE_STORAGE_CONF = /* @__PURE__ */ ((config) => config)({
@@ -2792,7 +2827,10 @@ var APP_STATE_STORAGE_CONF = /* @__PURE__ */ ((config) => config)({
2792
2827
  gridStep: { browser: true, export: true, server: true },
2793
2828
  gridModeEnabled: { browser: true, export: true, server: true },
2794
2829
  height: { browser: false, export: false, server: false },
2795
- isBindingEnabled: { browser: false, export: false, server: false },
2830
+ isBindingEnabled: { browser: true, export: false, server: false },
2831
+ boxSelectionMode: { browser: true, export: false, server: false },
2832
+ bindingPreference: { browser: true, export: false, server: false },
2833
+ isMidpointSnappingEnabled: { browser: true, export: false, server: false },
2796
2834
  defaultSidebarDockedPreference: {
2797
2835
  browser: true,
2798
2836
  export: false,
@@ -3749,12 +3787,12 @@ var setElementShapesCacheEntry = (element, shape, offset) => {
3749
3787
  }
3750
3788
  shapes.set(offset, shape);
3751
3789
  };
3752
- function deconstructLinearOrFreeDrawElement(element) {
3790
+ function deconstructLinearOrFreeDrawElement(element, elementsMap) {
3753
3791
  const cachedShape = getElementShapesCacheEntry(element, 0);
3754
3792
  if (cachedShape) {
3755
3793
  return cachedShape;
3756
3794
  }
3757
- const ops = generateLinearCollisionShape(element);
3795
+ const ops = generateLinearCollisionShape(element, elementsMap);
3758
3796
  const lines = [];
3759
3797
  const curves = [];
3760
3798
  for (let idx = 0; idx < ops.length; idx += 1) {
@@ -4171,19 +4209,21 @@ var getSnapOutlineMidPoint = (point, element, elementsMap, zoom) => {
4171
4209
  );
4172
4210
  return candidate;
4173
4211
  };
4174
- var projectFixedPointOntoDiagonal = (arrow, point, element, startOrEnd, elementsMap, zoom) => {
4212
+ var projectFixedPointOntoDiagonal = (arrow, point, element, startOrEnd, elementsMap, zoom, isMidpointSnappingEnabled = true) => {
4175
4213
  invariant(arrow.points.length >= 2, "Arrow must have at least two points");
4176
4214
  if (arrow.width < 3 && arrow.height < 3) {
4177
4215
  return null;
4178
4216
  }
4179
- const sideMidPoint = getSnapOutlineMidPoint(
4180
- point,
4181
- element,
4182
- elementsMap,
4183
- zoom
4184
- );
4185
- if (sideMidPoint) {
4186
- return sideMidPoint;
4217
+ if (isMidpointSnappingEnabled) {
4218
+ const sideMidPoint = getSnapOutlineMidPoint(
4219
+ point,
4220
+ element,
4221
+ elementsMap,
4222
+ zoom
4223
+ );
4224
+ if (sideMidPoint) {
4225
+ return sideMidPoint;
4226
+ }
4187
4227
  }
4188
4228
  const [diagonalOne, diagonalTwo] = getDiagonalsForBindableElement(
4189
4229
  element,
@@ -4294,9 +4334,9 @@ var getLineHeightInPx = (fontSize, lineHeight) => {
4294
4334
  var getApproxMinLineHeight = (fontSize, lineHeight) => {
4295
4335
  return getLineHeightInPx(fontSize, lineHeight) + BOUND_TEXT_PADDING * 2;
4296
4336
  };
4297
- var textMetricsProvider;
4337
+ var PROVIDER_KEY = Symbol.for("excalidraw.textMetricsProvider");
4298
4338
  var setCustomTextMetricsProvider = (provider) => {
4299
- textMetricsProvider = provider;
4339
+ globalThis[PROVIDER_KEY] = provider;
4300
4340
  };
4301
4341
  var CanvasTextMetricsProvider = class {
4302
4342
  constructor() {
@@ -4322,10 +4362,11 @@ var CanvasTextMetricsProvider = class {
4322
4362
  }
4323
4363
  };
4324
4364
  var getLineWidth = (text, font) => {
4325
- if (!textMetricsProvider) {
4326
- textMetricsProvider = new CanvasTextMetricsProvider();
4365
+ let provider = globalThis[PROVIDER_KEY];
4366
+ if (!provider) {
4367
+ provider = new CanvasTextMetricsProvider();
4327
4368
  }
4328
- return textMetricsProvider.getLineWidth(text, font);
4369
+ return provider.getLineWidth(text, font);
4329
4370
  };
4330
4371
  var getTextWidth = (text, font) => {
4331
4372
  const lines = splitIntoLines(text);
@@ -4620,91 +4661,168 @@ var parseTokens = (line2) => {
4620
4661
  return line2.normalize("NFC").split(breakLineRegex).filter(Boolean);
4621
4662
  };
4622
4663
  var wrapText = (text, font, maxWidth) => {
4664
+ return getWrappedTextLines(text, font, maxWidth).map((line2) => line2.text).join("\n");
4665
+ };
4666
+ var getHardLineBreaks = (text) => {
4667
+ let offset = 0;
4668
+ return text.split("\n").map((line2) => {
4669
+ const start = offset;
4670
+ const end = start + line2.length;
4671
+ offset = end + 1;
4672
+ return {
4673
+ text: line2,
4674
+ start,
4675
+ end
4676
+ };
4677
+ });
4678
+ };
4679
+ var getWrappedTextLines = (text, font, maxWidth) => {
4623
4680
  if (!Number.isFinite(maxWidth) || maxWidth < 0) {
4624
- return text;
4681
+ return getHardLineBreaks(text);
4625
4682
  }
4626
4683
  const lines = [];
4627
- const originalLines = text.split("\n");
4628
- for (const originalLine of originalLines) {
4629
- const currentLineWidth = getLineWidth(originalLine, font);
4630
- if (currentLineWidth <= maxWidth) {
4631
- lines.push(originalLine);
4632
- continue;
4684
+ let offset = 0;
4685
+ for (const originalLine of text.split("\n")) {
4686
+ const originalLineWidth = getLineWidth(originalLine, font);
4687
+ if (originalLineWidth <= maxWidth) {
4688
+ lines.push({
4689
+ text: originalLine,
4690
+ start: offset,
4691
+ end: offset + originalLine.length
4692
+ });
4693
+ } else {
4694
+ lines.push(...wrapLine(originalLine, font, maxWidth, offset));
4633
4695
  }
4634
- const wrappedLine = wrapLine(originalLine, font, maxWidth);
4635
- lines.push(...wrappedLine);
4696
+ offset += originalLine.length + 1;
4636
4697
  }
4637
- return lines.join("\n");
4698
+ return lines;
4638
4699
  };
4639
- var wrapLine = (line2, font, maxWidth) => {
4700
+ var wrapLine = (line2, font, maxWidth, lineStart) => {
4640
4701
  const lines = [];
4641
4702
  const tokens = parseTokens(line2);
4642
- const tokenIterator = tokens[Symbol.iterator]();
4643
4703
  let currentLine = "";
4704
+ let currentLineStart = lineStart;
4705
+ let currentLineEnd = lineStart;
4644
4706
  let currentLineWidth = 0;
4645
- let iterator = tokenIterator.next();
4646
- while (!iterator.done) {
4647
- const token = iterator.value;
4707
+ let tokenOffset = lineStart;
4708
+ let tokenIndex = 0;
4709
+ while (tokenIndex < tokens.length) {
4710
+ const token = tokens[tokenIndex];
4711
+ const tokenStart = tokenOffset;
4712
+ const tokenEnd = tokenStart + token.length;
4648
4713
  const testLine = currentLine + token;
4649
4714
  const testLineWidth = isSingleCharacter(token) ? currentLineWidth + charWidth.calculate(token, font) : getLineWidth(testLine, font);
4650
4715
  if (/\s/.test(token) || testLineWidth <= maxWidth) {
4716
+ if (!currentLine) {
4717
+ currentLineStart = tokenStart;
4718
+ }
4651
4719
  currentLine = testLine;
4720
+ currentLineEnd = tokenEnd;
4652
4721
  currentLineWidth = testLineWidth;
4653
- iterator = tokenIterator.next();
4722
+ tokenOffset = tokenEnd;
4723
+ tokenIndex++;
4654
4724
  continue;
4655
4725
  }
4656
4726
  if (!currentLine) {
4657
- const wrappedWord = wrapWord(token, font, maxWidth);
4658
- const trailingLine = wrappedWord[wrappedWord.length - 1] ?? "";
4727
+ const wrappedWord = wrapWord(token, font, maxWidth, tokenStart);
4728
+ const trailingLine = wrappedWord[wrappedWord.length - 1] ?? {
4729
+ text: "",
4730
+ start: tokenStart,
4731
+ end: tokenStart
4732
+ };
4659
4733
  const precedingLines = wrappedWord.slice(0, -1);
4660
4734
  lines.push(...precedingLines);
4661
- currentLine = trailingLine;
4662
- currentLineWidth = getLineWidth(trailingLine, font);
4663
- iterator = tokenIterator.next();
4735
+ currentLine = trailingLine.text;
4736
+ currentLineStart = trailingLine.start;
4737
+ currentLineEnd = trailingLine.end;
4738
+ currentLineWidth = getLineWidth(trailingLine.text, font);
4739
+ tokenOffset = tokenEnd;
4740
+ tokenIndex++;
4664
4741
  } else {
4665
- lines.push(currentLine.trimEnd());
4742
+ lines.push(
4743
+ trimLineEndAtSoftBreak(currentLine, currentLineStart, currentLineEnd)
4744
+ );
4666
4745
  currentLine = "";
4746
+ currentLineStart = tokenStart;
4747
+ currentLineEnd = tokenStart;
4667
4748
  currentLineWidth = 0;
4668
4749
  }
4669
4750
  }
4670
4751
  if (currentLine) {
4671
- const trailingLine = trimLine(currentLine, font, maxWidth);
4752
+ const trailingLine = trimLine(
4753
+ currentLine,
4754
+ currentLineStart,
4755
+ currentLineEnd,
4756
+ font,
4757
+ maxWidth
4758
+ );
4672
4759
  lines.push(trailingLine);
4673
4760
  }
4674
4761
  return lines;
4675
4762
  };
4676
- var wrapWord = (word, font, maxWidth) => {
4763
+ var wrapWord = (word, font, maxWidth, wordStart) => {
4677
4764
  if (getEmojiRegex().test(word)) {
4678
- return [word];
4765
+ return [
4766
+ {
4767
+ text: word,
4768
+ start: wordStart,
4769
+ end: wordStart + word.length
4770
+ }
4771
+ ];
4679
4772
  }
4680
4773
  satisfiesWordInvariant(word);
4681
4774
  const lines = [];
4682
4775
  const chars = Array.from(word);
4683
4776
  let currentLine = "";
4777
+ let currentLineStart = wordStart;
4778
+ let currentLineEnd = wordStart;
4684
4779
  let currentLineWidth = 0;
4780
+ let offset = wordStart;
4685
4781
  for (const char of chars) {
4782
+ const charStart = offset;
4783
+ const charEnd = charStart + char.length;
4686
4784
  const _charWidth = charWidth.calculate(char, font);
4687
4785
  const testLineWidth = currentLineWidth + _charWidth;
4688
4786
  if (testLineWidth <= maxWidth) {
4787
+ if (!currentLine) {
4788
+ currentLineStart = charStart;
4789
+ }
4689
4790
  currentLine = currentLine + char;
4791
+ currentLineEnd = charEnd;
4690
4792
  currentLineWidth = testLineWidth;
4793
+ offset = charEnd;
4691
4794
  continue;
4692
4795
  }
4693
4796
  if (currentLine) {
4694
- lines.push(currentLine);
4797
+ lines.push({
4798
+ text: currentLine,
4799
+ start: currentLineStart,
4800
+ end: currentLineEnd
4801
+ });
4695
4802
  }
4696
4803
  currentLine = char;
4804
+ currentLineStart = charStart;
4805
+ currentLineEnd = charEnd;
4697
4806
  currentLineWidth = _charWidth;
4807
+ offset = charEnd;
4698
4808
  }
4699
4809
  if (currentLine) {
4700
- lines.push(currentLine);
4810
+ lines.push({
4811
+ text: currentLine,
4812
+ start: currentLineStart,
4813
+ end: currentLineEnd
4814
+ });
4701
4815
  }
4702
4816
  return lines;
4703
4817
  };
4704
- var trimLine = (line2, font, maxWidth) => {
4818
+ var trimLine = (line2, start, end, font, maxWidth) => {
4705
4819
  const shouldTrimWhitespaces = getLineWidth(line2, font) > maxWidth;
4706
4820
  if (!shouldTrimWhitespaces) {
4707
- return line2;
4821
+ return {
4822
+ text: line2,
4823
+ start,
4824
+ end
4825
+ };
4708
4826
  }
4709
4827
  let [, trimmedLine, whitespaces] = line2.match(/^(.+?)(\s+)$/) ?? [
4710
4828
  line2,
@@ -4721,7 +4839,19 @@ var trimLine = (line2, font, maxWidth) => {
4721
4839
  trimmedLine = trimmedLine + whitespace;
4722
4840
  trimmedLineWidth = testLineWidth;
4723
4841
  }
4724
- return trimmedLine;
4842
+ return {
4843
+ text: trimmedLine,
4844
+ start,
4845
+ end: end - (line2.length - trimmedLine.length)
4846
+ };
4847
+ };
4848
+ var trimLineEndAtSoftBreak = (line2, start, end) => {
4849
+ const trimmedLine = line2.trimEnd();
4850
+ return {
4851
+ text: trimmedLine,
4852
+ start,
4853
+ end: end - (line2.length - trimmedLine.length)
4854
+ };
4725
4855
  };
4726
4856
  var isSingleCharacter = (maybeSingleCharacter) => {
4727
4857
  return maybeSingleCharacter.codePointAt(0) !== void 0 && maybeSingleCharacter.codePointAt(1) === void 0;
@@ -4960,7 +5090,8 @@ var getContainerCenter = (container, appState, elementsMap) => {
4960
5090
  if (!midSegmentMidpoint) {
4961
5091
  midSegmentMidpoint = LinearElementEditor.getSegmentMidPoint(
4962
5092
  container,
4963
- index + 1
5093
+ index + 1,
5094
+ elementsMap
4964
5095
  );
4965
5096
  }
4966
5097
  return { x: midSegmentMidpoint[0], y: midSegmentMidpoint[1] };
@@ -5095,7 +5226,7 @@ var distanceToElement = (element, elementsMap, p) => {
5095
5226
  case "line":
5096
5227
  case "arrow":
5097
5228
  case "freedraw":
5098
- return distanceToLinearOrFreeDraElement(element, p);
5229
+ return distanceToLinearOrFreeDraElement(element, elementsMap, p);
5099
5230
  }
5100
5231
  };
5101
5232
  var distanceToRectanguloidElement = (element, elementsMap, p) => {
@@ -5124,8 +5255,11 @@ var distanceToEllipseElement = (element, elementsMap, p) => {
5124
5255
  ellipse(center, element.width / 2, element.height / 2)
5125
5256
  );
5126
5257
  };
5127
- var distanceToLinearOrFreeDraElement = (element, p) => {
5128
- const [lines, curves] = deconstructLinearOrFreeDrawElement(element);
5258
+ var distanceToLinearOrFreeDraElement = (element, elementsMap, p) => {
5259
+ const [lines, curves] = deconstructLinearOrFreeDrawElement(
5260
+ element,
5261
+ elementsMap
5262
+ );
5129
5263
  return Math.min(
5130
5264
  ...lines.map((s) => distanceToLineSegment(p, s)),
5131
5265
  ...curves.map((a) => curvePointDistance(a, p))
@@ -5174,14 +5308,11 @@ var hitElementItself = ({
5174
5308
  )
5175
5309
  ) : false;
5176
5310
  const bounds = getElementBounds(element, elementsMap, true);
5177
- const hitBounds = isPointWithinBounds(
5178
- pointFrom(bounds[0] - threshold, bounds[1] - threshold),
5179
- pointRotateRads(
5180
- point,
5181
- getCenterForBounds(bounds),
5182
- -element.angle
5183
- ),
5184
- pointFrom(bounds[2] + threshold, bounds[3] + threshold)
5311
+ const hitBounds = isPointInRotatedBounds(
5312
+ point,
5313
+ bounds,
5314
+ element.angle,
5315
+ threshold
5185
5316
  );
5186
5317
  if (!hitBounds && !hitFrameName) {
5187
5318
  return false;
@@ -5199,13 +5330,17 @@ var hitElementItself = ({
5199
5330
  cachedHit = result;
5200
5331
  return result;
5201
5332
  };
5333
+ var isPointInRotatedBounds = (point, bounds, angle, tolerance = 0) => {
5334
+ const adjustedPoint = angle === 0 ? point : pointRotateRads(point, getCenterForBounds(bounds), -angle);
5335
+ return isPointWithinBounds(
5336
+ pointFrom(bounds[0] - tolerance, bounds[1] - tolerance),
5337
+ adjustedPoint,
5338
+ pointFrom(bounds[2] + tolerance, bounds[3] + tolerance)
5339
+ );
5340
+ };
5202
5341
  var hitElementBoundingBox = (point, element, elementsMap, tolerance = 0) => {
5203
- let [x1, y1, x2, y2] = getElementBounds(element, elementsMap);
5204
- x1 -= tolerance;
5205
- y1 -= tolerance;
5206
- x2 += tolerance;
5207
- y2 += tolerance;
5208
- return isPointWithinBounds(pointFrom(x1, y1), point, pointFrom(x2, y2));
5342
+ const bounds = getElementBounds(element, elementsMap, true);
5343
+ return isPointInRotatedBounds(point, bounds, element.angle, tolerance);
5209
5344
  };
5210
5345
  var hitElementBoundingBoxOnly = (hitArgs, elementsMap) => !hitElementItself(hitArgs) && // bound text is considered part of the element (even if it's outside the bounding box)
5211
5346
  !hitElementBoundText(hitArgs.point, hitArgs.element, elementsMap) && hitElementBoundingBox(hitArgs.point, hitArgs.element, elementsMap);
@@ -5364,7 +5499,12 @@ var intersectElementWithLineSegment = (element, elementsMap, line2, offset = 0,
5364
5499
  case "line":
5365
5500
  case "freedraw":
5366
5501
  case "arrow":
5367
- return intersectLinearOrFreeDrawWithLineSegment(element, line2, onlyFirst);
5502
+ return intersectLinearOrFreeDrawWithLineSegment(
5503
+ element,
5504
+ line2,
5505
+ elementsMap,
5506
+ onlyFirst
5507
+ );
5368
5508
  }
5369
5509
  };
5370
5510
  var curveIntersections = (curves, segment, intersections, center, angle, onlyFirst = false) => {
@@ -5403,8 +5543,11 @@ var lineIntersections = (lines, segment, intersections, center, angle, onlyFirst
5403
5543
  }
5404
5544
  return intersections;
5405
5545
  };
5406
- var intersectLinearOrFreeDrawWithLineSegment = (element, segment, onlyFirst = false) => {
5407
- const [lines, curves] = deconstructLinearOrFreeDrawElement(element);
5546
+ var intersectLinearOrFreeDrawWithLineSegment = (element, segment, elementsMap, onlyFirst = false) => {
5547
+ const [lines, curves] = deconstructLinearOrFreeDrawElement(
5548
+ element,
5549
+ elementsMap
5550
+ );
5408
5551
  const intersections = [];
5409
5552
  for (const l of lines) {
5410
5553
  const intersection = lineSegmentIntersectionPoints(l, segment);
@@ -5426,7 +5569,9 @@ var intersectLinearOrFreeDrawWithLineSegment = (element, segment, onlyFirst = fa
5426
5569
  if (!doBoundsIntersect(b1, b2)) {
5427
5570
  continue;
5428
5571
  }
5429
- const hits = curveIntersectLineSegment(c, segment);
5572
+ const hits = curveIntersectLineSegment(c, segment, {
5573
+ iterLimit: 10
5574
+ });
5430
5575
  if (hits.length > 0) {
5431
5576
  intersections.push(...hits);
5432
5577
  if (onlyFirst) {
@@ -6484,7 +6629,7 @@ var getElbowArrowData = (arrow, elementsMap, nextPoints, options) => {
6484
6629
  const origEndGlobalPoint = pointTranslate(nextPoints[nextPoints.length - 1], vector(arrow.x, arrow.y));
6485
6630
  let hoveredStartElement = null;
6486
6631
  let hoveredEndElement = null;
6487
- if (options?.isDragging) {
6632
+ if (options?.isDragging && options?.isBindingEnabled !== false) {
6488
6633
  const elements = Array.from(elementsMap.values());
6489
6634
  hoveredStartElement = getHoveredElement(
6490
6635
  origStartGlobalPoint,
@@ -6515,7 +6660,9 @@ var getElbowArrowData = (arrow, elementsMap, nextPoints, options) => {
6515
6660
  origStartGlobalPoint,
6516
6661
  hoveredStartElement,
6517
6662
  elementsMap,
6518
- options?.isDragging
6663
+ options?.isDragging,
6664
+ options?.isBindingEnabled,
6665
+ options?.isMidpointSnappingEnabled
6519
6666
  );
6520
6667
  const endGlobalPoint = getGlobalPoint(
6521
6668
  {
@@ -6530,7 +6677,9 @@ var getElbowArrowData = (arrow, elementsMap, nextPoints, options) => {
6530
6677
  origEndGlobalPoint,
6531
6678
  hoveredEndElement,
6532
6679
  elementsMap,
6533
- options?.isDragging
6680
+ options?.isDragging,
6681
+ options?.isBindingEnabled,
6682
+ options?.isMidpointSnappingEnabled
6534
6683
  );
6535
6684
  const startHeading = getBindPointHeading(
6536
6685
  startGlobalPoint,
@@ -7153,14 +7302,16 @@ var neighborIndexToHeading = (idx) => {
7153
7302
  }
7154
7303
  return HEADING_LEFT;
7155
7304
  };
7156
- var getGlobalPoint = (arrow, startOrEnd, fixedPointRatio, initialPoint, element, elementsMap, isDragging) => {
7305
+ var getGlobalPoint = (arrow, startOrEnd, fixedPointRatio, initialPoint, element, elementsMap, isDragging, isBindingEnabled2 = true, isMidpointSnappingEnabled = true) => {
7157
7306
  if (isDragging) {
7158
- if (element && elementsMap) {
7307
+ if (isBindingEnabled2 && element && elementsMap) {
7159
7308
  return bindPointToSnapToElementOutline(
7160
7309
  arrow,
7161
7310
  element,
7162
7311
  startOrEnd,
7163
- elementsMap
7312
+ elementsMap,
7313
+ void 0,
7314
+ isMidpointSnappingEnabled
7164
7315
  );
7165
7316
  }
7166
7317
  return initialPoint;
@@ -7321,9 +7472,6 @@ var maxBindingDistance_simple = (zoom) => {
7321
7472
  BASE_BINDING_DISTANCE * 2
7322
7473
  );
7323
7474
  };
7324
- var shouldEnableBindingForPointerEvent = (event) => {
7325
- return !event[KEYS.CTRL_OR_CMD];
7326
- };
7327
7475
  var isBindingEnabled = (appState) => {
7328
7476
  return appState.isBindingEnabled;
7329
7477
  };
@@ -7341,8 +7489,20 @@ var bindOrUnbindBindingElement = (arrow, draggingPoints, scenePointerX, scenePoi
7341
7489
  finalize: true
7342
7490
  }
7343
7491
  );
7344
- bindOrUnbindBindingElementEdge(arrow, start, "start", scene);
7345
- bindOrUnbindBindingElementEdge(arrow, end, "end", scene);
7492
+ bindOrUnbindBindingElementEdge(
7493
+ arrow,
7494
+ start,
7495
+ "start",
7496
+ scene,
7497
+ appState.isBindingEnabled
7498
+ );
7499
+ bindOrUnbindBindingElementEdge(
7500
+ arrow,
7501
+ end,
7502
+ "end",
7503
+ scene,
7504
+ appState.isBindingEnabled
7505
+ );
7346
7506
  if (start.focusPoint || end.focusPoint) {
7347
7507
  const updates = /* @__PURE__ */ new Map();
7348
7508
  if (start.focusPoint) {
@@ -7371,11 +7531,19 @@ var bindOrUnbindBindingElement = (arrow, draggingPoints, scenePointerX, scenePoi
7371
7531
  }
7372
7532
  return { start, end };
7373
7533
  };
7374
- var bindOrUnbindBindingElementEdge = (arrow, { mode, element, focusPoint }, startOrEnd, scene) => {
7534
+ var bindOrUnbindBindingElementEdge = (arrow, { mode, element, focusPoint }, startOrEnd, scene, shouldSnapToOutline = true) => {
7375
7535
  if (mode === null) {
7376
7536
  unbindBindingElement(arrow, startOrEnd, scene);
7377
7537
  } else if (mode !== void 0) {
7378
- bindBindingElement(arrow, element, mode, startOrEnd, scene, focusPoint);
7538
+ bindBindingElement(
7539
+ arrow,
7540
+ element,
7541
+ mode,
7542
+ startOrEnd,
7543
+ scene,
7544
+ focusPoint,
7545
+ shouldSnapToOutline
7546
+ );
7379
7547
  }
7380
7548
  };
7381
7549
  var bindingStrategyForElbowArrowEndpointDragging = (arrow, draggingPoints, elementsMap, elements, zoom) => {
@@ -7729,7 +7897,8 @@ var getBindingStrategyForDraggingBindingElementEndpoints_simple = (arrow, draggi
7729
7897
  hit,
7730
7898
  startDragged ? "start" : "end",
7731
7899
  elementsMap,
7732
- appState.zoom
7900
+ appState.zoom,
7901
+ appState.isMidpointSnappingEnabled
7733
7902
  ) || globalPoint
7734
7903
  } : { mode: null };
7735
7904
  const otherEndpoint = LinearElementEditor.getPointAtIndexGlobalCoordinates(
@@ -7758,7 +7927,8 @@ var getBindingStrategyForDraggingBindingElementEndpoints_simple = (arrow, draggi
7758
7927
  otherBindableElement,
7759
7928
  startDragged ? "end" : "start",
7760
7929
  elementsMap,
7761
- appState.zoom
7930
+ appState.zoom,
7931
+ appState.isMidpointSnappingEnabled
7762
7932
  ) || otherEndpoint
7763
7933
  } : { mode: void 0 } : { mode: void 0 };
7764
7934
  return {
@@ -7868,7 +8038,7 @@ var bindOrUnbindBindingElements = (selectedArrows, scene, appState) => {
7868
8038
  );
7869
8039
  });
7870
8040
  };
7871
- var bindBindingElement = (arrow, hoveredElement, mode, startOrEnd, scene, focusPoint) => {
8041
+ var bindBindingElement = (arrow, hoveredElement, mode, startOrEnd, scene, focusPoint, shouldSnapToOutline = true) => {
7872
8042
  const elementsMap = scene.getNonDeletedElementsMap();
7873
8043
  let binding;
7874
8044
  if (isElbowArrow(arrow)) {
@@ -7879,7 +8049,8 @@ var bindBindingElement = (arrow, hoveredElement, mode, startOrEnd, scene, focusP
7879
8049
  arrow,
7880
8050
  hoveredElement,
7881
8051
  startOrEnd,
7882
- elementsMap
8052
+ elementsMap,
8053
+ shouldSnapToOutline
7883
8054
  )
7884
8055
  };
7885
8056
  } else {
@@ -8091,7 +8262,7 @@ var getDistanceForBinding = (point, bindableElement, elementsMap, zoom) => {
8091
8262
  const bindDistance = maxBindingDistance_simple(zoom);
8092
8263
  return distance2 > bindDistance ? null : distance2;
8093
8264
  };
8094
- var bindPointToSnapToElementOutline = (arrowElement, bindableElement, startOrEnd, elementsMap, customIntersector) => {
8265
+ var bindPointToSnapToElementOutline = (arrowElement, bindableElement, startOrEnd, elementsMap, customIntersector, isMidpointSnappingEnabled = true) => {
8095
8266
  const elbowed = isElbowArrow(arrowElement);
8096
8267
  const point = LinearElementEditor.getPointAtIndexGlobalCoordinates(
8097
8268
  arrowElement,
@@ -8120,13 +8291,7 @@ var bindPointToSnapToElementOutline = (arrowElement, bindableElement, startOrEnd
8120
8291
  const isHorizontal = headingIsHorizontal(
8121
8292
  headingForPointFromElement(bindableElement, aabb, point)
8122
8293
  );
8123
- const snapPoint = snapToMid(
8124
- bindableElement,
8125
- elementsMap,
8126
- edgePoint,
8127
- 0.05,
8128
- arrowElement
8129
- );
8294
+ const snapPoint = isMidpointSnappingEnabled ? snapToMid(bindableElement, elementsMap, edgePoint, 0.05, arrowElement) : void 0;
8130
8295
  const resolved = snapPoint || point;
8131
8296
  const otherPoint = pointFrom(
8132
8297
  isHorizontal ? bindableCenter[0] : resolved[0],
@@ -8458,17 +8623,23 @@ var updateBoundPoint = (arrow, startOrEnd, binding, bindableElement, elementsMap
8458
8623
  null
8459
8624
  );
8460
8625
  };
8461
- var calculateFixedPointForElbowArrowBinding = (linearElement, hoveredElement, startOrEnd, elementsMap) => {
8626
+ var calculateFixedPointForElbowArrowBinding = (linearElement, hoveredElement, startOrEnd, elementsMap, shouldSnapToOutline = true, isMidpointSnappingEnabled = true) => {
8462
8627
  const bounds = [
8463
8628
  hoveredElement.x,
8464
8629
  hoveredElement.y,
8465
8630
  hoveredElement.x + hoveredElement.width,
8466
8631
  hoveredElement.y + hoveredElement.height
8467
8632
  ];
8468
- const snappedPoint = bindPointToSnapToElementOutline(
8633
+ const snappedPoint = shouldSnapToOutline ? bindPointToSnapToElementOutline(
8469
8634
  linearElement,
8470
8635
  hoveredElement,
8471
8636
  startOrEnd,
8637
+ elementsMap,
8638
+ void 0,
8639
+ isMidpointSnappingEnabled
8640
+ ) : LinearElementEditor.getPointAtIndexGlobalCoordinates(
8641
+ linearElement,
8642
+ startOrEnd === "start" ? 0 : -1,
8472
8643
  elementsMap
8473
8644
  );
8474
8645
  const globalMidPoint = pointFrom(
@@ -8551,16 +8722,20 @@ var fixDuplicatedBindingsAfterDuplication = (duplicatedElements, origIdToDuplica
8551
8722
  if (isElbowArrow(duplicateElement2)) {
8552
8723
  Object.assign(
8553
8724
  duplicateElement2,
8554
- updateElbowArrowPoints(duplicateElement2, duplicateElementsMap, {
8555
- points: [
8556
- duplicateElement2.points[0],
8557
- duplicateElement2.points[duplicateElement2.points.length - 1]
8558
- ]
8559
- })
8725
+ normalizeElbowArrow(duplicateElement2, duplicateElementsMap)
8560
8726
  );
8561
8727
  }
8562
8728
  }
8563
8729
  };
8730
+ var normalizeElbowArrow = (arrow, elementsMap) => updateElbowArrowPoints(arrow, elementsMap, {
8731
+ points: [arrow.points[0], arrow.points[arrow.points.length - 1]]
8732
+ });
8733
+ var normalizeElbowArrows = (elements, elementsMap) => {
8734
+ const map = elementsMap ?? arrayToMap(elements);
8735
+ return elements.map(
8736
+ (element) => isElbowArrow(element) ? { ...element, ...normalizeElbowArrow(element, map) } : element
8737
+ );
8738
+ };
8564
8739
  var fixBindingsAfterDeletion = (sceneElements, deletedElements) => {
8565
8740
  const elements = arrayToMap(sceneElements);
8566
8741
  for (const element of deletedElements) {
@@ -9006,11 +9181,20 @@ var _LinearElementEditor = class _LinearElementEditor {
9006
9181
  event.altKey,
9007
9182
  linearElementEditor
9008
9183
  );
9009
- _LinearElementEditor.movePoints(element, app.scene, positions, {
9010
- startBinding: updates?.startBinding,
9011
- endBinding: updates?.endBinding,
9012
- moveMidPointsWithElement: updates?.moveMidPointsWithElement
9013
- });
9184
+ _LinearElementEditor.movePoints(
9185
+ element,
9186
+ app.scene,
9187
+ positions,
9188
+ {
9189
+ startBinding: updates?.startBinding,
9190
+ endBinding: updates?.endBinding,
9191
+ moveMidPointsWithElement: updates?.moveMidPointsWithElement
9192
+ },
9193
+ {
9194
+ isBindingEnabled: app.state.isBindingEnabled,
9195
+ isMidpointSnappingEnabled: app.state.isMidpointSnappingEnabled
9196
+ }
9197
+ );
9014
9198
  if (isBindingElement(element, false)) {
9015
9199
  if (isBindingEnabled(app.state)) {
9016
9200
  suggestedBinding = updates?.suggestedBinding ?? null;
@@ -9046,7 +9230,8 @@ var _LinearElementEditor = class _LinearElementEditor {
9046
9230
  startBindingElement,
9047
9231
  "start",
9048
9232
  elementsMap,
9049
- app.state.zoom
9233
+ app.state.zoom,
9234
+ app.state.isMidpointSnappingEnabled
9050
9235
  ) : linearElementEditor.initialState.altFocusPoint
9051
9236
  }
9052
9237
  };
@@ -9137,11 +9322,20 @@ var _LinearElementEditor = class _LinearElementEditor {
9137
9322
  event.altKey,
9138
9323
  linearElementEditor
9139
9324
  );
9140
- _LinearElementEditor.movePoints(element, app.scene, positions, {
9141
- startBinding: updates?.startBinding,
9142
- endBinding: updates?.endBinding,
9143
- moveMidPointsWithElement: updates?.moveMidPointsWithElement
9144
- });
9325
+ _LinearElementEditor.movePoints(
9326
+ element,
9327
+ app.scene,
9328
+ positions,
9329
+ {
9330
+ startBinding: updates?.startBinding,
9331
+ endBinding: updates?.endBinding,
9332
+ moveMidPointsWithElement: updates?.moveMidPointsWithElement
9333
+ },
9334
+ {
9335
+ isBindingEnabled: app.state.isBindingEnabled,
9336
+ isMidpointSnappingEnabled: app.state.isMidpointSnappingEnabled
9337
+ }
9338
+ );
9145
9339
  if (isBindingElement(element, false)) {
9146
9340
  if (isBindingEnabled(app.state) && (startIsSelected || endIsSelected)) {
9147
9341
  suggestedBinding = updates?.suggestedBinding ?? null;
@@ -9194,7 +9388,8 @@ var _LinearElementEditor = class _LinearElementEditor {
9194
9388
  altFocusPointBindableElement,
9195
9389
  "start",
9196
9390
  elementsMap,
9197
- app.state.zoom
9391
+ app.state.zoom,
9392
+ app.state.isMidpointSnappingEnabled
9198
9393
  ) : linearElementEditor.initialState.altFocusPoint
9199
9394
  },
9200
9395
  segmentMidPointHoveredCoords: newSelectedMidPointHoveredCoords,
@@ -9272,7 +9467,7 @@ var _LinearElementEditor = class _LinearElementEditor {
9272
9467
  }
9273
9468
  };
9274
9469
  }
9275
- static isSegmentTooShort(element, startPoint, endPoint, index, zoom) {
9470
+ static isSegmentTooShort(element, startPoint, endPoint, index, zoom, elementsMap) {
9276
9471
  if (isElbowArrow(element)) {
9277
9472
  if (index >= 0 && index < element.points.length) {
9278
9473
  return pointDistance(startPoint, endPoint) * zoom.value < _LinearElementEditor.POINT_HANDLE_SIZE / 2;
@@ -9281,7 +9476,10 @@ var _LinearElementEditor = class _LinearElementEditor {
9281
9476
  }
9282
9477
  let distance2 = pointDistance(startPoint, endPoint);
9283
9478
  if (element.points.length > 2 && element.roundness) {
9284
- const [lines, curves] = deconstructLinearOrFreeDrawElement(element);
9479
+ const [lines, curves] = deconstructLinearOrFreeDrawElement(
9480
+ element,
9481
+ elementsMap
9482
+ );
9285
9483
  invariant(
9286
9484
  lines.length === 0 && curves.length > 0,
9287
9485
  "Only linears built out of curves are supported"
@@ -9294,7 +9492,7 @@ var _LinearElementEditor = class _LinearElementEditor {
9294
9492
  }
9295
9493
  return distance2 * zoom.value < _LinearElementEditor.POINT_HANDLE_SIZE * 4;
9296
9494
  }
9297
- static getSegmentMidPoint(element, index) {
9495
+ static getSegmentMidPoint(element, index, elementsMap) {
9298
9496
  if (isElbowArrow(element)) {
9299
9497
  invariant(
9300
9498
  element.points.length >= index,
@@ -9303,7 +9501,10 @@ var _LinearElementEditor = class _LinearElementEditor {
9303
9501
  const p = pointCenter(element.points[index - 1], element.points[index]);
9304
9502
  return pointFrom(element.x + p[0], element.y + p[1]);
9305
9503
  }
9306
- const [lines, curves] = deconstructLinearOrFreeDrawElement(element);
9504
+ const [lines, curves] = deconstructLinearOrFreeDrawElement(
9505
+ element,
9506
+ elementsMap
9507
+ );
9307
9508
  invariant(
9308
9509
  lines.length === 0 && curves.length > 0 || lines.length > 0 && curves.length === 0,
9309
9510
  "Only linears built out of either segments or curves are supported"
@@ -9735,7 +9936,7 @@ var _LinearElementEditor = class _LinearElementEditor {
9735
9936
  offsetY
9736
9937
  );
9737
9938
  }
9738
- static movePoints(element, scene, pointUpdates, otherUpdates) {
9939
+ static movePoints(element, scene, pointUpdates, otherUpdates, options) {
9739
9940
  const { points } = element;
9740
9941
  if (isLineElement(element) && element.polygon) {
9741
9942
  const firstPointUpdate = pointUpdates.get(0);
@@ -9778,7 +9979,9 @@ var _LinearElementEditor = class _LinearElementEditor {
9778
9979
  offsetY,
9779
9980
  otherUpdates,
9780
9981
  {
9781
- isDragging: Array.from(pointUpdates.values()).some((t) => t.isDragging)
9982
+ isDragging: Array.from(pointUpdates.values()).some((t) => t.isDragging),
9983
+ isBindingEnabled: options?.isBindingEnabled,
9984
+ isMidpointSnappingEnabled: options?.isMidpointSnappingEnabled
9782
9985
  }
9783
9986
  );
9784
9987
  }
@@ -9857,7 +10060,9 @@ var _LinearElementEditor = class _LinearElementEditor {
9857
10060
  updates.points = Array.from(nextPoints);
9858
10061
  scene.mutateElement(element, updates, {
9859
10062
  informMutation: true,
9860
- isDragging: options?.isDragging ?? false
10063
+ isDragging: options?.isDragging ?? false,
10064
+ isBindingEnabled: options?.isBindingEnabled,
10065
+ isMidpointSnappingEnabled: options?.isMidpointSnappingEnabled
9861
10066
  });
9862
10067
  } else {
9863
10068
  const nextCoords = getElementPointsCoords(element, nextPoints);
@@ -9999,7 +10204,8 @@ __publicField(_LinearElementEditor, "getEditorMidPoints", (element, elementsMap,
9999
10204
  element.points[index],
10000
10205
  element.points[index + 1],
10001
10206
  index,
10002
- appState.zoom
10207
+ appState.zoom,
10208
+ elementsMap
10003
10209
  )) {
10004
10210
  midpoints.push(null);
10005
10211
  index++;
@@ -10007,7 +10213,8 @@ __publicField(_LinearElementEditor, "getEditorMidPoints", (element, elementsMap,
10007
10213
  }
10008
10214
  const segmentMidPoint = _LinearElementEditor.getSegmentMidPoint(
10009
10215
  element,
10010
- index + 1
10216
+ index + 1,
10217
+ elementsMap
10011
10218
  );
10012
10219
  midpoints.push(segmentMidPoint);
10013
10220
  index++;
@@ -10094,7 +10301,8 @@ __publicField(_LinearElementEditor, "getBoundTextElementPosition", (element, bou
10094
10301
  const index = element.points.length / 2 - 1;
10095
10302
  const midSegmentMidpoint = _LinearElementEditor.getSegmentMidPoint(
10096
10303
  element,
10097
- index + 1
10304
+ index + 1,
10305
+ elementsMap
10098
10306
  );
10099
10307
  x = midSegmentMidpoint[0] - boundTextElement.width / 2;
10100
10308
  y = midSegmentMidpoint[1] - boundTextElement.height / 2;
@@ -10258,14 +10466,14 @@ var pointDraggingUpdates = (selectedPointsIndices, deltaX, deltaY, scenePointerX
10258
10466
  updates: {
10259
10467
  suggestedBinding: suggestedBindingElement ? {
10260
10468
  element: suggestedBindingElement,
10261
- midPoint: snapToMid(
10469
+ midPoint: app.state.isMidpointSnappingEnabled ? snapToMid(
10262
10470
  suggestedBindingElement,
10263
10471
  elementsMap,
10264
10472
  pointFrom(
10265
10473
  scenePointerX - linearElementEditor.pointerOffset.x,
10266
10474
  scenePointerY - linearElementEditor.pointerOffset.y
10267
10475
  )
10268
- )
10476
+ ) : void 0
10269
10477
  } : null
10270
10478
  }
10271
10479
  };
@@ -10409,7 +10617,7 @@ var pointDraggingUpdates = (selectedPointsIndices, deltaX, deltaY, scenePointerX
10409
10617
  nextArrow.endBinding.elementId
10410
10618
  ) : null;
10411
10619
  const endLocalPoint = startIsDraggingOverEndElement ? nextArrow.points[nextArrow.points.length - 1] : endIsDraggingOverStartElement && app.state.bindMode !== "inside" && getFeatureFlag("COMPLEX_BINDINGS") ? nextArrow.points[0] : endBindable ? updateBoundPoint(
10412
- element,
10620
+ nextArrow,
10413
10621
  "endBinding",
10414
10622
  nextArrow.endBinding,
10415
10623
  endBindable,
@@ -10421,7 +10629,7 @@ var pointDraggingUpdates = (selectedPointsIndices, deltaX, deltaY, scenePointerX
10421
10629
  nextArrow.startBinding.elementId
10422
10630
  ) : null;
10423
10631
  const startLocalPoint = endIsDraggingOverStartElement && getFeatureFlag("COMPLEX_BINDINGS") ? nextArrow.points[0] : startIsDraggingOverEndElement && app.state.bindMode !== "inside" && getFeatureFlag("COMPLEX_BINDINGS") ? endLocalPoint : startBindable ? updateBoundPoint(
10424
- element,
10632
+ nextArrow,
10425
10633
  "startBinding",
10426
10634
  nextArrow.startBinding,
10427
10635
  startBindable,
@@ -10489,131 +10697,6 @@ function doLineSegmentsIntersect(a, b) {
10489
10697
  return doBBoxesIntersect(getBBox(a), getBBox(b)) && isLineSegmentTouchingOrCrossingLine(a, b) && isLineSegmentTouchingOrCrossingLine(b, a);
10490
10698
  }
10491
10699
 
10492
- // ../utils/src/withinBounds.ts
10493
- var getNonLinearElementRelativePoints = (element) => {
10494
- if (element.type === "diamond") {
10495
- return [
10496
- pointFrom(element.width / 2, 0),
10497
- pointFrom(element.width, element.height / 2),
10498
- pointFrom(element.width / 2, element.height),
10499
- pointFrom(0, element.height / 2)
10500
- ];
10501
- }
10502
- return [
10503
- pointFrom(0, 0),
10504
- pointFrom(0 + element.width, 0),
10505
- pointFrom(0 + element.width, element.height),
10506
- pointFrom(0, element.height)
10507
- ];
10508
- };
10509
- var getElementRelativePoints = (element) => {
10510
- if (isLinearElement(element) || isFreeDrawElement(element)) {
10511
- return element.points;
10512
- }
10513
- return getNonLinearElementRelativePoints(element);
10514
- };
10515
- var getMinMaxPoints = (points) => {
10516
- const ret = points.reduce(
10517
- (limits, [x, y]) => {
10518
- limits.minY = Math.min(limits.minY, y);
10519
- limits.minX = Math.min(limits.minX, x);
10520
- limits.maxX = Math.max(limits.maxX, x);
10521
- limits.maxY = Math.max(limits.maxY, y);
10522
- return limits;
10523
- },
10524
- {
10525
- minX: Infinity,
10526
- minY: Infinity,
10527
- maxX: -Infinity,
10528
- maxY: -Infinity,
10529
- cx: 0,
10530
- cy: 0
10531
- }
10532
- );
10533
- ret.cx = (ret.maxX + ret.minX) / 2;
10534
- ret.cy = (ret.maxY + ret.minY) / 2;
10535
- return ret;
10536
- };
10537
- var getRotatedBBox = (element) => {
10538
- const points = getElementRelativePoints(element);
10539
- const { cx, cy } = getMinMaxPoints(points);
10540
- const centerPoint = pointFrom(cx, cy);
10541
- const rotatedPoints = points.map(
10542
- (p) => pointRotateRads(p, centerPoint, element.angle)
10543
- );
10544
- const { minX, minY, maxX, maxY } = getMinMaxPoints(rotatedPoints);
10545
- return [
10546
- minX + element.x,
10547
- minY + element.y,
10548
- maxX + element.x,
10549
- maxY + element.y
10550
- ];
10551
- };
10552
- var isElementInsideBBox = (element, bbox, eitherDirection = false) => {
10553
- const elementBBox = getRotatedBBox(element);
10554
- const elementInsideBbox = bbox[0] <= elementBBox[0] && bbox[2] >= elementBBox[2] && bbox[1] <= elementBBox[1] && bbox[3] >= elementBBox[3];
10555
- if (!eitherDirection) {
10556
- return elementInsideBbox;
10557
- }
10558
- if (elementInsideBbox) {
10559
- return true;
10560
- }
10561
- return elementBBox[0] <= bbox[0] && elementBBox[2] >= bbox[2] && elementBBox[1] <= bbox[1] && elementBBox[3] >= bbox[3];
10562
- };
10563
- var elementPartiallyOverlapsWithOrContainsBBox = (element, bbox) => {
10564
- const elementBBox = getRotatedBBox(element);
10565
- return (rangeIncludesValue(elementBBox[0], rangeInclusive(bbox[0], bbox[2])) || rangeIncludesValue(
10566
- bbox[0],
10567
- rangeInclusive(elementBBox[0], elementBBox[2])
10568
- )) && (rangeIncludesValue(elementBBox[1], rangeInclusive(bbox[1], bbox[3])) || rangeIncludesValue(
10569
- bbox[1],
10570
- rangeInclusive(elementBBox[1], elementBBox[3])
10571
- ));
10572
- };
10573
- var elementsOverlappingBBox = ({
10574
- elements,
10575
- bounds,
10576
- type,
10577
- errorMargin = 0
10578
- }) => {
10579
- if (isExcalidrawElement(bounds)) {
10580
- bounds = getElementBounds(bounds, arrayToMap(elements));
10581
- }
10582
- const adjustedBBox = [
10583
- bounds[0] - errorMargin,
10584
- bounds[1] - errorMargin,
10585
- bounds[2] + errorMargin,
10586
- bounds[3] + errorMargin
10587
- ];
10588
- const includedElementSet = /* @__PURE__ */ new Set();
10589
- for (const element of elements) {
10590
- if (includedElementSet.has(element.id)) {
10591
- continue;
10592
- }
10593
- const isOverlaping = type === "overlap" ? elementPartiallyOverlapsWithOrContainsBBox(element, adjustedBBox) : type === "inside" ? isElementInsideBBox(element, adjustedBBox) : isElementInsideBBox(element, adjustedBBox, true);
10594
- if (isOverlaping) {
10595
- includedElementSet.add(element.id);
10596
- if (element.boundElements) {
10597
- for (const boundElement of element.boundElements) {
10598
- includedElementSet.add(boundElement.id);
10599
- }
10600
- }
10601
- if (isTextElement(element) && element.containerId) {
10602
- includedElementSet.add(element.containerId);
10603
- }
10604
- if (isArrowElement(element)) {
10605
- if (element.startBinding) {
10606
- includedElementSet.add(element.startBinding.elementId);
10607
- }
10608
- if (element.endBinding) {
10609
- includedElementSet.add(element.endBinding?.elementId);
10610
- }
10611
- }
10612
- }
10613
- }
10614
- return elements.filter((element) => includedElementSet.has(element.id));
10615
- };
10616
-
10617
10700
  // ../element/src/groups.ts
10618
10701
  var selectGroup = (groupId, appState, elements) => {
10619
10702
  const elementsInGroup = elements.reduce(
@@ -10887,6 +10970,15 @@ var getSelectedElementsByGroup = (selectedElements, elementsMap, appState) => {
10887
10970
  };
10888
10971
 
10889
10972
  // ../element/src/selection.ts
10973
+ var shouldIgnoreElementFromSelection = (element) => element.locked || isBoundToContainer(element);
10974
+ var excludeElementsFromFrames = (selectedElements, framesInSelection) => {
10975
+ return selectedElements.filter((element) => {
10976
+ if (element.frameId && framesInSelection.has(element.frameId)) {
10977
+ return false;
10978
+ }
10979
+ return true;
10980
+ });
10981
+ };
10890
10982
  var excludeElementsInFramesFromSelection = (selectedElements) => {
10891
10983
  const framesInSelection = /* @__PURE__ */ new Set();
10892
10984
  selectedElements.forEach((element) => {
@@ -10894,34 +10986,182 @@ var excludeElementsInFramesFromSelection = (selectedElements) => {
10894
10986
  framesInSelection.add(element.id);
10895
10987
  }
10896
10988
  });
10897
- return selectedElements.filter((element) => {
10898
- if (element.frameId && framesInSelection.has(element.frameId)) {
10899
- return false;
10989
+ return excludeElementsFromFrames(selectedElements, framesInSelection);
10990
+ };
10991
+ var getElementsWithinSelection = (elements, selection, elementsMap, excludeElementsInFrames = true, boxSelectionMode = "contain") => {
10992
+ const [selectionStartX, selectionStartY, selectionEndX, selectionEndY] = getElementAbsoluteCoords(selection, elementsMap);
10993
+ const selectionX1 = Math.min(selectionStartX, selectionEndX);
10994
+ const selectionY1 = Math.min(selectionStartY, selectionEndY);
10995
+ const selectionX2 = Math.max(selectionStartX, selectionEndX);
10996
+ const selectionY2 = Math.max(selectionStartY, selectionEndY);
10997
+ const selectionBounds = [
10998
+ selectionX1,
10999
+ selectionY1,
11000
+ selectionX2,
11001
+ selectionY2
11002
+ ];
11003
+ const selectionEdges = [
11004
+ lineSegment(
11005
+ pointFrom(selectionX1, selectionY1),
11006
+ pointFrom(selectionX2, selectionY1)
11007
+ ),
11008
+ lineSegment(
11009
+ pointFrom(selectionX2, selectionY1),
11010
+ pointFrom(selectionX2, selectionY2)
11011
+ ),
11012
+ lineSegment(
11013
+ pointFrom(selectionX2, selectionY2),
11014
+ pointFrom(selectionX1, selectionY2)
11015
+ ),
11016
+ lineSegment(
11017
+ pointFrom(selectionX1, selectionY2),
11018
+ pointFrom(selectionX1, selectionY1)
11019
+ )
11020
+ ];
11021
+ const framesInSelection = excludeElementsInFrames ? /* @__PURE__ */ new Set() : null;
11022
+ let elementsInSelection = [];
11023
+ for (const element of elements) {
11024
+ if (shouldIgnoreElementFromSelection(element)) {
11025
+ continue;
10900
11026
  }
10901
- return true;
10902
- });
10903
- };
10904
- var getElementsWithinSelection = (elements, selection, elementsMap, excludeElementsInFrames = true) => {
10905
- const [selectionX1, selectionY1, selectionX2, selectionY2] = getElementAbsoluteCoords(selection, elementsMap);
10906
- let elementsInSelection = elements.filter((element) => {
10907
- let [elementX1, elementY1, elementX2, elementY2] = getElementBounds(
10908
- element,
10909
- elementsMap
10910
- );
10911
- const containingFrame = getContainingFrame(element, elementsMap);
10912
- if (containingFrame) {
10913
- const [fx1, fy1, fx2, fy2] = getElementBounds(
10914
- containingFrame,
11027
+ const strokeWidth = element.strokeWidth;
11028
+ let labelAABB = null;
11029
+ let elementAABB = getElementBounds(element, elementsMap);
11030
+ elementAABB = [
11031
+ elementAABB[0] - strokeWidth / 2,
11032
+ elementAABB[1] - strokeWidth / 2,
11033
+ elementAABB[2] + strokeWidth / 2,
11034
+ elementAABB[3] + strokeWidth / 2
11035
+ ];
11036
+ const boundTextElement = isArrowElement(element) && getBoundTextElement(element, elementsMap);
11037
+ if (boundTextElement) {
11038
+ const { x, y } = LinearElementEditor.getBoundTextElementPosition(
11039
+ element,
11040
+ boundTextElement,
10915
11041
  elementsMap
10916
11042
  );
10917
- elementX1 = Math.max(fx1, elementX1);
10918
- elementY1 = Math.max(fy1, elementY1);
10919
- elementX2 = Math.min(fx2, elementX2);
10920
- elementY2 = Math.min(fy2, elementY2);
11043
+ labelAABB = [
11044
+ x,
11045
+ y,
11046
+ x + boundTextElement.width,
11047
+ y + boundTextElement.height
11048
+ ];
10921
11049
  }
10922
- return element.locked === false && element.type !== "selection" && !isBoundToContainer(element) && selectionX1 <= elementX1 && selectionY1 <= elementY1 && selectionX2 >= elementX2 && selectionY2 >= elementY2;
10923
- });
10924
- elementsInSelection = excludeElementsInFrames ? excludeElementsInFramesFromSelection(elementsInSelection) : elementsInSelection;
11050
+ const associatedFrame = getContainingFrame(element, elementsMap);
11051
+ if (associatedFrame && isElementIntersectingFrame(element, associatedFrame, elementsMap)) {
11052
+ const frameAABB = getElementBounds(associatedFrame, elementsMap);
11053
+ elementAABB = [
11054
+ Math.max(elementAABB[0], frameAABB[0]),
11055
+ Math.max(elementAABB[1], frameAABB[1]),
11056
+ Math.min(elementAABB[2], frameAABB[2]),
11057
+ Math.min(elementAABB[3], frameAABB[3])
11058
+ ];
11059
+ labelAABB = labelAABB ? [
11060
+ Math.max(labelAABB[0], frameAABB[0]),
11061
+ Math.max(labelAABB[1], frameAABB[1]),
11062
+ Math.min(labelAABB[2], frameAABB[2]),
11063
+ Math.min(labelAABB[3], frameAABB[3])
11064
+ ] : null;
11065
+ }
11066
+ const commonAABB2 = labelAABB ? [
11067
+ Math.min(labelAABB[0], elementAABB[0]),
11068
+ Math.min(labelAABB[1], elementAABB[1]),
11069
+ Math.max(labelAABB[2], elementAABB[2]),
11070
+ Math.max(labelAABB[3], elementAABB[3])
11071
+ ] : elementAABB;
11072
+ if (boundsContainBounds(selectionBounds, commonAABB2)) {
11073
+ if (framesInSelection && isFrameLikeElement(element)) {
11074
+ framesInSelection.add(element.id);
11075
+ } else {
11076
+ elementsInSelection.push(element);
11077
+ continue;
11078
+ }
11079
+ }
11080
+ if (boxSelectionMode === "overlap" && labelAABB && doBoundsIntersect(selectionBounds, labelAABB)) {
11081
+ elementsInSelection.push(element);
11082
+ continue;
11083
+ }
11084
+ if (boxSelectionMode === "overlap" && doBoundsIntersect(selectionBounds, elementAABB)) {
11085
+ let hasIntersection = false;
11086
+ if (isLinearElement(element) || isFreeDrawElement(element)) {
11087
+ const center = elementCenterPoint(element, elementsMap);
11088
+ hasIntersection = element.points.some((point) => {
11089
+ const rotatedPoint = pointRotateRads(
11090
+ pointFrom(element.x + point[0], element.y + point[1]),
11091
+ center,
11092
+ element.angle
11093
+ );
11094
+ return pointInsideBounds(rotatedPoint, selectionBounds);
11095
+ });
11096
+ } else {
11097
+ const nonRotatedElementBounds = getElementBounds(
11098
+ element,
11099
+ elementsMap,
11100
+ true
11101
+ );
11102
+ const center = elementCenterPoint(element, elementsMap);
11103
+ hasIntersection = [
11104
+ pointRotateRads(
11105
+ pointFrom(
11106
+ (nonRotatedElementBounds[0] + nonRotatedElementBounds[2]) / 2,
11107
+ nonRotatedElementBounds[1]
11108
+ ),
11109
+ center,
11110
+ element.angle
11111
+ ),
11112
+ pointRotateRads(
11113
+ pointFrom(
11114
+ nonRotatedElementBounds[2],
11115
+ (nonRotatedElementBounds[1] + nonRotatedElementBounds[3]) / 2
11116
+ ),
11117
+ center,
11118
+ element.angle
11119
+ ),
11120
+ pointRotateRads(
11121
+ pointFrom(
11122
+ (nonRotatedElementBounds[0] + nonRotatedElementBounds[2]) / 2,
11123
+ nonRotatedElementBounds[3]
11124
+ ),
11125
+ center,
11126
+ element.angle
11127
+ ),
11128
+ pointRotateRads(
11129
+ pointFrom(
11130
+ nonRotatedElementBounds[0],
11131
+ (nonRotatedElementBounds[1] + nonRotatedElementBounds[3]) / 2
11132
+ ),
11133
+ center,
11134
+ element.angle
11135
+ )
11136
+ ].some((point) => {
11137
+ return pointInsideBounds(
11138
+ pointRotateRads(point, center, element.angle),
11139
+ selectionBounds
11140
+ );
11141
+ });
11142
+ }
11143
+ if (!hasIntersection) {
11144
+ hasIntersection = selectionEdges.some(
11145
+ (selectionEdge) => intersectElementWithLineSegment(
11146
+ element,
11147
+ elementsMap,
11148
+ selectionEdge,
11149
+ strokeWidth / 2,
11150
+ true
11151
+ // Stop at first hit for better performance
11152
+ ).length > 0
11153
+ );
11154
+ }
11155
+ if (hasIntersection) {
11156
+ if (framesInSelection && isFrameLikeElement(element)) {
11157
+ framesInSelection.add(element.id);
11158
+ }
11159
+ elementsInSelection.push(element);
11160
+ continue;
11161
+ }
11162
+ }
11163
+ }
11164
+ elementsInSelection = framesInSelection ? excludeElementsFromFrames(elementsInSelection, framesInSelection) : elementsInSelection;
10925
11165
  elementsInSelection = elementsInSelection.filter((element) => {
10926
11166
  const containingFrame = getContainingFrame(element, elementsMap);
10927
11167
  if (containingFrame) {
@@ -11041,6 +11281,10 @@ var getSelectionStateForElements = (targetElements, allElements, appState) => {
11041
11281
  )
11042
11282
  };
11043
11283
  };
11284
+ var getActiveTextElement = (selectedElements, appState) => {
11285
+ const activeTextElement = appState.editingTextElement || selectedElements.length === 1 && isTextElement(selectedElements[0]) && selectedElements[0];
11286
+ return activeTextElement || null;
11287
+ };
11044
11288
 
11045
11289
  // ../element/src/frame.ts
11046
11290
  var bindElementsToFramesAfterDuplication = (nextElements, origElements, origIdToDuplicateId) => {
@@ -11516,12 +11760,17 @@ var getDefaultFrameName = (element) => {
11516
11760
  var getFrameLikeTitle = (element) => {
11517
11761
  return element.name === null ? getDefaultFrameName(element) : element.name;
11518
11762
  };
11519
- var getElementsOverlappingFrame = (elements, frame) => {
11520
- return elementsOverlappingBBox({
11521
- elements,
11522
- bounds: frame,
11523
- type: "overlap"
11524
- }).filter((el) => !el.frameId || el.frameId === frame.id);
11763
+ var getElementsOverlappingFrame = (elements, frame, elementsMap) => {
11764
+ return elements.filter(
11765
+ (el) => (
11766
+ // exclude elements which are overlapping, but are in a different frame,
11767
+ // and thus invisible in target frame
11768
+ (!el.frameId || el.frameId === frame.id) && doBoundsIntersect(
11769
+ getElementBounds(el, elementsMap),
11770
+ getElementBounds(frame, elementsMap)
11771
+ )
11772
+ )
11773
+ );
11525
11774
  };
11526
11775
  var frameAndChildrenSelectedTogether = (selectedElements) => {
11527
11776
  const selectedElementsMap = arrayToMap(selectedElements);
@@ -12354,45 +12603,88 @@ var modifyIframeLikeForRoughOptions = (element, isExporting, embedsValidationSta
12354
12603
  }
12355
12604
  return element;
12356
12605
  };
12357
- var getArrowheadShapes = (element, shape, position, arrowhead, generator, options, canvasBackgroundColor, isDarkMode) => {
12358
- canvasBackgroundColor = canvasBackgroundColor || "transparent";
12359
- const arrowheadPoints = getArrowheadPoints(
12360
- element,
12361
- shape,
12362
- position,
12363
- arrowhead
12364
- );
12606
+ var generateArrowheadCardinalityOne = (generator, arrowheadPoints, lineOptions) => {
12365
12607
  if (arrowheadPoints === null) {
12366
12608
  return [];
12367
12609
  }
12368
- const generateCrowfootOne = (arrowheadPoints2, options2) => {
12369
- if (arrowheadPoints2 === null) {
12370
- return [];
12371
- }
12372
- const [, , x3, y3, x4, y4] = arrowheadPoints2;
12373
- return [generator.line(x3, y3, x4, y4, options2)];
12610
+ const [, , x3, y3, x4, y4] = arrowheadPoints;
12611
+ return [generator.line(x3, y3, x4, y4, lineOptions)];
12612
+ };
12613
+ var generateArrowheadLinesToTip = (generator, arrowheadPoints, lineOptions) => {
12614
+ if (arrowheadPoints === null) {
12615
+ return [];
12616
+ }
12617
+ const [x2, y2, x3, y3, x4, y4] = arrowheadPoints;
12618
+ return [
12619
+ generator.line(x3, y3, x2, y2, lineOptions),
12620
+ generator.line(x4, y4, x2, y2, lineOptions)
12621
+ ];
12622
+ };
12623
+ var getArrowheadLineOptions = (element, options) => {
12624
+ const lineOptions = { ...options };
12625
+ if (element.strokeStyle === "dotted") {
12626
+ const dash = getDashArrayDotted(element.strokeWidth - 1);
12627
+ lineOptions.strokeLineDash = [dash[0], dash[1] - 1];
12628
+ } else {
12629
+ delete lineOptions.strokeLineDash;
12630
+ }
12631
+ lineOptions.roughness = Math.min(1, lineOptions.roughness || 0);
12632
+ return lineOptions;
12633
+ };
12634
+ var generateArrowheadOutlineCircle = (generator, options, strokeColor, arrowheadPoints, fill, diameterScale = 1) => {
12635
+ if (arrowheadPoints === null) {
12636
+ return [];
12637
+ }
12638
+ const [x, y, diameter] = arrowheadPoints;
12639
+ const circleOptions = {
12640
+ ...options,
12641
+ fill,
12642
+ fillStyle: "solid",
12643
+ stroke: strokeColor,
12644
+ roughness: Math.min(0.5, options.roughness || 0)
12374
12645
  };
12646
+ delete circleOptions.strokeLineDash;
12647
+ return [generator.circle(x, y, diameter * diameterScale, circleOptions)];
12648
+ };
12649
+ var getArrowheadShapes = (element, shape, position, arrowhead, generator, options, canvasBackgroundColor, isDarkMode) => {
12650
+ canvasBackgroundColor = canvasBackgroundColor || "transparent";
12651
+ if (arrowhead === null) {
12652
+ return [];
12653
+ }
12375
12654
  const strokeColor = isDarkMode ? applyDarkModeFilter(element.strokeColor) : element.strokeColor;
12655
+ const backgroundFillColor = isDarkMode ? applyDarkModeFilter(canvasBackgroundColor) : canvasBackgroundColor;
12656
+ const cardinalityOneOrManyOffset = -0.25;
12657
+ const cardinalityZeroCircleScale = 0.8;
12376
12658
  switch (arrowhead) {
12377
- case "dot":
12378
12659
  case "circle":
12379
12660
  case "circle_outline": {
12380
- const [x, y, diameter] = arrowheadPoints;
12381
- delete options.strokeLineDash;
12382
- return [
12383
- generator.circle(x, y, diameter, {
12384
- ...options,
12385
- fill: arrowhead === "circle_outline" ? canvasBackgroundColor : strokeColor,
12386
- fillStyle: "solid",
12387
- stroke: strokeColor,
12388
- roughness: Math.min(0.5, options.roughness || 0)
12389
- })
12390
- ];
12661
+ return generateArrowheadOutlineCircle(
12662
+ generator,
12663
+ options,
12664
+ strokeColor,
12665
+ getArrowheadPoints(element, shape, position, arrowhead),
12666
+ arrowhead === "circle_outline" ? backgroundFillColor : strokeColor
12667
+ );
12391
12668
  }
12392
12669
  case "triangle":
12393
12670
  case "triangle_outline": {
12671
+ const arrowheadPoints = getArrowheadPoints(
12672
+ element,
12673
+ shape,
12674
+ position,
12675
+ arrowhead
12676
+ );
12677
+ if (arrowheadPoints === null) {
12678
+ return [];
12679
+ }
12394
12680
  const [x, y, x2, y2, x3, y3] = arrowheadPoints;
12395
- delete options.strokeLineDash;
12681
+ const triangleOptions = {
12682
+ ...options,
12683
+ fill: arrowhead === "triangle_outline" ? backgroundFillColor : strokeColor,
12684
+ fillStyle: "solid",
12685
+ roughness: Math.min(1, options.roughness || 0)
12686
+ };
12687
+ delete triangleOptions.strokeLineDash;
12396
12688
  return [
12397
12689
  generator.polygon(
12398
12690
  [
@@ -12401,19 +12693,29 @@ var getArrowheadShapes = (element, shape, position, arrowhead, generator, option
12401
12693
  [x3, y3],
12402
12694
  [x, y]
12403
12695
  ],
12404
- {
12405
- ...options,
12406
- fill: arrowhead === "triangle_outline" ? canvasBackgroundColor : strokeColor,
12407
- fillStyle: "solid",
12408
- roughness: Math.min(1, options.roughness || 0)
12409
- }
12696
+ triangleOptions
12410
12697
  )
12411
12698
  ];
12412
12699
  }
12413
12700
  case "diamond":
12414
12701
  case "diamond_outline": {
12702
+ const arrowheadPoints = getArrowheadPoints(
12703
+ element,
12704
+ shape,
12705
+ position,
12706
+ arrowhead
12707
+ );
12708
+ if (arrowheadPoints === null) {
12709
+ return [];
12710
+ }
12415
12711
  const [x, y, x2, y2, x3, y3, x4, y4] = arrowheadPoints;
12416
- delete options.strokeLineDash;
12712
+ const diamondOptions = {
12713
+ ...options,
12714
+ fill: arrowhead === "diamond_outline" ? backgroundFillColor : strokeColor,
12715
+ fillStyle: "solid",
12716
+ roughness: Math.min(1, options.roughness || 0)
12717
+ };
12718
+ delete diamondOptions.strokeLineDash;
12417
12719
  return [
12418
12720
  generator.polygon(
12419
12721
  [
@@ -12423,42 +12725,106 @@ var getArrowheadShapes = (element, shape, position, arrowhead, generator, option
12423
12725
  [x4, y4],
12424
12726
  [x, y]
12425
12727
  ],
12426
- {
12427
- ...options,
12428
- fill: arrowhead === "diamond_outline" ? canvasBackgroundColor : strokeColor,
12429
- fillStyle: "solid",
12430
- roughness: Math.min(1, options.roughness || 0)
12431
- }
12728
+ diamondOptions
12729
+ )
12730
+ ];
12731
+ }
12732
+ case "cardinality_one":
12733
+ return generateArrowheadCardinalityOne(
12734
+ generator,
12735
+ getArrowheadPoints(element, shape, position, arrowhead),
12736
+ getArrowheadLineOptions(element, options)
12737
+ );
12738
+ case "cardinality_many":
12739
+ return generateArrowheadLinesToTip(
12740
+ generator,
12741
+ getArrowheadPoints(element, shape, position, arrowhead),
12742
+ getArrowheadLineOptions(element, options)
12743
+ );
12744
+ case "cardinality_one_or_many": {
12745
+ const lineOptions = getArrowheadLineOptions(element, options);
12746
+ return [
12747
+ ...generateArrowheadLinesToTip(
12748
+ generator,
12749
+ getArrowheadPoints(element, shape, position, "cardinality_many"),
12750
+ lineOptions
12751
+ ),
12752
+ ...generateArrowheadCardinalityOne(
12753
+ generator,
12754
+ getArrowheadPoints(
12755
+ element,
12756
+ shape,
12757
+ position,
12758
+ "cardinality_one",
12759
+ cardinalityOneOrManyOffset
12760
+ ),
12761
+ lineOptions
12762
+ )
12763
+ ];
12764
+ }
12765
+ case "cardinality_exactly_one": {
12766
+ const lineOptions = getArrowheadLineOptions(element, options);
12767
+ return [
12768
+ ...generateArrowheadCardinalityOne(
12769
+ generator,
12770
+ getArrowheadPoints(element, shape, position, "cardinality_one", -0.5),
12771
+ lineOptions
12772
+ ),
12773
+ ...generateArrowheadCardinalityOne(
12774
+ generator,
12775
+ getArrowheadPoints(element, shape, position, "cardinality_one"),
12776
+ lineOptions
12777
+ )
12778
+ ];
12779
+ }
12780
+ case "cardinality_zero_or_one": {
12781
+ const lineOptions = getArrowheadLineOptions(element, options);
12782
+ return [
12783
+ ...generateArrowheadOutlineCircle(
12784
+ generator,
12785
+ options,
12786
+ strokeColor,
12787
+ getArrowheadPoints(element, shape, position, "circle_outline", 1.5),
12788
+ backgroundFillColor,
12789
+ cardinalityZeroCircleScale
12790
+ ),
12791
+ ...generateArrowheadCardinalityOne(
12792
+ generator,
12793
+ getArrowheadPoints(element, shape, position, "cardinality_one", -0.5),
12794
+ lineOptions
12795
+ )
12796
+ ];
12797
+ }
12798
+ case "cardinality_zero_or_many": {
12799
+ const lineOptions = getArrowheadLineOptions(element, options);
12800
+ return [
12801
+ ...generateArrowheadLinesToTip(
12802
+ generator,
12803
+ getArrowheadPoints(element, shape, position, "cardinality_many"),
12804
+ lineOptions
12805
+ ),
12806
+ ...generateArrowheadOutlineCircle(
12807
+ generator,
12808
+ options,
12809
+ strokeColor,
12810
+ getArrowheadPoints(element, shape, position, "circle_outline", 1.5),
12811
+ backgroundFillColor,
12812
+ cardinalityZeroCircleScale
12432
12813
  )
12433
12814
  ];
12434
12815
  }
12435
- case "crowfoot_one":
12436
- return generateCrowfootOne(arrowheadPoints, options);
12437
12816
  case "bar":
12438
12817
  case "arrow":
12439
- case "crowfoot_many":
12440
- case "crowfoot_one_or_many":
12441
12818
  default: {
12442
- const [x2, y2, x3, y3, x4, y4] = arrowheadPoints;
12443
- if (element.strokeStyle === "dotted") {
12444
- const dash = getDashArrayDotted(element.strokeWidth - 1);
12445
- options.strokeLineDash = [dash[0], dash[1] - 1];
12446
- } else {
12447
- delete options.strokeLineDash;
12448
- }
12449
- options.roughness = Math.min(1, options.roughness || 0);
12450
- return [
12451
- generator.line(x3, y3, x2, y2, options),
12452
- generator.line(x4, y4, x2, y2, options),
12453
- ...arrowhead === "crowfoot_one_or_many" ? generateCrowfootOne(
12454
- getArrowheadPoints(element, shape, position, "crowfoot_one"),
12455
- options
12456
- ) : []
12457
- ];
12819
+ return generateArrowheadLinesToTip(
12820
+ generator,
12821
+ getArrowheadPoints(element, shape, position, arrowhead),
12822
+ getArrowheadLineOptions(element, options)
12823
+ );
12458
12824
  }
12459
12825
  }
12460
12826
  };
12461
- var generateLinearCollisionShape = (element) => {
12827
+ var generateLinearCollisionShape = (element, elementsMap) => {
12462
12828
  const generator = new RoughGenerator();
12463
12829
  const options = {
12464
12830
  seed: element.seed,
@@ -12467,20 +12833,7 @@ var generateLinearCollisionShape = (element) => {
12467
12833
  roughness: 0,
12468
12834
  preserveVertices: true
12469
12835
  };
12470
- const center = getCenterForBounds(
12471
- // Need a non-rotated center point
12472
- element.points.reduce(
12473
- (acc, point) => {
12474
- return [
12475
- Math.min(element.x + point[0], acc[0]),
12476
- Math.min(element.y + point[1], acc[1]),
12477
- Math.max(element.x + point[0], acc[2]),
12478
- Math.max(element.y + point[1], acc[3])
12479
- ];
12480
- },
12481
- [Infinity, Infinity, -Infinity, -Infinity]
12482
- )
12483
- );
12836
+ const center = elementCenterPoint(element, elementsMap);
12484
12837
  switch (element.type) {
12485
12838
  case "line":
12486
12839
  case "arrow": {
@@ -13362,7 +13715,7 @@ var getMinMaxXYFromCurvePathOps = (ops, transformXY) => {
13362
13715
  );
13363
13716
  return [minX, minY, maxX, maxY];
13364
13717
  };
13365
- var getBoundsFromPoints = (points) => {
13718
+ var getBoundsFromPoints = (points, padding = 0) => {
13366
13719
  let minX = Infinity;
13367
13720
  let minY = Infinity;
13368
13721
  let maxX = -Infinity;
@@ -13373,7 +13726,7 @@ var getBoundsFromPoints = (points) => {
13373
13726
  maxX = Math.max(maxX, x);
13374
13727
  maxY = Math.max(maxY, y);
13375
13728
  }
13376
- return [minX, minY, maxX, maxY];
13729
+ return [minX - padding, minY - padding, maxX + padding, maxY + padding];
13377
13730
  };
13378
13731
  var getFreeDrawElementAbsoluteCoords = (element) => {
13379
13732
  const [minX, minY, maxX, maxY] = getBoundsFromPoints(element.points);
@@ -13383,6 +13736,8 @@ var getFreeDrawElementAbsoluteCoords = (element) => {
13383
13736
  const y2 = maxY + element.y;
13384
13737
  return [x1, y1, x2, y2, (x1 + x2) / 2, (y1 + y2) / 2];
13385
13738
  };
13739
+ var CARDINALITY_MARKER_SIZE = 20;
13740
+ var CROWFOOT_ARROWHEAD_SIZE = 15;
13386
13741
  var getArrowheadSize = (arrowhead) => {
13387
13742
  switch (arrowhead) {
13388
13743
  case "arrow":
@@ -13390,10 +13745,14 @@ var getArrowheadSize = (arrowhead) => {
13390
13745
  case "diamond":
13391
13746
  case "diamond_outline":
13392
13747
  return 12;
13393
- case "crowfoot_many":
13394
- case "crowfoot_one":
13395
- case "crowfoot_one_or_many":
13396
- return 20;
13748
+ case "cardinality_many":
13749
+ case "cardinality_one_or_many":
13750
+ case "cardinality_zero_or_many":
13751
+ return CROWFOOT_ARROWHEAD_SIZE;
13752
+ case "cardinality_one":
13753
+ case "cardinality_exactly_one":
13754
+ case "cardinality_zero_or_one":
13755
+ return CARDINALITY_MARKER_SIZE;
13397
13756
  default:
13398
13757
  return 15;
13399
13758
  }
@@ -13408,7 +13767,10 @@ var getArrowheadAngle = (arrowhead) => {
13408
13767
  return 25;
13409
13768
  }
13410
13769
  };
13411
- var getArrowheadPoints = (element, shape, position, arrowhead) => {
13770
+ var getArrowheadPoints = (element, shape, position, arrowhead, offsetMultiplier = 0) => {
13771
+ if (arrowhead === null) {
13772
+ return null;
13773
+ }
13412
13774
  if (shape.length < 1) {
13413
13775
  return null;
13414
13776
  }
@@ -13446,21 +13808,23 @@ var getArrowheadPoints = (element, shape, position, arrowhead) => {
13446
13808
  }
13447
13809
  const lengthMultiplier = arrowhead === "diamond" || arrowhead === "diamond_outline" ? 0.25 : 0.5;
13448
13810
  const minSize = Math.min(size, length * lengthMultiplier);
13449
- const xs = x2 - nx * minSize;
13450
- const ys = y2 - ny * minSize;
13451
- if (arrowhead === "dot" || arrowhead === "circle" || arrowhead === "circle_outline") {
13452
- const diameter = Math.hypot(ys - y2, xs - x2) + element.strokeWidth - 2;
13453
- return [x2, y2, diameter];
13811
+ const tx = x2 - nx * minSize * offsetMultiplier;
13812
+ const ty = y2 - ny * minSize * offsetMultiplier;
13813
+ const xs = tx - nx * minSize;
13814
+ const ys = ty - ny * minSize;
13815
+ if (arrowhead === "circle" || arrowhead === "circle_outline") {
13816
+ const diameter = Math.hypot(ys - ty, xs - tx) + element.strokeWidth - 2;
13817
+ return [tx, ty, diameter];
13454
13818
  }
13455
13819
  const angle = getArrowheadAngle(arrowhead);
13456
- if (arrowhead === "crowfoot_many" || arrowhead === "crowfoot_one_or_many") {
13820
+ if (arrowhead === "cardinality_many" || arrowhead === "cardinality_one_or_many") {
13457
13821
  const [x32, y32] = pointRotateRads(
13458
- pointFrom(x2, y2),
13822
+ pointFrom(tx, ty),
13459
13823
  pointFrom(xs, ys),
13460
13824
  degreesToRadians(-angle)
13461
13825
  );
13462
13826
  const [x42, y42] = pointRotateRads(
13463
- pointFrom(x2, y2),
13827
+ pointFrom(tx, ty),
13464
13828
  pointFrom(xs, ys),
13465
13829
  degreesToRadians(angle)
13466
13830
  );
@@ -13468,12 +13832,12 @@ var getArrowheadPoints = (element, shape, position, arrowhead) => {
13468
13832
  }
13469
13833
  const [x3, y3] = pointRotateRads(
13470
13834
  pointFrom(xs, ys),
13471
- pointFrom(x2, y2),
13835
+ pointFrom(tx, ty),
13472
13836
  -angle * Math.PI / 180
13473
13837
  );
13474
13838
  const [x4, y4] = pointRotateRads(
13475
13839
  pointFrom(xs, ys),
13476
- pointFrom(x2, y2),
13840
+ pointFrom(tx, ty),
13477
13841
  degreesToRadians(angle)
13478
13842
  );
13479
13843
  if (arrowhead === "diamond" || arrowhead === "diamond_outline") {
@@ -13482,21 +13846,21 @@ var getArrowheadPoints = (element, shape, position, arrowhead) => {
13482
13846
  if (position === "start") {
13483
13847
  const [px, py] = element.points.length > 1 ? element.points[1] : [0, 0];
13484
13848
  [ox, oy] = pointRotateRads(
13485
- pointFrom(x2 + minSize * 2, y2),
13486
- pointFrom(x2, y2),
13487
- Math.atan2(py - y2, px - x2)
13849
+ pointFrom(tx + minSize * 2, ty),
13850
+ pointFrom(tx, ty),
13851
+ Math.atan2(py - ty, px - tx)
13488
13852
  );
13489
13853
  } else {
13490
13854
  const [px, py] = element.points.length > 1 ? element.points[element.points.length - 2] : [0, 0];
13491
13855
  [ox, oy] = pointRotateRads(
13492
- pointFrom(x2 - minSize * 2, y2),
13493
- pointFrom(x2, y2),
13494
- Math.atan2(y2 - py, x2 - px)
13856
+ pointFrom(tx - minSize * 2, ty),
13857
+ pointFrom(tx, ty),
13858
+ Math.atan2(ty - py, tx - px)
13495
13859
  );
13496
13860
  }
13497
- return [x2, y2, x3, y3, ox, oy, x4, y4];
13861
+ return [tx, ty, x3, y3, ox, oy, x4, y4];
13498
13862
  }
13499
- return [x2, y2, x3, y3, x4, y4];
13863
+ return [tx, ty, x3, y3, x4, y4];
13500
13864
  };
13501
13865
  var generateLinearElementShape = (element) => {
13502
13866
  const generator = rough2.generator();
@@ -13746,6 +14110,7 @@ var aabbForElement = (element, elementsMap, offset) => {
13746
14110
  return bounds;
13747
14111
  };
13748
14112
  var pointInsideBounds = (p, bounds) => p[0] > bounds[0] && p[0] < bounds[2] && p[1] > bounds[1] && p[1] < bounds[3];
14113
+ var pointInsideBoundsInclusive = (p, bounds) => p[0] >= bounds[0] && p[0] <= bounds[2] && p[1] >= bounds[1] && p[1] <= bounds[3];
13749
14114
  var doBoundsIntersect = (bounds1, bounds2) => {
13750
14115
  if (bounds1 == null || bounds2 == null) {
13751
14116
  return false;
@@ -13754,8 +14119,14 @@ var doBoundsIntersect = (bounds1, bounds2) => {
13754
14119
  const [minX2, minY2, maxX2, maxY2] = bounds2;
13755
14120
  return minX1 < maxX2 && maxX1 > minX2 && minY1 < maxY2 && maxY1 > minY2;
13756
14121
  };
14122
+ var boundsContainBounds = (outerBounds, innerBounds) => [
14123
+ pointFrom(innerBounds[0], innerBounds[1]),
14124
+ pointFrom(innerBounds[0], innerBounds[3]),
14125
+ pointFrom(innerBounds[2], innerBounds[1]),
14126
+ pointFrom(innerBounds[2], innerBounds[3])
14127
+ ].every((point) => pointInsideBoundsInclusive(point, outerBounds));
13757
14128
  var elementCenterPoint = (element, elementsMap, xOffset = 0, yOffset = 0) => {
13758
- if (isLinearElement(element)) {
14129
+ if (isLinearElement(element) || isFreeDrawElement(element)) {
13759
14130
  const [x1, y1, x2, y2] = getElementAbsoluteCoords(element, elementsMap);
13760
14131
  const [x3, y3] = pointFrom((x1 + x2) / 2, (y1 + y2) / 2);
13761
14132
  return pointFrom(x3 + xOffset, y3 + yOffset);
@@ -20578,6 +20949,12 @@ var bindLinearElementToElement = (linearElement, start, end, elementStore, scene
20578
20949
  });
20579
20950
  break;
20580
20951
  }
20952
+ case "frame": {
20953
+ if (existingElement && isBindableElement(existingElement)) {
20954
+ startBoundElement = existingElement;
20955
+ }
20956
+ break;
20957
+ }
20581
20958
  default: {
20582
20959
  assertNever(
20583
20960
  linearElement,
@@ -20587,6 +20964,8 @@ var bindLinearElementToElement = (linearElement, start, end, elementStore, scene
20587
20964
  }
20588
20965
  }
20589
20966
  }
20967
+ }
20968
+ if (startBoundElement && isBindableElement(startBoundElement)) {
20590
20969
  bindBindingElement(
20591
20970
  linearElement,
20592
20971
  startBoundElement,
@@ -20649,6 +21028,12 @@ var bindLinearElementToElement = (linearElement, start, end, elementStore, scene
20649
21028
  });
20650
21029
  break;
20651
21030
  }
21031
+ case "frame": {
21032
+ if (existingElement && isBindableElement(existingElement)) {
21033
+ endBoundElement = existingElement;
21034
+ }
21035
+ break;
21036
+ }
20652
21037
  default: {
20653
21038
  assertNever(
20654
21039
  linearElement,
@@ -20658,13 +21043,9 @@ var bindLinearElementToElement = (linearElement, start, end, elementStore, scene
20658
21043
  }
20659
21044
  }
20660
21045
  }
20661
- bindBindingElement(
20662
- linearElement,
20663
- endBoundElement,
20664
- "orbit",
20665
- "end",
20666
- scene
20667
- );
21046
+ }
21047
+ if (endBoundElement && isBindableElement(endBoundElement)) {
21048
+ bindBindingElement(linearElement, endBoundElement, "orbit", "end", scene);
20668
21049
  }
20669
21050
  }
20670
21051
  if (linearElement.points.length < 2) {
@@ -20947,7 +21328,8 @@ var convertToExcalidrawElements = (elementsSkeleton, opts) => {
20947
21328
  }
20948
21329
  Object.assign(elementInFrame, { frameId: frame.id });
20949
21330
  elementInFrame?.boundElements?.forEach((boundElement) => {
20950
- const ele = elementStore.getElement(boundElement.id);
21331
+ const boundElementId = oldToNewElementIdMap.get(boundElement.id) ?? boundElement.id;
21332
+ const ele = elementStore.getElement(boundElementId);
20951
21333
  if (!ele) {
20952
21334
  throw new Error(
20953
21335
  `Bound element with id ${boundElement.id} doesn't exist`
@@ -20964,20 +21346,61 @@ var convertToExcalidrawElements = (elementsSkeleton, opts) => {
20964
21346
  minY = minY - PADDING;
20965
21347
  maxX = maxX + PADDING;
20966
21348
  maxY = maxY + PADDING;
20967
- const frameX = frame?.x || minX;
20968
- const frameY = frame?.y || minY;
20969
- const frameWidth = frame?.width || maxX - minX;
20970
- const frameHeight = frame?.height || maxY - minY;
21349
+ const frameX = frame?.x ?? minX;
21350
+ const frameY = frame?.y ?? minY;
21351
+ const frameWidth = frame?.width ?? maxX - minX;
21352
+ const frameHeight = frame?.height ?? maxY - minY;
20971
21353
  Object.assign(frame, {
20972
21354
  x: frameX,
20973
21355
  y: frameY,
20974
21356
  width: frameWidth,
20975
21357
  height: frameHeight
20976
21358
  });
20977
- if (isDevEnv() && element.children.length && (frame?.x || frame?.y || frame?.width || frame?.height)) {
20978
- console.info(
20979
- "User provided frame attributes are being considered, if you find this inaccurate, please remove any of the attributes - x, y, width and height so frame coordinates and dimensions are calculated automatically"
20980
- );
21359
+ }
21360
+ if (opts?.regenerateIds && oldToNewElementIdMap.size) {
21361
+ const remapId = (id) => id ? oldToNewElementIdMap.get(id) ?? id : id;
21362
+ const remapBoundElements = (boundElements) => {
21363
+ if (!boundElements?.length) {
21364
+ return boundElements;
21365
+ }
21366
+ let didChange = false;
21367
+ const nextBoundElements = boundElements.map((boundElement) => {
21368
+ const nextId = remapId(boundElement.id);
21369
+ if (nextId !== boundElement.id) {
21370
+ didChange = true;
21371
+ return { ...boundElement, id: nextId };
21372
+ }
21373
+ return boundElement;
21374
+ });
21375
+ return didChange ? nextBoundElements : boundElements;
21376
+ };
21377
+ for (const element of elementStore.excalidrawElements.values()) {
21378
+ const mutableElement = element;
21379
+ if ("containerId" in mutableElement && mutableElement.containerId) {
21380
+ mutableElement.containerId = remapId(mutableElement.containerId) ?? null;
21381
+ }
21382
+ if (mutableElement.boundElements?.length) {
21383
+ mutableElement.boundElements = remapBoundElements(
21384
+ mutableElement.boundElements
21385
+ );
21386
+ }
21387
+ if ("startBinding" in mutableElement && mutableElement.startBinding?.elementId) {
21388
+ const nextId = remapId(mutableElement.startBinding.elementId) ?? mutableElement.startBinding.elementId;
21389
+ mutableElement.startBinding = {
21390
+ ...mutableElement.startBinding,
21391
+ elementId: nextId
21392
+ };
21393
+ }
21394
+ if ("endBinding" in mutableElement && mutableElement.endBinding?.elementId) {
21395
+ const nextId = remapId(mutableElement.endBinding.elementId) ?? mutableElement.endBinding.elementId;
21396
+ mutableElement.endBinding = {
21397
+ ...mutableElement.endBinding,
21398
+ elementId: nextId
21399
+ };
21400
+ }
21401
+ if ("frameId" in mutableElement && mutableElement.frameId) {
21402
+ mutableElement.frameId = remapId(mutableElement.frameId) ?? null;
21403
+ }
20981
21404
  }
20982
21405
  }
20983
21406
  return elementStore.getElements();
@@ -21015,6 +21438,32 @@ var maybeHandleArrowPointlikeDrag = ({
21015
21438
  return false;
21016
21439
  };
21017
21440
 
21441
+ // ../element/src/arrowheads.ts
21442
+ var normalizeArrowhead = (arrowhead) => {
21443
+ switch (arrowhead) {
21444
+ case void 0:
21445
+ case null:
21446
+ return null;
21447
+ case "dot":
21448
+ return "circle";
21449
+ case "crowfoot_one":
21450
+ return "cardinality_one";
21451
+ case "crowfoot_many":
21452
+ return "cardinality_many";
21453
+ case "crowfoot_one_or_many":
21454
+ return "cardinality_one_or_many";
21455
+ default:
21456
+ return arrowhead;
21457
+ }
21458
+ };
21459
+ var getArrowheadForPicker = (arrowhead) => {
21460
+ const normalizedArrowhead = normalizeArrowhead(arrowhead);
21461
+ if (normalizedArrowhead === null) {
21462
+ return null;
21463
+ }
21464
+ return normalizedArrowhead;
21465
+ };
21466
+
21018
21467
  // ../element/src/index.ts
21019
21468
  var getSceneVersion = (elements) => elements.reduce((acc, el) => acc + el.version, 0);
21020
21469
  var hashElementsVersion = (elements) => {
@@ -24114,8 +24563,7 @@ var _renderStaticScene = ({
24114
24563
  var renderStaticSceneThrottled = throttleRAF(
24115
24564
  (config) => {
24116
24565
  _renderStaticScene(config);
24117
- },
24118
- { trailing: true }
24566
+ }
24119
24567
  );
24120
24568
  var renderStaticScene = (renderConfig, throttle2) => {
24121
24569
  if (throttle2) {
@@ -24886,7 +25334,8 @@ var restoreElement = (element, targetElementsMap, existingElementsMap, opts) =>
24886
25334
  });
24887
25335
  case "line":
24888
25336
  case "draw":
24889
- const { startArrowhead = null, endArrowhead = null } = element;
25337
+ const startArrowhead = normalizeArrowhead(element.startArrowhead);
25338
+ const endArrowhead = normalizeArrowhead(element.endArrowhead);
24890
25339
  let x = element.x;
24891
25340
  let y = element.y;
24892
25341
  let points = (
@@ -24911,7 +25360,8 @@ var restoreElement = (element, targetElementsMap, existingElementsMap, opts) =>
24911
25360
  ...getSizeFromPoints(points)
24912
25361
  });
24913
25362
  case "arrow": {
24914
- const { startArrowhead: startArrowhead2 = null, endArrowhead: endArrowhead2 = "arrow" } = element;
25363
+ const startArrowhead2 = normalizeArrowhead(element.startArrowhead);
25364
+ const endArrowhead2 = element.endArrowhead === void 0 ? "arrow" : normalizeArrowhead(element.endArrowhead);
24915
25365
  const x2 = element.x;
24916
25366
  const y2 = element.y;
24917
25367
  const points2 = (
@@ -25179,6 +25629,10 @@ var restoreAppState = (appState, localAppState) => {
25179
25629
  const localValue = localAppState ? localAppState[key] : void 0;
25180
25630
  nextAppState[key] = suppliedValue !== void 0 ? suppliedValue : localValue !== void 0 ? localValue : defaultValue;
25181
25631
  }
25632
+ const boxSelectionMode = appState.boxSelectionMode ?? localAppState?.boxSelectionMode;
25633
+ if (boxSelectionMode !== void 0) {
25634
+ nextAppState.boxSelectionMode = boxSelectionMode;
25635
+ }
25182
25636
  return {
25183
25637
  ...nextAppState,
25184
25638
  cursorButton: localAppState?.cursorButton || "up",
@@ -25309,7 +25763,11 @@ var prepareElementsForRender = ({
25309
25763
  }) => {
25310
25764
  let nextElements;
25311
25765
  if (exportingFrame) {
25312
- nextElements = getElementsOverlappingFrame(elements, exportingFrame);
25766
+ nextElements = getElementsOverlappingFrame(
25767
+ elements,
25768
+ exportingFrame,
25769
+ arrayToMap(elements)
25770
+ );
25313
25771
  } else if (frameRendering.enabled && frameRendering.name) {
25314
25772
  nextElements = addFrameLabelsAsTextElements(elements, {
25315
25773
  exportWithDarkMode
@@ -25708,7 +26166,7 @@ var parseFileContents = async (blob) => {
25708
26166
  let contents;
25709
26167
  if (blob.type === MIME_TYPES.png) {
25710
26168
  try {
25711
- return await (await import("./data/image-BUI6GQJR.js")).decodePngMetadata(blob);
26169
+ return await (await import("./data/image-UQK7BQY4.js")).decodePngMetadata(blob);
25712
26170
  } catch (error) {
25713
26171
  if (error.message === "INVALID") {
25714
26172
  throw new ImageSceneDataError(
@@ -26097,6 +26555,7 @@ export {
26097
26555
  rangeInclusive,
26098
26556
  rangesOverlap,
26099
26557
  rangeIntersection,
26558
+ rangeIncludesValue,
26100
26559
  supportsResizeObserver,
26101
26560
  APP_NAME,
26102
26561
  DRAGGING_THRESHOLD,
@@ -26213,6 +26672,7 @@ export {
26213
26672
  getGridPoint,
26214
26673
  getDateTime,
26215
26674
  capitalizeString,
26675
+ formatTimeToHourMinute,
26216
26676
  isToolIcon,
26217
26677
  isInputLike,
26218
26678
  isInteractive,
@@ -26231,6 +26691,7 @@ export {
26231
26691
  viewportCoordsToSceneCoords,
26232
26692
  sceneCoordsToViewportCoords,
26233
26693
  getGlobalCSSVariable,
26694
+ isRTL,
26234
26695
  tupleToCoors,
26235
26696
  muteFSAbortError,
26236
26697
  findLastIndex,
@@ -26323,8 +26784,10 @@ export {
26323
26784
  getLineHeightInPx,
26324
26785
  getApproxMinLineHeight,
26325
26786
  setCustomTextMetricsProvider,
26787
+ getLineWidth,
26326
26788
  getTextWidth,
26327
26789
  wrapText,
26790
+ getWrappedTextLines,
26328
26791
  redrawTextBoundingBox,
26329
26792
  handleBindTextResize,
26330
26793
  computeBoundTextPosition,
@@ -26354,7 +26817,6 @@ export {
26354
26817
  bumpVersion,
26355
26818
  FOCUS_POINT_SIZE,
26356
26819
  maxBindingDistance_simple,
26357
- shouldEnableBindingForPointerEvent,
26358
26820
  isBindingEnabled,
26359
26821
  bindOrUnbindBindingElement,
26360
26822
  bindOrUnbindBindingElements,
@@ -26364,12 +26826,10 @@ export {
26364
26826
  updateBindings,
26365
26827
  calculateFixedPointForElbowArrowBinding,
26366
26828
  calculateFixedPointForNonElbowArrowBinding,
26829
+ normalizeElbowArrows,
26367
26830
  fixBindingsAfterDeletion,
26368
26831
  getGlobalFixedPointForBindableElement,
26369
26832
  LinearElementEditor,
26370
- isElementInsideBBox,
26371
- elementPartiallyOverlapsWithOrContainsBBox,
26372
- elementsOverlappingBBox,
26373
26833
  selectGroup,
26374
26834
  selectGroupsForSelectedElements,
26375
26835
  isSelectedViaGroup,
@@ -26393,6 +26853,7 @@ export {
26393
26853
  getTargetElements,
26394
26854
  makeNextSelectedElementIds,
26395
26855
  getSelectionStateForElements,
26856
+ getActiveTextElement,
26396
26857
  elementOverlapsWithFrame,
26397
26858
  isCursorInFrame,
26398
26859
  groupByFrameLikes,
@@ -26514,6 +26975,7 @@ export {
26514
26975
  showSelectedShapeActions,
26515
26976
  convertToExcalidrawElements,
26516
26977
  maybeHandleArrowPointlikeDrag,
26978
+ getArrowheadForPicker,
26517
26979
  getSceneVersion,
26518
26980
  hashElementsVersion,
26519
26981
  hashString,
@@ -26582,4 +27044,4 @@ export {
26582
27044
  createFile,
26583
27045
  normalizeFile
26584
27046
  };
26585
- //# sourceMappingURL=chunk-P7XQCHXR.js.map
27047
+ //# sourceMappingURL=chunk-HJWER26G.js.map