@excalidraw/excalidraw 0.17.1-c0b80a0 → 0.17.1-c329470

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 (178) hide show
  1. package/dist/browser/dev/excalidraw-assets-dev/{chunk-JGDL4H2X.js → chunk-3DLVY5XU.js} +8272 -6864
  2. package/dist/browser/dev/excalidraw-assets-dev/chunk-3DLVY5XU.js.map +7 -0
  3. package/dist/browser/dev/excalidraw-assets-dev/{chunk-V7NFEZA6.js → chunk-NOAEU4NM.js} +9 -2
  4. package/dist/browser/dev/excalidraw-assets-dev/chunk-NOAEU4NM.js.map +7 -0
  5. package/dist/browser/dev/excalidraw-assets-dev/{en-ZSVWGT55.js → en-7IBTMWBG.js} +2 -2
  6. package/dist/browser/dev/excalidraw-assets-dev/{image-RJG3J34Y.js → image-N5AC7SEK.js} +2 -6
  7. package/dist/browser/dev/index.css +85 -50
  8. package/dist/browser/dev/index.css.map +3 -3
  9. package/dist/browser/dev/index.js +4375 -3766
  10. package/dist/browser/dev/index.js.map +4 -4
  11. package/dist/browser/prod/excalidraw-assets/{chunk-LDVEIXGO.js → chunk-7CSIPVOW.js} +2 -2
  12. package/dist/browser/prod/excalidraw-assets/chunk-TX3BU7T2.js +47 -0
  13. package/dist/browser/prod/excalidraw-assets/{en-UPNEHLDS.js → en-LOGQBETY.js} +1 -1
  14. package/dist/browser/prod/excalidraw-assets/image-3V4U7GZE.js +1 -0
  15. package/dist/browser/prod/index.css +1 -1
  16. package/dist/browser/prod/index.js +40 -40
  17. package/dist/dev/index.css +85 -50
  18. package/dist/dev/index.css.map +3 -3
  19. package/dist/dev/index.js +8688 -6706
  20. package/dist/dev/index.js.map +4 -4
  21. package/dist/{prod/locales/en-ZXYG7GCR.json → dev/locales/en-V6KXFSCK.json} +8 -1
  22. package/dist/excalidraw/actions/actionAlign.d.ts +7 -6
  23. package/dist/excalidraw/actions/actionAlign.js +14 -14
  24. package/dist/excalidraw/actions/actionClipboard.d.ts +7 -3
  25. package/dist/excalidraw/actions/actionDeleteSelected.d.ts +7 -3
  26. package/dist/excalidraw/actions/actionDeleteSelected.js +103 -34
  27. package/dist/excalidraw/actions/actionDuplicateSelection.js +105 -95
  28. package/dist/excalidraw/actions/actionFlip.js +16 -7
  29. package/dist/excalidraw/actions/actionFrame.d.ts +493 -0
  30. package/dist/excalidraw/actions/actionFrame.js +45 -2
  31. package/dist/excalidraw/actions/actionGroup.js +6 -4
  32. package/dist/excalidraw/actions/actionProperties.js +145 -116
  33. package/dist/excalidraw/actions/actionSelectAll.js +4 -3
  34. package/dist/excalidraw/actions/shortcuts.d.ts +1 -1
  35. package/dist/excalidraw/actions/shortcuts.js +1 -0
  36. package/dist/excalidraw/actions/types.d.ts +1 -1
  37. package/dist/excalidraw/align.d.ts +2 -1
  38. package/dist/excalidraw/align.js +15 -6
  39. package/dist/excalidraw/clipboard.d.ts +27 -5
  40. package/dist/excalidraw/clipboard.js +55 -28
  41. package/dist/excalidraw/components/Actions.d.ts +2 -1
  42. package/dist/excalidraw/components/Actions.js +4 -2
  43. package/dist/excalidraw/components/ActiveConfirmDialog.d.ts +1 -1
  44. package/dist/excalidraw/components/ActiveConfirmDialog.js +2 -3
  45. package/dist/excalidraw/components/App.d.ts +1 -0
  46. package/dist/excalidraw/components/App.js +216 -111
  47. package/dist/excalidraw/components/ColorPicker/ColorInput.js +2 -3
  48. package/dist/excalidraw/components/ColorPicker/ColorPicker.js +2 -3
  49. package/dist/excalidraw/components/ColorPicker/CustomColorList.js +1 -1
  50. package/dist/excalidraw/components/ColorPicker/Picker.js +1 -1
  51. package/dist/excalidraw/components/ColorPicker/PickerColorList.js +1 -1
  52. package/dist/excalidraw/components/ColorPicker/ShadeList.js +1 -1
  53. package/dist/excalidraw/components/ColorPicker/colorPickerUtils.d.ts +1 -1
  54. package/dist/excalidraw/components/ColorPicker/colorPickerUtils.js +1 -1
  55. package/dist/excalidraw/components/CommandPalette/CommandPalette.js +3 -3
  56. package/dist/excalidraw/components/ConfirmDialog.js +17 -5
  57. package/dist/excalidraw/components/Dialog.js +2 -3
  58. package/dist/excalidraw/components/EyeDropper.d.ts +1 -1
  59. package/dist/excalidraw/components/EyeDropper.js +1 -1
  60. package/dist/excalidraw/components/IconPicker.d.ts +2 -2
  61. package/dist/excalidraw/components/IconPicker.js +56 -53
  62. package/dist/excalidraw/components/LayerUI.js +6 -6
  63. package/dist/excalidraw/components/LibraryMenu.d.ts +2 -16
  64. package/dist/excalidraw/components/LibraryMenu.js +70 -28
  65. package/dist/excalidraw/components/LibraryMenuHeaderContent.js +4 -5
  66. package/dist/excalidraw/components/MobileMenu.js +1 -1
  67. package/dist/excalidraw/components/OverwriteConfirm/OverwriteConfirm.js +2 -3
  68. package/dist/excalidraw/components/OverwriteConfirm/OverwriteConfirmState.d.ts +1 -1
  69. package/dist/excalidraw/components/OverwriteConfirm/OverwriteConfirmState.js +2 -3
  70. package/dist/excalidraw/components/Range.d.ts +9 -0
  71. package/dist/excalidraw/components/Range.js +24 -0
  72. package/dist/excalidraw/components/SearchMenu.d.ts +1 -1
  73. package/dist/excalidraw/components/SearchMenu.js +3 -4
  74. package/dist/excalidraw/components/Sidebar/Sidebar.d.ts +1 -1
  75. package/dist/excalidraw/components/Sidebar/Sidebar.js +2 -3
  76. package/dist/excalidraw/components/Stats/Collapsible.d.ts +2 -1
  77. package/dist/excalidraw/components/Stats/Collapsible.js +2 -2
  78. package/dist/excalidraw/components/Stats/Dimension.js +94 -8
  79. package/dist/excalidraw/components/Stats/MultiDimension.js +8 -5
  80. package/dist/excalidraw/components/Stats/Position.js +63 -3
  81. package/dist/excalidraw/components/Stats/index.js +21 -4
  82. package/dist/excalidraw/components/Stats/utils.d.ts +1 -1
  83. package/dist/excalidraw/components/Stats/utils.js +2 -55
  84. package/dist/excalidraw/components/TTDDialog/TTDDialog.js +1 -1
  85. package/dist/excalidraw/components/ToolButton.js +4 -9
  86. package/dist/excalidraw/components/hoc/withInternalFallback.js +3 -3
  87. package/dist/excalidraw/components/hyperlink/Hyperlink.js +6 -12
  88. package/dist/excalidraw/components/icons.d.ts +9 -0
  89. package/dist/excalidraw/components/icons.js +4 -4
  90. package/dist/excalidraw/components/main-menu/DefaultItems.js +2 -3
  91. package/dist/excalidraw/constants.d.ts +5 -1
  92. package/dist/excalidraw/constants.js +9 -1
  93. package/dist/excalidraw/context/tunnels.d.ts +2 -1
  94. package/dist/excalidraw/context/tunnels.js +3 -1
  95. package/dist/excalidraw/data/blob.d.ts +1 -0
  96. package/dist/excalidraw/data/blob.js +7 -3
  97. package/dist/excalidraw/data/filesystem.d.ts +2 -1
  98. package/dist/excalidraw/data/filesystem.js +1 -0
  99. package/dist/excalidraw/data/image.d.ts +0 -6
  100. package/dist/excalidraw/data/image.js +1 -43
  101. package/dist/excalidraw/data/index.js +6 -6
  102. package/dist/excalidraw/data/library.d.ts +9 -3
  103. package/dist/excalidraw/data/library.js +43 -6
  104. package/dist/excalidraw/data/restore.js +26 -8
  105. package/dist/excalidraw/data/url.d.ts +0 -1
  106. package/dist/excalidraw/data/url.js +2 -4
  107. package/dist/excalidraw/editor-jotai.d.ts +56 -0
  108. package/dist/excalidraw/editor-jotai.js +8 -0
  109. package/dist/excalidraw/element/binding.d.ts +9 -6
  110. package/dist/excalidraw/element/binding.js +124 -44
  111. package/dist/excalidraw/element/bounds.js +10 -0
  112. package/dist/excalidraw/element/cropElement.d.ts +5 -0
  113. package/dist/excalidraw/element/cropElement.js +28 -1
  114. package/dist/excalidraw/element/dragElements.js +13 -7
  115. package/dist/excalidraw/element/elbowArrow.d.ts +16 -0
  116. package/dist/excalidraw/element/elbowArrow.js +1268 -0
  117. package/dist/excalidraw/element/embeddable.js +4 -5
  118. package/dist/excalidraw/element/flowchart.d.ts +1 -1
  119. package/dist/excalidraw/element/flowchart.js +25 -9
  120. package/dist/excalidraw/element/heading.d.ts +5 -1
  121. package/dist/excalidraw/element/heading.js +5 -1
  122. package/dist/excalidraw/element/image.js +19 -5
  123. package/dist/excalidraw/element/linearElementEditor.d.ts +9 -10
  124. package/dist/excalidraw/element/linearElementEditor.js +97 -38
  125. package/dist/excalidraw/element/mutateElement.d.ts +3 -1
  126. package/dist/excalidraw/element/mutateElement.js +31 -4
  127. package/dist/excalidraw/element/newElement.d.ts +8 -12
  128. package/dist/excalidraw/element/newElement.js +36 -21
  129. package/dist/excalidraw/element/resizeElements.d.ts +20 -5
  130. package/dist/excalidraw/element/resizeElements.js +593 -361
  131. package/dist/excalidraw/element/sortElements.js +1 -4
  132. package/dist/excalidraw/element/types.d.ts +23 -1
  133. package/dist/excalidraw/fonts/Fonts.d.ts +0 -16
  134. package/dist/excalidraw/fonts/Fonts.js +6 -31
  135. package/dist/excalidraw/frame.d.ts +11 -5
  136. package/dist/excalidraw/frame.js +146 -35
  137. package/dist/excalidraw/groups.js +3 -0
  138. package/dist/excalidraw/hooks/useLibraryItemSvg.d.ts +1 -1
  139. package/dist/excalidraw/hooks/useLibraryItemSvg.js +2 -3
  140. package/dist/excalidraw/hooks/useScrollPosition.js +1 -1
  141. package/dist/excalidraw/i18n.js +3 -4
  142. package/dist/excalidraw/index.js +3 -4
  143. package/dist/excalidraw/locales/en.json +8 -1
  144. package/dist/excalidraw/renderer/interactiveScene.js +43 -32
  145. package/dist/excalidraw/renderer/staticScene.js +6 -4
  146. package/dist/excalidraw/renderer/staticSvgScene.js +1 -1
  147. package/dist/excalidraw/scene/Shape.js +40 -17
  148. package/dist/excalidraw/scene/comparisons.d.ts +0 -477
  149. package/dist/excalidraw/scene/comparisons.js +0 -37
  150. package/dist/excalidraw/scene/export.d.ts +7 -0
  151. package/dist/excalidraw/scene/export.js +107 -43
  152. package/dist/excalidraw/scene/index.d.ts +1 -1
  153. package/dist/excalidraw/scene/index.js +1 -1
  154. package/dist/excalidraw/scene/selection.js +4 -1
  155. package/dist/excalidraw/types.d.ts +15 -0
  156. package/dist/excalidraw/utility-types.d.ts +1 -0
  157. package/dist/excalidraw/utils.d.ts +8 -1
  158. package/dist/excalidraw/utils.js +9 -0
  159. package/dist/excalidraw/visualdebug.d.ts +8 -1
  160. package/dist/excalidraw/visualdebug.js +3 -0
  161. package/dist/math/line.d.ts +19 -0
  162. package/dist/math/line.js +32 -3
  163. package/dist/math/point.d.ts +10 -0
  164. package/dist/math/point.js +12 -1
  165. package/dist/prod/index.css +1 -1
  166. package/dist/prod/index.js +29 -44
  167. package/dist/{dev/locales/en-ZXYG7GCR.json → prod/locales/en-V6KXFSCK.json} +8 -1
  168. package/package.json +5 -2
  169. package/dist/browser/dev/excalidraw-assets-dev/chunk-JGDL4H2X.js.map +0 -7
  170. package/dist/browser/dev/excalidraw-assets-dev/chunk-V7NFEZA6.js.map +0 -7
  171. package/dist/browser/prod/excalidraw-assets/chunk-S2XKB3DE.js +0 -62
  172. package/dist/browser/prod/excalidraw-assets/image-OFI2YYMP.js +0 -1
  173. package/dist/excalidraw/element/routing.d.ts +0 -12
  174. package/dist/excalidraw/element/routing.js +0 -642
  175. package/dist/excalidraw/jotai.d.ts +0 -34
  176. package/dist/excalidraw/jotai.js +0 -18
  177. /package/dist/browser/dev/excalidraw-assets-dev/{en-ZSVWGT55.js.map → en-7IBTMWBG.js.map} +0 -0
  178. /package/dist/browser/dev/excalidraw-assets-dev/{image-RJG3J34Y.js.map → image-N5AC7SEK.js.map} +0 -0
@@ -1,11 +1,10 @@
1
1
  import { register } from "../actions/register";
2
2
  import { FONT_FAMILY, VERTICAL_ALIGN } from "../constants";
3
- import { getFontString, updateActiveTool } from "../utils";
3
+ import { escapeDoubleQuotes, getFontString, updateActiveTool } from "../utils";
4
4
  import { setCursorForShape } from "../cursor";
5
5
  import { newTextElement } from "./newElement";
6
6
  import { wrapText } from "./textWrapping";
7
7
  import { isIframeElement } from "./typeChecks";
8
- import { sanitizeHTMLAttribute } from "../data/url";
9
8
  import { StoreAction } from "../store";
10
9
  const embeddedLinkCache = new Map();
11
10
  const RE_YOUTUBE = /^(?:http(?:s)?:\/\/)?(?:www\.)?youtu(?:be\.com|\.be)\/(embed\/|watch\?v=|shorts\/|playlist\?list=|embed\/videoseries\?list=)?([a-zA-Z0-9_-]+)(?:\?t=|&t=|\?start=|&start=)?([a-zA-Z0-9_-]+)?[^\s]*$/;
@@ -162,7 +161,7 @@ export const getEmbedLink = (link) => {
162
161
  // Note that we don't attempt to parse the username as it can consist of
163
162
  // non-latin1 characters, and the username in the url can be set to anything
164
163
  // without affecting the embed.
165
- const safeURL = sanitizeHTMLAttribute(`https://twitter.com/x/status/${postId}`);
164
+ const safeURL = escapeDoubleQuotes(`https://twitter.com/x/status/${postId}`);
166
165
  const ret = {
167
166
  type: "document",
168
167
  srcdoc: (theme) => createSrcDoc(`<blockquote class="twitter-tweet" data-dnt="true" data-theme="${theme}"><a href="${safeURL}"></a></blockquote> <script async src="https://platform.twitter.com/widgets.js" charset="utf-8"></script>`),
@@ -174,7 +173,7 @@ export const getEmbedLink = (link) => {
174
173
  }
175
174
  if (RE_REDDIT.test(link)) {
176
175
  const [, page, postId, title] = link.match(RE_REDDIT);
177
- const safeURL = sanitizeHTMLAttribute(`https://reddit.com/r/${page}/comments/${postId}/${title}`);
176
+ const safeURL = escapeDoubleQuotes(`https://reddit.com/r/${page}/comments/${postId}/${title}`);
178
177
  const ret = {
179
178
  type: "document",
180
179
  srcdoc: (theme) => createSrcDoc(`<blockquote class="reddit-embed-bq" data-embed-theme="${theme}"><a href="${safeURL}"></a><br></blockquote><script async="" src="https://embed.reddit.com/widgets.js" charset="UTF-8"></script>`),
@@ -186,7 +185,7 @@ export const getEmbedLink = (link) => {
186
185
  }
187
186
  if (RE_GH_GIST.test(link)) {
188
187
  const [, user, gistId] = link.match(RE_GH_GIST);
189
- const safeURL = sanitizeHTMLAttribute(`https://gist.github.com/${user}/${gistId}`);
188
+ const safeURL = escapeDoubleQuotes(`https://gist.github.com/${user}/${gistId}`);
190
189
  const ret = {
191
190
  type: "document",
192
191
  srcdoc: () => createSrcDoc(`
@@ -1,4 +1,4 @@
1
- import type { ElementsMap, ExcalidrawBindableElement, ExcalidrawElement, ExcalidrawFlowchartNodeElement } from "./types";
1
+ import { type ElementsMap, type ExcalidrawBindableElement, type ExcalidrawElement, type ExcalidrawFlowchartNodeElement } from "./types";
2
2
  import type { AppState, PendingExcalidrawElements } from "../types";
3
3
  type LinkDirection = "up" | "right" | "down" | "left";
4
4
  export declare const getLinkDirectionFromKey: (key: string) => LinkDirection;
@@ -6,9 +6,10 @@ import { KEYS } from "../keys";
6
6
  import { mutateElement } from "./mutateElement";
7
7
  import { elementOverlapsWithFrame, elementsAreInFrameBounds } from "../frame";
8
8
  import { isBindableElement, isElbowArrow, isFrameElement, isFlowchartNodeElement, } from "./typeChecks";
9
- import { invariant } from "../utils";
9
+ import { invariant, toBrandedType } from "../utils";
10
10
  import { pointFrom } from "../../math";
11
11
  import { aabbForElement } from "../shapes";
12
+ import { updateElbowArrowPoints } from "./elbowArrow";
12
13
  const VERTICAL_OFFSET = 100;
13
14
  const HORIZONTAL_OFFSET = 100;
14
15
  export const getLinkDirectionFromKey = (key) => {
@@ -158,6 +159,9 @@ const addNewNode = (element, elementsMap, appState, direction) => {
158
159
  backgroundColor: element.backgroundColor,
159
160
  strokeColor: element.strokeColor,
160
161
  strokeWidth: element.strokeWidth,
162
+ opacity: element.opacity,
163
+ fillStyle: element.fillStyle,
164
+ strokeStyle: element.strokeStyle,
161
165
  });
162
166
  invariant(isFlowchartNodeElement(nextNode), "not an ExcalidrawFlowchartNodeElement");
163
167
  const bindingArrow = createBindingArrow(element, nextNode, elementsMap, direction, appState);
@@ -208,6 +212,9 @@ export const addNewNodes = (startNode, elementsMap, appState, direction, numberO
208
212
  backgroundColor: startNode.backgroundColor,
209
213
  strokeColor: startNode.strokeColor,
210
214
  strokeWidth: startNode.strokeWidth,
215
+ opacity: startNode.opacity,
216
+ fillStyle: startNode.fillStyle,
217
+ strokeStyle: startNode.strokeStyle,
211
218
  });
212
219
  invariant(isFlowchartNodeElement(nextNode), "not an ExcalidrawFlowchartNodeElement");
213
220
  const bindingArrow = createBindingArrow(startNode, nextNode, elementsMap, direction, appState);
@@ -270,11 +277,13 @@ const createBindingArrow = (startBindingElement, endBindingElement, elementsMap,
270
277
  type: "arrow",
271
278
  x: startX,
272
279
  y: startY,
273
- startArrowhead: appState.currentItemStartArrowhead,
280
+ startArrowhead: null,
274
281
  endArrowhead: appState.currentItemEndArrowhead,
275
- strokeColor: appState.currentItemStrokeColor,
276
- strokeStyle: appState.currentItemStrokeStyle,
277
- strokeWidth: appState.currentItemStrokeWidth,
282
+ strokeColor: startBindingElement.strokeColor,
283
+ strokeStyle: startBindingElement.strokeStyle,
284
+ strokeWidth: startBindingElement.strokeWidth,
285
+ opacity: startBindingElement.opacity,
286
+ roughness: startBindingElement.roughness,
278
287
  points: [pointFrom(0, 0), pointFrom(endX, endY)],
279
288
  elbowed: true,
280
289
  });
@@ -289,10 +298,17 @@ const createBindingArrow = (startBindingElement, endBindingElement, elementsMap,
289
298
  index: 1,
290
299
  point: bindingArrow.points[1],
291
300
  },
292
- ], elementsMap, undefined, {
293
- changedElements,
294
- });
295
- return bindingArrow;
301
+ ]);
302
+ const update = updateElbowArrowPoints(bindingArrow, toBrandedType(new Map([
303
+ ...elementsMap.entries(),
304
+ [startBindingElement.id, startBindingElement],
305
+ [endBindingElement.id, endBindingElement],
306
+ [bindingArrow.id, bindingArrow],
307
+ ])), { points: bindingArrow.points });
308
+ return {
309
+ ...bindingArrow,
310
+ ...update,
311
+ };
296
312
  };
297
313
  export class FlowChartNavigator {
298
314
  isExploring = false;
@@ -7,6 +7,10 @@ export declare const HEADING_UP: Heading;
7
7
  export type Heading = [1, 0] | [0, 1] | [-1, 0] | [0, -1];
8
8
  export declare const headingForDiamond: <Point extends GlobalPoint | LocalPoint>(a: Point, b: Point) => Heading;
9
9
  export declare const vectorToHeading: (vec: Vector) => Heading;
10
+ export declare const headingForPoint: <P extends GlobalPoint | LocalPoint>(p: P, o: P) => Heading;
11
+ export declare const headingForPointIsHorizontal: <P extends GlobalPoint | LocalPoint>(p: P, o: P) => boolean;
10
12
  export declare const compareHeading: (a: Heading, b: Heading) => boolean;
11
- export declare const headingForPointFromElement: <Point extends GlobalPoint | LocalPoint>(element: Readonly<ExcalidrawBindableElement>, aabb: readonly [minX: number, minY: number, maxX: number, maxY: number], p: Readonly<LocalPoint | GlobalPoint>) => Heading;
13
+ export declare const headingIsHorizontal: (a: Heading) => boolean;
14
+ export declare const headingIsVertical: (a: Heading) => boolean;
15
+ export declare const headingForPointFromElement: <Point extends GlobalPoint | LocalPoint>(element: Readonly<ExcalidrawBindableElement>, aabb: readonly [minX: number, minY: number, maxX: number, maxY: number], p: Readonly<Point>) => Heading;
12
16
  export declare const flipHeading: (h: Heading) => Heading;
@@ -1,4 +1,4 @@
1
- import { pointFrom, pointRotateRads, pointScaleFromOrigin, radiansToDegrees, triangleIncludesPoint, } from "../../math";
1
+ import { pointFrom, pointRotateRads, pointScaleFromOrigin, radiansToDegrees, triangleIncludesPoint, vectorFromPoint, } from "../../math";
2
2
  import { getCenterForBounds } from "./bounds";
3
3
  export const HEADING_RIGHT = [1, 0];
4
4
  export const HEADING_DOWN = [0, 1];
@@ -32,7 +32,11 @@ export const vectorToHeading = (vec) => {
32
32
  }
33
33
  return HEADING_UP;
34
34
  };
35
+ export const headingForPoint = (p, o) => vectorToHeading(vectorFromPoint(p, o));
36
+ export const headingForPointIsHorizontal = (p, o) => headingIsHorizontal(headingForPoint(p, o));
35
37
  export const compareHeading = (a, b) => a[0] === b[0] && a[1] === b[1];
38
+ export const headingIsHorizontal = (a) => compareHeading(a, HEADING_RIGHT) || compareHeading(a, HEADING_LEFT);
39
+ export const headingIsVertical = (a) => !headingIsHorizontal(a);
36
40
  // Gets the heading for the point by creating a bounding box around the rotated
37
41
  // close fitting bounding box, then creating 4 search cones around the center of
38
42
  // the external bbox.
@@ -72,12 +72,22 @@ export const normalizeSVG = (SVGString) => {
72
72
  if (!svg.hasAttribute("xmlns")) {
73
73
  svg.setAttribute("xmlns", SVG_NS);
74
74
  }
75
- if (!svg.hasAttribute("width") || !svg.hasAttribute("height")) {
76
- const viewBox = svg.getAttribute("viewBox");
77
- let width = svg.getAttribute("width") || "50";
78
- let height = svg.getAttribute("height") || "50";
75
+ let width = svg.getAttribute("width");
76
+ let height = svg.getAttribute("height");
77
+ // Do not use % or auto values for width/height
78
+ // to avoid scaling issues when rendering at different sizes/zoom levels
79
+ if (width?.includes("%") || width === "auto") {
80
+ width = null;
81
+ }
82
+ if (height?.includes("%") || height === "auto") {
83
+ height = null;
84
+ }
85
+ const viewBox = svg.getAttribute("viewBox");
86
+ if (!width || !height) {
87
+ width = width || "50";
88
+ height = height || "50";
79
89
  if (viewBox) {
80
- const match = viewBox.match(/\d+ +\d+ +(\d+) +(\d+)/);
90
+ const match = viewBox.match(/\d+ +\d+ +(\d+(?:\.\d+)?) +(\d+(?:\.\d+)?)/);
81
91
  if (match) {
82
92
  [, width, height] = match;
83
93
  }
@@ -85,6 +95,10 @@ export const normalizeSVG = (SVGString) => {
85
95
  svg.setAttribute("width", width);
86
96
  svg.setAttribute("height", height);
87
97
  }
98
+ // Make sure viewBox is set
99
+ if (!viewBox) {
100
+ svg.setAttribute("viewBox", `0 0 ${width} ${height}`);
101
+ }
88
102
  return svg.outerHTML;
89
103
  }
90
104
  };
@@ -1,7 +1,7 @@
1
1
  /// <reference types="react" />
2
- import type { NonDeleted, ExcalidrawLinearElement, ExcalidrawElement, PointBinding, ExcalidrawBindableElement, ExcalidrawTextElementWithContainer, ElementsMap, NonDeletedSceneElementsMap, OrderedExcalidrawElement, SceneElementsMap } from "./types";
2
+ import type { NonDeleted, ExcalidrawLinearElement, ExcalidrawElement, PointBinding, ExcalidrawBindableElement, ExcalidrawTextElementWithContainer, ElementsMap, NonDeletedSceneElementsMap, SceneElementsMap, ExcalidrawElbowArrowElement } from "./types";
3
3
  import type { Bounds } from "./bounds";
4
- import type { AppState, PointerCoords, InteractiveCanvasAppState, AppClassProperties, NullableGridSize } from "../types";
4
+ import type { AppState, PointerCoords, InteractiveCanvasAppState, AppClassProperties, NullableGridSize, Zoom } from "../types";
5
5
  import type { Store } from "../store";
6
6
  import type Scene from "../scene/Scene";
7
7
  import { type GlobalPoint, type LocalPoint } from "../../math";
@@ -49,7 +49,7 @@ export declare class LinearElementEditor {
49
49
  * @param id the `elementId` from the instance of this class (so that we can
50
50
  * statically guarantee this method returns an ExcalidrawLinearElement)
51
51
  */
52
- static getElement(id: InstanceType<typeof LinearElementEditor>["elementId"], elementsMap: ElementsMap): NonDeleted<ExcalidrawLinearElement> | null;
52
+ static getElement<T extends ExcalidrawLinearElement>(id: InstanceType<typeof LinearElementEditor>["elementId"], elementsMap: ElementsMap): T | null;
53
53
  static handleBoxSelection(event: PointerEvent, appState: AppState, setState: React.Component<any, AppState>["setState"], elementsMap: NonDeletedSceneElementsMap): false | undefined;
54
54
  /** @returns whether point was dragged */
55
55
  static handlePointDragging(event: PointerEvent, app: AppClassProperties, scenePointerX: number, scenePointerY: number, maybeSuggestBinding: (element: NonDeleted<ExcalidrawLinearElement>, pointSceneCoords: {
@@ -63,7 +63,7 @@ export declare class LinearElementEditor {
63
63
  x: number;
64
64
  y: number;
65
65
  }, appState: AppState, elementsMap: ElementsMap) => GlobalPoint | null;
66
- static isSegmentTooShort(element: NonDeleted<ExcalidrawLinearElement>, startPoint: GlobalPoint | LocalPoint, endPoint: GlobalPoint | LocalPoint, zoom: AppState["zoom"]): boolean;
66
+ static isSegmentTooShort<P extends GlobalPoint | LocalPoint>(element: NonDeleted<ExcalidrawLinearElement>, startPoint: P, endPoint: P, index: number, zoom: Zoom): boolean;
67
67
  static getSegmentMidPoint(element: NonDeleted<ExcalidrawLinearElement>, startPoint: GlobalPoint, endPoint: GlobalPoint, endPointIndex: number, elementsMap: ElementsMap): GlobalPoint;
68
68
  static getSegmentMidPointIndex(linearElementEditor: LinearElementEditor, appState: AppState, midPoint: GlobalPoint, elementsMap: ElementsMap): number;
69
69
  static handlePointerDown(event: React.PointerEvent<HTMLElement>, app: AppClassProperties, store: Store, scenePointer: {
@@ -97,20 +97,17 @@ export declare class LinearElementEditor {
97
97
  };
98
98
  static normalizePoints(element: NonDeleted<ExcalidrawLinearElement>): void;
99
99
  static duplicateSelectedPoints(appState: AppState, elementsMap: NonDeletedSceneElementsMap | SceneElementsMap): AppState;
100
- static deletePoints(element: NonDeleted<ExcalidrawLinearElement>, pointIndices: readonly number[], elementsMap: NonDeletedSceneElementsMap | SceneElementsMap): void;
100
+ static deletePoints(element: NonDeleted<ExcalidrawLinearElement>, pointIndices: readonly number[]): void;
101
101
  static addPoints(element: NonDeleted<ExcalidrawLinearElement>, targetPoints: {
102
102
  point: LocalPoint;
103
- }[], elementsMap: NonDeletedSceneElementsMap | SceneElementsMap): void;
103
+ }[]): void;
104
104
  static movePoints(element: NonDeleted<ExcalidrawLinearElement>, targetPoints: {
105
105
  index: number;
106
106
  point: LocalPoint;
107
107
  isDragging?: boolean;
108
- }[], elementsMap: NonDeletedSceneElementsMap | SceneElementsMap, otherUpdates?: {
108
+ }[], otherUpdates?: {
109
109
  startBinding?: PointBinding | null;
110
110
  endBinding?: PointBinding | null;
111
- }, options?: {
112
- changedElements?: Map<string, OrderedExcalidrawElement>;
113
- isDragging?: boolean;
114
111
  }): void;
115
112
  static shouldAddMidpoint(linearElementEditor: LinearElementEditor, pointerCoords: PointerCoords, appState: AppState, elementsMap: ElementsMap): boolean;
116
113
  static addMidpoint(linearElementEditor: LinearElementEditor, pointerCoords: PointerCoords, app: AppClassProperties, snapToGrid: boolean, elementsMap: ElementsMap): {
@@ -125,5 +122,7 @@ export declare class LinearElementEditor {
125
122
  };
126
123
  static getMinMaxXYWithBoundText: (element: ExcalidrawLinearElement, elementsMap: ElementsMap, elementBounds: Bounds, boundTextElement: ExcalidrawTextElementWithContainer) => [number, number, number, number, number, number];
127
124
  static getElementAbsoluteCoords: (element: ExcalidrawLinearElement, elementsMap: ElementsMap, includeBoundText?: boolean) => [number, number, number, number, number, number];
125
+ static moveFixedSegment(linearElement: LinearElementEditor, index: number, x: number, y: number, elementsMap: ElementsMap): LinearElementEditor;
126
+ static deleteFixedSegment(element: ExcalidrawElbowArrowElement, index: number): void;
128
127
  }
129
128
  export {};
@@ -2,16 +2,16 @@ import { getElementAbsoluteCoords, getLockedLinearCursorAlignSize } from ".";
2
2
  import { getCurvePathOps, getElementPointsCoords, getMinMaxXYFromCurvePathOps, } from "./bounds";
3
3
  import { mutateElement } from "./mutateElement";
4
4
  import { bindOrUnbindLinearElement, getHoveredElementForBinding, isBindingEnabled, } from "./binding";
5
- import { invariant, toBrandedType, tupleToCoors } from "../utils";
5
+ import { invariant, tupleToCoors } from "../utils";
6
6
  import { isBindingElement, isElbowArrow, isFixedPointBinding, } from "./typeChecks";
7
7
  import { KEYS, shouldRotateWithDiscreteAngle } from "../keys";
8
8
  import { getBoundTextElement, handleBindTextResize } from "./textElement";
9
9
  import { DRAGGING_THRESHOLD } from "../constants";
10
10
  import { ShapeCache } from "../scene/ShapeCache";
11
- import { mutateElbowArrow } from "./routing";
12
- import { pointCenter, pointFrom, pointRotateRads, pointsEqual, vector, pointDistance, } from "../../math";
11
+ import { pointCenter, pointFrom, pointRotateRads, pointsEqual, vector, pointDistance, pointTranslate, vectorFromPoint, } from "../../math";
13
12
  import { getBezierCurveLength, getBezierXY, getControlPointsForBezierCurve, isPathALoop, mapIntervalToBezierT, } from "../shapes";
14
13
  import { getGridPoint } from "../snapping";
14
+ import { headingIsHorizontal, vectorToHeading } from "./heading";
15
15
  const editorMidPointsCache = { version: null, points: [], zoom: null };
16
16
  export class LinearElementEditor {
17
17
  elementId;
@@ -151,7 +151,7 @@ export class LinearElementEditor {
151
151
  point: pointFrom(width + referencePoint[0], height + referencePoint[1]),
152
152
  isDragging: selectedIndex === lastClickedPoint,
153
153
  },
154
- ], elementsMap);
154
+ ]);
155
155
  }
156
156
  else {
157
157
  const newDraggingPointPosition = LinearElementEditor.createPointAt(element, elementsMap, scenePointerX - linearElementEditor.pointerOffset.x, scenePointerY - linearElementEditor.pointerOffset.y, event[KEYS.CTRL_OR_CMD] ? null : app.getEffectiveGridSize());
@@ -166,7 +166,7 @@ export class LinearElementEditor {
166
166
  point: newPointPosition,
167
167
  isDragging: pointIndex === lastClickedPoint,
168
168
  };
169
- }), elementsMap);
169
+ }));
170
170
  }
171
171
  const boundTextElement = getBoundTextElement(element, elementsMap);
172
172
  if (boundTextElement) {
@@ -212,10 +212,10 @@ export class LinearElementEditor {
212
212
  ? element.points[element.points.length - 1]
213
213
  : element.points[0],
214
214
  },
215
- ], elementsMap);
215
+ ]);
216
216
  }
217
217
  const bindingElement = isBindingEnabled(appState)
218
- ? getHoveredElementForBinding(tupleToCoors(LinearElementEditor.getPointAtIndexGlobalCoordinates(element, selectedPoint, elementsMap)), elements, elementsMap)
218
+ ? getHoveredElementForBinding(tupleToCoors(LinearElementEditor.getPointAtIndexGlobalCoordinates(element, selectedPoint, elementsMap)), elements, elementsMap, appState.zoom, isElbowArrow(element), isElbowArrow(element))
219
219
  : null;
220
220
  bindings[selectedPoint === 0 ? "startBindingElement" : "endBindingElement"] = bindingElement;
221
221
  }
@@ -244,7 +244,8 @@ export class LinearElementEditor {
244
244
  static getEditorMidPoints = (element, elementsMap, appState) => {
245
245
  const boundText = getBoundTextElement(element, elementsMap);
246
246
  // Since its not needed outside editor unless 2 pointer lines or bound text
247
- if (!appState.editingLinearElement &&
247
+ if (!isElbowArrow(element) &&
248
+ !appState.editingLinearElement &&
248
249
  element.points.length > 2 &&
249
250
  !boundText) {
250
251
  return [];
@@ -261,7 +262,7 @@ export class LinearElementEditor {
261
262
  let index = 0;
262
263
  const midpoints = [];
263
264
  while (index < points.length - 1) {
264
- if (LinearElementEditor.isSegmentTooShort(element, element.points[index], element.points[index + 1], appState.zoom)) {
265
+ if (LinearElementEditor.isSegmentTooShort(element, element.points[index], element.points[index + 1], index, appState.zoom)) {
265
266
  midpoints.push(null);
266
267
  index++;
267
268
  continue;
@@ -281,14 +282,16 @@ export class LinearElementEditor {
281
282
  return null;
282
283
  }
283
284
  const clickedPointIndex = LinearElementEditor.getPointIndexUnderCursor(element, elementsMap, appState.zoom, scenePointer.x, scenePointer.y);
284
- if (clickedPointIndex >= 0) {
285
+ if (!isElbowArrow(element) && clickedPointIndex >= 0) {
285
286
  return null;
286
287
  }
287
288
  const points = LinearElementEditor.getPointsGlobalCoordinates(element, elementsMap);
288
- if (points.length >= 3 && !appState.editingLinearElement) {
289
+ if (points.length >= 3 &&
290
+ !appState.editingLinearElement &&
291
+ !isElbowArrow(element)) {
289
292
  return null;
290
293
  }
291
- const threshold = LinearElementEditor.POINT_HANDLE_SIZE / appState.zoom.value;
294
+ const threshold = (LinearElementEditor.POINT_HANDLE_SIZE + 1) / appState.zoom.value;
292
295
  const existingSegmentMidpointHitCoords = linearElementEditor.segmentMidPointHoveredCoords;
293
296
  if (existingSegmentMidpointHitCoords) {
294
297
  const distance = pointDistance(pointFrom(existingSegmentMidpointHitCoords[0], existingSegmentMidpointHitCoords[1]), pointFrom(scenePointer.x, scenePointer.y));
@@ -300,7 +303,7 @@ export class LinearElementEditor {
300
303
  const midPoints = LinearElementEditor.getEditorMidPoints(element, elementsMap, appState);
301
304
  while (index < midPoints.length) {
302
305
  if (midPoints[index] !== null) {
303
- const distance = pointDistance(pointFrom(midPoints[index][0], midPoints[index][1]), pointFrom(scenePointer.x, scenePointer.y));
306
+ const distance = pointDistance(midPoints[index], pointFrom(scenePointer.x, scenePointer.y));
304
307
  if (distance <= threshold) {
305
308
  return midPoints[index];
306
309
  }
@@ -309,8 +312,15 @@ export class LinearElementEditor {
309
312
  }
310
313
  return null;
311
314
  };
312
- static isSegmentTooShort(element, startPoint, endPoint, zoom) {
313
- let distance = pointDistance(pointFrom(startPoint[0], startPoint[1]), pointFrom(endPoint[0], endPoint[1]));
315
+ static isSegmentTooShort(element, startPoint, endPoint, index, zoom) {
316
+ if (isElbowArrow(element)) {
317
+ if (index >= 0 && index < element.points.length) {
318
+ return (pointDistance(startPoint, endPoint) * zoom.value <
319
+ LinearElementEditor.POINT_HANDLE_SIZE / 2);
320
+ }
321
+ return false;
322
+ }
323
+ let distance = pointDistance(startPoint, endPoint);
314
324
  if (element.points.length > 2 && element.roundness) {
315
325
  distance = getBezierCurveLength(element, endPoint);
316
326
  }
@@ -364,9 +374,8 @@ export class LinearElementEditor {
364
374
  if (segmentMidpoint) {
365
375
  segmentMidpointIndex = LinearElementEditor.getSegmentMidPointIndex(linearElementEditor, appState, segmentMidpoint, elementsMap);
366
376
  }
367
- if (event.altKey && appState.editingLinearElement) {
368
- if (linearElementEditor.lastUncommittedPoint == null &&
369
- !isElbowArrow(element)) {
377
+ else if (event.altKey && appState.editingLinearElement) {
378
+ if (linearElementEditor.lastUncommittedPoint == null) {
370
379
  mutateElement(element, {
371
380
  points: [
372
381
  ...element.points,
@@ -391,7 +400,7 @@ export class LinearElementEditor {
391
400
  },
392
401
  selectedPointsIndices: [element.points.length - 1],
393
402
  lastUncommittedPoint: null,
394
- endBindingElement: getHoveredElementForBinding(scenePointer, elements, elementsMap),
403
+ endBindingElement: getHoveredElementForBinding(scenePointer, elements, elementsMap, app.state.zoom, linearElementEditor.elbowed),
395
404
  };
396
405
  ret.didAddPoint = true;
397
406
  return ret;
@@ -473,7 +482,7 @@ export class LinearElementEditor {
473
482
  const lastPoint = points[points.length - 1];
474
483
  if (!event.altKey) {
475
484
  if (lastPoint === lastUncommittedPoint) {
476
- LinearElementEditor.deletePoints(element, [points.length - 1], elementsMap);
485
+ LinearElementEditor.deletePoints(element, [points.length - 1]);
477
486
  }
478
487
  return {
479
488
  ...appState.editingLinearElement,
@@ -497,10 +506,10 @@ export class LinearElementEditor {
497
506
  index: element.points.length - 1,
498
507
  point: newPoint,
499
508
  },
500
- ], elementsMap);
509
+ ]);
501
510
  }
502
511
  else {
503
- LinearElementEditor.addPoints(element, [{ point: newPoint }], elementsMap);
512
+ LinearElementEditor.addPoints(element, [{ point: newPoint }]);
504
513
  }
505
514
  return {
506
515
  ...appState.editingLinearElement,
@@ -633,7 +642,7 @@ export class LinearElementEditor {
633
642
  index: element.points.length - 1,
634
643
  point: pointFrom(lastPoint[0] + 30, lastPoint[1] + 30),
635
644
  },
636
- ], elementsMap);
645
+ ]);
637
646
  }
638
647
  return {
639
648
  ...appState,
@@ -643,7 +652,7 @@ export class LinearElementEditor {
643
652
  },
644
653
  };
645
654
  }
646
- static deletePoints(element, pointIndices, elementsMap) {
655
+ static deletePoints(element, pointIndices) {
647
656
  let offsetX = 0;
648
657
  let offsetY = 0;
649
658
  const isDeletingOriginPoint = pointIndices.includes(0);
@@ -666,15 +675,15 @@ export class LinearElementEditor {
666
675
  }
667
676
  return acc;
668
677
  }, []);
669
- LinearElementEditor._updatePoints(element, nextPoints, offsetX, offsetY, elementsMap);
678
+ LinearElementEditor._updatePoints(element, nextPoints, offsetX, offsetY);
670
679
  }
671
- static addPoints(element, targetPoints, elementsMap) {
680
+ static addPoints(element, targetPoints) {
672
681
  const offsetX = 0;
673
682
  const offsetY = 0;
674
683
  const nextPoints = [...element.points, ...targetPoints.map((x) => x.point)];
675
- LinearElementEditor._updatePoints(element, nextPoints, offsetX, offsetY, elementsMap);
684
+ LinearElementEditor._updatePoints(element, nextPoints, offsetX, offsetY);
676
685
  }
677
- static movePoints(element, targetPoints, elementsMap, otherUpdates, options) {
686
+ static movePoints(element, targetPoints, otherUpdates) {
678
687
  const { points } = element;
679
688
  // in case we're moving start point, instead of modifying its position
680
689
  // which would break the invariant of it being at [0,0], we move
@@ -702,9 +711,8 @@ export class LinearElementEditor {
702
711
  }
703
712
  return offsetX || offsetY ? pointFrom(p[0] - offsetX, p[1] - offsetY) : p;
704
713
  });
705
- LinearElementEditor._updatePoints(element, nextPoints, offsetX, offsetY, elementsMap, otherUpdates, {
714
+ LinearElementEditor._updatePoints(element, nextPoints, offsetX, offsetY, otherUpdates, {
706
715
  isDragging: targetPoints.reduce((dragging, targetPoint) => dragging || targetPoint.isDragging === true, false),
707
- changedElements: options?.changedElements,
708
716
  });
709
717
  }
710
718
  static shouldAddMidpoint(linearElementEditor, pointerCoords, appState, elementsMap) {
@@ -761,27 +769,27 @@ export class LinearElementEditor {
761
769
  ret.selectedPointsIndices = [segmentMidpoint.index];
762
770
  return ret;
763
771
  }
764
- static _updatePoints(element, nextPoints, offsetX, offsetY, elementsMap, otherUpdates, options) {
772
+ static _updatePoints(element, nextPoints, offsetX, offsetY, otherUpdates, options) {
765
773
  if (isElbowArrow(element)) {
766
- const bindings = {};
774
+ const updates = {};
767
775
  if (otherUpdates?.startBinding !== undefined) {
768
- bindings.startBinding =
776
+ updates.startBinding =
769
777
  otherUpdates.startBinding !== null &&
770
778
  isFixedPointBinding(otherUpdates.startBinding)
771
779
  ? otherUpdates.startBinding
772
780
  : null;
773
781
  }
774
782
  if (otherUpdates?.endBinding !== undefined) {
775
- bindings.endBinding =
783
+ updates.endBinding =
776
784
  otherUpdates.endBinding !== null &&
777
785
  isFixedPointBinding(otherUpdates.endBinding)
778
786
  ? otherUpdates.endBinding
779
787
  : null;
780
788
  }
781
- const mergedElementsMap = options?.changedElements
782
- ? toBrandedType(new Map([...elementsMap, ...options.changedElements]))
783
- : elementsMap;
784
- mutateElbowArrow(element, mergedElementsMap, nextPoints, vector(offsetX, offsetY), bindings, {
789
+ updates.points = Array.from(nextPoints);
790
+ updates.points[0] = pointTranslate(updates.points[0], vector(offsetX, offsetY));
791
+ updates.points[updates.points.length - 1] = pointTranslate(updates.points[updates.points.length - 1], vector(offsetX, offsetY));
792
+ mutateElement(element, updates, true, {
785
793
  isDragging: options?.isDragging,
786
794
  });
787
795
  }
@@ -927,6 +935,57 @@ export class LinearElementEditor {
927
935
  }
928
936
  return coords;
929
937
  };
938
+ static moveFixedSegment(linearElement, index, x, y, elementsMap) {
939
+ const element = LinearElementEditor.getElement(linearElement.elementId, elementsMap);
940
+ if (!element || !isElbowArrow(element)) {
941
+ return linearElement;
942
+ }
943
+ if (index && index > 0 && index < element.points.length) {
944
+ const isHorizontal = headingIsHorizontal(vectorToHeading(vectorFromPoint(element.points[index], element.points[index - 1])));
945
+ const fixedSegments = (element.fixedSegments ?? []).reduce((segments, s) => {
946
+ segments[s.index] = s;
947
+ return segments;
948
+ }, {});
949
+ fixedSegments[index] = {
950
+ index,
951
+ start: pointFrom(!isHorizontal ? x - element.x : element.points[index - 1][0], isHorizontal ? y - element.y : element.points[index - 1][1]),
952
+ end: pointFrom(!isHorizontal ? x - element.x : element.points[index][0], isHorizontal ? y - element.y : element.points[index][1]),
953
+ };
954
+ const nextFixedSegments = Object.values(fixedSegments).sort((a, b) => a.index - b.index);
955
+ const offset = nextFixedSegments
956
+ .map((segment) => segment.index)
957
+ .reduce((count, idx) => (idx < index ? count + 1 : count), 0);
958
+ mutateElement(element, {
959
+ fixedSegments: nextFixedSegments,
960
+ });
961
+ const point = pointFrom(element.x +
962
+ (element.fixedSegments[offset].start[0] +
963
+ element.fixedSegments[offset].end[0]) /
964
+ 2, element.y +
965
+ (element.fixedSegments[offset].start[1] +
966
+ element.fixedSegments[offset].end[1]) /
967
+ 2);
968
+ return {
969
+ ...linearElement,
970
+ segmentMidPointHoveredCoords: point,
971
+ pointerDownState: {
972
+ ...linearElement.pointerDownState,
973
+ segmentMidpoint: {
974
+ added: false,
975
+ index: element.fixedSegments[offset].index,
976
+ value: point,
977
+ },
978
+ },
979
+ };
980
+ }
981
+ return linearElement;
982
+ }
983
+ static deleteFixedSegment(element, index) {
984
+ mutateElement(element, {
985
+ fixedSegments: element.fixedSegments?.filter((segment) => segment.index !== index),
986
+ });
987
+ mutateElement(element, {}, true);
988
+ }
930
989
  }
931
990
  const normalizeSelectedPoints = (points) => {
932
991
  let nextPoints = [
@@ -1,7 +1,9 @@
1
1
  import type { ExcalidrawElement } from "./types";
2
2
  import type { Mutable } from "../utility-types";
3
3
  export type ElementUpdate<TElement extends ExcalidrawElement> = Omit<Partial<TElement>, "id" | "version" | "versionNonce" | "updated">;
4
- export declare const mutateElement: <TElement extends Mutable<ExcalidrawElement>>(element: TElement, updates: ElementUpdate<TElement>, informMutation?: boolean) => TElement;
4
+ export declare const mutateElement: <TElement extends Mutable<ExcalidrawElement>>(element: TElement, updates: ElementUpdate<TElement>, informMutation?: boolean, options?: {
5
+ isDragging?: boolean;
6
+ }) => TElement;
5
7
  export declare const newElementWith: <TElement extends ExcalidrawElement>(element: TElement, updates: ElementUpdate<TElement>, force?: boolean) => TElement;
6
8
  /**
7
9
  * Mutates element, bumping `version`, `versionNonce`, and `updated`.
@@ -1,18 +1,45 @@
1
1
  import Scene from "../scene/Scene";
2
2
  import { getSizeFromPoints } from "../points";
3
3
  import { randomInteger } from "../random";
4
- import { getUpdatedTimestamp } from "../utils";
4
+ import { getUpdatedTimestamp, toBrandedType } from "../utils";
5
5
  import { ShapeCache } from "../scene/ShapeCache";
6
+ import { isElbowArrow } from "./typeChecks";
7
+ import { updateElbowArrowPoints } from "./elbowArrow";
6
8
  // This function tracks updates of text elements for the purposes for collaboration.
7
9
  // The version is used to compare updates when more than one user is working in
8
10
  // the same drawing. Note: this will trigger the component to update. Make sure you
9
11
  // are calling it either from a React event handler or within unstable_batchedUpdates().
10
- export const mutateElement = (element, updates, informMutation = true) => {
12
+ export const mutateElement = (element, updates, informMutation = true, options) => {
11
13
  let didChange = false;
12
14
  // casting to any because can't use `in` operator
13
15
  // (see https://github.com/microsoft/TypeScript/issues/21732)
14
- const { points, fileId } = updates;
15
- if (typeof points !== "undefined") {
16
+ const { points, fixedSegments, fileId, startBinding, endBinding } = updates;
17
+ if (isElbowArrow(element) &&
18
+ (Object.keys(updates).length === 0 || // normalization case
19
+ typeof points !== "undefined" || // repositioning
20
+ typeof fixedSegments !== "undefined" || // segment fixing
21
+ typeof startBinding !== "undefined" ||
22
+ typeof endBinding !== "undefined") // manual binding to element
23
+ ) {
24
+ const elementsMap = toBrandedType(Scene.getScene(element)?.getNonDeletedElementsMap() ?? new Map());
25
+ updates = {
26
+ ...updates,
27
+ angle: 0,
28
+ ...updateElbowArrowPoints({
29
+ ...element,
30
+ x: updates.x || element.x,
31
+ y: updates.y || element.y,
32
+ }, elementsMap, {
33
+ fixedSegments,
34
+ points,
35
+ startBinding,
36
+ endBinding,
37
+ }, {
38
+ isDragging: options?.isDragging,
39
+ }),
40
+ };
41
+ }
42
+ else if (typeof points !== "undefined") {
16
43
  updates = { ...getSizeFromPoints(points), ...updates };
17
44
  }
18
45
  for (const key in updates) {