@excalidraw/element 0.18.0-51ad895 → 0.18.0-54a9826

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 (201) hide show
  1. package/dist/dev/index.js +2215 -742
  2. package/dist/dev/index.js.map +4 -4
  3. package/dist/prod/index.js +17 -17
  4. package/dist/types/common/src/bounds.d.ts +10 -0
  5. package/dist/types/common/src/colors.d.ts +59 -39
  6. package/dist/types/common/src/constants.d.ts +16 -11
  7. package/dist/types/common/src/editorInterface.d.ts +1 -1
  8. package/dist/types/common/src/font-metadata.d.ts +1 -3
  9. package/dist/types/common/src/index.d.ts +1 -1
  10. package/dist/types/common/src/keys.d.ts +1 -1
  11. package/dist/types/common/src/utility-types.d.ts +0 -1
  12. package/dist/types/common/src/utils.d.ts +43 -34
  13. package/dist/types/element/src/Scene.d.ts +3 -3
  14. package/dist/types/element/src/arrows/focus.d.ts +27 -0
  15. package/dist/types/element/src/arrows/helpers.d.ts +5 -0
  16. package/dist/types/element/src/binding.d.ts +13 -6
  17. package/dist/types/element/src/bounds.d.ts +2 -10
  18. package/dist/types/element/src/collision.d.ts +4 -3
  19. package/dist/types/element/src/comparisons.d.ts +7 -7
  20. package/dist/types/element/src/distribute.d.ts +2 -1
  21. package/dist/types/element/src/dragElements.d.ts +3 -3
  22. package/dist/types/element/src/duplicate.d.ts +3 -3
  23. package/dist/types/element/src/fractionalIndex.d.ts +2 -2
  24. package/dist/types/element/src/frame.d.ts +5 -1
  25. package/dist/types/element/src/heading.d.ts +2 -1
  26. package/dist/types/element/src/image.d.ts +1 -11
  27. package/dist/types/element/src/index.d.ts +3 -0
  28. package/dist/types/element/src/linearElementEditor.d.ts +3 -2
  29. package/dist/types/element/src/mutateElement.d.ts +3 -1
  30. package/dist/types/element/src/newElement.d.ts +6 -6
  31. package/dist/types/element/src/renderElement.d.ts +0 -6
  32. package/dist/types/element/src/resizeElements.d.ts +10 -10
  33. package/dist/types/element/src/resizeTest.d.ts +1 -1
  34. package/dist/types/element/src/selection.d.ts +3 -7
  35. package/dist/types/element/src/shape.d.ts +8 -7
  36. package/dist/types/element/src/textMeasurements.d.ts +1 -3
  37. package/dist/types/{excalidraw/data → element/src}/transform.d.ts +3 -3
  38. package/dist/types/element/src/transformHandles.d.ts +3 -23
  39. package/dist/types/element/src/typeChecks.d.ts +2 -4
  40. package/dist/types/element/src/utils.d.ts +3 -1
  41. package/dist/types/{common → element}/src/visualdebug.d.ts +20 -2
  42. package/dist/types/element/src/zindex.d.ts +1 -1
  43. package/dist/types/excalidraw/actions/actionAddToLibrary.d.ts +62 -126
  44. package/dist/types/excalidraw/actions/actionAlign.d.ts +0 -1
  45. package/dist/types/excalidraw/actions/actionBoundText.d.ts +44 -87
  46. package/dist/types/excalidraw/actions/actionCanvas.d.ts +263 -510
  47. package/dist/types/excalidraw/actions/actionClipboard.d.ts +44 -87
  48. package/dist/types/excalidraw/actions/actionCropEditor.d.ts +21 -43
  49. package/dist/types/excalidraw/actions/actionDeleteSelected.d.ts +76 -142
  50. package/dist/types/excalidraw/actions/actionDistribute.d.ts +0 -1
  51. package/dist/types/excalidraw/actions/actionDuplicateSelection.d.ts +0 -1
  52. package/dist/types/excalidraw/actions/actionElementLink.d.ts +18 -40
  53. package/dist/types/excalidraw/actions/actionElementLock.d.ts +45 -88
  54. package/dist/types/excalidraw/actions/actionEmbeddable.d.ts +22 -44
  55. package/dist/types/excalidraw/actions/actionExport.d.ts +85 -170
  56. package/dist/types/excalidraw/actions/actionFinalize.d.ts +1 -2
  57. package/dist/types/excalidraw/actions/actionFlip.d.ts +0 -1
  58. package/dist/types/excalidraw/actions/actionFrame.d.ts +181 -302
  59. package/dist/types/excalidraw/actions/actionGroup.d.ts +48 -99
  60. package/dist/types/excalidraw/actions/actionLinearEditor.d.ts +124 -180
  61. package/dist/types/excalidraw/actions/actionLink.d.ts +22 -44
  62. package/dist/types/excalidraw/actions/actionMenu.d.ts +17 -39
  63. package/dist/types/excalidraw/actions/actionNavigate.d.ts +14 -17
  64. package/dist/types/excalidraw/actions/actionProperties.d.ts +59 -102
  65. package/dist/types/excalidraw/actions/actionSelectAll.d.ts +24 -50
  66. package/dist/types/excalidraw/actions/actionStyles.d.ts +20 -42
  67. package/dist/types/excalidraw/actions/actionToggleGridMode.d.ts +22 -44
  68. package/dist/types/excalidraw/actions/actionToggleObjectsSnapMode.d.ts +22 -44
  69. package/dist/types/excalidraw/actions/actionToggleSearchMenu.d.ts +16 -38
  70. package/dist/types/excalidraw/actions/actionToggleStats.d.ts +22 -44
  71. package/dist/types/excalidraw/actions/actionToggleViewMode.d.ts +22 -44
  72. package/dist/types/excalidraw/actions/actionToggleZenMode.d.ts +22 -44
  73. package/dist/types/excalidraw/actions/actionZindex.d.ts +0 -1
  74. package/dist/types/excalidraw/actions/manager.d.ts +1 -1
  75. package/dist/types/excalidraw/actions/register.d.ts +2 -2
  76. package/dist/types/excalidraw/appState.d.ts +3 -3
  77. package/dist/types/excalidraw/clipboard.d.ts +11 -33
  78. package/dist/types/excalidraw/components/Actions.d.ts +1 -1
  79. package/dist/types/excalidraw/components/App.d.ts +39 -41
  80. package/dist/types/excalidraw/components/Card.d.ts +1 -3
  81. package/dist/types/excalidraw/components/ColorPicker/ColorInput.d.ts +2 -4
  82. package/dist/types/excalidraw/components/ColorPicker/ColorPicker.d.ts +0 -1
  83. package/dist/types/excalidraw/components/ColorPicker/colorPickerUtils.d.ts +0 -1
  84. package/dist/types/excalidraw/components/ColorPicker/keyboardNavHandlers.d.ts +0 -1
  85. package/dist/types/excalidraw/components/CommandPalette/types.d.ts +0 -1
  86. package/dist/types/excalidraw/components/ConvertElementTypePopup.d.ts +2 -2
  87. package/dist/types/excalidraw/components/DarkModeToggle.d.ts +1 -1
  88. package/dist/types/excalidraw/components/DefaultSidebar.d.ts +9 -13
  89. package/dist/types/excalidraw/components/ElementLinkDialog.d.ts +1 -1
  90. package/dist/types/excalidraw/components/Ellipsify.d.ts +1 -2
  91. package/dist/types/excalidraw/components/ErrorDialog.d.ts +1 -1
  92. package/dist/types/excalidraw/components/ExcalidrawLogo.d.ts +0 -1
  93. package/dist/types/excalidraw/components/EyeDropper.d.ts +0 -1
  94. package/dist/types/excalidraw/components/FilledButton.d.ts +1 -0
  95. package/dist/types/excalidraw/components/FontPicker/keyboardNavHandlers.d.ts +0 -1
  96. package/dist/types/excalidraw/components/HelpDialog.d.ts +1 -1
  97. package/dist/types/excalidraw/components/InlineIcon.d.ts +2 -2
  98. package/dist/types/excalidraw/components/LibraryMenuControlButtons.d.ts +1 -1
  99. package/dist/types/excalidraw/components/LibraryMenuHeaderContent.d.ts +1 -2
  100. package/dist/types/excalidraw/components/LibraryUnit.d.ts +2 -3
  101. package/dist/types/excalidraw/components/LoadingMessage.d.ts +0 -1
  102. package/dist/types/excalidraw/components/MobileToolBar.d.ts +0 -1
  103. package/dist/types/excalidraw/components/Modal.d.ts +0 -1
  104. package/dist/types/excalidraw/components/OverwriteConfirm/OverwriteConfirm.d.ts +1 -1
  105. package/dist/types/excalidraw/components/RadioGroup.d.ts +0 -1
  106. package/dist/types/excalidraw/components/RadioSelection.d.ts +4 -4
  107. package/dist/types/excalidraw/components/ScrollableList.d.ts +0 -1
  108. package/dist/types/excalidraw/components/Sidebar/Sidebar.d.ts +15 -21
  109. package/dist/types/excalidraw/components/Sidebar/SidebarHeader.d.ts +1 -1
  110. package/dist/types/excalidraw/components/Sidebar/SidebarTab.d.ts +1 -2
  111. package/dist/types/excalidraw/components/Sidebar/SidebarTabTrigger.d.ts +1 -2
  112. package/dist/types/excalidraw/components/Sidebar/SidebarTabTriggers.d.ts +1 -2
  113. package/dist/types/excalidraw/components/Sidebar/SidebarTabs.d.ts +1 -2
  114. package/dist/types/excalidraw/components/Spinner.d.ts +4 -4
  115. package/dist/types/excalidraw/components/Stats/CanvasGrid.d.ts +0 -1
  116. package/dist/types/excalidraw/components/Stats/Collapsible.d.ts +0 -1
  117. package/dist/types/excalidraw/components/Stats/DragInput.d.ts +0 -1
  118. package/dist/types/excalidraw/components/Stats/index.d.ts +7 -8
  119. package/dist/types/excalidraw/components/TTDDialog/Chat/ChatHistoryMenu.d.ts +15 -0
  120. package/dist/types/excalidraw/components/TTDDialog/Chat/ChatInterface.d.ts +23 -0
  121. package/dist/types/excalidraw/components/TTDDialog/Chat/ChatMessage.d.ts +14 -0
  122. package/dist/types/excalidraw/components/TTDDialog/Chat/TTDChatPanel.d.ts +27 -0
  123. package/dist/types/excalidraw/components/TTDDialog/Chat/index.d.ts +3 -0
  124. package/dist/types/excalidraw/components/TTDDialog/Chat/useChatAgent.d.ts +8 -0
  125. package/dist/types/excalidraw/components/TTDDialog/MermaidToExcalidraw.d.ts +3 -2
  126. package/dist/types/excalidraw/components/TTDDialog/TTDContext.d.ts +13 -0
  127. package/dist/types/excalidraw/components/TTDDialog/TTDDialog.d.ts +12 -29
  128. package/dist/types/excalidraw/components/TTDDialog/TTDDialogOutput.d.ts +2 -2
  129. package/dist/types/excalidraw/components/TTDDialog/TTDDialogPanel.d.ts +13 -9
  130. package/dist/types/excalidraw/components/TTDDialog/TTDDialogTab.d.ts +1 -2
  131. package/dist/types/excalidraw/components/TTDDialog/TTDDialogTabTrigger.d.ts +1 -2
  132. package/dist/types/excalidraw/components/TTDDialog/TTDDialogTabTriggers.d.ts +1 -2
  133. package/dist/types/excalidraw/components/TTDDialog/TTDDialogTrigger.d.ts +1 -1
  134. package/dist/types/excalidraw/components/TTDDialog/TTDPreviewPanel.d.ts +9 -0
  135. package/dist/types/excalidraw/components/TTDDialog/TTDWelcomeMessage.d.ts +1 -0
  136. package/dist/types/excalidraw/components/TTDDialog/TextToDiagram.d.ts +9 -0
  137. package/dist/types/excalidraw/components/TTDDialog/common.d.ts +16 -16
  138. package/dist/types/excalidraw/components/TTDDialog/hooks/useChatManagement.d.ts +13 -0
  139. package/dist/types/excalidraw/components/TTDDialog/hooks/useMermaidRenderer.d.ts +14 -0
  140. package/dist/types/excalidraw/components/TTDDialog/hooks/useTextGeneration.d.ts +7 -0
  141. package/dist/types/excalidraw/components/TTDDialog/types.d.ts +95 -0
  142. package/dist/types/excalidraw/components/TTDDialog/useTTDChatStorage.d.ts +22 -0
  143. package/dist/types/excalidraw/components/TTDDialog/utils/TTDStreamFetch.d.ts +24 -0
  144. package/dist/types/excalidraw/components/TTDDialog/utils/chat.d.ts +10 -0
  145. package/dist/types/excalidraw/components/TTDDialog/utils/mermaidValidation.d.ts +1 -0
  146. package/dist/types/excalidraw/components/Toast.d.ts +3 -3
  147. package/dist/types/excalidraw/components/Trans.d.ts +2 -2
  148. package/dist/types/excalidraw/components/dropdownMenu/DropdownMenu.d.ts +30 -33
  149. package/dist/types/excalidraw/components/dropdownMenu/DropdownMenuContent.d.ts +5 -5
  150. package/dist/types/excalidraw/components/dropdownMenu/DropdownMenuGroup.d.ts +3 -3
  151. package/dist/types/excalidraw/components/dropdownMenu/DropdownMenuItem.d.ts +12 -19
  152. package/dist/types/excalidraw/components/dropdownMenu/DropdownMenuItemContent.d.ts +5 -4
  153. package/dist/types/excalidraw/components/dropdownMenu/DropdownMenuItemContentRadio.d.ts +0 -1
  154. package/dist/types/excalidraw/components/dropdownMenu/DropdownMenuItemCustom.d.ts +2 -2
  155. package/dist/types/excalidraw/components/dropdownMenu/DropdownMenuItemLink.d.ts +6 -6
  156. package/dist/types/excalidraw/components/dropdownMenu/DropdownMenuTrigger.d.ts +3 -4
  157. package/dist/types/excalidraw/components/dropdownMenu/common.d.ts +1 -1
  158. package/dist/types/excalidraw/components/hoc/withInternalFallback.d.ts +1 -1
  159. package/dist/types/excalidraw/components/hyperlink/helpers.d.ts +1 -1
  160. package/dist/types/excalidraw/components/icons.d.ts +16 -12
  161. package/dist/types/excalidraw/components/live-collaboration/LiveCollaborationTrigger.d.ts +2 -13
  162. package/dist/types/excalidraw/components/main-menu/DefaultItems.d.ts +2 -2
  163. package/dist/types/excalidraw/components/main-menu/MainMenu.d.ts +26 -29
  164. package/dist/types/excalidraw/components/welcome-screen/WelcomeScreen.Center.d.ts +6 -6
  165. package/dist/types/excalidraw/components/welcome-screen/WelcomeScreen.d.ts +15 -16
  166. package/dist/types/excalidraw/data/blob.d.ts +321 -3
  167. package/dist/types/excalidraw/data/encode.d.ts +4 -4
  168. package/dist/types/excalidraw/data/encryption.d.ts +5 -5
  169. package/dist/types/excalidraw/data/filesystem.d.ts +2 -2
  170. package/dist/types/excalidraw/data/index.d.ts +3 -3
  171. package/dist/types/excalidraw/data/json.d.ts +159 -2
  172. package/dist/types/excalidraw/data/library.d.ts +24 -9
  173. package/dist/types/excalidraw/data/restore.d.ts +25 -10
  174. package/dist/types/excalidraw/editor-jotai.d.ts +11 -11
  175. package/dist/types/excalidraw/errors.d.ts +14 -0
  176. package/dist/types/excalidraw/hooks/useOutsideClick.d.ts +1 -2
  177. package/dist/types/excalidraw/hooks/useScrollPosition.d.ts +1 -2
  178. package/dist/types/excalidraw/i18n.d.ts +2 -2
  179. package/dist/types/excalidraw/index.d.ts +5 -4
  180. package/dist/types/excalidraw/renderer/helpers.d.ts +6 -4
  181. package/dist/types/excalidraw/renderer/interactiveScene.d.ts +8 -6
  182. package/dist/types/excalidraw/scene/Renderer.d.ts +5 -2
  183. package/dist/types/excalidraw/scene/export.d.ts +2 -2
  184. package/dist/types/excalidraw/scene/scroll.d.ts +1 -6
  185. package/dist/types/excalidraw/scene/types.d.ts +7 -2
  186. package/dist/types/excalidraw/snapping.d.ts +5 -5
  187. package/dist/types/excalidraw/subset/harfbuzz/harfbuzz-bindings.d.ts +1 -1
  188. package/dist/types/excalidraw/subset/harfbuzz/harfbuzz-loader.d.ts +1 -1
  189. package/dist/types/excalidraw/subset/harfbuzz/harfbuzz-wasm.d.ts +1 -1
  190. package/dist/types/excalidraw/subset/woff2/woff2-loader.d.ts +2 -2
  191. package/dist/types/excalidraw/subset/woff2/woff2-wasm.d.ts +1 -1
  192. package/dist/types/excalidraw/types.d.ts +2 -3
  193. package/dist/types/excalidraw/wysiwyg/textWysiwyg.d.ts +2 -2
  194. package/dist/types/math/src/polygon.d.ts +2 -2
  195. package/dist/types/math/src/range.d.ts +1 -3
  196. package/dist/types/math/src/segment.d.ts +3 -3
  197. package/dist/types/utils/src/bbox.d.ts +1 -1
  198. package/dist/types/utils/src/export.d.ts +5 -5
  199. package/dist/types/utils/src/shape.d.ts +6 -6
  200. package/dist/types/utils/src/withinBounds.d.ts +2 -2
  201. package/package.json +9 -3
package/dist/dev/index.js CHANGED
@@ -199,7 +199,7 @@ import {
199
199
  radiansBetweenAngles,
200
200
  radiansDifference
201
201
  } from "@excalidraw/math";
202
- import { pointsEqual as pointsEqual6 } from "@excalidraw/math";
202
+ import { pointsEqual as pointsEqual7 } from "@excalidraw/math";
203
203
 
204
204
  // src/bounds.ts
205
205
  init_define_import_meta_env();
@@ -2447,21 +2447,6 @@ var getClosedCurveShape = (element, roughShape, startingPoint = pointFrom(0, 0),
2447
2447
 
2448
2448
  // src/shape.ts
2449
2449
  init_define_import_meta_env();
2450
- import {
2451
- pointFrom as pointFrom13,
2452
- pointDistance as pointDistance6,
2453
- pointRotateRads as pointRotateRads12
2454
- } from "@excalidraw/math";
2455
- import {
2456
- ROUGHNESS,
2457
- isTransparent as isTransparent3,
2458
- assertNever as assertNever2,
2459
- COLOR_PALETTE,
2460
- LINE_POLYGON_POINT_MERGE_DISTANCE
2461
- } from "@excalidraw/common";
2462
-
2463
- // src/renderElement.ts
2464
- init_define_import_meta_env();
2465
2450
 
2466
2451
  // ../../node_modules/perfect-freehand/dist/esm/index.js
2467
2452
  init_define_import_meta_env();
@@ -2626,7 +2611,24 @@ function ae(e, t = {}) {
2626
2611
  return ce(me(e, t), t);
2627
2612
  }
2628
2613
 
2614
+ // src/shape.ts
2615
+ import {
2616
+ pointFrom as pointFrom13,
2617
+ pointDistance as pointDistance6,
2618
+ pointRotateRads as pointRotateRads12
2619
+ } from "@excalidraw/math";
2620
+ import {
2621
+ ROUGHNESS,
2622
+ THEME as THEME2,
2623
+ isTransparent as isTransparent3,
2624
+ assertNever as assertNever2,
2625
+ COLOR_PALETTE,
2626
+ LINE_POLYGON_POINT_MERGE_DISTANCE,
2627
+ applyDarkModeFilter as applyDarkModeFilter2
2628
+ } from "@excalidraw/common";
2629
+
2629
2630
  // src/renderElement.ts
2631
+ init_define_import_meta_env();
2630
2632
  import {
2631
2633
  isRightAngleRads,
2632
2634
  lineSegment as lineSegment6,
@@ -2638,13 +2640,16 @@ import {
2638
2640
  DEFAULT_REDUCED_GLOBAL_ALPHA,
2639
2641
  ELEMENT_READY_TO_ERASE_OPACITY,
2640
2642
  FRAME_STYLE,
2643
+ DARK_THEME_FILTER,
2641
2644
  MIME_TYPES,
2642
2645
  THEME,
2643
2646
  distance as distance2,
2644
2647
  getFontString as getFontString3,
2645
2648
  isRTL,
2646
2649
  getVerticalOffset,
2647
- invariant as invariant9
2650
+ invariant as invariant9,
2651
+ applyDarkModeFilter,
2652
+ isSafari
2648
2653
  } from "@excalidraw/common";
2649
2654
 
2650
2655
  // src/cropElement.ts
@@ -3111,7 +3116,7 @@ import {
3111
3116
  pointCenter as pointCenter2,
3112
3117
  pointFrom as pointFrom9,
3113
3118
  pointRotateRads as pointRotateRads9,
3114
- pointsEqual as pointsEqual5,
3119
+ pointsEqual as pointsEqual6,
3115
3120
  pointDistance as pointDistance5,
3116
3121
  vectorFromPoint as vectorFromPoint8,
3117
3122
  curveLength,
@@ -3129,7 +3134,6 @@ import {
3129
3134
  } from "@excalidraw/common";
3130
3135
  import {
3131
3136
  deconstructLinearOrFreeDrawElement as deconstructLinearOrFreeDrawElement2,
3132
- getHoveredElementForBinding as getHoveredElementForBinding2,
3133
3137
  isPathALoop as isPathALoop2,
3134
3138
  moveArrowAboveBindable,
3135
3139
  projectFixedPointOntoDiagonal as projectFixedPointOntoDiagonal2
@@ -3153,6 +3157,7 @@ import {
3153
3157
  pointFrom as pointFrom8,
3154
3158
  pointFromVector as pointFromVector6,
3155
3159
  pointRotateRads as pointRotateRads8,
3160
+ pointsEqual as pointsEqual5,
3156
3161
  vectorFromPoint as vectorFromPoint7,
3157
3162
  vectorNormalize as vectorNormalize4,
3158
3163
  vectorScale as vectorScale7
@@ -3350,7 +3355,6 @@ var getDefaultRoundnessTypeForElement = (element) => {
3350
3355
  }
3351
3356
  return null;
3352
3357
  };
3353
- var isBounds = (box) => Array.isArray(box) && box.length === 4 && typeof box[0] === "number" && typeof box[1] === "number" && typeof box[2] === "number" && typeof box[3] === "number";
3354
3358
  var getLinearElementSubType = (element) => {
3355
3359
  if (isSharpArrow(element)) {
3356
3360
  return "sharpArrow";
@@ -4776,6 +4780,11 @@ var shouldTestInside = (element) => {
4776
4780
  }
4777
4781
  return isDraggableFromInside || isImageElement(element);
4778
4782
  };
4783
+ var cachedPoint = null;
4784
+ var cachedElement = null;
4785
+ var cachedThreshold = Infinity;
4786
+ var cachedHit = false;
4787
+ var cachedOverrideShouldTestInside = false;
4779
4788
  var hitElementItself = ({
4780
4789
  point,
4781
4790
  element,
@@ -4784,6 +4793,12 @@ var hitElementItself = ({
4784
4793
  frameNameBound = null,
4785
4794
  overrideShouldTestInside = false
4786
4795
  }) => {
4796
+ if (cachedPoint && pointsEqual2(point, cachedPoint) && cachedThreshold <= threshold && overrideShouldTestInside === cachedOverrideShouldTestInside) {
4797
+ const derefElement = cachedElement?.deref();
4798
+ if (derefElement && derefElement.id === element.id && derefElement.version === element.version && derefElement.versionNonce === element.versionNonce) {
4799
+ return cachedHit;
4800
+ }
4801
+ }
4787
4802
  const hitFrameName = frameNameBound ? isPointWithinBounds(
4788
4803
  pointFrom5(frameNameBound.x - threshold, frameNameBound.y - threshold),
4789
4804
  point,
@@ -4810,7 +4825,13 @@ var hitElementItself = ({
4810
4825
  // we would need `onShape` as well to include the "borders"
4811
4826
  isPointInElement(point, element, elementsMap) || isPointOnElementOutline(point, element, elementsMap, threshold)
4812
4827
  ) : isPointOnElementOutline(point, element, elementsMap, threshold);
4813
- return hitElement || hitFrameName;
4828
+ const result = hitElement || hitFrameName;
4829
+ cachedPoint = point;
4830
+ cachedElement = new WeakRef(element);
4831
+ cachedThreshold = threshold;
4832
+ cachedOverrideShouldTestInside = overrideShouldTestInside;
4833
+ cachedHit = result;
4834
+ return result;
4814
4835
  };
4815
4836
  var hitElementBoundingBox = (point, element, elementsMap, tolerance = 0) => {
4816
4837
  let [x1, y1, x2, y2] = getElementBounds(element, elementsMap);
@@ -4872,7 +4893,7 @@ var bindingBorderTest = (element, [x, y], elementsMap, tolerance = 0) => {
4872
4893
  const distance3 = distanceToElement(element, elementsMap, p);
4873
4894
  return shouldTestInside2 ? intersections.length === 0 || distance3 <= tolerance : intersections.length > 0 && distance3 <= t;
4874
4895
  };
4875
- var getAllHoveredElementAtPoint = (point, elements, elementsMap, toleranceFn) => {
4896
+ var getAllHoveredElementAtPoint = (point, elements, elementsMap, tolerance) => {
4876
4897
  const candidateElements = [];
4877
4898
  for (let index = elements.length - 1; index >= 0; --index) {
4878
4899
  const element = elements[index];
@@ -4880,7 +4901,7 @@ var getAllHoveredElementAtPoint = (point, elements, elementsMap, toleranceFn) =>
4880
4901
  !element.isDeleted,
4881
4902
  "Elements in the function parameter for getAllElementsAtPositionForBinding() should not contain deleted elements"
4882
4903
  );
4883
- if (isBindableElement(element, false) && bindingBorderTest(element, point, elementsMap, toleranceFn?.(element))) {
4904
+ if (isBindableElement(element, false) && bindingBorderTest(element, point, elementsMap, tolerance)) {
4884
4905
  candidateElements.push(element);
4885
4906
  if (!isTransparent(element.backgroundColor)) {
4886
4907
  break;
@@ -4889,12 +4910,12 @@ var getAllHoveredElementAtPoint = (point, elements, elementsMap, toleranceFn) =>
4889
4910
  }
4890
4911
  return candidateElements;
4891
4912
  };
4892
- var getHoveredElementForBinding = (point, elements, elementsMap, toleranceFn) => {
4913
+ var getHoveredElementForBinding = (point, elements, elementsMap, tolerance) => {
4893
4914
  const candidateElements = getAllHoveredElementAtPoint(
4894
4915
  point,
4895
4916
  elements,
4896
4917
  elementsMap,
4897
- toleranceFn
4918
+ tolerance
4898
4919
  );
4899
4920
  if (!candidateElements || candidateElements.length === 0) {
4900
4921
  return null;
@@ -4906,6 +4927,32 @@ var getHoveredElementForBinding = (point, elements, elementsMap, toleranceFn) =>
4906
4927
  (a2, b2) => b2.width ** 2 + b2.height ** 2 - (a2.width ** 2 + a2.height ** 2)
4907
4928
  ).pop();
4908
4929
  };
4930
+ var getHoveredElementForFocusPoint = (point, arrow, elements, elementsMap, tolerance) => {
4931
+ const candidateElements = [];
4932
+ for (let index = elements.length - 1; index >= 0; --index) {
4933
+ const element = elements[index];
4934
+ invariant4(
4935
+ !element.isDeleted,
4936
+ "Elements in the function parameter for getAllElementsAtPositionForBinding() should not contain deleted elements"
4937
+ );
4938
+ if (isBindableElement(element, false) && bindingBorderTest(element, point, elementsMap, tolerance)) {
4939
+ candidateElements.push(element);
4940
+ }
4941
+ }
4942
+ if (!candidateElements || candidateElements.length === 0) {
4943
+ return null;
4944
+ }
4945
+ if (candidateElements.length === 1) {
4946
+ return candidateElements[0];
4947
+ }
4948
+ const distanceFilteredCandidateElements = candidateElements.filter(
4949
+ (el) => distanceToElement(el, elementsMap, point) <= getBindingGap(el, arrow) || isPointInElement(point, el, elementsMap)
4950
+ );
4951
+ if (distanceFilteredCandidateElements.length === 0) {
4952
+ return null;
4953
+ }
4954
+ return distanceFilteredCandidateElements[0];
4955
+ };
4909
4956
  var intersectElementWithLineSegment = (element, elementsMap, line2, offset = 0, onlyFirst = false) => {
4910
4957
  const intersectorBounds = [
4911
4958
  Math.min(line2[0][0] - offset, line2[1][0] - offset),
@@ -5177,7 +5224,11 @@ var isBindableElementInsideOtherBindable = (innerElement, outerElement, elements
5177
5224
 
5178
5225
  // src/heading.ts
5179
5226
  init_define_import_meta_env();
5180
- import { invariant as invariant5, isDevEnv as isDevEnv2, isTestEnv as isTestEnv3 } from "@excalidraw/common";
5227
+ import {
5228
+ invariant as invariant5,
5229
+ isDevEnv as isDevEnv2,
5230
+ isTestEnv as isTestEnv3
5231
+ } from "@excalidraw/common";
5181
5232
  import {
5182
5233
  pointFrom as pointFrom6,
5183
5234
  pointFromVector as pointFromVector5,
@@ -6822,7 +6873,7 @@ var getHoveredElement = (origPoint, elementsMap, elements, zoom) => {
6822
6873
  origPoint,
6823
6874
  elements,
6824
6875
  elementsMap,
6825
- (element) => maxBindingDistance_simple(zoom)
6876
+ maxBindingDistance_simple(zoom)
6826
6877
  );
6827
6878
  };
6828
6879
  var gridAddressesEqual = (a2, b2) => a2[0] === b2[0] && a2[1] === b2[1];
@@ -6935,6 +6986,7 @@ var bumpVersion = (element, version) => {
6935
6986
  // src/binding.ts
6936
6987
  var BASE_BINDING_GAP = 10;
6937
6988
  var BASE_BINDING_GAP_ELBOW = 5;
6989
+ var FOCUS_POINT_SIZE = 10 / 1.5;
6938
6990
  var getBindingGap = (bindTarget, opts) => {
6939
6991
  return (opts.elbowed ? BASE_BINDING_GAP_ELBOW : BASE_BINDING_GAP) + bindTarget.strokeWidth / 2;
6940
6992
  };
@@ -6955,10 +7007,12 @@ var shouldEnableBindingForPointerEvent = (event) => {
6955
7007
  var isBindingEnabled = (appState) => {
6956
7008
  return appState.isBindingEnabled;
6957
7009
  };
6958
- var bindOrUnbindBindingElement = (arrow, draggingPoints, scene, appState, opts) => {
7010
+ var bindOrUnbindBindingElement = (arrow, draggingPoints, scenePointerX, scenePointerY, scene, appState, opts) => {
6959
7011
  const { start, end } = getBindingStrategyForDraggingBindingElementEndpoints(
6960
7012
  arrow,
6961
7013
  draggingPoints,
7014
+ scenePointerX,
7015
+ scenePointerY,
6962
7016
  scene.getNonDeletedElementsMap(),
6963
7017
  scene.getNonDeletedElements(),
6964
7018
  appState,
@@ -7021,7 +7075,7 @@ var bindingStrategyForElbowArrowEndpointDragging = (arrow, draggingPoints, eleme
7021
7075
  globalPoint,
7022
7076
  elements,
7023
7077
  elementsMap,
7024
- (element) => maxBindingDistance_simple(zoom)
7078
+ maxBindingDistance_simple(zoom)
7025
7079
  );
7026
7080
  const current = hit ? {
7027
7081
  element: hit,
@@ -7205,7 +7259,7 @@ var bindingStrategyForSimpleArrowEndpointDragging_complex = (point, currentBindi
7205
7259
  }
7206
7260
  return { current, other: isMultiPoint ? { mode: void 0 } : other };
7207
7261
  };
7208
- var getBindingStrategyForDraggingBindingElementEndpoints = (arrow, draggingPoints, elementsMap, elements, appState, opts) => {
7262
+ var getBindingStrategyForDraggingBindingElementEndpoints = (arrow, draggingPoints, screenPointerX, screenPointerY, elementsMap, elements, appState, opts) => {
7209
7263
  if (getFeatureFlag("COMPLEX_BINDINGS")) {
7210
7264
  return getBindingStrategyForDraggingBindingElementEndpoints_complex(
7211
7265
  arrow,
@@ -7219,13 +7273,15 @@ var getBindingStrategyForDraggingBindingElementEndpoints = (arrow, draggingPoint
7219
7273
  return getBindingStrategyForDraggingBindingElementEndpoints_simple(
7220
7274
  arrow,
7221
7275
  draggingPoints,
7276
+ screenPointerX,
7277
+ screenPointerY,
7222
7278
  elementsMap,
7223
7279
  elements,
7224
7280
  appState,
7225
7281
  opts
7226
7282
  );
7227
7283
  };
7228
- var getBindingStrategyForDraggingBindingElementEndpoints_simple = (arrow, draggingPoints, elementsMap, elements, appState, opts) => {
7284
+ var getBindingStrategyForDraggingBindingElementEndpoints_simple = (arrow, draggingPoints, scenePointerX, scenePointerY, elementsMap, elements, appState, opts) => {
7229
7285
  const startIdx = 0;
7230
7286
  const endIdx = arrow.points.length - 1;
7231
7287
  const startDragged = draggingPoints.has(startIdx);
@@ -7273,9 +7329,13 @@ var getBindingStrategyForDraggingBindingElementEndpoints_simple = (arrow, draggi
7273
7329
  globalPoint,
7274
7330
  elements,
7275
7331
  elementsMap,
7276
- (e) => maxBindingDistance_simple(appState.zoom)
7332
+ maxBindingDistance_simple(appState.zoom)
7277
7333
  );
7278
- const pointInElement = hit && isPointInElement(globalPoint, hit, elementsMap);
7334
+ const pointInElement = hit && (opts?.angleLocked ? isPointInElement(
7335
+ pointFrom8(scenePointerX, scenePointerY),
7336
+ hit,
7337
+ elementsMap
7338
+ ) : isPointInElement(globalPoint, hit, elementsMap));
7279
7339
  const otherBindableElement = otherBinding ? elementsMap.get(
7280
7340
  otherBinding.elementId
7281
7341
  ) : void 0;
@@ -7284,7 +7344,13 @@ var getBindingStrategyForDraggingBindingElementEndpoints_simple = (arrow, draggi
7284
7344
  otherBindableElement,
7285
7345
  elementsMap
7286
7346
  );
7287
- const otherFocusPointIsInElement = otherBindableElement && otherFocusPoint && isPointInElement(otherFocusPoint, otherBindableElement, elementsMap);
7347
+ const otherFocusPointIsInElement = otherBindableElement && otherFocusPoint && hitElementItself({
7348
+ point: otherFocusPoint,
7349
+ element: otherBindableElement,
7350
+ elementsMap,
7351
+ threshold: 0,
7352
+ overrideShouldTestInside: true
7353
+ });
7288
7354
  if (otherBinding && otherBinding.elementId === hit?.id) {
7289
7355
  invariant7(
7290
7356
  !opts?.newArrow || appState.selectedLinearElement?.initialState.origin,
@@ -7345,10 +7411,25 @@ var getBindingStrategyForDraggingBindingElementEndpoints_simple = (arrow, draggi
7345
7411
  elementsMap
7346
7412
  ) || globalPoint
7347
7413
  } : { mode: null };
7414
+ const otherEndpoint = LinearElementEditor.getPointAtIndexGlobalCoordinates(
7415
+ arrow,
7416
+ startDragged ? -1 : 0,
7417
+ elementsMap
7418
+ );
7348
7419
  const other = otherBindableElement && !otherFocusPointIsInElement && appState.selectedLinearElement?.initialState.altFocusPoint ? {
7349
7420
  mode: "orbit",
7350
7421
  element: otherBindableElement,
7351
7422
  focusPoint: appState.selectedLinearElement.initialState.altFocusPoint
7423
+ } : opts?.angleLocked && otherBindableElement ? {
7424
+ mode: "orbit",
7425
+ element: otherBindableElement,
7426
+ focusPoint: projectFixedPointOntoDiagonal(
7427
+ arrow,
7428
+ otherEndpoint,
7429
+ otherBindableElement,
7430
+ startDragged ? "end" : "start",
7431
+ elementsMap
7432
+ ) || otherEndpoint
7352
7433
  } : { mode: void 0 };
7353
7434
  return {
7354
7435
  start: startDragged ? current : other,
@@ -7450,6 +7531,8 @@ var bindOrUnbindBindingElements = (selectedArrows, scene, appState) => {
7450
7531
  arrow,
7451
7532
  /* @__PURE__ */ new Map(),
7452
7533
  // No dragging points in this case
7534
+ Infinity,
7535
+ Infinity,
7453
7536
  scene,
7454
7537
  appState
7455
7538
  );
@@ -7576,9 +7659,71 @@ var updateBoundElements = (changedElement, scene, options) => {
7576
7659
  }
7577
7660
  });
7578
7661
  };
7662
+ var updateArrowBindings = (latestElement, startOrEnd, elementsMap, scene, appState) => {
7663
+ invariant7(
7664
+ !isElbowArrow(latestElement),
7665
+ "Elbow arrows not supported for indirect updates"
7666
+ );
7667
+ const binding = latestElement[startOrEnd];
7668
+ const bindableElement = binding && elementsMap.get(binding.elementId);
7669
+ const point = LinearElementEditor.getPointAtIndexGlobalCoordinates(
7670
+ latestElement,
7671
+ startOrEnd === "startBinding" ? 0 : -1,
7672
+ elementsMap
7673
+ );
7674
+ const hit = bindableElement && hitElementItself({
7675
+ element: bindableElement,
7676
+ point,
7677
+ elementsMap,
7678
+ threshold: maxBindingDistance_simple(appState.zoom)
7679
+ });
7680
+ const strategyName = startOrEnd === "startBinding" ? "start" : "end";
7681
+ unbindBindingElement(latestElement, strategyName, scene);
7682
+ if (hit) {
7683
+ const pointIdx = startOrEnd === "startBinding" ? 0 : latestElement.points.length - 1;
7684
+ const localPoint = latestElement.points[pointIdx];
7685
+ const strategy = getBindingStrategyForDraggingBindingElementEndpoints_simple(
7686
+ latestElement,
7687
+ /* @__PURE__ */ new Map([[pointIdx, { point: localPoint }]]),
7688
+ point[0],
7689
+ point[1],
7690
+ elementsMap,
7691
+ scene.getNonDeletedElements(),
7692
+ appState
7693
+ );
7694
+ if (strategy[strategyName] && strategy[strategyName].element?.id === bindableElement.id && strategy[strategyName].mode) {
7695
+ bindBindingElement(
7696
+ latestElement,
7697
+ bindableElement,
7698
+ strategy[strategyName].mode,
7699
+ strategyName,
7700
+ scene,
7701
+ strategy[strategyName].focusPoint
7702
+ );
7703
+ }
7704
+ }
7705
+ };
7579
7706
  var updateBindings = (latestElement, scene, appState, options) => {
7580
7707
  if (isArrowElement(latestElement)) {
7581
- bindOrUnbindBindingElement(latestElement, /* @__PURE__ */ new Map(), scene, appState);
7708
+ const elementsMap = scene.getNonDeletedElementsMap();
7709
+ if (latestElement.startBinding) {
7710
+ updateArrowBindings(
7711
+ latestElement,
7712
+ "startBinding",
7713
+ elementsMap,
7714
+ scene,
7715
+ appState
7716
+ );
7717
+ }
7718
+ if (latestElement.endBinding) {
7719
+ updateArrowBindings(
7720
+ latestElement,
7721
+ "endBinding",
7722
+ elementsMap,
7723
+ scene,
7724
+ appState
7725
+ );
7726
+ }
7582
7727
  } else {
7583
7728
  updateBoundElements(latestElement, scene, {
7584
7729
  ...options,
@@ -7852,9 +7997,13 @@ var snapToMid = (arrowElement, bindTarget, elementsMap, p, tolerance = 0.05) =>
7852
7997
  return p;
7853
7998
  };
7854
7999
  var compareElementArea = (a2, b2) => b2.width ** 2 + b2.height ** 2 - (a2.width ** 2 + a2.height ** 2);
7855
- var updateBoundPoint = (arrow, startOrEnd, binding, bindableElement, elementsMap, customIntersector) => {
8000
+ var updateBoundPoint = (arrow, startOrEnd, binding, bindableElement, elementsMap, opts) => {
7856
8001
  if (binding == null || // We only need to update the other end if this is a 2 point line element
7857
- binding.elementId !== bindableElement.id && arrow.points.length > 2) {
8002
+ binding.elementId !== bindableElement.id && arrow.points.length > 2 || // Initial arrow created on pointer down needs to not update the points
8003
+ pointsEqual5(
8004
+ arrow.points[arrow.points.length - 1],
8005
+ pointFrom8(0, 0)
8006
+ )) {
7858
8007
  return null;
7859
8008
  }
7860
8009
  const global2 = getGlobalFixedPointForBindableElement(
@@ -7904,14 +8053,14 @@ var updateBoundPoint = (arrow, startOrEnd, binding, bindableElement, elementsMap
7904
8053
  }
7905
8054
  }
7906
8055
  const isNested = (arrowTooShort || isOverlapping) && isLargerThanOther;
7907
- let _customIntersector = customIntersector;
8056
+ let _customIntersector = opts?.customIntersector;
7908
8057
  if (!elbowed && !_customIntersector) {
7909
8058
  const [x1, y1, x2, y2] = LinearElementEditor.getElementAbsoluteCoords(
7910
8059
  arrow,
7911
8060
  elementsMap
7912
8061
  );
7913
8062
  const center = pointFrom8((x1 + x2) / 2, (y1 + y2) / 2);
7914
- const edgePoint = isRectanguloidElement(bindableElement) ? avoidRectangularCorner(arrow, bindableElement, elementsMap, global2) : global2;
8063
+ const edgePoint = global2;
7915
8064
  const adjacentPoint = pointRotateRads8(
7916
8065
  pointFrom8(
7917
8066
  arrow.x + arrow.points[pointIndex === 0 ? 1 : arrow.points.length - 2][0],
@@ -7999,10 +8148,7 @@ var calculateFixedPointForNonElbowArrowBinding = (linearElement, hoveredElement,
7999
8148
  startOrEnd === "start" ? 0 : -1,
8000
8149
  elementsMap
8001
8150
  );
8002
- const elementCenter = pointFrom8(
8003
- hoveredElement.x + hoveredElement.width / 2,
8004
- hoveredElement.y + hoveredElement.height / 2
8005
- );
8151
+ const elementCenter = elementCenterPoint(hoveredElement, elementsMap);
8006
8152
  const nonRotatedPoint = pointRotateRads8(
8007
8153
  edgePoint,
8008
8154
  elementCenter,
@@ -8339,6 +8485,356 @@ var normalizeFixedPoint = (fixedPoint) => {
8339
8485
  }
8340
8486
  return fixedPoint;
8341
8487
  };
8488
+ var getShapeType = (element) => {
8489
+ if (element.type === "ellipse" || element.type === "diamond") {
8490
+ return element.type;
8491
+ }
8492
+ return "rectangle";
8493
+ };
8494
+ var SHAPE_CONFIGS = {
8495
+ // rectangle: 15° corners, 75° edges
8496
+ rectangle: [
8497
+ { centerAngle: 0, sectorWidth: 75, side: "right" },
8498
+ { centerAngle: 45, sectorWidth: 15, side: "bottom-right" },
8499
+ { centerAngle: 90, sectorWidth: 75, side: "bottom" },
8500
+ { centerAngle: 135, sectorWidth: 15, side: "bottom-left" },
8501
+ { centerAngle: 180, sectorWidth: 75, side: "left" },
8502
+ { centerAngle: 225, sectorWidth: 15, side: "top-left" },
8503
+ { centerAngle: 270, sectorWidth: 75, side: "top" },
8504
+ { centerAngle: 315, sectorWidth: 15, side: "top-right" }
8505
+ ],
8506
+ // diamond: 15° vertices, 75° edges
8507
+ diamond: [
8508
+ { centerAngle: 0, sectorWidth: 15, side: "right" },
8509
+ { centerAngle: 45, sectorWidth: 75, side: "bottom-right" },
8510
+ { centerAngle: 90, sectorWidth: 15, side: "bottom" },
8511
+ { centerAngle: 135, sectorWidth: 75, side: "bottom-left" },
8512
+ { centerAngle: 180, sectorWidth: 15, side: "left" },
8513
+ { centerAngle: 225, sectorWidth: 75, side: "top-left" },
8514
+ { centerAngle: 270, sectorWidth: 15, side: "top" },
8515
+ { centerAngle: 315, sectorWidth: 75, side: "top-right" }
8516
+ ],
8517
+ // ellipse: 15° cardinal points, 75° diagonals
8518
+ ellipse: [
8519
+ { centerAngle: 0, sectorWidth: 15, side: "right" },
8520
+ { centerAngle: 45, sectorWidth: 75, side: "bottom-right" },
8521
+ { centerAngle: 90, sectorWidth: 15, side: "bottom" },
8522
+ { centerAngle: 135, sectorWidth: 75, side: "bottom-left" },
8523
+ { centerAngle: 180, sectorWidth: 15, side: "left" },
8524
+ { centerAngle: 225, sectorWidth: 75, side: "top-left" },
8525
+ { centerAngle: 270, sectorWidth: 15, side: "top" },
8526
+ { centerAngle: 315, sectorWidth: 75, side: "top-right" }
8527
+ ]
8528
+ };
8529
+ var getSectorBoundaries = (config) => {
8530
+ return config.map((sector, index) => {
8531
+ const halfWidth = sector.sectorWidth / 2;
8532
+ let start = sector.centerAngle - halfWidth;
8533
+ let end = sector.centerAngle + halfWidth;
8534
+ start = (start % 360 + 360) % 360;
8535
+ end = (end % 360 + 360) % 360;
8536
+ return { start, end, side: sector.side };
8537
+ });
8538
+ };
8539
+ var getShapeSideAdaptive = (fixedPoint, shapeType) => {
8540
+ const [x, y] = fixedPoint;
8541
+ const centerX = x - 0.5;
8542
+ const centerY = y - 0.5;
8543
+ let angle = Math.atan2(centerY, centerX);
8544
+ if (angle < 0) {
8545
+ angle += 2 * Math.PI;
8546
+ }
8547
+ const degrees = angle * 180 / Math.PI;
8548
+ const config = SHAPE_CONFIGS[shapeType];
8549
+ const boundaries = getSectorBoundaries(config);
8550
+ for (const boundary of boundaries) {
8551
+ if (boundary.start <= boundary.end) {
8552
+ if (degrees >= boundary.start && degrees <= boundary.end) {
8553
+ return boundary.side;
8554
+ }
8555
+ } else if (degrees >= boundary.start || degrees <= boundary.end) {
8556
+ return boundary.side;
8557
+ }
8558
+ }
8559
+ let minDiff = Infinity;
8560
+ let nearestSide = config[0].side;
8561
+ for (const sector of config) {
8562
+ let diff = Math.abs(degrees - sector.centerAngle);
8563
+ if (diff > 180) {
8564
+ diff = 360 - diff;
8565
+ }
8566
+ if (diff < minDiff) {
8567
+ minDiff = diff;
8568
+ nearestSide = sector.side;
8569
+ }
8570
+ }
8571
+ return nearestSide;
8572
+ };
8573
+ var getBindingSideMidPoint = (binding, elementsMap) => {
8574
+ const bindableElement = elementsMap.get(binding.elementId);
8575
+ if (!bindableElement || bindableElement.isDeleted || !isBindableElement(bindableElement)) {
8576
+ return null;
8577
+ }
8578
+ const center = elementCenterPoint(bindableElement, elementsMap);
8579
+ const shapeType = getShapeType(bindableElement);
8580
+ const side = getShapeSideAdaptive(
8581
+ normalizeFixedPoint(binding.fixedPoint),
8582
+ shapeType
8583
+ );
8584
+ const OFFSET = 0.01;
8585
+ if (bindableElement.type === "diamond") {
8586
+ const [sides, corners] = deconstructDiamondElement(bindableElement);
8587
+ const [bottomRight, bottomLeft, topLeft, topRight] = sides;
8588
+ let x;
8589
+ let y;
8590
+ switch (side) {
8591
+ case "left": {
8592
+ if (corners.length >= 3) {
8593
+ const leftCorner = corners[2];
8594
+ const midPoint = leftCorner[1];
8595
+ x = midPoint[0] - OFFSET;
8596
+ y = midPoint[1];
8597
+ } else {
8598
+ const midPoint = getMidPoint(bottomLeft[1], topLeft[0]);
8599
+ x = midPoint[0] - OFFSET;
8600
+ y = midPoint[1];
8601
+ }
8602
+ break;
8603
+ }
8604
+ case "right": {
8605
+ if (corners.length >= 1) {
8606
+ const rightCorner = corners[0];
8607
+ const midPoint = rightCorner[1];
8608
+ x = midPoint[0] + OFFSET;
8609
+ y = midPoint[1];
8610
+ } else {
8611
+ const midPoint = getMidPoint(topRight[1], bottomRight[0]);
8612
+ x = midPoint[0] + OFFSET;
8613
+ y = midPoint[1];
8614
+ }
8615
+ break;
8616
+ }
8617
+ case "top": {
8618
+ if (corners.length >= 4) {
8619
+ const topCorner = corners[3];
8620
+ const midPoint = topCorner[1];
8621
+ x = midPoint[0];
8622
+ y = midPoint[1] - OFFSET;
8623
+ } else {
8624
+ const midPoint = getMidPoint(topLeft[1], topRight[0]);
8625
+ x = midPoint[0];
8626
+ y = midPoint[1] - OFFSET;
8627
+ }
8628
+ break;
8629
+ }
8630
+ case "bottom": {
8631
+ if (corners.length >= 2) {
8632
+ const bottomCorner = corners[1];
8633
+ const midPoint = bottomCorner[1];
8634
+ x = midPoint[0];
8635
+ y = midPoint[1] + OFFSET;
8636
+ } else {
8637
+ const midPoint = getMidPoint(bottomRight[1], bottomLeft[0]);
8638
+ x = midPoint[0];
8639
+ y = midPoint[1] + OFFSET;
8640
+ }
8641
+ break;
8642
+ }
8643
+ case "top-right": {
8644
+ const midPoint = getMidPoint(topRight[0], topRight[1]);
8645
+ x = midPoint[0] + OFFSET * 0.707;
8646
+ y = midPoint[1] - OFFSET * 0.707;
8647
+ break;
8648
+ }
8649
+ case "bottom-right": {
8650
+ const midPoint = getMidPoint(bottomRight[0], bottomRight[1]);
8651
+ x = midPoint[0] + OFFSET * 0.707;
8652
+ y = midPoint[1] + OFFSET * 0.707;
8653
+ break;
8654
+ }
8655
+ case "bottom-left": {
8656
+ const midPoint = getMidPoint(bottomLeft[0], bottomLeft[1]);
8657
+ x = midPoint[0] - OFFSET * 0.707;
8658
+ y = midPoint[1] + OFFSET * 0.707;
8659
+ break;
8660
+ }
8661
+ case "top-left": {
8662
+ const midPoint = getMidPoint(topLeft[0], topLeft[1]);
8663
+ x = midPoint[0] - OFFSET * 0.707;
8664
+ y = midPoint[1] - OFFSET * 0.707;
8665
+ break;
8666
+ }
8667
+ default: {
8668
+ return null;
8669
+ }
8670
+ }
8671
+ return pointRotateRads8(pointFrom8(x, y), center, bindableElement.angle);
8672
+ }
8673
+ if (bindableElement.type === "ellipse") {
8674
+ const ellipseCenterX = bindableElement.x + bindableElement.width / 2;
8675
+ const ellipseCenterY = bindableElement.y + bindableElement.height / 2;
8676
+ const radiusX = bindableElement.width / 2;
8677
+ const radiusY = bindableElement.height / 2;
8678
+ let x;
8679
+ let y;
8680
+ switch (side) {
8681
+ case "top": {
8682
+ x = ellipseCenterX;
8683
+ y = ellipseCenterY - radiusY - OFFSET;
8684
+ break;
8685
+ }
8686
+ case "right": {
8687
+ x = ellipseCenterX + radiusX + OFFSET;
8688
+ y = ellipseCenterY;
8689
+ break;
8690
+ }
8691
+ case "bottom": {
8692
+ x = ellipseCenterX;
8693
+ y = ellipseCenterY + radiusY + OFFSET;
8694
+ break;
8695
+ }
8696
+ case "left": {
8697
+ x = ellipseCenterX - radiusX - OFFSET;
8698
+ y = ellipseCenterY;
8699
+ break;
8700
+ }
8701
+ case "top-right": {
8702
+ const angle = -Math.PI / 4;
8703
+ const ellipseX = radiusX * Math.cos(angle);
8704
+ const ellipseY = radiusY * Math.sin(angle);
8705
+ x = ellipseCenterX + ellipseX + OFFSET * 0.707;
8706
+ y = ellipseCenterY + ellipseY - OFFSET * 0.707;
8707
+ break;
8708
+ }
8709
+ case "bottom-right": {
8710
+ const angle = Math.PI / 4;
8711
+ const ellipseX = radiusX * Math.cos(angle);
8712
+ const ellipseY = radiusY * Math.sin(angle);
8713
+ x = ellipseCenterX + ellipseX + OFFSET * 0.707;
8714
+ y = ellipseCenterY + ellipseY + OFFSET * 0.707;
8715
+ break;
8716
+ }
8717
+ case "bottom-left": {
8718
+ const angle = 3 * Math.PI / 4;
8719
+ const ellipseX = radiusX * Math.cos(angle);
8720
+ const ellipseY = radiusY * Math.sin(angle);
8721
+ x = ellipseCenterX + ellipseX - OFFSET * 0.707;
8722
+ y = ellipseCenterY + ellipseY + OFFSET * 0.707;
8723
+ break;
8724
+ }
8725
+ case "top-left": {
8726
+ const angle = -3 * Math.PI / 4;
8727
+ const ellipseX = radiusX * Math.cos(angle);
8728
+ const ellipseY = radiusY * Math.sin(angle);
8729
+ x = ellipseCenterX + ellipseX - OFFSET * 0.707;
8730
+ y = ellipseCenterY + ellipseY - OFFSET * 0.707;
8731
+ break;
8732
+ }
8733
+ default: {
8734
+ return null;
8735
+ }
8736
+ }
8737
+ return pointRotateRads8(pointFrom8(x, y), center, bindableElement.angle);
8738
+ }
8739
+ if (isRectangularElement(bindableElement)) {
8740
+ const [sides, corners] = deconstructRectanguloidElement(
8741
+ bindableElement
8742
+ );
8743
+ const [top, right, bottom, left] = sides;
8744
+ let x;
8745
+ let y;
8746
+ switch (side) {
8747
+ case "top": {
8748
+ const midPoint = getMidPoint(top[0], top[1]);
8749
+ x = midPoint[0];
8750
+ y = midPoint[1] - OFFSET;
8751
+ break;
8752
+ }
8753
+ case "right": {
8754
+ const midPoint = getMidPoint(right[0], right[1]);
8755
+ x = midPoint[0] + OFFSET;
8756
+ y = midPoint[1];
8757
+ break;
8758
+ }
8759
+ case "bottom": {
8760
+ const midPoint = getMidPoint(bottom[0], bottom[1]);
8761
+ x = midPoint[0];
8762
+ y = midPoint[1] + OFFSET;
8763
+ break;
8764
+ }
8765
+ case "left": {
8766
+ const midPoint = getMidPoint(left[0], left[1]);
8767
+ x = midPoint[0] - OFFSET;
8768
+ y = midPoint[1];
8769
+ break;
8770
+ }
8771
+ case "top-left": {
8772
+ if (corners.length >= 1) {
8773
+ const corner = corners[0];
8774
+ const p1 = corner[0];
8775
+ const p2 = corner[3];
8776
+ const midPoint = getMidPoint(p1, p2);
8777
+ x = midPoint[0] - OFFSET * 0.707;
8778
+ y = midPoint[1] - OFFSET * 0.707;
8779
+ } else {
8780
+ x = bindableElement.x - OFFSET;
8781
+ y = bindableElement.y - OFFSET;
8782
+ }
8783
+ break;
8784
+ }
8785
+ case "top-right": {
8786
+ if (corners.length >= 2) {
8787
+ const corner = corners[1];
8788
+ const p1 = corner[0];
8789
+ const p2 = corner[3];
8790
+ const midPoint = getMidPoint(p1, p2);
8791
+ x = midPoint[0] + OFFSET * 0.707;
8792
+ y = midPoint[1] - OFFSET * 0.707;
8793
+ } else {
8794
+ x = bindableElement.x + bindableElement.width + OFFSET;
8795
+ y = bindableElement.y - OFFSET;
8796
+ }
8797
+ break;
8798
+ }
8799
+ case "bottom-right": {
8800
+ if (corners.length >= 3) {
8801
+ const corner = corners[2];
8802
+ const p1 = corner[0];
8803
+ const p2 = corner[3];
8804
+ const midPoint = getMidPoint(p1, p2);
8805
+ x = midPoint[0] + OFFSET * 0.707;
8806
+ y = midPoint[1] + OFFSET * 0.707;
8807
+ } else {
8808
+ x = bindableElement.x + bindableElement.width + OFFSET;
8809
+ y = bindableElement.y + bindableElement.height + OFFSET;
8810
+ }
8811
+ break;
8812
+ }
8813
+ case "bottom-left": {
8814
+ if (corners.length >= 4) {
8815
+ const corner = corners[3];
8816
+ const p1 = corner[0];
8817
+ const p2 = corner[3];
8818
+ const midPoint = getMidPoint(p1, p2);
8819
+ x = midPoint[0] - OFFSET * 0.707;
8820
+ y = midPoint[1] + OFFSET * 0.707;
8821
+ } else {
8822
+ x = bindableElement.x - OFFSET;
8823
+ y = bindableElement.y + bindableElement.height + OFFSET;
8824
+ }
8825
+ break;
8826
+ }
8827
+ default: {
8828
+ return null;
8829
+ }
8830
+ }
8831
+ return pointRotateRads8(pointFrom8(x, y), center, bindableElement.angle);
8832
+ }
8833
+ return null;
8834
+ };
8835
+ var getMidPoint = (p1, p2) => {
8836
+ return pointFrom8((p1[0] + p2[0]) / 2, (p1[1] + p2[1]) / 2);
8837
+ };
8342
8838
 
8343
8839
  // src/linearElementEditor.ts
8344
8840
  var getNormalizedPoints = ({
@@ -8366,6 +8862,8 @@ var LinearElementEditor = class _LinearElementEditor {
8366
8862
  pointerOffset;
8367
8863
  hoverPointIndex;
8368
8864
  segmentMidPointHoveredCoords;
8865
+ hoveredFocusPointBinding;
8866
+ draggedFocusPointBinding;
8369
8867
  elbowed;
8370
8868
  customLineAngle;
8371
8869
  isEditing;
@@ -8375,7 +8873,7 @@ var LinearElementEditor = class _LinearElementEditor {
8375
8873
  pointerDownState;
8376
8874
  constructor(element, elementsMap, isEditing = false) {
8377
8875
  this.elementId = element.id;
8378
- if (!pointsEqual5(element.points[0], pointFrom9(0, 0))) {
8876
+ if (!pointsEqual6(element.points[0], pointFrom9(0, 0))) {
8379
8877
  console.error("Linear element is not normalized", Error().stack);
8380
8878
  mutateElement(
8381
8879
  element,
@@ -8402,6 +8900,8 @@ var LinearElementEditor = class _LinearElementEditor {
8402
8900
  };
8403
8901
  this.hoverPointIndex = -1;
8404
8902
  this.segmentMidPointHoveredCoords = null;
8903
+ this.hoveredFocusPointBinding = null;
8904
+ this.draggedFocusPointBinding = null;
8405
8905
  this.elbowed = isElbowArrow(element) && element.elbowed;
8406
8906
  this.customLineAngle = null;
8407
8907
  this.isEditing = isEditing;
@@ -8465,14 +8965,9 @@ var LinearElementEditor = class _LinearElementEditor {
8465
8965
  const point = element.points[idx];
8466
8966
  const pivotPoint = element.points[idx - 1];
8467
8967
  const customLineAngle = linearElementEditor.customLineAngle ?? determineCustomLinearAngle(pivotPoint, element.points[idx]);
8468
- const hoveredElement = getHoveredElementForBinding2(
8469
- pointFrom9(scenePointerX, scenePointerY),
8470
- elements,
8471
- elementsMap
8472
- );
8473
8968
  let deltaX = 0;
8474
8969
  let deltaY = 0;
8475
- if (shouldRotateWithDiscreteAngle(event) && !hoveredElement && !element.startBinding && !element.endBinding) {
8970
+ if (shouldRotateWithDiscreteAngle(event)) {
8476
8971
  const [width, height] = _LinearElementEditor._getShiftLockedDelta(
8477
8972
  element,
8478
8973
  elementsMap,
@@ -8503,11 +8998,13 @@ var LinearElementEditor = class _LinearElementEditor {
8503
8998
  [idx],
8504
8999
  deltaX,
8505
9000
  deltaY,
9001
+ scenePointerX,
9002
+ scenePointerY,
8506
9003
  elementsMap,
8507
9004
  element,
8508
9005
  elements,
8509
9006
  app,
8510
- event.shiftKey,
9007
+ shouldRotateWithDiscreteAngle(event),
8511
9008
  event.altKey
8512
9009
  );
8513
9010
  _LinearElementEditor.movePoints(element, app.scene, positions, {
@@ -8597,14 +9094,9 @@ var LinearElementEditor = class _LinearElementEditor {
8597
9094
  const endIsSelected = selectedPointsIndices.includes(
8598
9095
  element.points.length - 1
8599
9096
  );
8600
- const hoveredElement = getHoveredElementForBinding2(
8601
- pointFrom9(scenePointerX, scenePointerY),
8602
- elements,
8603
- elementsMap
8604
- );
8605
9097
  let deltaX = 0;
8606
9098
  let deltaY = 0;
8607
- if (shouldRotateWithDiscreteAngle(event) && singlePointDragged && !hoveredElement && !element.startBinding && !element.endBinding) {
9099
+ if (shouldRotateWithDiscreteAngle(event) && singlePointDragged) {
8608
9100
  const [width, height] = _LinearElementEditor._getShiftLockedDelta(
8609
9101
  element,
8610
9102
  elementsMap,
@@ -8635,11 +9127,13 @@ var LinearElementEditor = class _LinearElementEditor {
8635
9127
  selectedPointsIndices,
8636
9128
  deltaX,
8637
9129
  deltaY,
9130
+ scenePointerX,
9131
+ scenePointerY,
8638
9132
  elementsMap,
8639
9133
  element,
8640
9134
  elements,
8641
9135
  app,
8642
- event.shiftKey,
9136
+ shouldRotateWithDiscreteAngle(event) && singlePointDragged,
8643
9137
  event.altKey
8644
9138
  );
8645
9139
  _LinearElementEditor.movePoints(element, app.scene, positions, {
@@ -8768,7 +9262,6 @@ var LinearElementEditor = class _LinearElementEditor {
8768
9262
  (pointIndex) => pointIndex !== pointerDownState.lastClickedPoint
8769
9263
  ) : selectedPointsIndices : selectedPointsIndices?.includes(pointerDownState.lastClickedPoint) ? [pointerDownState.lastClickedPoint] : selectedPointsIndices,
8770
9264
  isDragging: false,
8771
- pointerOffset: { x: 0, y: 0 },
8772
9265
  customLineAngle: null,
8773
9266
  initialState: {
8774
9267
  ...editingLinearElement.initialState,
@@ -9060,7 +9553,7 @@ var LinearElementEditor = class _LinearElementEditor {
9060
9553
  if (!point1 || !point2) {
9061
9554
  return false;
9062
9555
  }
9063
- return pointsEqual5(point1, point2);
9556
+ return pointsEqual6(point1, point2);
9064
9557
  }
9065
9558
  static handlePointerMoveInEditMode(event, scenePointerX, scenePointerY, app) {
9066
9559
  const appState = app.state;
@@ -9713,7 +10206,7 @@ var normalizeSelectedPoints = (points) => {
9713
10206
  nextPoints = nextPoints.sort((a2, b2) => a2 - b2);
9714
10207
  return nextPoints.length ? nextPoints : null;
9715
10208
  };
9716
- var pointDraggingUpdates = (selectedPointsIndices, deltaX, deltaY, elementsMap, element, elements, app, shiftKey, altKey) => {
10209
+ var pointDraggingUpdates = (selectedPointsIndices, deltaX, deltaY, scenePointerX, scenePointerY, elementsMap, element, elements, app, angleLocked, altKey) => {
9717
10210
  const naiveDraggingPoints = new Map(
9718
10211
  selectedPointsIndices.map((pointIndex) => {
9719
10212
  return [
@@ -9740,12 +10233,14 @@ var pointDraggingUpdates = (selectedPointsIndices, deltaX, deltaY, elementsMap,
9740
10233
  const { start, end } = getBindingStrategyForDraggingBindingElementEndpoints(
9741
10234
  element,
9742
10235
  naiveDraggingPoints,
10236
+ scenePointerX,
10237
+ scenePointerY,
9743
10238
  elementsMap,
9744
10239
  elements,
9745
10240
  app.state,
9746
10241
  {
9747
10242
  newArrow: !!app.state.newElement,
9748
- shiftKey,
10243
+ angleLocked,
9749
10244
  altKey
9750
10245
  }
9751
10246
  );
@@ -9757,6 +10252,51 @@ var pointDraggingUpdates = (selectedPointsIndices, deltaX, deltaY, elementsMap,
9757
10252
  }
9758
10253
  };
9759
10254
  }
10255
+ if (!startIsDragged && !endIsDragged) {
10256
+ const nextArrow2 = {
10257
+ ...element,
10258
+ points: element.points.map((p, idx) => {
10259
+ return naiveDraggingPoints.get(idx)?.point ?? p;
10260
+ })
10261
+ };
10262
+ const positions = new Map(naiveDraggingPoints);
10263
+ if (element.startBinding) {
10264
+ const startBindable2 = elementsMap.get(element.startBinding.elementId);
10265
+ if (startBindable2) {
10266
+ const startPoint = updateBoundPoint(
10267
+ nextArrow2,
10268
+ "startBinding",
10269
+ element.startBinding,
10270
+ startBindable2,
10271
+ elementsMap
10272
+ ) ?? null;
10273
+ if (startPoint) {
10274
+ positions.set(0, { point: startPoint, isDragging: true });
10275
+ }
10276
+ }
10277
+ }
10278
+ if (element.endBinding) {
10279
+ const endBindable2 = elementsMap.get(element.endBinding.elementId);
10280
+ if (endBindable2) {
10281
+ const endPoint = updateBoundPoint(
10282
+ nextArrow2,
10283
+ "endBinding",
10284
+ element.endBinding,
10285
+ endBindable2,
10286
+ elementsMap
10287
+ ) ?? null;
10288
+ if (endPoint) {
10289
+ positions.set(element.points.length - 1, {
10290
+ point: endPoint,
10291
+ isDragging: true
10292
+ });
10293
+ }
10294
+ }
10295
+ }
10296
+ return {
10297
+ positions
10298
+ };
10299
+ }
9760
10300
  if (startIsDragged === endIsDragged) {
9761
10301
  return {
9762
10302
  positions: naiveDraggingPoints
@@ -9823,7 +10363,8 @@ var pointDraggingUpdates = (selectedPointsIndices, deltaX, deltaY, elementsMap,
9823
10363
  startBinding: updates.startBinding === void 0 ? element.startBinding : updates.startBinding === null ? null : updates.startBinding,
9824
10364
  endBinding: updates.endBinding === void 0 ? element.endBinding : updates.endBinding === null ? null : updates.endBinding
9825
10365
  };
9826
- const customIntersector = start.focusPoint && end.focusPoint ? lineSegment5(start.focusPoint, end.focusPoint) : void 0;
10366
+ const startCustomIntersector = start.focusPoint && end.focusPoint ? lineSegment5(start.focusPoint, end.focusPoint) : void 0;
10367
+ const endCustomIntersector = start.focusPoint && end.focusPoint ? lineSegment5(end.focusPoint, start.focusPoint) : void 0;
9827
10368
  const startIsDraggingOverEndElement = element.endBinding && nextArrow.startBinding && startIsDragged && nextArrow.startBinding.elementId === element.endBinding.elementId;
9828
10369
  const endIsDraggingOverStartElement = element.startBinding && nextArrow.endBinding && endIsDragged && element.startBinding.elementId === nextArrow.endBinding.elementId;
9829
10370
  const endBindable = nextArrow.endBinding ? end.element ?? elementsMap.get(
@@ -9835,24 +10376,23 @@ var pointDraggingUpdates = (selectedPointsIndices, deltaX, deltaY, elementsMap,
9835
10376
  nextArrow.endBinding,
9836
10377
  endBindable,
9837
10378
  elementsMap,
9838
- customIntersector
10379
+ {
10380
+ customIntersector: endCustomIntersector
10381
+ }
9839
10382
  ) || nextArrow.points[nextArrow.points.length - 1] : nextArrow.points[nextArrow.points.length - 1];
9840
10383
  nextArrow.points[nextArrow.points.length - 1] = endLocalPoint;
9841
10384
  const startBindable = nextArrow.startBinding ? start.element ?? elementsMap.get(
9842
10385
  nextArrow.startBinding.elementId
9843
10386
  ) : null;
9844
- const startLocalPoint = endIsDraggingOverStartElement && getFeatureFlag2("COMPLEX_BINDINGS") ? nextArrow.points[0] : startIsDraggingOverEndElement && app.state.bindMode !== "inside" && getFeatureFlag2("COMPLEX_BINDINGS") ? nextArrow.points[nextArrow.points.length - 1] : startBindable ? updateBoundPoint(
10387
+ const startLocalPoint = endIsDraggingOverStartElement && getFeatureFlag2("COMPLEX_BINDINGS") ? nextArrow.points[0] : startIsDraggingOverEndElement && app.state.bindMode !== "inside" && getFeatureFlag2("COMPLEX_BINDINGS") ? endLocalPoint : startBindable ? updateBoundPoint(
9845
10388
  element,
9846
10389
  "startBinding",
9847
10390
  nextArrow.startBinding,
9848
10391
  startBindable,
9849
10392
  elementsMap,
9850
- customIntersector
10393
+ { customIntersector: startCustomIntersector }
9851
10394
  ) || nextArrow.points[0] : nextArrow.points[0];
9852
- const endChanged = pointDistance5(
9853
- endLocalPoint,
9854
- nextArrow.points[nextArrow.points.length - 1]
9855
- ) !== 0;
10395
+ const endChanged = !startIsDraggingOverEndElement && !(endIsDraggingOverStartElement && app.state.bindMode !== "inside" && getFeatureFlag2("COMPLEX_BINDINGS")) && !!endBindable;
9856
10396
  const startChanged = pointDistance5(startLocalPoint, nextArrow.points[0]) !== 0;
9857
10397
  const indicesSet = new Set(selectedPointsIndices);
9858
10398
  if (startBindable && startChanged) {
@@ -9863,10 +10403,7 @@ var pointDraggingUpdates = (selectedPointsIndices, deltaX, deltaY, elementsMap,
9863
10403
  }
9864
10404
  const indices = Array.from(indicesSet);
9865
10405
  return {
9866
- updates: updates.startBinding || updates.suggestedBinding ? {
9867
- startBinding: updates.startBinding,
9868
- suggestedBinding: updates.suggestedBinding
9869
- } : void 0,
10406
+ updates,
9870
10407
  positions: new Map(
9871
10408
  indices.map((idx) => {
9872
10409
  return [
@@ -11019,11 +11556,7 @@ var frameAndChildrenSelectedTogether = (selectedElements) => {
11019
11556
  };
11020
11557
 
11021
11558
  // src/renderElement.ts
11022
- var IMAGE_INVERT_FILTER = "invert(100%) hue-rotate(180deg) saturate(1.25)";
11023
11559
  var isPendingImageElement = (element, renderConfig) => isInitializedImageElement(element) && !renderConfig.imageCache.has(element.fileId);
11024
- var shouldResetImageFilter = (element, renderConfig, appState) => {
11025
- return appState.theme === THEME.DARK && isInitializedImageElement(element) && !isPendingImageElement(element, renderConfig) && renderConfig.imageCache.get(element.fileId)?.mimeType !== MIME_TYPES.svg;
11026
- };
11027
11560
  var getCanvasPadding = (element) => {
11028
11561
  switch (element.type) {
11029
11562
  case "freedraw":
@@ -11095,9 +11628,6 @@ var generateElementCanvas = (element, elementsMap, zoom, renderConfig, appState)
11095
11628
  window.devicePixelRatio * scale
11096
11629
  );
11097
11630
  const rc = rough_default.canvas(canvas);
11098
- if (shouldResetImageFilter(element, renderConfig, appState)) {
11099
- context.filter = IMAGE_INVERT_FILTER;
11100
- }
11101
11631
  drawElementOnCanvas(element, rc, context, renderConfig);
11102
11632
  context.restore();
11103
11633
  const boundTextElement = getBoundTextElement(element, elementsMap);
@@ -11161,8 +11691,8 @@ var IMAGE_ERROR_PLACEHOLDER_IMG = typeof document !== "undefined" ? document.cre
11161
11691
  IMAGE_ERROR_PLACEHOLDER_IMG.src = `data:${MIME_TYPES.svg},${encodeURIComponent(
11162
11692
  `<svg viewBox="0 0 668 668" xmlns="http://www.w3.org/2000/svg" xml:space="preserve" style="fill-rule:evenodd;clip-rule:evenodd;stroke-linejoin:round;stroke-miterlimit:2"><path d="M464 448H48c-26.51 0-48-21.49-48-48V112c0-26.51 21.49-48 48-48h416c26.51 0 48 21.49 48 48v288c0 26.51-21.49 48-48 48ZM112 120c-30.928 0-56 25.072-56 56s25.072 56 56 56 56-25.072 56-56-25.072-56-56-56ZM64 384h384V272l-87.515-87.515c-4.686-4.686-12.284-4.686-16.971 0L208 320l-55.515-55.515c-4.686-4.686-12.284-4.686-16.971 0L64 336v48Z" style="fill:#888;fill-rule:nonzero" transform="matrix(.81709 0 0 .81709 124.825 145.825)"/><path d="M256 8C119.034 8 8 119.033 8 256c0 136.967 111.034 248 248 248s248-111.034 248-248S392.967 8 256 8Zm130.108 117.892c65.448 65.448 70 165.481 20.677 235.637L150.47 105.216c70.204-49.356 170.226-44.735 235.638 20.676ZM125.892 386.108c-65.448-65.448-70-165.481-20.677-235.637L361.53 406.784c-70.203 49.356-170.226 44.736-235.638-20.676Z" style="fill:#888;fill-rule:nonzero" transform="matrix(.30366 0 0 .30366 506.822 60.065)"/></svg>`
11163
11693
  )}`;
11164
- var drawImagePlaceholder = (element, context) => {
11165
- context.fillStyle = "#E7E7E7";
11694
+ var drawImagePlaceholder = (element, context, theme) => {
11695
+ context.fillStyle = theme === THEME.DARK ? "#2E2E2E" : "#E7E7E7";
11166
11696
  context.fillRect(0, 0, element.width, element.height);
11167
11697
  const imageMinWidthOrHeight = Math.min(element.width, element.height);
11168
11698
  const size = Math.min(
@@ -11186,33 +11716,38 @@ var drawElementOnCanvas = (element, rc, context, renderConfig) => {
11186
11716
  case "ellipse": {
11187
11717
  context.lineJoin = "round";
11188
11718
  context.lineCap = "round";
11189
- rc.draw(ShapeCache.get(element));
11719
+ rc.draw(ShapeCache.generateElementShape(element, renderConfig));
11190
11720
  break;
11191
11721
  }
11192
11722
  case "arrow":
11193
11723
  case "line": {
11194
11724
  context.lineJoin = "round";
11195
11725
  context.lineCap = "round";
11196
- ShapeCache.get(element).forEach((shape) => {
11197
- rc.draw(shape);
11198
- });
11726
+ ShapeCache.generateElementShape(element, renderConfig).forEach(
11727
+ (shape) => {
11728
+ rc.draw(shape);
11729
+ }
11730
+ );
11199
11731
  break;
11200
11732
  }
11201
11733
  case "freedraw": {
11202
11734
  context.save();
11203
- context.fillStyle = element.strokeColor;
11204
- const path = getFreeDrawPath2D(element);
11205
- const fillShape = ShapeCache.get(element);
11206
- if (fillShape) {
11207
- rc.draw(fillShape);
11208
- }
11209
- context.fillStyle = element.strokeColor;
11210
- context.fill(path);
11735
+ const shapes = ShapeCache.generateElementShape(element, renderConfig);
11736
+ for (const shape of shapes) {
11737
+ if (typeof shape === "string") {
11738
+ context.fillStyle = renderConfig.theme === THEME.DARK ? applyDarkModeFilter(element.strokeColor) : element.strokeColor;
11739
+ context.fill(new Path2D(shape));
11740
+ } else {
11741
+ rc.draw(shape);
11742
+ }
11743
+ }
11211
11744
  context.restore();
11212
11745
  break;
11213
11746
  }
11214
11747
  case "image": {
11215
- const img = isInitializedImageElement(element) ? renderConfig.imageCache.get(element.fileId)?.image : void 0;
11748
+ context.save();
11749
+ const cacheEntry = element.fileId !== null ? renderConfig.imageCache.get(element.fileId) : null;
11750
+ const img = isInitializedImageElement(element) ? cacheEntry?.image : void 0;
11216
11751
  if (img != null && !(img instanceof Promise)) {
11217
11752
  if (element.roundness && context.roundRect) {
11218
11753
  context.beginPath();
@@ -11231,33 +11766,84 @@ var drawElementOnCanvas = (element, rc, context, renderConfig) => {
11231
11766
  width: img.naturalWidth,
11232
11767
  height: img.naturalHeight
11233
11768
  };
11234
- context.drawImage(
11235
- img,
11236
- x,
11237
- y,
11238
- width,
11239
- height,
11240
- 0,
11241
- 0,
11242
- element.width,
11243
- element.height
11244
- );
11245
- } else {
11246
- drawImagePlaceholder(element, context);
11247
- }
11248
- break;
11249
- }
11250
- default: {
11251
- if (isTextElement(element)) {
11252
- const rtl = isRTL(element.text);
11253
- const shouldTemporarilyAttach = rtl && !context.canvas.isConnected;
11254
- if (shouldTemporarilyAttach) {
11255
- document.body.appendChild(context.canvas);
11256
- }
11257
- context.canvas.setAttribute("dir", rtl ? "rtl" : "ltr");
11258
- context.save();
11769
+ const shouldInvertImage = renderConfig.theme === THEME.DARK && cacheEntry?.mimeType === MIME_TYPES.svg;
11770
+ if (shouldInvertImage && isSafari) {
11771
+ const devicePixelRatio = window.devicePixelRatio || 1;
11772
+ const tempCanvas = document.createElement("canvas");
11773
+ tempCanvas.width = element.width * devicePixelRatio;
11774
+ tempCanvas.height = element.height * devicePixelRatio;
11775
+ const tempContext = tempCanvas.getContext("2d");
11776
+ if (tempContext) {
11777
+ tempContext.scale(devicePixelRatio, devicePixelRatio);
11778
+ tempContext.drawImage(
11779
+ img,
11780
+ x,
11781
+ y,
11782
+ width,
11783
+ height,
11784
+ 0,
11785
+ 0,
11786
+ element.width,
11787
+ element.height
11788
+ );
11789
+ const imageData = tempContext.getImageData(
11790
+ 0,
11791
+ 0,
11792
+ tempCanvas.width,
11793
+ tempCanvas.height
11794
+ );
11795
+ const data = imageData.data;
11796
+ for (let i = 0; i < data.length; i += 4) {
11797
+ data[i] = 255 - data[i];
11798
+ data[i + 1] = 255 - data[i + 1];
11799
+ data[i + 2] = 255 - data[i + 2];
11800
+ }
11801
+ tempContext.putImageData(imageData, 0, 0);
11802
+ context.drawImage(
11803
+ tempCanvas,
11804
+ 0,
11805
+ 0,
11806
+ tempCanvas.width,
11807
+ tempCanvas.height,
11808
+ 0,
11809
+ 0,
11810
+ element.width,
11811
+ element.height
11812
+ );
11813
+ }
11814
+ } else {
11815
+ if (shouldInvertImage) {
11816
+ context.filter = DARK_THEME_FILTER;
11817
+ }
11818
+ context.drawImage(
11819
+ img,
11820
+ x,
11821
+ y,
11822
+ width,
11823
+ height,
11824
+ 0,
11825
+ 0,
11826
+ element.width,
11827
+ element.height
11828
+ );
11829
+ }
11830
+ } else {
11831
+ drawImagePlaceholder(element, context, renderConfig.theme);
11832
+ }
11833
+ context.restore();
11834
+ break;
11835
+ }
11836
+ default: {
11837
+ if (isTextElement(element)) {
11838
+ const rtl = isRTL(element.text);
11839
+ const shouldTemporarilyAttach = rtl && !context.canvas.isConnected;
11840
+ if (shouldTemporarilyAttach) {
11841
+ document.body.appendChild(context.canvas);
11842
+ }
11843
+ context.canvas.setAttribute("dir", rtl ? "rtl" : "ltr");
11844
+ context.save();
11259
11845
  context.font = getFontString3(element);
11260
- context.fillStyle = element.strokeColor;
11846
+ context.fillStyle = renderConfig.theme === THEME.DARK ? applyDarkModeFilter(element.strokeColor) : element.strokeColor;
11261
11847
  context.textAlign = element.textAlign;
11262
11848
  const lines = element.text.replace(/\r\n?/g, "\n").split("\n");
11263
11849
  const horizontalOffset = element.textAlign === "center" ? element.width / 2 : element.textAlign === "right" ? element.width : 0;
@@ -11405,9 +11991,9 @@ var renderElement = (element, elementsMap, allElementsMap, rc, context, renderCo
11405
11991
  );
11406
11992
  context.fillStyle = "rgba(0, 0, 200, 0.04)";
11407
11993
  context.lineWidth = FRAME_STYLE.strokeWidth / appState.zoom.value;
11408
- context.strokeStyle = FRAME_STYLE.strokeColor;
11994
+ context.strokeStyle = appState.theme === THEME.DARK ? applyDarkModeFilter(FRAME_STYLE.strokeColor) : FRAME_STYLE.strokeColor;
11409
11995
  if (isMagicFrameElement(element)) {
11410
- context.strokeStyle = appState.theme === THEME.LIGHT ? "#7affd7" : "#1d8264";
11996
+ context.strokeStyle = appState.theme === THEME.LIGHT ? "#7affd7" : applyDarkModeFilter("#1d8264");
11411
11997
  }
11412
11998
  if (FRAME_STYLE.radius && context.roundRect) {
11413
11999
  context.beginPath();
@@ -11428,7 +12014,6 @@ var renderElement = (element, elementsMap, allElementsMap, rc, context, renderCo
11428
12014
  break;
11429
12015
  }
11430
12016
  case "freedraw": {
11431
- ShapeCache.generateElementShape(element, null);
11432
12017
  if (renderConfig.isExporting) {
11433
12018
  const [x1, y1, x2, y2] = getElementAbsoluteCoords2(element, elementsMap);
11434
12019
  const cx = (x1 + x2) / 2 + appState.scrollX;
@@ -11470,7 +12055,6 @@ var renderElement = (element, elementsMap, allElementsMap, rc, context, renderCo
11470
12055
  case "text":
11471
12056
  case "iframe":
11472
12057
  case "embeddable": {
11473
- ShapeCache.generateElementShape(element, renderConfig);
11474
12058
  if (renderConfig.isExporting) {
11475
12059
  const [x1, y1, x2, y2] = getElementAbsoluteCoords2(element, elementsMap);
11476
12060
  const cx = (x1 + x2) / 2 + appState.scrollX;
@@ -11491,9 +12075,6 @@ var renderElement = (element, elementsMap, allElementsMap, rc, context, renderCo
11491
12075
  }
11492
12076
  context.save();
11493
12077
  context.translate(cx, cy);
11494
- if (shouldResetImageFilter(element, renderConfig, appState)) {
11495
- context.filter = "none";
11496
- }
11497
12078
  const boundTextElement = getBoundTextElement(element, elementsMap);
11498
12079
  if (isArrowElement(element) && boundTextElement) {
11499
12080
  const tempCanvas = document.createElement("canvas");
@@ -11605,19 +12186,6 @@ var renderElement = (element, elementsMap, allElementsMap, rc, context, renderCo
11605
12186
  }
11606
12187
  context.globalAlpha = 1;
11607
12188
  };
11608
- var pathsCache = /* @__PURE__ */ new WeakMap([]);
11609
- function generateFreeDrawShape(element) {
11610
- const svgPathData = getFreeDrawSvgPath(element);
11611
- const path = new Path2D(svgPathData);
11612
- pathsCache.set(element, path);
11613
- return path;
11614
- }
11615
- function getFreeDrawPath2D(element) {
11616
- return pathsCache.get(element);
11617
- }
11618
- function getFreeDrawSvgPath(element) {
11619
- return getSvgPathFromStroke(getFreedrawOutlinePoints(element));
11620
- }
11621
12189
  function getFreedrawOutlineAsSegments(element, points, elementsMap) {
11622
12190
  const bounds = getElementBounds(
11623
12191
  {
@@ -11667,46 +12235,11 @@ function getFreedrawOutlineAsSegments(element, points, elementsMap) {
11667
12235
  ]
11668
12236
  );
11669
12237
  }
11670
- function getFreedrawOutlinePoints(element) {
11671
- const inputPoints = element.simulatePressure ? element.points : element.points.length ? element.points.map(([x, y], i) => [x, y, element.pressures[i]]) : [[0, 0, 0.5]];
11672
- const options = {
11673
- simulatePressure: element.simulatePressure,
11674
- size: element.strokeWidth * 4.25,
11675
- thinning: 0.6,
11676
- smoothing: 0.5,
11677
- streamline: 0.5,
11678
- easing: (t) => Math.sin(t * Math.PI / 2),
11679
- // https://easings.net/#easeOutSine
11680
- last: true
11681
- };
11682
- return ae(inputPoints, options);
11683
- }
11684
- function med(A2, B2) {
11685
- return [(A2[0] + B2[0]) / 2, (A2[1] + B2[1]) / 2];
11686
- }
11687
- var TO_FIXED_PRECISION = /(\s?[A-Z]?,?-?[0-9]*\.[0-9]{0,2})(([0-9]|e|-)*)/g;
11688
- function getSvgPathFromStroke(points) {
11689
- if (!points.length) {
11690
- return "";
11691
- }
11692
- const max = points.length - 1;
11693
- return points.reduce(
11694
- (acc, point, i, arr) => {
11695
- if (i === max) {
11696
- acc.push(point, med(point, arr[0]), "L", arr[0], "Z");
11697
- } else {
11698
- acc.push(point, med(point, arr[i + 1]));
11699
- }
11700
- return acc;
11701
- },
11702
- ["M", points[0], "Q"]
11703
- ).join(" ").replace(TO_FIXED_PRECISION, "$1");
11704
- }
11705
12238
 
11706
12239
  // src/comparisons.ts
11707
12240
  init_define_import_meta_env();
11708
12241
  var hasBackground = (type) => type === "rectangle" || type === "iframe" || type === "embeddable" || type === "ellipse" || type === "diamond" || type === "line" || type === "freedraw";
11709
- var hasStrokeColor = (type) => type === "rectangle" || type === "ellipse" || type === "diamond" || type === "freedraw" || type === "arrow" || type === "line" || type === "text";
12242
+ var hasStrokeColor = (type) => type === "rectangle" || type === "ellipse" || type === "diamond" || type === "freedraw" || type === "arrow" || type === "line" || type === "text" || type === "embeddable";
11710
12243
  var hasStrokeWidth = (type) => type === "rectangle" || type === "iframe" || type === "embeddable" || type === "ellipse" || type === "diamond" || type === "freedraw" || type === "arrow" || type === "line";
11711
12244
  var hasStrokeStyle = (type) => type === "rectangle" || type === "iframe" || type === "embeddable" || type === "ellipse" || type === "diamond" || type === "arrow" || type === "line";
11712
12245
  var canChangeRoundness = (type) => type === "rectangle" || type === "iframe" || type === "embeddable" || type === "line" || type === "diamond" || type === "image";
@@ -11721,13 +12254,17 @@ var ShapeCache = class _ShapeCache {
11721
12254
  * Retrieves shape from cache if available. Use this only if shape
11722
12255
  * is optional and you have a fallback in case it's not cached.
11723
12256
  */
11724
- static get = (element) => {
11725
- return _ShapeCache.cache.get(
11726
- element
11727
- );
12257
+ static get = (element, theme) => {
12258
+ const cached = _ShapeCache.cache.get(element);
12259
+ if (cached && (theme === null || cached.theme === theme)) {
12260
+ return cached.shape;
12261
+ }
12262
+ return void 0;
12263
+ };
12264
+ static delete = (element) => {
12265
+ _ShapeCache.cache.delete(element);
12266
+ elementWithCanvasCache.delete(element);
11728
12267
  };
11729
- static set = (element, shape) => _ShapeCache.cache.set(element, shape);
11730
- static delete = (element) => _ShapeCache.cache.delete(element);
11731
12268
  static destroy = () => {
11732
12269
  _ShapeCache.cache = /* @__PURE__ */ new WeakMap();
11733
12270
  };
@@ -11736,21 +12273,27 @@ var ShapeCache = class _ShapeCache {
11736
12273
  * returns cached shape.
11737
12274
  */
11738
12275
  static generateElementShape = (element, renderConfig) => {
11739
- const cachedShape = renderConfig?.isExporting ? void 0 : _ShapeCache.get(element);
12276
+ const cachedShape = renderConfig?.isExporting ? void 0 : _ShapeCache.get(element, renderConfig ? renderConfig.theme : null);
11740
12277
  if (cachedShape !== void 0) {
11741
12278
  return cachedShape;
11742
12279
  }
11743
12280
  elementWithCanvasCache.delete(element);
11744
- const shape = generateElementShape(
12281
+ const shape = _generateElementShape(
11745
12282
  element,
11746
12283
  _ShapeCache.rg,
11747
12284
  renderConfig || {
11748
12285
  isExporting: false,
11749
12286
  canvasBackgroundColor: COLOR_PALETTE.white,
11750
- embedsValidationStatus: null
12287
+ embedsValidationStatus: null,
12288
+ theme: THEME2.LIGHT
11751
12289
  }
11752
12290
  );
11753
- _ShapeCache.cache.set(element, shape);
12291
+ if (!renderConfig?.isExporting) {
12292
+ _ShapeCache.cache.set(element, {
12293
+ shape,
12294
+ theme: renderConfig?.theme || THEME2.LIGHT
12295
+ });
12296
+ }
11754
12297
  return shape;
11755
12298
  };
11756
12299
  };
@@ -11770,7 +12313,7 @@ function adjustRoughness(element) {
11770
12313
  }
11771
12314
  return Math.min(roughness / (maxSize < 10 ? 3 : 2), 2.5);
11772
12315
  }
11773
- var generateRoughOptions = (element, continuousPath = false) => {
12316
+ var generateRoughOptions = (element, continuousPath = false, isDarkMode = false) => {
11774
12317
  const options = {
11775
12318
  seed: element.seed,
11776
12319
  strokeLineDash: element.strokeStyle === "dashed" ? getDashArrayDashed(element.strokeWidth) : element.strokeStyle === "dotted" ? getDashArrayDotted(element.strokeWidth) : void 0,
@@ -11786,7 +12329,7 @@ var generateRoughOptions = (element, continuousPath = false) => {
11786
12329
  fillWeight: element.strokeWidth / 2,
11787
12330
  hachureGap: element.strokeWidth * 4,
11788
12331
  roughness: adjustRoughness(element),
11789
- stroke: element.strokeColor,
12332
+ stroke: isDarkMode ? applyDarkModeFilter2(element.strokeColor) : element.strokeColor,
11790
12333
  preserveVertices: continuousPath || element.roughness < ROUGHNESS.cartoonist
11791
12334
  };
11792
12335
  switch (element.type) {
@@ -11796,7 +12339,7 @@ var generateRoughOptions = (element, continuousPath = false) => {
11796
12339
  case "diamond":
11797
12340
  case "ellipse": {
11798
12341
  options.fillStyle = element.fillStyle;
11799
- options.fill = isTransparent3(element.backgroundColor) ? void 0 : element.backgroundColor;
12342
+ options.fill = isTransparent3(element.backgroundColor) ? void 0 : isDarkMode ? applyDarkModeFilter2(element.backgroundColor) : element.backgroundColor;
11800
12343
  if (element.type === "ellipse") {
11801
12344
  options.curveFitting = 1;
11802
12345
  }
@@ -11806,7 +12349,7 @@ var generateRoughOptions = (element, continuousPath = false) => {
11806
12349
  case "freedraw": {
11807
12350
  if (isPathALoop(element.points)) {
11808
12351
  options.fillStyle = element.fillStyle;
11809
- options.fill = element.backgroundColor === "transparent" ? void 0 : element.backgroundColor;
12352
+ options.fill = element.backgroundColor === "transparent" ? void 0 : isDarkMode ? applyDarkModeFilter2(element.backgroundColor) : element.backgroundColor;
11810
12353
  }
11811
12354
  return options;
11812
12355
  }
@@ -11834,7 +12377,7 @@ var modifyIframeLikeForRoughOptions = (element, isExporting, embedsValidationSta
11834
12377
  }
11835
12378
  return element;
11836
12379
  };
11837
- var getArrowheadShapes = (element, shape, position, arrowhead, generator, options, canvasBackgroundColor) => {
12380
+ var getArrowheadShapes = (element, shape, position, arrowhead, generator, options, canvasBackgroundColor, isDarkMode) => {
11838
12381
  const arrowheadPoints = getArrowheadPoints(
11839
12382
  element,
11840
12383
  shape,
@@ -11851,6 +12394,7 @@ var getArrowheadShapes = (element, shape, position, arrowhead, generator, option
11851
12394
  const [, , x3, y3, x4, y4] = arrowheadPoints2;
11852
12395
  return [generator.line(x3, y3, x4, y4, options2)];
11853
12396
  };
12397
+ const strokeColor = isDarkMode ? applyDarkModeFilter2(element.strokeColor) : element.strokeColor;
11854
12398
  switch (arrowhead) {
11855
12399
  case "dot":
11856
12400
  case "circle":
@@ -11860,9 +12404,9 @@ var getArrowheadShapes = (element, shape, position, arrowhead, generator, option
11860
12404
  return [
11861
12405
  generator.circle(x, y, diameter, {
11862
12406
  ...options,
11863
- fill: arrowhead === "circle_outline" ? canvasBackgroundColor : element.strokeColor,
12407
+ fill: arrowhead === "circle_outline" ? canvasBackgroundColor : strokeColor,
11864
12408
  fillStyle: "solid",
11865
- stroke: element.strokeColor,
12409
+ stroke: strokeColor,
11866
12410
  roughness: Math.min(0.5, options.roughness || 0)
11867
12411
  })
11868
12412
  ];
@@ -11881,7 +12425,7 @@ var getArrowheadShapes = (element, shape, position, arrowhead, generator, option
11881
12425
  ],
11882
12426
  {
11883
12427
  ...options,
11884
- fill: arrowhead === "triangle_outline" ? canvasBackgroundColor : element.strokeColor,
12428
+ fill: arrowhead === "triangle_outline" ? canvasBackgroundColor : strokeColor,
11885
12429
  fillStyle: "solid",
11886
12430
  roughness: Math.min(1, options.roughness || 0)
11887
12431
  }
@@ -11903,7 +12447,7 @@ var getArrowheadShapes = (element, shape, position, arrowhead, generator, option
11903
12447
  ],
11904
12448
  {
11905
12449
  ...options,
11906
- fill: arrowhead === "diamond_outline" ? canvasBackgroundColor : element.strokeColor,
12450
+ fill: arrowhead === "diamond_outline" ? canvasBackgroundColor : strokeColor,
11907
12451
  fillStyle: "solid",
11908
12452
  roughness: Math.min(1, options.roughness || 0)
11909
12453
  }
@@ -12084,11 +12628,13 @@ var generateLinearCollisionShape = (element) => {
12084
12628
  }
12085
12629
  }
12086
12630
  };
12087
- var generateElementShape = (element, generator, {
12631
+ var _generateElementShape = (element, generator, {
12088
12632
  isExporting,
12089
12633
  canvasBackgroundColor,
12090
- embedsValidationStatus
12634
+ embedsValidationStatus,
12635
+ theme
12091
12636
  }) => {
12637
+ const isDarkMode = theme === THEME2.DARK;
12092
12638
  switch (element.type) {
12093
12639
  case "rectangle":
12094
12640
  case "iframe":
@@ -12106,7 +12652,8 @@ var generateElementShape = (element, generator, {
12106
12652
  isExporting,
12107
12653
  embedsValidationStatus
12108
12654
  ),
12109
- true
12655
+ true,
12656
+ isDarkMode
12110
12657
  )
12111
12658
  );
12112
12659
  } else {
@@ -12121,7 +12668,8 @@ var generateElementShape = (element, generator, {
12121
12668
  isExporting,
12122
12669
  embedsValidationStatus
12123
12670
  ),
12124
- false
12671
+ false,
12672
+ isDarkMode
12125
12673
  )
12126
12674
  );
12127
12675
  }
@@ -12145,7 +12693,7 @@ var generateElementShape = (element, generator, {
12145
12693
  C ${leftX} ${leftY}, ${leftX} ${leftY}, ${leftX + verticalRadius} ${leftY - horizontalRadius}
12146
12694
  L ${topX - verticalRadius} ${topY + horizontalRadius}
12147
12695
  C ${topX} ${topY}, ${topX} ${topY}, ${topX + verticalRadius} ${topY + horizontalRadius}`,
12148
- generateRoughOptions(element, true)
12696
+ generateRoughOptions(element, true, isDarkMode)
12149
12697
  );
12150
12698
  } else {
12151
12699
  shape = generator.polygon(
@@ -12155,7 +12703,7 @@ var generateElementShape = (element, generator, {
12155
12703
  [bottomX, bottomY],
12156
12704
  [leftX, leftY]
12157
12705
  ],
12158
- generateRoughOptions(element)
12706
+ generateRoughOptions(element, false, isDarkMode)
12159
12707
  );
12160
12708
  }
12161
12709
  return shape;
@@ -12166,14 +12714,14 @@ var generateElementShape = (element, generator, {
12166
12714
  element.height / 2,
12167
12715
  element.width,
12168
12716
  element.height,
12169
- generateRoughOptions(element)
12717
+ generateRoughOptions(element, false, isDarkMode)
12170
12718
  );
12171
12719
  return shape;
12172
12720
  }
12173
12721
  case "line":
12174
12722
  case "arrow": {
12175
12723
  let shape;
12176
- const options = generateRoughOptions(element);
12724
+ const options = generateRoughOptions(element, false, isDarkMode);
12177
12725
  const points = element.points.length ? element.points : [pointFrom13(0, 0)];
12178
12726
  if (isElbowArrow(element)) {
12179
12727
  if (!points.every(
@@ -12189,7 +12737,7 @@ var generateElementShape = (element, generator, {
12189
12737
  shape = [
12190
12738
  generator.path(
12191
12739
  generateElbowArrowShape(points, 16),
12192
- generateRoughOptions(element, true)
12740
+ generateRoughOptions(element, true, isDarkMode)
12193
12741
  )
12194
12742
  ];
12195
12743
  }
@@ -12216,7 +12764,8 @@ var generateElementShape = (element, generator, {
12216
12764
  startArrowhead,
12217
12765
  generator,
12218
12766
  options,
12219
- canvasBackgroundColor
12767
+ canvasBackgroundColor,
12768
+ isDarkMode
12220
12769
  );
12221
12770
  shape.push(...shapes);
12222
12771
  }
@@ -12230,7 +12779,8 @@ var generateElementShape = (element, generator, {
12230
12779
  endArrowhead,
12231
12780
  generator,
12232
12781
  options,
12233
- canvasBackgroundColor
12782
+ canvasBackgroundColor,
12783
+ isDarkMode
12234
12784
  );
12235
12785
  shape.push(...shapes);
12236
12786
  }
@@ -12238,21 +12788,21 @@ var generateElementShape = (element, generator, {
12238
12788
  return shape;
12239
12789
  }
12240
12790
  case "freedraw": {
12241
- let shape;
12242
- generateFreeDrawShape(element);
12791
+ const shapes = [];
12243
12792
  if (isPathALoop(element.points)) {
12244
12793
  const simplifiedPoints = simplify(
12245
12794
  element.points,
12246
12795
  0.75
12247
12796
  );
12248
- shape = generator.curve(simplifiedPoints, {
12249
- ...generateRoughOptions(element),
12250
- stroke: "none"
12251
- });
12252
- } else {
12253
- shape = null;
12797
+ shapes.push(
12798
+ generator.curve(simplifiedPoints, {
12799
+ ...generateRoughOptions(element, false, isDarkMode),
12800
+ stroke: "none"
12801
+ })
12802
+ );
12254
12803
  }
12255
- return shape;
12804
+ shapes.push(getFreeDrawSvgPath(element));
12805
+ return shapes;
12256
12806
  }
12257
12807
  case "frame":
12258
12808
  case "magicframe":
@@ -12331,7 +12881,7 @@ var getElementShape = (element, elementsMap) => {
12331
12881
  return getPolygonShape(element);
12332
12882
  case "arrow":
12333
12883
  case "line": {
12334
- const roughShape = ShapeCache.get(element)?.[0] ?? ShapeCache.generateElementShape(element, null)[0];
12884
+ const roughShape = ShapeCache.generateElementShape(element, null)[0];
12335
12885
  const [, , , , cx, cy] = getElementAbsoluteCoords2(element, elementsMap);
12336
12886
  return shouldTestInside(element) ? getClosedCurveShape(
12337
12887
  element,
@@ -12385,6 +12935,45 @@ var toggleLinePolygonState = (element, nextPolygonState) => {
12385
12935
  };
12386
12936
  return ret;
12387
12937
  };
12938
+ var getFreeDrawSvgPath = (element) => {
12939
+ return getSvgPathFromStroke(
12940
+ getFreedrawOutlinePoints(element)
12941
+ );
12942
+ };
12943
+ var getFreedrawOutlinePoints = (element) => {
12944
+ const inputPoints = element.simulatePressure ? element.points : element.points.length ? element.points.map(([x, y], i) => [x, y, element.pressures[i]]) : [[0, 0, 0.5]];
12945
+ return ae(inputPoints, {
12946
+ simulatePressure: element.simulatePressure,
12947
+ size: element.strokeWidth * 4.25,
12948
+ thinning: 0.6,
12949
+ smoothing: 0.5,
12950
+ streamline: 0.5,
12951
+ easing: (t) => Math.sin(t * Math.PI / 2),
12952
+ // https://easings.net/#easeOutSine
12953
+ last: true
12954
+ });
12955
+ };
12956
+ var med = (A2, B2) => {
12957
+ return [(A2[0] + B2[0]) / 2, (A2[1] + B2[1]) / 2];
12958
+ };
12959
+ var TO_FIXED_PRECISION = /(\s?[A-Z]?,?-?[0-9]*\.[0-9]{0,2})(([0-9]|e|-)*)/g;
12960
+ var getSvgPathFromStroke = (points) => {
12961
+ if (!points.length) {
12962
+ return "";
12963
+ }
12964
+ const max = points.length - 1;
12965
+ return points.reduce(
12966
+ (acc, point, i, arr) => {
12967
+ if (i === max) {
12968
+ acc.push(point, med(point, arr[0]), "L", arr[0], "Z");
12969
+ } else {
12970
+ acc.push(point, med(point, arr[i + 1]));
12971
+ }
12972
+ return acc;
12973
+ },
12974
+ ["M", points[0], "Q"]
12975
+ ).join(" ").replace(TO_FIXED_PRECISION, "$1");
12976
+ };
12388
12977
 
12389
12978
  // src/bounds.ts
12390
12979
  var ElementBounds = class _ElementBounds {
@@ -12983,7 +13572,7 @@ var getLinearElementRotatedBounds = (element, cx, cy, elementsMap) => {
12983
13572
  }
12984
13573
  return coords2;
12985
13574
  }
12986
- const cachedShape = ShapeCache.get(element)?.[0];
13575
+ const cachedShape = ShapeCache.get(element, null)?.[0];
12987
13576
  const shape = cachedShape ?? generateLinearElementShape(element);
12988
13577
  const ops = getCurvePathOps(shape);
12989
13578
  const transformXY = ([x, y]) => pointRotateRads13(
@@ -13210,7 +13799,7 @@ var elementCenterPoint = (element, elementsMap, xOffset = 0, yOffset = 0) => {
13210
13799
  var INVISIBLY_SMALL_ELEMENT_SIZE = 0.1;
13211
13800
  var isInvisiblySmallElement = (element) => {
13212
13801
  if (isLinearElement(element) || isFreeDrawElement(element)) {
13213
- return element.points.length < 2 || element.points.length === 2 && isArrowElement(element) && pointsEqual6(
13802
+ return element.points.length < 2 || element.points.length === 2 && isArrowElement(element) && pointsEqual7(
13214
13803
  element.points[0],
13215
13804
  element.points[element.points.length - 1],
13216
13805
  INVISIBLY_SMALL_ELEMENT_SIZE
@@ -16435,7 +17024,7 @@ var ElementsDelta = class _ElementsDelta {
16435
17024
 
16436
17025
  // src/distribute.ts
16437
17026
  init_define_import_meta_env();
16438
- var distributeElements = (selectedElements, elementsMap, distribution, appState) => {
17027
+ var distributeElements = (selectedElements, elementsMap, distribution, appState, scene) => {
16439
17028
  const [start, mid, end, extent] = distribution.axis === "x" ? ["minX", "midX", "maxX", "width"] : ["minY", "midY", "maxY", "height"];
16440
17029
  const bounds = getCommonBoundingBox(selectedElements);
16441
17030
  const groups = getSelectedElementsByGroup(
@@ -16462,12 +17051,16 @@ var distributeElements = (selectedElements, elementsMap, distribution, appState)
16462
17051
  pos2 += step2;
16463
17052
  translation[distribution.axis] = pos2 - box[mid];
16464
17053
  }
16465
- return group.map(
16466
- (element) => newElementWith(element, {
17054
+ return group.map((element) => {
17055
+ const updatedElement = scene.mutateElement(element, {
16467
17056
  x: element.x + translation.x,
16468
17057
  y: element.y + translation.y
16469
- })
16470
- );
17058
+ });
17059
+ updateBoundElements(element, scene, {
17060
+ simultaneouslyUpdated: group
17061
+ });
17062
+ return updatedElement;
17063
+ });
16471
17064
  });
16472
17065
  }
16473
17066
  let pos = bounds[start];
@@ -16479,12 +17072,16 @@ var distributeElements = (selectedElements, elementsMap, distribution, appState)
16479
17072
  translation[distribution.axis] = pos - box[start];
16480
17073
  pos += step;
16481
17074
  pos += box[extent];
16482
- return group.map(
16483
- (element) => newElementWith(element, {
17075
+ return group.map((element) => {
17076
+ const updatedElement = scene.mutateElement(element, {
16484
17077
  x: element.x + translation.x,
16485
17078
  y: element.y + translation.y
16486
- })
16487
- );
17079
+ });
17080
+ updateBoundElements(element, scene, {
17081
+ simultaneouslyUpdated: group
17082
+ });
17083
+ return updatedElement;
17084
+ });
16488
17085
  });
16489
17086
  };
16490
17087
 
@@ -17921,116 +18518,829 @@ var isNodeInFlowchart = (element, elementsMap) => {
17921
18518
  return false;
17922
18519
  };
17923
18520
 
17924
- // src/image.ts
18521
+ // src/arrows/focus.ts
17925
18522
  init_define_import_meta_env();
17926
- import { MIME_TYPES as MIME_TYPES2, SVG_NS } from "@excalidraw/common";
17927
- var loadHTMLImageElement = (dataURL) => {
17928
- return new Promise((resolve, reject) => {
17929
- const image = new Image();
17930
- image.onload = () => {
17931
- resolve(image);
17932
- };
17933
- image.onerror = (error) => {
17934
- reject(error);
17935
- };
17936
- image.src = dataURL;
17937
- });
18523
+ import { pointDistance as pointDistance8, pointFrom as pointFrom16 } from "@excalidraw/math";
18524
+ import { invariant as invariant12 } from "@excalidraw/common";
18525
+
18526
+ // src/zindex.ts
18527
+ init_define_import_meta_env();
18528
+ import { arrayToMap as arrayToMap11, findIndex, findLastIndex as findLastIndex2 } from "@excalidraw/common";
18529
+ var isOfTargetFrame = (element, frameId) => {
18530
+ return element.frameId === frameId || element.id === frameId;
17938
18531
  };
17939
- var updateImageCache = async ({
17940
- fileIds,
17941
- files,
17942
- imageCache
17943
- }) => {
17944
- const updatedFiles = /* @__PURE__ */ new Map();
17945
- const erroredFiles = /* @__PURE__ */ new Map();
17946
- await Promise.all(
17947
- fileIds.reduce((promises, fileId) => {
17948
- const fileData = files[fileId];
17949
- if (fileData && !updatedFiles.has(fileId)) {
17950
- updatedFiles.set(fileId, true);
17951
- return promises.concat(
17952
- (async () => {
17953
- try {
17954
- if (fileData.mimeType === MIME_TYPES2.binary) {
17955
- throw new Error("Only images can be added to ImageCache");
17956
- }
17957
- const imagePromise = loadHTMLImageElement(fileData.dataURL);
17958
- const data = {
17959
- image: imagePromise,
17960
- mimeType: fileData.mimeType
17961
- };
17962
- imageCache.set(fileId, data);
17963
- const image = await imagePromise;
17964
- imageCache.set(fileId, { ...data, image });
17965
- } catch (error) {
17966
- erroredFiles.set(fileId, true);
17967
- }
17968
- })()
17969
- );
17970
- }
17971
- return promises;
17972
- }, [])
18532
+ var getIndicesToMove = (elements, appState, elementsToBeMoved) => {
18533
+ let selectedIndices = [];
18534
+ let deletedIndices = [];
18535
+ let includeDeletedIndex = null;
18536
+ let index = -1;
18537
+ const selectedElementIds = arrayToMap11(
18538
+ elementsToBeMoved ? elementsToBeMoved : getSelectedElements(elements, appState, {
18539
+ includeBoundTextElement: true,
18540
+ includeElementsInFrames: true
18541
+ })
17973
18542
  );
17974
- return {
17975
- imageCache,
17976
- /** includes errored files because they cache was updated nonetheless */
17977
- updatedFiles,
17978
- /** files that failed when creating HTMLImageElement */
17979
- erroredFiles
17980
- };
17981
- };
17982
- var getInitializedImageElements = (elements) => elements.filter(
17983
- (element) => isInitializedImageElement(element)
17984
- );
17985
- var isHTMLSVGElement = (node) => {
17986
- return node?.nodeName.toLowerCase() === "svg";
17987
- };
17988
- var normalizeSVG = (SVGString) => {
17989
- const doc = new DOMParser().parseFromString(SVGString, MIME_TYPES2.svg);
17990
- const svg = doc.querySelector("svg");
17991
- const errorNode = doc.querySelector("parsererror");
17992
- if (errorNode || !isHTMLSVGElement(svg)) {
17993
- throw new Error("Invalid SVG");
17994
- } else {
17995
- if (!svg.hasAttribute("xmlns")) {
17996
- svg.setAttribute("xmlns", SVG_NS);
17997
- }
17998
- let width = svg.getAttribute("width");
17999
- let height = svg.getAttribute("height");
18000
- if (width?.includes("%") || width === "auto") {
18001
- width = null;
18002
- }
18003
- if (height?.includes("%") || height === "auto") {
18004
- height = null;
18005
- }
18006
- const viewBox = svg.getAttribute("viewBox");
18007
- if (!width || !height) {
18008
- width = width || "50";
18009
- height = height || "50";
18010
- if (viewBox) {
18011
- const match = viewBox.match(
18012
- /\d+ +\d+ +(\d+(?:\.\d+)?) +(\d+(?:\.\d+)?)/
18013
- );
18014
- if (match) {
18015
- [, width, height] = match;
18016
- }
18543
+ while (++index < elements.length) {
18544
+ const element = elements[index];
18545
+ if (selectedElementIds.get(element.id)) {
18546
+ if (deletedIndices.length) {
18547
+ selectedIndices = selectedIndices.concat(deletedIndices);
18548
+ deletedIndices = [];
18017
18549
  }
18018
- svg.setAttribute("width", width);
18019
- svg.setAttribute("height", height);
18020
- }
18021
- if (!viewBox) {
18022
- svg.setAttribute("viewBox", `0 0 ${width} ${height}`);
18550
+ selectedIndices.push(index);
18551
+ includeDeletedIndex = index + 1;
18552
+ } else if (element.isDeleted && includeDeletedIndex === index) {
18553
+ includeDeletedIndex = index + 1;
18554
+ deletedIndices.push(index);
18555
+ } else {
18556
+ deletedIndices = [];
18023
18557
  }
18024
- return svg.outerHTML;
18025
18558
  }
18559
+ return selectedIndices;
18026
18560
  };
18027
-
18028
- // src/positionElementsOnGrid.ts
18029
- init_define_import_meta_env();
18030
- var positionElementsOnGrid = (elements, centerX, centerY, padding = 50) => {
18031
- if (!elements || elements.length === 0) {
18032
- return [];
18033
- }
18561
+ var toContiguousGroups = (array) => {
18562
+ let cursor = 0;
18563
+ return array.reduce((acc, value, index) => {
18564
+ if (index > 0 && array[index - 1] !== value - 1) {
18565
+ cursor = ++cursor;
18566
+ }
18567
+ (acc[cursor] || (acc[cursor] = [])).push(value);
18568
+ return acc;
18569
+ }, []);
18570
+ };
18571
+ var getTargetIndexAccountingForBinding = (nextElement, elements, direction, scene) => {
18572
+ if ("containerId" in nextElement && nextElement.containerId) {
18573
+ const containerElement = scene.getElement(nextElement.containerId);
18574
+ if (containerElement) {
18575
+ return direction === "left" ? Math.min(
18576
+ elements.indexOf(containerElement),
18577
+ elements.indexOf(nextElement)
18578
+ ) : Math.max(
18579
+ elements.indexOf(containerElement),
18580
+ elements.indexOf(nextElement)
18581
+ );
18582
+ }
18583
+ } else {
18584
+ const boundElementId = nextElement.boundElements?.find(
18585
+ (binding) => binding.type !== "arrow"
18586
+ )?.id;
18587
+ if (boundElementId) {
18588
+ const boundTextElement = scene.getElement(boundElementId);
18589
+ if (boundTextElement) {
18590
+ return direction === "left" ? Math.min(
18591
+ elements.indexOf(boundTextElement),
18592
+ elements.indexOf(nextElement)
18593
+ ) : Math.max(
18594
+ elements.indexOf(boundTextElement),
18595
+ elements.indexOf(nextElement)
18596
+ );
18597
+ }
18598
+ }
18599
+ }
18600
+ };
18601
+ var getContiguousFrameRangeElements = (allElements, frameId) => {
18602
+ let rangeStart = -1;
18603
+ let rangeEnd = -1;
18604
+ allElements.forEach((element, index) => {
18605
+ if (isOfTargetFrame(element, frameId)) {
18606
+ if (rangeStart === -1) {
18607
+ rangeStart = index;
18608
+ }
18609
+ rangeEnd = index;
18610
+ }
18611
+ });
18612
+ if (rangeStart === -1) {
18613
+ return [];
18614
+ }
18615
+ return allElements.slice(rangeStart, rangeEnd + 1);
18616
+ };
18617
+ var moveArrowAboveBindable2 = (point, arrow, elements, elementsMap, scene, hit) => {
18618
+ const hoveredElement = hit ? hit : getHoveredElementForBinding(point, elements, elementsMap);
18619
+ if (!hoveredElement) {
18620
+ return elements;
18621
+ }
18622
+ const boundTextElement = getBoundTextElement(hoveredElement, elementsMap);
18623
+ const containerElement = isTextElement(hoveredElement) ? getContainerElement(hoveredElement, elementsMap) : null;
18624
+ const bindableIds = [
18625
+ hoveredElement.id,
18626
+ boundTextElement?.id,
18627
+ containerElement?.id
18628
+ ].filter((id) => !!id);
18629
+ const bindableIdx = elements.findIndex((el) => bindableIds.includes(el.id));
18630
+ const arrowIdx = elements.findIndex((el) => el.id === arrow.id);
18631
+ if (arrowIdx !== -1 && bindableIdx !== -1 && arrowIdx < bindableIdx) {
18632
+ const updatedElements = Array.from(elements);
18633
+ const arrow2 = updatedElements.splice(arrowIdx, 1)[0];
18634
+ updatedElements.splice(bindableIdx, 0, arrow2);
18635
+ scene.replaceAllElements(updatedElements);
18636
+ }
18637
+ return elements;
18638
+ };
18639
+ var getTargetIndex = (appState, elements, boundaryIndex, direction, containingFrame, scene) => {
18640
+ const sourceElement = elements[boundaryIndex];
18641
+ const indexFilter = (element) => {
18642
+ if (element.isDeleted) {
18643
+ return false;
18644
+ }
18645
+ if (containingFrame) {
18646
+ return element.frameId === containingFrame;
18647
+ }
18648
+ if (appState.editingGroupId) {
18649
+ return element.groupIds.includes(appState.editingGroupId);
18650
+ }
18651
+ return true;
18652
+ };
18653
+ const candidateIndex = direction === "left" ? findLastIndex2(
18654
+ elements,
18655
+ (el) => indexFilter(el),
18656
+ Math.max(0, boundaryIndex - 1)
18657
+ ) : findIndex(elements, (el) => indexFilter(el), boundaryIndex + 1);
18658
+ const nextElement = elements[candidateIndex];
18659
+ if (!nextElement) {
18660
+ return -1;
18661
+ }
18662
+ if (appState.editingGroupId) {
18663
+ if (
18664
+ // candidate element is a sibling in current editing group → return
18665
+ sourceElement?.groupIds.join("") === nextElement?.groupIds.join("")
18666
+ ) {
18667
+ return getTargetIndexAccountingForBinding(
18668
+ nextElement,
18669
+ elements,
18670
+ direction,
18671
+ scene
18672
+ ) ?? candidateIndex;
18673
+ } else if (!nextElement?.groupIds.includes(appState.editingGroupId)) {
18674
+ return -1;
18675
+ }
18676
+ }
18677
+ if (!containingFrame && (nextElement.frameId || isFrameLikeElement(nextElement))) {
18678
+ const frameElements = getContiguousFrameRangeElements(
18679
+ elements,
18680
+ nextElement.frameId || nextElement.id
18681
+ );
18682
+ return direction === "left" ? elements.indexOf(frameElements[0]) : elements.indexOf(frameElements[frameElements.length - 1]);
18683
+ }
18684
+ if (!nextElement.groupIds.length) {
18685
+ return getTargetIndexAccountingForBinding(
18686
+ nextElement,
18687
+ elements,
18688
+ direction,
18689
+ scene
18690
+ ) ?? candidateIndex;
18691
+ }
18692
+ const siblingGroupId = appState.editingGroupId ? nextElement.groupIds[nextElement.groupIds.indexOf(appState.editingGroupId) - 1] : nextElement.groupIds[nextElement.groupIds.length - 1];
18693
+ const elementsInSiblingGroup = getElementsInGroup(elements, siblingGroupId);
18694
+ if (elementsInSiblingGroup.length) {
18695
+ return direction === "left" ? elements.indexOf(elementsInSiblingGroup[0]) : elements.indexOf(
18696
+ elementsInSiblingGroup[elementsInSiblingGroup.length - 1]
18697
+ );
18698
+ }
18699
+ return candidateIndex;
18700
+ };
18701
+ var getTargetElementsMap = (elements, indices) => {
18702
+ return indices.reduce((acc, index) => {
18703
+ const element = elements[index];
18704
+ acc.set(element.id, element);
18705
+ return acc;
18706
+ }, /* @__PURE__ */ new Map());
18707
+ };
18708
+ var shiftElementsByOne = (elements, appState, direction, scene) => {
18709
+ const indicesToMove = getIndicesToMove(elements, appState);
18710
+ const targetElementsMap = getTargetElementsMap(elements, indicesToMove);
18711
+ let groupedIndices = toContiguousGroups(indicesToMove);
18712
+ if (direction === "right") {
18713
+ groupedIndices = groupedIndices.reverse();
18714
+ }
18715
+ const selectedFrames = new Set(
18716
+ indicesToMove.filter((idx) => isFrameLikeElement(elements[idx])).map((idx) => elements[idx].id)
18717
+ );
18718
+ groupedIndices.forEach((indices, i) => {
18719
+ const leadingIndex = indices[0];
18720
+ const trailingIndex = indices[indices.length - 1];
18721
+ const boundaryIndex = direction === "left" ? leadingIndex : trailingIndex;
18722
+ const containingFrame = indices.some((idx) => {
18723
+ const el = elements[idx];
18724
+ return el.frameId && selectedFrames.has(el.frameId);
18725
+ }) ? null : elements[boundaryIndex]?.frameId;
18726
+ const targetIndex = getTargetIndex(
18727
+ appState,
18728
+ elements,
18729
+ boundaryIndex,
18730
+ direction,
18731
+ containingFrame,
18732
+ scene
18733
+ );
18734
+ if (targetIndex === -1 || boundaryIndex === targetIndex) {
18735
+ return;
18736
+ }
18737
+ const leadingElements = direction === "left" ? elements.slice(0, targetIndex) : elements.slice(0, leadingIndex);
18738
+ const targetElements = elements.slice(leadingIndex, trailingIndex + 1);
18739
+ const displacedElements = direction === "left" ? elements.slice(targetIndex, leadingIndex) : elements.slice(trailingIndex + 1, targetIndex + 1);
18740
+ const trailingElements = direction === "left" ? elements.slice(trailingIndex + 1) : elements.slice(targetIndex + 1);
18741
+ elements = direction === "left" ? [
18742
+ ...leadingElements,
18743
+ ...targetElements,
18744
+ ...displacedElements,
18745
+ ...trailingElements
18746
+ ] : [
18747
+ ...leadingElements,
18748
+ ...displacedElements,
18749
+ ...targetElements,
18750
+ ...trailingElements
18751
+ ];
18752
+ });
18753
+ syncMovedIndices(elements, targetElementsMap);
18754
+ return elements;
18755
+ };
18756
+ var shiftElementsToEnd = (elements, appState, direction, containingFrame, elementsToBeMoved) => {
18757
+ const indicesToMove = getIndicesToMove(elements, appState, elementsToBeMoved);
18758
+ const targetElementsMap = getTargetElementsMap(elements, indicesToMove);
18759
+ const displacedElements = [];
18760
+ let leadingIndex;
18761
+ let trailingIndex;
18762
+ if (direction === "left") {
18763
+ if (containingFrame) {
18764
+ leadingIndex = findIndex(
18765
+ elements,
18766
+ (el) => isOfTargetFrame(el, containingFrame)
18767
+ );
18768
+ } else if (appState.editingGroupId) {
18769
+ const groupElements = getElementsInGroup(
18770
+ elements,
18771
+ appState.editingGroupId
18772
+ );
18773
+ if (!groupElements.length) {
18774
+ return elements;
18775
+ }
18776
+ leadingIndex = elements.indexOf(groupElements[0]);
18777
+ } else {
18778
+ leadingIndex = 0;
18779
+ }
18780
+ trailingIndex = indicesToMove[indicesToMove.length - 1];
18781
+ } else {
18782
+ if (containingFrame) {
18783
+ trailingIndex = findLastIndex2(
18784
+ elements,
18785
+ (el) => isOfTargetFrame(el, containingFrame)
18786
+ );
18787
+ } else if (appState.editingGroupId) {
18788
+ const groupElements = getElementsInGroup(
18789
+ elements,
18790
+ appState.editingGroupId
18791
+ );
18792
+ if (!groupElements.length) {
18793
+ return elements;
18794
+ }
18795
+ trailingIndex = elements.indexOf(groupElements[groupElements.length - 1]);
18796
+ } else {
18797
+ trailingIndex = elements.length - 1;
18798
+ }
18799
+ leadingIndex = indicesToMove[0];
18800
+ }
18801
+ if (leadingIndex === -1) {
18802
+ leadingIndex = 0;
18803
+ }
18804
+ for (let index = leadingIndex; index < trailingIndex + 1; index++) {
18805
+ if (!indicesToMove.includes(index)) {
18806
+ displacedElements.push(elements[index]);
18807
+ }
18808
+ }
18809
+ const targetElements = Array.from(targetElementsMap.values());
18810
+ const leadingElements = elements.slice(0, leadingIndex);
18811
+ const trailingElements = elements.slice(trailingIndex + 1);
18812
+ const nextElements = direction === "left" ? [
18813
+ ...leadingElements,
18814
+ ...targetElements,
18815
+ ...displacedElements,
18816
+ ...trailingElements
18817
+ ] : [
18818
+ ...leadingElements,
18819
+ ...displacedElements,
18820
+ ...targetElements,
18821
+ ...trailingElements
18822
+ ];
18823
+ syncMovedIndices(nextElements, targetElementsMap);
18824
+ return nextElements;
18825
+ };
18826
+ function shiftElementsAccountingForFrames(allElements, appState, direction, shiftFunction) {
18827
+ const elementsToMove = arrayToMap11(
18828
+ getSelectedElements(allElements, appState, {
18829
+ includeBoundTextElement: true,
18830
+ includeElementsInFrames: true
18831
+ })
18832
+ );
18833
+ const frameAwareContiguousElementsToMove = { regularElements: [], frameChildren: /* @__PURE__ */ new Map() };
18834
+ const fullySelectedFrames = /* @__PURE__ */ new Set();
18835
+ for (const element of allElements) {
18836
+ if (elementsToMove.has(element.id) && isFrameLikeElement(element)) {
18837
+ fullySelectedFrames.add(element.id);
18838
+ }
18839
+ }
18840
+ for (const element of allElements) {
18841
+ if (elementsToMove.has(element.id)) {
18842
+ if (isFrameLikeElement(element) || element.frameId && fullySelectedFrames.has(element.frameId)) {
18843
+ frameAwareContiguousElementsToMove.regularElements.push(element);
18844
+ } else if (!element.frameId) {
18845
+ frameAwareContiguousElementsToMove.regularElements.push(element);
18846
+ } else {
18847
+ const frameChildren = frameAwareContiguousElementsToMove.frameChildren.get(
18848
+ element.frameId
18849
+ ) || [];
18850
+ frameChildren.push(element);
18851
+ frameAwareContiguousElementsToMove.frameChildren.set(
18852
+ element.frameId,
18853
+ frameChildren
18854
+ );
18855
+ }
18856
+ }
18857
+ }
18858
+ let nextElements = allElements;
18859
+ const frameChildrenSets = Array.from(
18860
+ frameAwareContiguousElementsToMove.frameChildren.entries()
18861
+ );
18862
+ for (const [frameId, children] of frameChildrenSets) {
18863
+ nextElements = shiftFunction(
18864
+ allElements,
18865
+ appState,
18866
+ direction,
18867
+ frameId,
18868
+ children
18869
+ );
18870
+ }
18871
+ return shiftFunction(
18872
+ nextElements,
18873
+ appState,
18874
+ direction,
18875
+ null,
18876
+ frameAwareContiguousElementsToMove.regularElements
18877
+ );
18878
+ }
18879
+ var moveOneLeft = (allElements, appState, scene) => {
18880
+ return shiftElementsByOne(allElements, appState, "left", scene);
18881
+ };
18882
+ var moveOneRight = (allElements, appState, scene) => {
18883
+ return shiftElementsByOne(allElements, appState, "right", scene);
18884
+ };
18885
+ var moveAllLeft = (allElements, appState) => {
18886
+ return shiftElementsAccountingForFrames(
18887
+ allElements,
18888
+ appState,
18889
+ "left",
18890
+ shiftElementsToEnd
18891
+ );
18892
+ };
18893
+ var moveAllRight = (allElements, appState) => {
18894
+ return shiftElementsAccountingForFrames(
18895
+ allElements,
18896
+ appState,
18897
+ "right",
18898
+ shiftElementsToEnd
18899
+ );
18900
+ };
18901
+
18902
+ // src/arrows/focus.ts
18903
+ var isFocusPointVisible = (focusPoint, arrow, bindableElement, elementsMap, appState, ignoreOverlap = false) => {
18904
+ if (isElbowArrow(arrow) || !isBindingEnabled(appState) || arrow.points.length !== 2) {
18905
+ return false;
18906
+ }
18907
+ if (!ignoreOverlap) {
18908
+ const associatedPointIdx = arrow.startBinding?.elementId === bindableElement.id ? 0 : arrow.points.length - 1;
18909
+ const associatedArrowPoint = LinearElementEditor.getPointAtIndexGlobalCoordinates(
18910
+ arrow,
18911
+ associatedPointIdx,
18912
+ elementsMap
18913
+ );
18914
+ if (pointDistance8(focusPoint, associatedArrowPoint) < FOCUS_POINT_SIZE * 1.5 / appState.zoom.value) {
18915
+ return false;
18916
+ }
18917
+ }
18918
+ return hitElementItself({
18919
+ element: bindableElement,
18920
+ elementsMap,
18921
+ point: focusPoint,
18922
+ threshold: getBindingGap(bindableElement, arrow),
18923
+ overrideShouldTestInside: true
18924
+ });
18925
+ };
18926
+ var focusPointUpdate = (arrow, bindableElement, isStartBinding, elementsMap, scene, appState, switchToInsideBinding) => {
18927
+ const pointUpdates = /* @__PURE__ */ new Map();
18928
+ const bindingField = isStartBinding ? "startBinding" : "endBinding";
18929
+ const adjacentBindingField = isStartBinding ? "endBinding" : "startBinding";
18930
+ let currentBinding = arrow[bindingField];
18931
+ let adjacentBinding = arrow[adjacentBindingField];
18932
+ if (currentBinding && bindableElement) {
18933
+ const boundToSameElement = bindableElement && adjacentBinding && currentBinding.elementId === adjacentBinding.elementId;
18934
+ if (switchToInsideBinding || boundToSameElement) {
18935
+ currentBinding = {
18936
+ ...currentBinding,
18937
+ mode: "inside"
18938
+ };
18939
+ } else {
18940
+ currentBinding = {
18941
+ ...currentBinding,
18942
+ mode: "orbit"
18943
+ };
18944
+ }
18945
+ const pointIndex = isStartBinding ? 0 : arrow.points.length - 1;
18946
+ const newPoint = updateBoundPoint(
18947
+ arrow,
18948
+ bindingField,
18949
+ currentBinding,
18950
+ bindableElement,
18951
+ elementsMap
18952
+ );
18953
+ if (newPoint) {
18954
+ pointUpdates.set(pointIndex, { point: newPoint });
18955
+ }
18956
+ }
18957
+ if (adjacentBinding) {
18958
+ const adjacentBindableElement = elementsMap.get(
18959
+ adjacentBinding.elementId
18960
+ );
18961
+ if (adjacentBindableElement && isBindableElement(adjacentBindableElement) && isBindingEnabled(appState)) {
18962
+ const boundToSameElementAfterUpdate = bindableElement && adjacentBinding.elementId === bindableElement.id;
18963
+ if (switchToInsideBinding || boundToSameElementAfterUpdate) {
18964
+ adjacentBinding = {
18965
+ ...adjacentBinding,
18966
+ mode: "inside"
18967
+ };
18968
+ } else {
18969
+ adjacentBinding = {
18970
+ ...adjacentBinding,
18971
+ mode: "orbit"
18972
+ };
18973
+ }
18974
+ const adjacentPointIndex = isStartBinding ? arrow.points.length - 1 : 0;
18975
+ const adjacentNewPoint = updateBoundPoint(
18976
+ arrow,
18977
+ adjacentBindingField,
18978
+ adjacentBinding,
18979
+ adjacentBindableElement,
18980
+ elementsMap
18981
+ );
18982
+ if (adjacentNewPoint) {
18983
+ pointUpdates.set(adjacentPointIndex, {
18984
+ point: adjacentNewPoint
18985
+ });
18986
+ }
18987
+ }
18988
+ }
18989
+ if (pointUpdates.size > 0) {
18990
+ LinearElementEditor.movePoints(arrow, scene, pointUpdates, {
18991
+ [bindingField]: currentBinding,
18992
+ [adjacentBindingField]: adjacentBinding
18993
+ });
18994
+ }
18995
+ };
18996
+ var handleFocusPointDrag = (linearElementEditor, elementsMap, pointerCoords, scene, appState, gridSize, switchToInsideBinding) => {
18997
+ const arrow = LinearElementEditor.getElement(
18998
+ linearElementEditor.elementId,
18999
+ elementsMap
19000
+ );
19001
+ if (!arrow || !isBindingElement(arrow) || isElbowArrow(arrow) || !linearElementEditor.hoveredFocusPointBinding || !linearElementEditor.draggedFocusPointBinding) {
19002
+ return;
19003
+ }
19004
+ const isStartBinding = linearElementEditor.draggedFocusPointBinding === "start";
19005
+ const binding = isStartBinding ? arrow.startBinding : arrow.endBinding;
19006
+ const { x: offsetX, y: offsetY } = linearElementEditor.pointerOffset;
19007
+ const point = pointFrom16(
19008
+ pointerCoords.x - offsetX,
19009
+ pointerCoords.y - offsetY
19010
+ );
19011
+ const bindingField = isStartBinding ? "startBinding" : "endBinding";
19012
+ const hit = getHoveredElementForFocusPoint(
19013
+ point,
19014
+ arrow,
19015
+ scene.getNonDeletedElements(),
19016
+ elementsMap,
19017
+ maxBindingDistance_simple(appState.zoom)
19018
+ );
19019
+ if (hit && isBindingEnabled(appState)) {
19020
+ if (arrow[bindingField] && hit.id !== binding?.elementId) {
19021
+ unbindBindingElement(
19022
+ arrow,
19023
+ linearElementEditor.draggedFocusPointBinding,
19024
+ scene
19025
+ );
19026
+ }
19027
+ const newMode = switchToInsideBinding && arrow[bindingField]?.mode === "orbit" ? "inside" : !switchToInsideBinding && arrow[bindingField]?.mode === "inside" ? "orbit" : null;
19028
+ if (!arrow[bindingField] || newMode) {
19029
+ bindBindingElement(
19030
+ arrow,
19031
+ hit,
19032
+ newMode || "orbit",
19033
+ linearElementEditor.draggedFocusPointBinding,
19034
+ scene,
19035
+ point
19036
+ );
19037
+ }
19038
+ scene.mutateElement(arrow, {
19039
+ [bindingField]: {
19040
+ ...arrow[bindingField],
19041
+ elementId: hit.id,
19042
+ mode: newMode || arrow[bindingField]?.mode || "orbit",
19043
+ ...calculateFixedPointForNonElbowArrowBinding(
19044
+ arrow,
19045
+ hit,
19046
+ linearElementEditor.draggedFocusPointBinding,
19047
+ elementsMap,
19048
+ point
19049
+ )
19050
+ }
19051
+ });
19052
+ } else {
19053
+ const pointUpdates = /* @__PURE__ */ new Map();
19054
+ const pointIndex = isStartBinding ? 0 : arrow.points.length - 1;
19055
+ pointUpdates.set(pointIndex, {
19056
+ point: LinearElementEditor.createPointAt(
19057
+ arrow,
19058
+ elementsMap,
19059
+ point[0],
19060
+ point[1],
19061
+ gridSize
19062
+ )
19063
+ });
19064
+ LinearElementEditor.movePoints(arrow, scene, pointUpdates);
19065
+ if (arrow[bindingField]) {
19066
+ unbindBindingElement(arrow, isStartBinding ? "start" : "end", scene);
19067
+ }
19068
+ }
19069
+ focusPointUpdate(
19070
+ arrow,
19071
+ hit,
19072
+ isStartBinding,
19073
+ elementsMap,
19074
+ scene,
19075
+ appState,
19076
+ switchToInsideBinding
19077
+ );
19078
+ if (hit && isBindingEnabled(appState)) {
19079
+ moveArrowAboveBindable2(
19080
+ point,
19081
+ arrow,
19082
+ scene.getElementsIncludingDeleted(),
19083
+ elementsMap,
19084
+ scene,
19085
+ hit
19086
+ );
19087
+ }
19088
+ };
19089
+ var handleFocusPointPointerDown = (arrow, pointerDownState, elementsMap, appState) => {
19090
+ const pointerPos = pointFrom16(
19091
+ pointerDownState.origin.x,
19092
+ pointerDownState.origin.y
19093
+ );
19094
+ const hitThreshold = FOCUS_POINT_SIZE * 1.5 / appState.zoom.value;
19095
+ if (arrow.startBinding?.elementId) {
19096
+ const bindableElement = elementsMap.get(arrow.startBinding.elementId);
19097
+ if (bindableElement && isBindableElement(bindableElement) && !bindableElement.isDeleted) {
19098
+ const focusPoint = getGlobalFixedPointForBindableElement(
19099
+ arrow.startBinding.fixedPoint,
19100
+ bindableElement,
19101
+ elementsMap
19102
+ );
19103
+ if (isFocusPointVisible(
19104
+ focusPoint,
19105
+ arrow,
19106
+ bindableElement,
19107
+ elementsMap,
19108
+ appState
19109
+ ) && pointDistance8(pointerPos, focusPoint) <= hitThreshold) {
19110
+ return {
19111
+ hitFocusPoint: "start",
19112
+ pointerOffset: {
19113
+ x: pointerPos[0] - focusPoint[0],
19114
+ y: pointerPos[1] - focusPoint[1]
19115
+ }
19116
+ };
19117
+ }
19118
+ }
19119
+ }
19120
+ if (arrow.endBinding?.elementId) {
19121
+ const bindableElement = elementsMap.get(arrow.endBinding.elementId);
19122
+ if (bindableElement && isBindableElement(bindableElement) && !bindableElement.isDeleted) {
19123
+ const focusPoint = getGlobalFixedPointForBindableElement(
19124
+ arrow.endBinding.fixedPoint,
19125
+ bindableElement,
19126
+ elementsMap
19127
+ );
19128
+ if (isFocusPointVisible(
19129
+ focusPoint,
19130
+ arrow,
19131
+ bindableElement,
19132
+ elementsMap,
19133
+ appState
19134
+ ) && pointDistance8(pointerPos, focusPoint) <= hitThreshold) {
19135
+ return {
19136
+ hitFocusPoint: "end",
19137
+ pointerOffset: {
19138
+ x: pointerPos[0] - focusPoint[0],
19139
+ y: pointerPos[1] - focusPoint[1]
19140
+ }
19141
+ };
19142
+ }
19143
+ }
19144
+ }
19145
+ return {
19146
+ hitFocusPoint: null,
19147
+ pointerOffset: { x: 0, y: 0 }
19148
+ };
19149
+ };
19150
+ var handleFocusPointPointerUp = (linearElementEditor, scene) => {
19151
+ invariant12(
19152
+ linearElementEditor.draggedFocusPointBinding,
19153
+ "Must have a dragged focus point at pointer release"
19154
+ );
19155
+ const arrow = LinearElementEditor.getElement(
19156
+ linearElementEditor.elementId,
19157
+ scene.getNonDeletedElementsMap()
19158
+ );
19159
+ invariant12(arrow, "Arrow must be in the scene");
19160
+ const bindingKey = linearElementEditor.draggedFocusPointBinding === "start" ? "startBinding" : "endBinding";
19161
+ const otherBindingKey = linearElementEditor.draggedFocusPointBinding === "start" ? "endBinding" : "startBinding";
19162
+ const boundElementId = arrow[bindingKey]?.elementId;
19163
+ const otherBoundElementId = arrow[otherBindingKey]?.elementId;
19164
+ const oldBoundElement = boundElementId && scene.getNonDeletedElements().find(
19165
+ (element) => element.id !== boundElementId && element.id !== otherBoundElementId && isBindableElement(element) && element.boundElements?.find(({ id }) => id === arrow.id)
19166
+ );
19167
+ if (oldBoundElement) {
19168
+ scene.mutateElement(oldBoundElement, {
19169
+ boundElements: oldBoundElement.boundElements?.filter(
19170
+ ({ id }) => id !== arrow.id
19171
+ )
19172
+ });
19173
+ }
19174
+ const boundElement = boundElementId && scene.getNonDeletedElementsMap().get(boundElementId);
19175
+ if (boundElement) {
19176
+ scene.mutateElement(boundElement, {
19177
+ boundElements: [
19178
+ ...(boundElement.boundElements || [])?.filter(
19179
+ ({ id }) => id !== arrow.id
19180
+ ),
19181
+ {
19182
+ id: arrow.id,
19183
+ type: "arrow"
19184
+ }
19185
+ ]
19186
+ });
19187
+ }
19188
+ };
19189
+ var handleFocusPointHover = (arrow, scenePointerX, scenePointerY, scene, appState) => {
19190
+ const elementsMap = scene.getNonDeletedElementsMap();
19191
+ const pointerPos = pointFrom16(scenePointerX, scenePointerY);
19192
+ const hitThreshold = FOCUS_POINT_SIZE * 1.5 / appState.zoom.value;
19193
+ if (arrow.startBinding?.elementId) {
19194
+ const bindableElement = elementsMap.get(arrow.startBinding.elementId);
19195
+ if (bindableElement && isBindableElement(bindableElement) && !bindableElement.isDeleted) {
19196
+ const focusPoint = getGlobalFixedPointForBindableElement(
19197
+ arrow.startBinding.fixedPoint,
19198
+ bindableElement,
19199
+ elementsMap
19200
+ );
19201
+ if (isFocusPointVisible(
19202
+ focusPoint,
19203
+ arrow,
19204
+ bindableElement,
19205
+ elementsMap,
19206
+ appState
19207
+ ) && pointDistance8(pointerPos, focusPoint) <= hitThreshold) {
19208
+ return "start";
19209
+ }
19210
+ }
19211
+ }
19212
+ if (arrow.endBinding?.elementId) {
19213
+ const bindableElement = elementsMap.get(arrow.endBinding.elementId);
19214
+ if (bindableElement && isBindableElement(bindableElement) && !bindableElement.isDeleted) {
19215
+ const focusPoint = getGlobalFixedPointForBindableElement(
19216
+ arrow.endBinding.fixedPoint,
19217
+ bindableElement,
19218
+ elementsMap
19219
+ );
19220
+ if (isFocusPointVisible(
19221
+ focusPoint,
19222
+ arrow,
19223
+ bindableElement,
19224
+ elementsMap,
19225
+ appState
19226
+ ) && pointDistance8(pointerPos, focusPoint) <= hitThreshold) {
19227
+ return "end";
19228
+ }
19229
+ }
19230
+ }
19231
+ return null;
19232
+ };
19233
+
19234
+ // src/image.ts
19235
+ init_define_import_meta_env();
19236
+ import { MIME_TYPES as MIME_TYPES2, SVG_NS } from "@excalidraw/common";
19237
+ var loadHTMLImageElement = (dataURL) => {
19238
+ return new Promise((resolve, reject) => {
19239
+ const image = new Image();
19240
+ image.onload = () => {
19241
+ resolve(image);
19242
+ };
19243
+ image.onerror = (error) => {
19244
+ reject(error);
19245
+ };
19246
+ image.src = dataURL;
19247
+ });
19248
+ };
19249
+ var updateImageCache = async ({
19250
+ fileIds,
19251
+ files,
19252
+ imageCache
19253
+ }) => {
19254
+ const updatedFiles = /* @__PURE__ */ new Map();
19255
+ const erroredFiles = /* @__PURE__ */ new Map();
19256
+ await Promise.all(
19257
+ fileIds.reduce((promises, fileId) => {
19258
+ const fileData = files[fileId];
19259
+ if (fileData && !updatedFiles.has(fileId)) {
19260
+ updatedFiles.set(fileId, true);
19261
+ return promises.concat(
19262
+ (async () => {
19263
+ try {
19264
+ if (fileData.mimeType === MIME_TYPES2.binary) {
19265
+ throw new Error("Only images can be added to ImageCache");
19266
+ }
19267
+ const imagePromise = loadHTMLImageElement(fileData.dataURL);
19268
+ const data = {
19269
+ image: imagePromise,
19270
+ mimeType: fileData.mimeType
19271
+ };
19272
+ imageCache.set(fileId, data);
19273
+ const image = await imagePromise;
19274
+ imageCache.set(fileId, { ...data, image });
19275
+ } catch (error) {
19276
+ erroredFiles.set(fileId, true);
19277
+ }
19278
+ })()
19279
+ );
19280
+ }
19281
+ return promises;
19282
+ }, [])
19283
+ );
19284
+ return {
19285
+ imageCache,
19286
+ /** includes errored files because they cache was updated nonetheless */
19287
+ updatedFiles,
19288
+ /** files that failed when creating HTMLImageElement */
19289
+ erroredFiles
19290
+ };
19291
+ };
19292
+ var getInitializedImageElements = (elements) => elements.filter(
19293
+ (element) => isInitializedImageElement(element)
19294
+ );
19295
+ var isHTMLSVGElement = (node) => {
19296
+ return node?.nodeName.toLowerCase() === "svg";
19297
+ };
19298
+ var normalizeSVG = (SVGString) => {
19299
+ const doc = new DOMParser().parseFromString(SVGString, MIME_TYPES2.svg);
19300
+ const svg = doc.querySelector("svg");
19301
+ const errorNode = doc.querySelector("parsererror");
19302
+ if (errorNode || !isHTMLSVGElement(svg)) {
19303
+ throw new Error("Invalid SVG");
19304
+ } else {
19305
+ if (!svg.hasAttribute("xmlns")) {
19306
+ svg.setAttribute("xmlns", SVG_NS);
19307
+ }
19308
+ let width = svg.getAttribute("width");
19309
+ let height = svg.getAttribute("height");
19310
+ if (width?.includes("%") || width === "auto") {
19311
+ width = null;
19312
+ }
19313
+ if (height?.includes("%") || height === "auto") {
19314
+ height = null;
19315
+ }
19316
+ const viewBox = svg.getAttribute("viewBox");
19317
+ if (!width || !height) {
19318
+ width = width || "50";
19319
+ height = height || "50";
19320
+ if (viewBox) {
19321
+ const match = viewBox.match(
19322
+ /\d+ +\d+ +(\d+(?:\.\d+)?) +(\d+(?:\.\d+)?)/
19323
+ );
19324
+ if (match) {
19325
+ [, width, height] = match;
19326
+ }
19327
+ }
19328
+ svg.setAttribute("width", width);
19329
+ svg.setAttribute("height", height);
19330
+ }
19331
+ if (!viewBox) {
19332
+ svg.setAttribute("viewBox", `0 0 ${width} ${height}`);
19333
+ }
19334
+ return svg.outerHTML;
19335
+ }
19336
+ };
19337
+
19338
+ // src/positionElementsOnGrid.ts
19339
+ init_define_import_meta_env();
19340
+ var positionElementsOnGrid = (elements, centerX, centerY, padding = 50) => {
19341
+ if (!elements || elements.length === 0) {
19342
+ return [];
19343
+ }
18034
19344
  const res = [];
18035
19345
  const atomicUnits = Array.isArray(elements[0]) ? elements : elements.map((element) => [element]);
18036
19346
  const numUnits = atomicUnits.length;
@@ -18097,7 +19407,7 @@ init_define_import_meta_env();
18097
19407
  import {
18098
19408
  pointCenter as pointCenter3,
18099
19409
  normalizeRadians as normalizeRadians2,
18100
- pointFrom as pointFrom16,
19410
+ pointFrom as pointFrom17,
18101
19411
  pointRotateRads as pointRotateRads14
18102
19412
  } from "@excalidraw/math";
18103
19413
  import {
@@ -18286,7 +19596,7 @@ var resizeSingleTextElement = (origElement, element, scene, transformHandleType,
18286
19596
  return;
18287
19597
  }
18288
19598
  if (transformHandleType.includes("n") || transformHandleType.includes("s")) {
18289
- const previousOrigin = pointFrom16(origElement.x, origElement.y);
19599
+ const previousOrigin = pointFrom17(origElement.x, origElement.y);
18290
19600
  const newOrigin = getResizedOrigin(
18291
19601
  previousOrigin,
18292
19602
  origElement.width,
@@ -18327,7 +19637,7 @@ var resizeSingleTextElement = (origElement, element, scene, transformHandleType,
18327
19637
  element.lineHeight
18328
19638
  );
18329
19639
  const newHeight = metrics2.height;
18330
- const previousOrigin = pointFrom16(origElement.x, origElement.y);
19640
+ const previousOrigin = pointFrom17(origElement.x, origElement.y);
18331
19641
  const newOrigin = getResizedOrigin(
18332
19642
  previousOrigin,
18333
19643
  origElement.width,
@@ -18365,8 +19675,8 @@ var rotateMultipleElements = (originalElements, elements, scene, pointerX, point
18365
19675
  const cy = (y1 + y2) / 2;
18366
19676
  const origAngle = originalElements.get(element.id)?.angle ?? element.angle;
18367
19677
  const [rotatedCX, rotatedCY] = pointRotateRads14(
18368
- pointFrom16(cx, cy),
18369
- pointFrom16(centerX, centerY),
19678
+ pointFrom17(cx, cy),
19679
+ pointFrom17(centerX, centerY),
18370
19680
  centerAngle + origAngle - element.angle
18371
19681
  );
18372
19682
  const updates = isElbowArrow(element) ? {
@@ -18416,43 +19726,43 @@ var getResizeOffsetXY = (transformHandleType, selectedElements, elementsMap, x,
18416
19726
  const cy = (y1 + y2) / 2;
18417
19727
  const angle = selectedElements.length === 1 ? selectedElements[0].angle : 0;
18418
19728
  [x, y] = pointRotateRads14(
18419
- pointFrom16(x, y),
18420
- pointFrom16(cx, cy),
19729
+ pointFrom17(x, y),
19730
+ pointFrom17(cx, cy),
18421
19731
  -angle
18422
19732
  );
18423
19733
  switch (transformHandleType) {
18424
19734
  case "n":
18425
19735
  return pointRotateRads14(
18426
- pointFrom16(x - (x1 + x2) / 2, y - y1),
18427
- pointFrom16(0, 0),
19736
+ pointFrom17(x - (x1 + x2) / 2, y - y1),
19737
+ pointFrom17(0, 0),
18428
19738
  angle
18429
19739
  );
18430
19740
  case "s":
18431
19741
  return pointRotateRads14(
18432
- pointFrom16(x - (x1 + x2) / 2, y - y2),
18433
- pointFrom16(0, 0),
19742
+ pointFrom17(x - (x1 + x2) / 2, y - y2),
19743
+ pointFrom17(0, 0),
18434
19744
  angle
18435
19745
  );
18436
19746
  case "w":
18437
19747
  return pointRotateRads14(
18438
- pointFrom16(x - x1, y - (y1 + y2) / 2),
18439
- pointFrom16(0, 0),
19748
+ pointFrom17(x - x1, y - (y1 + y2) / 2),
19749
+ pointFrom17(0, 0),
18440
19750
  angle
18441
19751
  );
18442
19752
  case "e":
18443
19753
  return pointRotateRads14(
18444
- pointFrom16(x - x2, y - (y1 + y2) / 2),
18445
- pointFrom16(0, 0),
19754
+ pointFrom17(x - x2, y - (y1 + y2) / 2),
19755
+ pointFrom17(0, 0),
18446
19756
  angle
18447
19757
  );
18448
19758
  case "nw":
18449
- return pointRotateRads14(pointFrom16(x - x1, y - y1), pointFrom16(0, 0), angle);
19759
+ return pointRotateRads14(pointFrom17(x - x1, y - y1), pointFrom17(0, 0), angle);
18450
19760
  case "ne":
18451
- return pointRotateRads14(pointFrom16(x - x2, y - y1), pointFrom16(0, 0), angle);
19761
+ return pointRotateRads14(pointFrom17(x - x2, y - y1), pointFrom17(0, 0), angle);
18452
19762
  case "sw":
18453
- return pointRotateRads14(pointFrom16(x - x1, y - y2), pointFrom16(0, 0), angle);
19763
+ return pointRotateRads14(pointFrom17(x - x1, y - y2), pointFrom17(0, 0), angle);
18454
19764
  case "se":
18455
- return pointRotateRads14(pointFrom16(x - x2, y - y2), pointFrom16(0, 0), angle);
19765
+ return pointRotateRads14(pointFrom17(x - x2, y - y2), pointFrom17(0, 0), angle);
18456
19766
  default:
18457
19767
  return [0, 0];
18458
19768
  }
@@ -18615,10 +19925,10 @@ var resizeSingleElement = (nextWidth, nextHeight, latestElement, origElement, or
18615
19925
  nextHeight,
18616
19926
  true
18617
19927
  );
18618
- let previousOrigin = pointFrom16(origElement.x, origElement.y);
19928
+ let previousOrigin = pointFrom17(origElement.x, origElement.y);
18619
19929
  if (isLinearElement(origElement)) {
18620
19930
  const [x1, y1] = getElementBounds(origElement, originalElementsMap);
18621
- previousOrigin = pointFrom16(x1, y1);
19931
+ previousOrigin = pointFrom17(x1, y1);
18622
19932
  }
18623
19933
  const newOrigin = getResizedOrigin(
18624
19934
  previousOrigin,
@@ -18641,7 +19951,7 @@ var resizeSingleElement = (nextWidth, nextHeight, latestElement, origElement, or
18641
19951
  newOrigin.x += scaledX;
18642
19952
  newOrigin.y += scaledY;
18643
19953
  rescaledPoints.points = rescaledPoints.points.map(
18644
- (p) => pointFrom16(p[0] - scaledX, p[1] - scaledY)
19954
+ (p) => pointFrom17(p[0] - scaledX, p[1] - scaledY)
18645
19955
  );
18646
19956
  }
18647
19957
  if (nextWidth < 0) {
@@ -18717,11 +20027,11 @@ var getNextSingleWidthAndHeightFromPointer = (latestElement, origElement, handle
18717
20027
  origElement.height,
18718
20028
  true
18719
20029
  );
18720
- const startTopLeft = pointFrom16(x1, y1);
18721
- const startBottomRight = pointFrom16(x2, y2);
20030
+ const startTopLeft = pointFrom17(x1, y1);
20031
+ const startBottomRight = pointFrom17(x2, y2);
18722
20032
  const startCenter = pointCenter3(startTopLeft, startBottomRight);
18723
20033
  const rotatedPointer = pointRotateRads14(
18724
- pointFrom16(pointerX, pointerY),
20034
+ pointFrom17(pointerX, pointerY),
18725
20035
  startCenter,
18726
20036
  -origElement.angle
18727
20037
  );
@@ -19091,7 +20401,7 @@ var resizeMultipleElements = (selectedElements, elementsMap, handleDirection, sc
19091
20401
  // src/resizeTest.ts
19092
20402
  init_define_import_meta_env();
19093
20403
  import {
19094
- pointFrom as pointFrom18,
20404
+ pointFrom as pointFrom19,
19095
20405
  pointOnLineSegment,
19096
20406
  pointRotateRads as pointRotateRads16
19097
20407
  } from "@excalidraw/math";
@@ -19104,7 +20414,7 @@ init_define_import_meta_env();
19104
20414
  import {
19105
20415
  DEFAULT_TRANSFORM_HANDLE_SPACING
19106
20416
  } from "@excalidraw/common";
19107
- import { pointFrom as pointFrom17, pointRotateRads as pointRotateRads15 } from "@excalidraw/math";
20417
+ import { pointFrom as pointFrom18, pointRotateRads as pointRotateRads15 } from "@excalidraw/math";
19108
20418
  var transformHandleSizes = {
19109
20419
  mouse: 8,
19110
20420
  pen: 16,
@@ -19146,8 +20456,8 @@ var OMIT_SIDES_FOR_LINE_BACKSLASH = {
19146
20456
  };
19147
20457
  var generateTransformHandle = (x, y, width, height, cx, cy, angle) => {
19148
20458
  const [xx, yy] = pointRotateRads15(
19149
- pointFrom17(x + width / 2, y + height / 2),
19150
- pointFrom17(cx, cy),
20459
+ pointFrom18(x + width / 2, y + height / 2),
20460
+ pointFrom18(cx, cy),
19151
20461
  angle
19152
20462
  );
19153
20463
  return [xx - width / 2, yy - height / 2, width, height];
@@ -19361,14 +20671,14 @@ var resizeTest = (element, elementsMap, appState, x, y, zoom, pointerType, edito
19361
20671
  const SPACING = isImageElement(element) ? 0 : SIDE_RESIZING_THRESHOLD / zoom.value;
19362
20672
  const ZOOMED_SIDE_RESIZING_THRESHOLD = SIDE_RESIZING_THRESHOLD / zoom.value;
19363
20673
  const sides = getSelectionBorders(
19364
- pointFrom18(x1 - SPACING, y1 - SPACING),
19365
- pointFrom18(x2 + SPACING, y2 + SPACING),
19366
- pointFrom18(cx, cy),
20674
+ pointFrom19(x1 - SPACING, y1 - SPACING),
20675
+ pointFrom19(x2 + SPACING, y2 + SPACING),
20676
+ pointFrom19(cx, cy),
19367
20677
  element.angle
19368
20678
  );
19369
20679
  for (const [dir, side] of Object.entries(sides)) {
19370
20680
  if (pointOnLineSegment(
19371
- pointFrom18(x, y),
20681
+ pointFrom19(x, y),
19372
20682
  side,
19373
20683
  ZOOMED_SIDE_RESIZING_THRESHOLD
19374
20684
  )) {
@@ -19417,14 +20727,14 @@ var getTransformHandleTypeFromCoords = ([x1, y1, x2, y2], scenePointerX, scenePo
19417
20727
  const cy = (y1 + y2) / 2;
19418
20728
  const SPACING = SIDE_RESIZING_THRESHOLD / zoom.value;
19419
20729
  const sides = getSelectionBorders(
19420
- pointFrom18(x1 - SPACING, y1 - SPACING),
19421
- pointFrom18(x2 + SPACING, y2 + SPACING),
19422
- pointFrom18(cx, cy),
20730
+ pointFrom19(x1 - SPACING, y1 - SPACING),
20731
+ pointFrom19(x2 + SPACING, y2 + SPACING),
20732
+ pointFrom19(cx, cy),
19423
20733
  0
19424
20734
  );
19425
20735
  for (const [dir, side] of Object.entries(sides)) {
19426
20736
  if (pointOnLineSegment(
19427
- pointFrom18(scenePointerX, scenePointerY),
20737
+ pointFrom19(scenePointerX, scenePointerY),
19428
20738
  side,
19429
20739
  SPACING
19430
20740
  )) {
@@ -19481,10 +20791,10 @@ var getCursorForResizingElement = (resizingElement) => {
19481
20791
  return cursor ? `${cursor}-resize` : "";
19482
20792
  };
19483
20793
  var getSelectionBorders = ([x1, y1], [x2, y2], center, angle) => {
19484
- const topLeft = pointRotateRads16(pointFrom18(x1, y1), center, angle);
19485
- const topRight = pointRotateRads16(pointFrom18(x2, y1), center, angle);
19486
- const bottomLeft = pointRotateRads16(pointFrom18(x1, y2), center, angle);
19487
- const bottomRight = pointRotateRads16(pointFrom18(x2, y2), center, angle);
20794
+ const topLeft = pointRotateRads16(pointFrom19(x1, y1), center, angle);
20795
+ const topRight = pointRotateRads16(pointFrom19(x2, y1), center, angle);
20796
+ const bottomLeft = pointRotateRads16(pointFrom19(x1, y2), center, angle);
20797
+ const bottomRight = pointRotateRads16(pointFrom19(x2, y2), center, angle);
19488
20798
  return {
19489
20799
  n: [topLeft, topRight],
19490
20800
  e: [topRight, bottomRight],
@@ -19497,386 +20807,545 @@ var getSelectionBorders = ([x1, y1], [x2, y2], center, angle) => {
19497
20807
  init_define_import_meta_env();
19498
20808
  var showSelectedShapeActions = (appState, elements) => Boolean(
19499
20809
  !appState.viewModeEnabled && appState.openDialog?.name !== "elementLinkSelector" && (appState.activeTool.type !== "custom" && (appState.editingTextElement || appState.activeTool.type !== "selection" && appState.activeTool.type !== "lasso" && appState.activeTool.type !== "eraser" && appState.activeTool.type !== "hand" && appState.activeTool.type !== "laser") || getSelectedElements(elements, appState).length)
19500
- );
19501
-
19502
- // src/zindex.ts
19503
- init_define_import_meta_env();
19504
- import { arrayToMap as arrayToMap11, findIndex, findLastIndex as findLastIndex2 } from "@excalidraw/common";
19505
- var isOfTargetFrame = (element, frameId) => {
19506
- return element.frameId === frameId || element.id === frameId;
19507
- };
19508
- var getIndicesToMove = (elements, appState, elementsToBeMoved) => {
19509
- let selectedIndices = [];
19510
- let deletedIndices = [];
19511
- let includeDeletedIndex = null;
19512
- let index = -1;
19513
- const selectedElementIds = arrayToMap11(
19514
- elementsToBeMoved ? elementsToBeMoved : getSelectedElements(elements, appState, {
19515
- includeBoundTextElement: true,
19516
- includeElementsInFrames: true
19517
- })
19518
- );
19519
- while (++index < elements.length) {
19520
- const element = elements[index];
19521
- if (selectedElementIds.get(element.id)) {
19522
- if (deletedIndices.length) {
19523
- selectedIndices = selectedIndices.concat(deletedIndices);
19524
- deletedIndices = [];
19525
- }
19526
- selectedIndices.push(index);
19527
- includeDeletedIndex = index + 1;
19528
- } else if (element.isDeleted && includeDeletedIndex === index) {
19529
- includeDeletedIndex = index + 1;
19530
- deletedIndices.push(index);
19531
- } else {
19532
- deletedIndices = [];
19533
- }
19534
- }
19535
- return selectedIndices;
19536
- };
19537
- var toContiguousGroups = (array) => {
19538
- let cursor = 0;
19539
- return array.reduce((acc, value, index) => {
19540
- if (index > 0 && array[index - 1] !== value - 1) {
19541
- cursor = ++cursor;
19542
- }
19543
- (acc[cursor] || (acc[cursor] = [])).push(value);
19544
- return acc;
19545
- }, []);
19546
- };
19547
- var getTargetIndexAccountingForBinding = (nextElement, elements, direction, scene) => {
19548
- if ("containerId" in nextElement && nextElement.containerId) {
19549
- const containerElement = scene.getElement(nextElement.containerId);
19550
- if (containerElement) {
19551
- return direction === "left" ? Math.min(
19552
- elements.indexOf(containerElement),
19553
- elements.indexOf(nextElement)
19554
- ) : Math.max(
19555
- elements.indexOf(containerElement),
19556
- elements.indexOf(nextElement)
19557
- );
19558
- }
19559
- } else {
19560
- const boundElementId = nextElement.boundElements?.find(
19561
- (binding) => binding.type !== "arrow"
19562
- )?.id;
19563
- if (boundElementId) {
19564
- const boundTextElement = scene.getElement(boundElementId);
19565
- if (boundTextElement) {
19566
- return direction === "left" ? Math.min(
19567
- elements.indexOf(boundTextElement),
19568
- elements.indexOf(nextElement)
19569
- ) : Math.max(
19570
- elements.indexOf(boundTextElement),
19571
- elements.indexOf(nextElement)
19572
- );
19573
- }
19574
- }
19575
- }
19576
- };
19577
- var getContiguousFrameRangeElements = (allElements, frameId) => {
19578
- let rangeStart = -1;
19579
- let rangeEnd = -1;
19580
- allElements.forEach((element, index) => {
19581
- if (isOfTargetFrame(element, frameId)) {
19582
- if (rangeStart === -1) {
19583
- rangeStart = index;
19584
- }
19585
- rangeEnd = index;
19586
- }
19587
- });
19588
- if (rangeStart === -1) {
19589
- return [];
19590
- }
19591
- return allElements.slice(rangeStart, rangeEnd + 1);
19592
- };
19593
- var moveArrowAboveBindable2 = (point, arrow, elements, elementsMap, scene) => {
19594
- const hoveredElement = getHoveredElementForBinding(
19595
- point,
19596
- elements,
19597
- elementsMap
19598
- );
19599
- if (!hoveredElement) {
19600
- return elements;
19601
- }
19602
- const boundTextElement = getBoundTextElement(hoveredElement, elementsMap);
19603
- const containerElement = isTextElement(hoveredElement) ? getContainerElement(hoveredElement, elementsMap) : null;
19604
- const bindableIds = [
19605
- hoveredElement.id,
19606
- boundTextElement?.id,
19607
- containerElement?.id
19608
- ].filter((id) => !!id);
19609
- const bindableIdx = elements.findIndex((el) => bindableIds.includes(el.id));
19610
- const arrowIdx = elements.findIndex((el) => el.id === arrow.id);
19611
- if (arrowIdx !== -1 && bindableIdx !== -1 && arrowIdx < bindableIdx) {
19612
- const updatedElements = Array.from(elements);
19613
- const arrow2 = updatedElements.splice(arrowIdx, 1)[0];
19614
- updatedElements.splice(bindableIdx, 0, arrow2);
19615
- scene.replaceAllElements(updatedElements);
19616
- }
19617
- return elements;
19618
- };
19619
- var getTargetIndex = (appState, elements, boundaryIndex, direction, containingFrame, scene) => {
19620
- const sourceElement = elements[boundaryIndex];
19621
- const indexFilter = (element) => {
19622
- if (element.isDeleted) {
19623
- return false;
19624
- }
19625
- if (containingFrame) {
19626
- return element.frameId === containingFrame;
19627
- }
19628
- if (appState.editingGroupId) {
19629
- return element.groupIds.includes(appState.editingGroupId);
19630
- }
19631
- return true;
19632
- };
19633
- const candidateIndex = direction === "left" ? findLastIndex2(
19634
- elements,
19635
- (el) => indexFilter(el),
19636
- Math.max(0, boundaryIndex - 1)
19637
- ) : findIndex(elements, (el) => indexFilter(el), boundaryIndex + 1);
19638
- const nextElement = elements[candidateIndex];
19639
- if (!nextElement) {
19640
- return -1;
19641
- }
19642
- if (appState.editingGroupId) {
19643
- if (
19644
- // candidate element is a sibling in current editing group → return
19645
- sourceElement?.groupIds.join("") === nextElement?.groupIds.join("")
19646
- ) {
19647
- return getTargetIndexAccountingForBinding(
19648
- nextElement,
19649
- elements,
19650
- direction,
19651
- scene
19652
- ) ?? candidateIndex;
19653
- } else if (!nextElement?.groupIds.includes(appState.editingGroupId)) {
19654
- return -1;
19655
- }
19656
- }
19657
- if (!containingFrame && (nextElement.frameId || isFrameLikeElement(nextElement))) {
19658
- const frameElements = getContiguousFrameRangeElements(
19659
- elements,
19660
- nextElement.frameId || nextElement.id
19661
- );
19662
- return direction === "left" ? elements.indexOf(frameElements[0]) : elements.indexOf(frameElements[frameElements.length - 1]);
19663
- }
19664
- if (!nextElement.groupIds.length) {
19665
- return getTargetIndexAccountingForBinding(
19666
- nextElement,
19667
- elements,
19668
- direction,
19669
- scene
19670
- ) ?? candidateIndex;
19671
- }
19672
- const siblingGroupId = appState.editingGroupId ? nextElement.groupIds[nextElement.groupIds.indexOf(appState.editingGroupId) - 1] : nextElement.groupIds[nextElement.groupIds.length - 1];
19673
- const elementsInSiblingGroup = getElementsInGroup(elements, siblingGroupId);
19674
- if (elementsInSiblingGroup.length) {
19675
- return direction === "left" ? elements.indexOf(elementsInSiblingGroup[0]) : elements.indexOf(
19676
- elementsInSiblingGroup[elementsInSiblingGroup.length - 1]
19677
- );
19678
- }
19679
- return candidateIndex;
19680
- };
19681
- var getTargetElementsMap = (elements, indices) => {
19682
- return indices.reduce((acc, index) => {
19683
- const element = elements[index];
19684
- acc.set(element.id, element);
19685
- return acc;
19686
- }, /* @__PURE__ */ new Map());
19687
- };
19688
- var shiftElementsByOne = (elements, appState, direction, scene) => {
19689
- const indicesToMove = getIndicesToMove(elements, appState);
19690
- const targetElementsMap = getTargetElementsMap(elements, indicesToMove);
19691
- let groupedIndices = toContiguousGroups(indicesToMove);
19692
- if (direction === "right") {
19693
- groupedIndices = groupedIndices.reverse();
19694
- }
19695
- const selectedFrames = new Set(
19696
- indicesToMove.filter((idx) => isFrameLikeElement(elements[idx])).map((idx) => elements[idx].id)
19697
- );
19698
- groupedIndices.forEach((indices, i) => {
19699
- const leadingIndex = indices[0];
19700
- const trailingIndex = indices[indices.length - 1];
19701
- const boundaryIndex = direction === "left" ? leadingIndex : trailingIndex;
19702
- const containingFrame = indices.some((idx) => {
19703
- const el = elements[idx];
19704
- return el.frameId && selectedFrames.has(el.frameId);
19705
- }) ? null : elements[boundaryIndex]?.frameId;
19706
- const targetIndex = getTargetIndex(
19707
- appState,
19708
- elements,
19709
- boundaryIndex,
19710
- direction,
19711
- containingFrame,
19712
- scene
19713
- );
19714
- if (targetIndex === -1 || boundaryIndex === targetIndex) {
19715
- return;
19716
- }
19717
- const leadingElements = direction === "left" ? elements.slice(0, targetIndex) : elements.slice(0, leadingIndex);
19718
- const targetElements = elements.slice(leadingIndex, trailingIndex + 1);
19719
- const displacedElements = direction === "left" ? elements.slice(targetIndex, leadingIndex) : elements.slice(trailingIndex + 1, targetIndex + 1);
19720
- const trailingElements = direction === "left" ? elements.slice(trailingIndex + 1) : elements.slice(targetIndex + 1);
19721
- elements = direction === "left" ? [
19722
- ...leadingElements,
19723
- ...targetElements,
19724
- ...displacedElements,
19725
- ...trailingElements
19726
- ] : [
19727
- ...leadingElements,
19728
- ...displacedElements,
19729
- ...targetElements,
19730
- ...trailingElements
19731
- ];
19732
- });
19733
- syncMovedIndices(elements, targetElementsMap);
19734
- return elements;
19735
- };
19736
- var shiftElementsToEnd = (elements, appState, direction, containingFrame, elementsToBeMoved) => {
19737
- const indicesToMove = getIndicesToMove(elements, appState, elementsToBeMoved);
19738
- const targetElementsMap = getTargetElementsMap(elements, indicesToMove);
19739
- const displacedElements = [];
19740
- let leadingIndex;
19741
- let trailingIndex;
19742
- if (direction === "left") {
19743
- if (containingFrame) {
19744
- leadingIndex = findIndex(
19745
- elements,
19746
- (el) => isOfTargetFrame(el, containingFrame)
19747
- );
19748
- } else if (appState.editingGroupId) {
19749
- const groupElements = getElementsInGroup(
19750
- elements,
19751
- appState.editingGroupId
19752
- );
19753
- if (!groupElements.length) {
19754
- return elements;
20810
+ );
20811
+
20812
+ // src/transform.ts
20813
+ init_define_import_meta_env();
20814
+ import { pointFrom as pointFrom20 } from "@excalidraw/math";
20815
+ import {
20816
+ DEFAULT_FONT_FAMILY as DEFAULT_FONT_FAMILY3,
20817
+ DEFAULT_FONT_SIZE as DEFAULT_FONT_SIZE4,
20818
+ TEXT_ALIGN as TEXT_ALIGN2,
20819
+ VERTICAL_ALIGN as VERTICAL_ALIGN4,
20820
+ getSizeFromPoints as getSizeFromPoints3,
20821
+ randomId as randomId4,
20822
+ arrayToMap as arrayToMap12,
20823
+ assertNever as assertNever5,
20824
+ cloneJSON,
20825
+ getFontString as getFontString8,
20826
+ isDevEnv as isDevEnv7,
20827
+ toBrandedType as toBrandedType3,
20828
+ getLineHeight as getLineHeight2
20829
+ } from "@excalidraw/common";
20830
+ var DEFAULT_LINEAR_ELEMENT_PROPS = {
20831
+ width: 100,
20832
+ height: 0
20833
+ };
20834
+ var DEFAULT_DIMENSION = 100;
20835
+ var bindTextToContainer = (container, textProps, scene) => {
20836
+ const textElement = newTextElement({
20837
+ x: 0,
20838
+ y: 0,
20839
+ textAlign: TEXT_ALIGN2.CENTER,
20840
+ verticalAlign: VERTICAL_ALIGN4.MIDDLE,
20841
+ ...textProps,
20842
+ containerId: container.id,
20843
+ strokeColor: textProps.strokeColor || container.strokeColor
20844
+ });
20845
+ Object.assign(container, {
20846
+ boundElements: (container.boundElements || []).concat({
20847
+ type: "text",
20848
+ id: textElement.id
20849
+ })
20850
+ });
20851
+ redrawTextBoundingBox(textElement, container, scene);
20852
+ return [container, textElement];
20853
+ };
20854
+ var bindLinearElementToElement = (linearElement, start, end, elementStore, scene) => {
20855
+ let startBoundElement;
20856
+ let endBoundElement;
20857
+ Object.assign(linearElement, {
20858
+ startBinding: linearElement?.startBinding || null,
20859
+ endBinding: linearElement.endBinding || null
20860
+ });
20861
+ if (start) {
20862
+ const width = start?.width ?? DEFAULT_DIMENSION;
20863
+ const height = start?.height ?? DEFAULT_DIMENSION;
20864
+ let existingElement;
20865
+ if (start.id) {
20866
+ existingElement = elementStore.getElement(start.id);
20867
+ if (!existingElement) {
20868
+ console.error(`No element for start binding with id ${start.id} found`);
20869
+ }
20870
+ }
20871
+ const startX = start.x || linearElement.x - width;
20872
+ const startY = start.y || linearElement.y - height / 2;
20873
+ const startType = existingElement ? existingElement.type : start.type;
20874
+ if (startType) {
20875
+ if (startType === "text") {
20876
+ let text = "";
20877
+ if (existingElement && existingElement.type === "text") {
20878
+ text = existingElement.text;
20879
+ } else if (start.type === "text") {
20880
+ text = start.text;
20881
+ }
20882
+ if (!text) {
20883
+ console.error(
20884
+ `No text found for start binding text element for ${linearElement.id}`
20885
+ );
20886
+ }
20887
+ startBoundElement = newTextElement({
20888
+ x: startX,
20889
+ y: startY,
20890
+ type: "text",
20891
+ ...existingElement,
20892
+ ...start,
20893
+ text
20894
+ });
20895
+ Object.assign(startBoundElement, {
20896
+ x: start.x || linearElement.x - startBoundElement.width,
20897
+ y: start.y || linearElement.y - startBoundElement.height / 2
20898
+ });
20899
+ } else {
20900
+ switch (startType) {
20901
+ case "rectangle":
20902
+ case "ellipse":
20903
+ case "diamond": {
20904
+ startBoundElement = newElement({
20905
+ x: startX,
20906
+ y: startY,
20907
+ width,
20908
+ height,
20909
+ ...existingElement,
20910
+ ...start,
20911
+ type: startType
20912
+ });
20913
+ break;
20914
+ }
20915
+ default: {
20916
+ assertNever5(
20917
+ linearElement,
20918
+ `Unhandled element start type "${start.type}"`,
20919
+ true
20920
+ );
20921
+ }
20922
+ }
19755
20923
  }
19756
- leadingIndex = elements.indexOf(groupElements[0]);
19757
- } else {
19758
- leadingIndex = 0;
19759
- }
19760
- trailingIndex = indicesToMove[indicesToMove.length - 1];
19761
- } else {
19762
- if (containingFrame) {
19763
- trailingIndex = findLastIndex2(
19764
- elements,
19765
- (el) => isOfTargetFrame(el, containingFrame)
19766
- );
19767
- } else if (appState.editingGroupId) {
19768
- const groupElements = getElementsInGroup(
19769
- elements,
19770
- appState.editingGroupId
20924
+ bindBindingElement(
20925
+ linearElement,
20926
+ startBoundElement,
20927
+ "orbit",
20928
+ "start",
20929
+ scene
19771
20930
  );
19772
- if (!groupElements.length) {
19773
- return elements;
20931
+ }
20932
+ }
20933
+ if (end) {
20934
+ const height = end?.height ?? DEFAULT_DIMENSION;
20935
+ const width = end?.width ?? DEFAULT_DIMENSION;
20936
+ let existingElement;
20937
+ if (end.id) {
20938
+ existingElement = elementStore.getElement(end.id);
20939
+ if (!existingElement) {
20940
+ console.error(`No element for end binding with id ${end.id} found`);
20941
+ }
20942
+ }
20943
+ const endX = end.x || linearElement.x + linearElement.width;
20944
+ const endY = end.y || linearElement.y - height / 2;
20945
+ const endType = existingElement ? existingElement.type : end.type;
20946
+ if (endType) {
20947
+ if (endType === "text") {
20948
+ let text = "";
20949
+ if (existingElement && existingElement.type === "text") {
20950
+ text = existingElement.text;
20951
+ } else if (end.type === "text") {
20952
+ text = end.text;
20953
+ }
20954
+ if (!text) {
20955
+ console.error(
20956
+ `No text found for end binding text element for ${linearElement.id}`
20957
+ );
20958
+ }
20959
+ endBoundElement = newTextElement({
20960
+ x: endX,
20961
+ y: endY,
20962
+ type: "text",
20963
+ ...existingElement,
20964
+ ...end,
20965
+ text
20966
+ });
20967
+ Object.assign(endBoundElement, {
20968
+ y: end.y || linearElement.y - endBoundElement.height / 2
20969
+ });
20970
+ } else {
20971
+ switch (endType) {
20972
+ case "rectangle":
20973
+ case "ellipse":
20974
+ case "diamond": {
20975
+ endBoundElement = newElement({
20976
+ x: endX,
20977
+ y: endY,
20978
+ width,
20979
+ height,
20980
+ ...existingElement,
20981
+ ...end,
20982
+ type: endType
20983
+ });
20984
+ break;
20985
+ }
20986
+ default: {
20987
+ assertNever5(
20988
+ linearElement,
20989
+ `Unhandled element end type "${endType}"`,
20990
+ true
20991
+ );
20992
+ }
20993
+ }
19774
20994
  }
19775
- trailingIndex = elements.indexOf(groupElements[groupElements.length - 1]);
19776
- } else {
19777
- trailingIndex = elements.length - 1;
20995
+ bindBindingElement(
20996
+ linearElement,
20997
+ endBoundElement,
20998
+ "orbit",
20999
+ "end",
21000
+ scene
21001
+ );
19778
21002
  }
19779
- leadingIndex = indicesToMove[0];
19780
21003
  }
19781
- if (leadingIndex === -1) {
19782
- leadingIndex = 0;
21004
+ if (linearElement.points.length < 2) {
21005
+ return {
21006
+ linearElement,
21007
+ startBoundElement,
21008
+ endBoundElement
21009
+ };
19783
21010
  }
19784
- for (let index = leadingIndex; index < trailingIndex + 1; index++) {
19785
- if (!indicesToMove.includes(index)) {
19786
- displacedElements.push(elements[index]);
19787
- }
21011
+ const endPointIndex = linearElement.points.length - 1;
21012
+ const delta = 0.5;
21013
+ const newPoints = cloneJSON(linearElement.points);
21014
+ if (linearElement.points[endPointIndex][0] > linearElement.points[endPointIndex - 1][0]) {
21015
+ newPoints[0][0] = delta;
21016
+ newPoints[endPointIndex][0] -= delta;
19788
21017
  }
19789
- const targetElements = Array.from(targetElementsMap.values());
19790
- const leadingElements = elements.slice(0, leadingIndex);
19791
- const trailingElements = elements.slice(trailingIndex + 1);
19792
- const nextElements = direction === "left" ? [
19793
- ...leadingElements,
19794
- ...targetElements,
19795
- ...displacedElements,
19796
- ...trailingElements
19797
- ] : [
19798
- ...leadingElements,
19799
- ...displacedElements,
19800
- ...targetElements,
19801
- ...trailingElements
19802
- ];
19803
- syncMovedIndices(nextElements, targetElementsMap);
19804
- return nextElements;
19805
- };
19806
- function shiftElementsAccountingForFrames(allElements, appState, direction, shiftFunction) {
19807
- const elementsToMove = arrayToMap11(
19808
- getSelectedElements(allElements, appState, {
19809
- includeBoundTextElement: true,
19810
- includeElementsInFrames: true
21018
+ if (linearElement.points[endPointIndex][0] < linearElement.points[endPointIndex - 1][0]) {
21019
+ newPoints[0][0] = -delta;
21020
+ newPoints[endPointIndex][0] += delta;
21021
+ }
21022
+ if (linearElement.points[endPointIndex][1] > linearElement.points[endPointIndex - 1][1]) {
21023
+ newPoints[0][1] = delta;
21024
+ newPoints[endPointIndex][1] -= delta;
21025
+ }
21026
+ if (linearElement.points[endPointIndex][1] < linearElement.points[endPointIndex - 1][1]) {
21027
+ newPoints[0][1] = -delta;
21028
+ newPoints[endPointIndex][1] += delta;
21029
+ }
21030
+ Object.assign(
21031
+ linearElement,
21032
+ LinearElementEditor.getNormalizeElementPointsAndCoords({
21033
+ ...linearElement,
21034
+ points: newPoints
19811
21035
  })
19812
21036
  );
19813
- const frameAwareContiguousElementsToMove = { regularElements: [], frameChildren: /* @__PURE__ */ new Map() };
19814
- const fullySelectedFrames = /* @__PURE__ */ new Set();
19815
- for (const element of allElements) {
19816
- if (elementsToMove.has(element.id) && isFrameLikeElement(element)) {
19817
- fullySelectedFrames.add(element.id);
21037
+ return {
21038
+ linearElement,
21039
+ startBoundElement,
21040
+ endBoundElement
21041
+ };
21042
+ };
21043
+ var ElementStore = class {
21044
+ excalidrawElements = /* @__PURE__ */ new Map();
21045
+ add = (ele) => {
21046
+ if (!ele) {
21047
+ return;
19818
21048
  }
21049
+ this.excalidrawElements.set(ele.id, ele);
21050
+ };
21051
+ getElements = () => {
21052
+ return syncInvalidIndices(Array.from(this.excalidrawElements.values()));
21053
+ };
21054
+ getElementsMap = () => {
21055
+ return toBrandedType3(
21056
+ arrayToMap12(this.getElements())
21057
+ );
21058
+ };
21059
+ getElement = (id) => {
21060
+ return this.excalidrawElements.get(id);
21061
+ };
21062
+ };
21063
+ var convertToExcalidrawElements = (elementsSkeleton, opts) => {
21064
+ if (!elementsSkeleton) {
21065
+ return [];
19819
21066
  }
19820
- for (const element of allElements) {
19821
- if (elementsToMove.has(element.id)) {
19822
- if (isFrameLikeElement(element) || element.frameId && fullySelectedFrames.has(element.frameId)) {
19823
- frameAwareContiguousElementsToMove.regularElements.push(element);
19824
- } else if (!element.frameId) {
19825
- frameAwareContiguousElementsToMove.regularElements.push(element);
19826
- } else {
19827
- const frameChildren = frameAwareContiguousElementsToMove.frameChildren.get(
19828
- element.frameId
19829
- ) || [];
19830
- frameChildren.push(element);
19831
- frameAwareContiguousElementsToMove.frameChildren.set(
19832
- element.frameId,
19833
- frameChildren
21067
+ const elements = cloneJSON(elementsSkeleton);
21068
+ const elementStore = new ElementStore();
21069
+ const elementsWithIds = /* @__PURE__ */ new Map();
21070
+ const oldToNewElementIdMap = /* @__PURE__ */ new Map();
21071
+ for (const element of elements) {
21072
+ let excalidrawElement;
21073
+ const originalId = element.id;
21074
+ if (opts?.regenerateIds !== false) {
21075
+ Object.assign(element, { id: randomId4() });
21076
+ }
21077
+ switch (element.type) {
21078
+ case "rectangle":
21079
+ case "ellipse":
21080
+ case "diamond": {
21081
+ const width = element?.label?.text && element.width === void 0 ? 0 : element?.width || DEFAULT_DIMENSION;
21082
+ const height = element?.label?.text && element.height === void 0 ? 0 : element?.height || DEFAULT_DIMENSION;
21083
+ excalidrawElement = newElement({
21084
+ ...element,
21085
+ width,
21086
+ height
21087
+ });
21088
+ break;
21089
+ }
21090
+ case "line": {
21091
+ const width = element.width || DEFAULT_LINEAR_ELEMENT_PROPS.width;
21092
+ const height = element.height || DEFAULT_LINEAR_ELEMENT_PROPS.height;
21093
+ excalidrawElement = newLinearElement({
21094
+ width,
21095
+ height,
21096
+ points: [pointFrom20(0, 0), pointFrom20(width, height)],
21097
+ ...element
21098
+ });
21099
+ break;
21100
+ }
21101
+ case "arrow": {
21102
+ const width = element.width || DEFAULT_LINEAR_ELEMENT_PROPS.width;
21103
+ const height = element.height || DEFAULT_LINEAR_ELEMENT_PROPS.height;
21104
+ excalidrawElement = newArrowElement({
21105
+ width,
21106
+ height,
21107
+ endArrowhead: "arrow",
21108
+ points: [pointFrom20(0, 0), pointFrom20(width, height)],
21109
+ ...element,
21110
+ type: "arrow"
21111
+ });
21112
+ Object.assign(
21113
+ excalidrawElement,
21114
+ getSizeFromPoints3(excalidrawElement.points)
21115
+ );
21116
+ break;
21117
+ }
21118
+ case "text": {
21119
+ const fontFamily = element?.fontFamily || DEFAULT_FONT_FAMILY3;
21120
+ const fontSize = element?.fontSize || DEFAULT_FONT_SIZE4;
21121
+ const lineHeight = element?.lineHeight || getLineHeight2(fontFamily);
21122
+ const text = element.text ?? "";
21123
+ const normalizedText = normalizeText(text);
21124
+ const metrics = measureText(
21125
+ normalizedText,
21126
+ getFontString8({ fontFamily, fontSize }),
21127
+ lineHeight
21128
+ );
21129
+ excalidrawElement = newTextElement({
21130
+ width: metrics.width,
21131
+ height: metrics.height,
21132
+ fontFamily,
21133
+ fontSize,
21134
+ ...element
21135
+ });
21136
+ break;
21137
+ }
21138
+ case "image": {
21139
+ excalidrawElement = newImageElement({
21140
+ width: element?.width || DEFAULT_DIMENSION,
21141
+ height: element?.height || DEFAULT_DIMENSION,
21142
+ ...element
21143
+ });
21144
+ break;
21145
+ }
21146
+ case "frame": {
21147
+ excalidrawElement = newFrameElement({
21148
+ x: 0,
21149
+ y: 0,
21150
+ ...element
21151
+ });
21152
+ break;
21153
+ }
21154
+ case "magicframe": {
21155
+ excalidrawElement = newMagicFrameElement({
21156
+ x: 0,
21157
+ y: 0,
21158
+ ...element
21159
+ });
21160
+ break;
21161
+ }
21162
+ case "freedraw":
21163
+ case "iframe":
21164
+ case "embeddable": {
21165
+ excalidrawElement = element;
21166
+ break;
21167
+ }
21168
+ default: {
21169
+ excalidrawElement = element;
21170
+ assertNever5(
21171
+ element,
21172
+ `Unhandled element type "${element.type}"`,
21173
+ true
19834
21174
  );
19835
21175
  }
19836
21176
  }
21177
+ const existingElement = elementStore.getElement(excalidrawElement.id);
21178
+ if (existingElement) {
21179
+ console.error(`Duplicate id found for ${excalidrawElement.id}`);
21180
+ } else {
21181
+ elementStore.add(excalidrawElement);
21182
+ elementsWithIds.set(excalidrawElement.id, element);
21183
+ if (originalId) {
21184
+ oldToNewElementIdMap.set(originalId, excalidrawElement.id);
21185
+ }
21186
+ }
21187
+ }
21188
+ const elementsMap = elementStore.getElementsMap();
21189
+ const scene = new Scene(elementsMap);
21190
+ for (const [id, element] of elementsWithIds) {
21191
+ const excalidrawElement = elementStore.getElement(id);
21192
+ switch (element.type) {
21193
+ case "rectangle":
21194
+ case "ellipse":
21195
+ case "diamond":
21196
+ case "arrow": {
21197
+ if (element.label?.text) {
21198
+ let [container, text] = bindTextToContainer(
21199
+ excalidrawElement,
21200
+ element?.label,
21201
+ scene
21202
+ );
21203
+ elementStore.add(container);
21204
+ elementStore.add(text);
21205
+ if (isArrowElement(container)) {
21206
+ const originalStart = element.type === "arrow" ? element?.start : void 0;
21207
+ const originalEnd = element.type === "arrow" ? element?.end : void 0;
21208
+ if (originalStart && originalStart.id) {
21209
+ const newStartId = oldToNewElementIdMap.get(originalStart.id);
21210
+ if (newStartId) {
21211
+ Object.assign(originalStart, { id: newStartId });
21212
+ }
21213
+ }
21214
+ if (originalEnd && originalEnd.id) {
21215
+ const newEndId = oldToNewElementIdMap.get(originalEnd.id);
21216
+ if (newEndId) {
21217
+ Object.assign(originalEnd, { id: newEndId });
21218
+ }
21219
+ }
21220
+ const { linearElement, startBoundElement, endBoundElement } = bindLinearElementToElement(
21221
+ container,
21222
+ originalStart,
21223
+ originalEnd,
21224
+ elementStore,
21225
+ scene
21226
+ );
21227
+ container = linearElement;
21228
+ elementStore.add(linearElement);
21229
+ elementStore.add(startBoundElement);
21230
+ elementStore.add(endBoundElement);
21231
+ }
21232
+ } else {
21233
+ switch (element.type) {
21234
+ case "arrow": {
21235
+ const { start, end } = element;
21236
+ if (start && start.id) {
21237
+ const newStartId = oldToNewElementIdMap.get(start.id);
21238
+ Object.assign(start, { id: newStartId });
21239
+ }
21240
+ if (end && end.id) {
21241
+ const newEndId = oldToNewElementIdMap.get(end.id);
21242
+ Object.assign(end, { id: newEndId });
21243
+ }
21244
+ const { linearElement, startBoundElement, endBoundElement } = bindLinearElementToElement(
21245
+ excalidrawElement,
21246
+ start,
21247
+ end,
21248
+ elementStore,
21249
+ scene
21250
+ );
21251
+ elementStore.add(linearElement);
21252
+ elementStore.add(startBoundElement);
21253
+ elementStore.add(endBoundElement);
21254
+ break;
21255
+ }
21256
+ }
21257
+ }
21258
+ break;
21259
+ }
21260
+ }
19837
21261
  }
19838
- let nextElements = allElements;
19839
- const frameChildrenSets = Array.from(
19840
- frameAwareContiguousElementsToMove.frameChildren.entries()
19841
- );
19842
- for (const [frameId, children] of frameChildrenSets) {
19843
- nextElements = shiftFunction(
19844
- allElements,
19845
- appState,
19846
- direction,
19847
- frameId,
19848
- children
19849
- );
21262
+ for (const [id, element] of elementsWithIds) {
21263
+ if (element.type !== "frame" && element.type !== "magicframe") {
21264
+ continue;
21265
+ }
21266
+ const frame = elementStore.getElement(id);
21267
+ if (!frame) {
21268
+ throw new Error(`Excalidraw element with id ${id} doesn't exist`);
21269
+ }
21270
+ const childrenElements = [];
21271
+ element.children.forEach((id2) => {
21272
+ const newElementId = oldToNewElementIdMap.get(id2);
21273
+ if (!newElementId) {
21274
+ throw new Error(`Element with ${id2} wasn't mapped correctly`);
21275
+ }
21276
+ const elementInFrame = elementStore.getElement(newElementId);
21277
+ if (!elementInFrame) {
21278
+ throw new Error(`Frame element with id ${newElementId} doesn't exist`);
21279
+ }
21280
+ Object.assign(elementInFrame, { frameId: frame.id });
21281
+ elementInFrame?.boundElements?.forEach((boundElement) => {
21282
+ const ele = elementStore.getElement(boundElement.id);
21283
+ if (!ele) {
21284
+ throw new Error(
21285
+ `Bound element with id ${boundElement.id} doesn't exist`
21286
+ );
21287
+ }
21288
+ Object.assign(ele, { frameId: frame.id });
21289
+ childrenElements.push(ele);
21290
+ });
21291
+ childrenElements.push(elementInFrame);
21292
+ });
21293
+ let [minX, minY, maxX, maxY] = getCommonBounds(childrenElements);
21294
+ const PADDING = 10;
21295
+ minX = minX - PADDING;
21296
+ minY = minY - PADDING;
21297
+ maxX = maxX + PADDING;
21298
+ maxY = maxY + PADDING;
21299
+ const frameX = frame?.x || minX;
21300
+ const frameY = frame?.y || minY;
21301
+ const frameWidth = frame?.width || maxX - minX;
21302
+ const frameHeight = frame?.height || maxY - minY;
21303
+ Object.assign(frame, {
21304
+ x: frameX,
21305
+ y: frameY,
21306
+ width: frameWidth,
21307
+ height: frameHeight
21308
+ });
21309
+ if (isDevEnv7() && element.children.length && (frame?.x || frame?.y || frame?.width || frame?.height)) {
21310
+ console.info(
21311
+ "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"
21312
+ );
21313
+ }
19850
21314
  }
19851
- return shiftFunction(
19852
- nextElements,
19853
- appState,
19854
- direction,
19855
- null,
19856
- frameAwareContiguousElementsToMove.regularElements
19857
- );
19858
- }
19859
- var moveOneLeft = (allElements, appState, scene) => {
19860
- return shiftElementsByOne(allElements, appState, "left", scene);
19861
- };
19862
- var moveOneRight = (allElements, appState, scene) => {
19863
- return shiftElementsByOne(allElements, appState, "right", scene);
19864
- };
19865
- var moveAllLeft = (allElements, appState) => {
19866
- return shiftElementsAccountingForFrames(
19867
- allElements,
19868
- appState,
19869
- "left",
19870
- shiftElementsToEnd
19871
- );
21315
+ return elementStore.getElements();
19872
21316
  };
19873
- var moveAllRight = (allElements, appState) => {
19874
- return shiftElementsAccountingForFrames(
19875
- allElements,
19876
- appState,
19877
- "right",
19878
- shiftElementsToEnd
19879
- );
21317
+
21318
+ // src/arrows/helpers.ts
21319
+ init_define_import_meta_env();
21320
+ var maybeHandleArrowPointlikeDrag = ({
21321
+ app,
21322
+ event
21323
+ }) => {
21324
+ const appState = app.state;
21325
+ if (appState.selectedLinearElement && app.lastPointerMoveCoords) {
21326
+ if (appState.selectedLinearElement.draggedFocusPointBinding) {
21327
+ handleFocusPointDrag(
21328
+ appState.selectedLinearElement,
21329
+ app.scene.getNonDeletedElementsMap(),
21330
+ app.lastPointerMoveCoords,
21331
+ app.scene,
21332
+ appState,
21333
+ app.getEffectiveGridSize(),
21334
+ event.altKey
21335
+ );
21336
+ return true;
21337
+ } else if (appState.selectedLinearElement.hoverPointIndex !== null && app.lastPointerMoveEvent && appState.selectedLinearElement.initialState.lastClickedPoint >= 0 && appState.selectedLinearElement.isDragging) {
21338
+ LinearElementEditor.handlePointDragging(
21339
+ app.lastPointerMoveEvent,
21340
+ app,
21341
+ app.lastPointerMoveCoords.x,
21342
+ app.lastPointerMoveCoords.y,
21343
+ appState.selectedLinearElement
21344
+ );
21345
+ return true;
21346
+ }
21347
+ }
21348
+ return false;
19880
21349
  };
19881
21350
 
19882
21351
  // src/index.ts
@@ -19916,13 +21385,13 @@ export {
19916
21385
  ElementBounds,
19917
21386
  ElementsDelta,
19918
21387
  EphemeralIncrement,
21388
+ FOCUS_POINT_SIZE,
19919
21389
  FlowChartCreator,
19920
21390
  FlowChartNavigator,
19921
21391
  HEADING_DOWN,
19922
21392
  HEADING_LEFT,
19923
21393
  HEADING_RIGHT,
19924
21394
  HEADING_UP,
19925
- IMAGE_INVERT_FILTER,
19926
21395
  INVISIBLY_SMALL_ELEMENT_SIZE,
19927
21396
  InvalidFractionalIndexError,
19928
21397
  LinearElementEditor,
@@ -19962,6 +21431,7 @@ export {
19962
21431
  computeBoundTextPosition,
19963
21432
  computeContainerDimensionForBoundText,
19964
21433
  containsCJK,
21434
+ convertToExcalidrawElements,
19965
21435
  createPlaceholderEmbeddableLabel,
19966
21436
  createSrcDoc,
19967
21437
  cropElement,
@@ -19991,7 +21461,6 @@ export {
19991
21461
  fixDuplicatedBindingsAfterDuplication,
19992
21462
  flipHeading,
19993
21463
  frameAndChildrenSelectedTogether,
19994
- generateFreeDrawShape,
19995
21464
  generateLinearCollisionShape,
19996
21465
  generateRoughOptions,
19997
21466
  getAllHoveredElementAtPoint,
@@ -20002,6 +21471,7 @@ export {
20002
21471
  getArrowheadPoints,
20003
21472
  getArrowheadSize,
20004
21473
  getBindingGap,
21474
+ getBindingSideMidPoint,
20005
21475
  getBindingStrategyForDraggingBindingElementEndpoints,
20006
21476
  getBoundTextElement,
20007
21477
  getBoundTextElementId,
@@ -20043,14 +21513,13 @@ export {
20043
21513
  getFrameChildren,
20044
21514
  getFrameLikeElements,
20045
21515
  getFrameLikeTitle,
20046
- getFreeDrawPath2D,
20047
- getFreeDrawSvgPath,
20048
21516
  getFreedrawOutlineAsSegments,
20049
21517
  getFreedrawOutlinePoints,
20050
21518
  getGlobalFixedPointForBindableElement,
20051
21519
  getGlobalFixedPoints,
20052
21520
  getHeadingForElbowArrowSnap,
20053
21521
  getHoveredElementForBinding,
21522
+ getHoveredElementForFocusPoint,
20054
21523
  getInitializedImageElements,
20055
21524
  getLineHeightInPx,
20056
21525
  getLineWidth,
@@ -20103,6 +21572,10 @@ export {
20103
21572
  groupsAreAtLeastIntersectingTheFrame,
20104
21573
  groupsAreCompletelyOutOfFrame,
20105
21574
  handleBindTextResize,
21575
+ handleFocusPointDrag,
21576
+ handleFocusPointHover,
21577
+ handleFocusPointPointerDown,
21578
+ handleFocusPointPointerUp,
20106
21579
  hasBackground,
20107
21580
  hasBoundTextElement,
20108
21581
  hasBoundingBox,
@@ -20129,7 +21602,6 @@ export {
20129
21602
  isBindingElementType,
20130
21603
  isBindingEnabled,
20131
21604
  isBoundToContainer,
20132
- isBounds,
20133
21605
  isCursorInFrame,
20134
21606
  isCurvedArrow,
20135
21607
  isElbowArrow,
@@ -20143,6 +21615,7 @@ export {
20143
21615
  isEmbeddableElement,
20144
21616
  isExcalidrawElement,
20145
21617
  isFlowchartNodeElement,
21618
+ isFocusPointVisible,
20146
21619
  isFrameElement,
20147
21620
  isFrameLikeElement,
20148
21621
  isFreeDrawElement,
@@ -20178,6 +21651,7 @@ export {
20178
21651
  loadHTMLImageElement,
20179
21652
  makeNextSelectedElementIds,
20180
21653
  maxBindingDistance_simple,
21654
+ maybeHandleArrowPointlikeDrag,
20181
21655
  maybeParseEmbedSrc,
20182
21656
  measureFontSizeFromWidth,
20183
21657
  measureText,
@@ -20208,7 +21682,6 @@ export {
20208
21682
  originalContainerCache,
20209
21683
  parseElementLinkFromURL,
20210
21684
  parseTokens,
20211
- pathsCache,
20212
21685
  pointInsideBounds,
20213
21686
  positionElementsOnGrid,
20214
21687
  projectFixedPointOntoDiagonal,