@excalidraw/excalidraw 0.18.0-58f7d33 → 0.18.0-6d870b1c8

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 (174) hide show
  1. package/dist/dev/chunk-CP5DND7P.js +7 -0
  2. package/dist/dev/chunk-CP5DND7P.js.map +7 -0
  3. package/dist/dev/chunk-D5WIFFIO.js +5678 -0
  4. package/dist/dev/chunk-D5WIFFIO.js.map +7 -0
  5. package/dist/dev/{chunk-X3RYHLJU.js → chunk-QF5FRM6O.js} +15 -5
  6. package/dist/dev/chunk-QF5FRM6O.js.map +7 -0
  7. package/dist/dev/data/{image-U2IPNUKJ.js → image-WMAXQLTI.js} +3 -3
  8. package/dist/dev/index.css +104 -22
  9. package/dist/dev/index.css.map +3 -3
  10. package/dist/dev/index.js +8871 -9726
  11. package/dist/dev/index.js.map +4 -4
  12. package/dist/dev/locales/{en-CKWC2GMK.js → en-SMAPCEOQ.js} +2 -2
  13. package/dist/dev/subset-shared.chunk.js +1 -1
  14. package/dist/dev/subset-worker.chunk.js +1 -1
  15. package/dist/prod/chunk-A66AFZZU.js +7 -0
  16. package/dist/prod/chunk-I4UNSFV6.js +12 -0
  17. package/dist/prod/chunk-KK52DCS3.js +4 -0
  18. package/dist/prod/data/image-U3WTNYT7.js +1 -0
  19. package/dist/prod/index.css +1 -1
  20. package/dist/prod/index.js +25 -17
  21. package/dist/prod/locales/{en-SBO6ZHT2.js → en-TYY6KWIJ.js} +1 -1
  22. package/dist/prod/subset-shared.chunk.js +1 -1
  23. package/dist/prod/subset-worker.chunk.js +1 -1
  24. package/dist/types/common/src/constants.d.ts +21 -3
  25. package/dist/types/{excalidraw → common/src}/emitter.d.ts +1 -1
  26. package/dist/types/common/src/font-metadata.d.ts +4 -2
  27. package/dist/types/common/src/index.d.ts +1 -0
  28. package/dist/types/common/src/utility-types.d.ts +5 -0
  29. package/dist/types/common/src/utils.d.ts +17 -4
  30. package/dist/types/{excalidraw/scene → element/src}/Scene.d.ts +11 -14
  31. package/dist/types/element/src/align.d.ts +4 -3
  32. package/dist/types/element/src/binding.d.ts +26 -16
  33. package/dist/types/element/src/bounds.d.ts +13 -5
  34. package/dist/types/element/src/collision.d.ts +18 -12
  35. package/dist/types/element/src/cropElement.d.ts +1 -1
  36. package/dist/types/{excalidraw/change.d.ts → element/src/delta.d.ts} +74 -39
  37. package/dist/types/element/src/distance.d.ts +2 -2
  38. package/dist/types/element/src/distribute.d.ts +2 -1
  39. package/dist/types/element/src/dragElements.d.ts +3 -2
  40. package/dist/types/element/src/duplicate.d.ts +10 -13
  41. package/dist/types/element/src/elbowArrow.d.ts +1 -1
  42. package/dist/types/element/src/flowchart.d.ts +3 -2
  43. package/dist/types/element/src/fractionalIndex.d.ts +9 -3
  44. package/dist/types/element/src/frame.d.ts +5 -4
  45. package/dist/types/element/src/groups.d.ts +1 -0
  46. package/dist/types/element/src/index.d.ts +43 -2
  47. package/dist/types/element/src/linearElementEditor.d.ts +23 -36
  48. package/dist/types/element/src/mutateElement.d.ts +11 -3
  49. package/dist/types/element/src/newElement.d.ts +4 -3
  50. package/dist/types/element/src/resizeElements.d.ts +5 -4
  51. package/dist/types/element/src/selection.d.ts +11 -5
  52. package/dist/types/element/src/shape.d.ts +42 -0
  53. package/dist/types/element/src/sizeHelpers.d.ts +2 -2
  54. package/dist/types/element/src/store.d.ts +232 -0
  55. package/dist/types/element/src/textElement.d.ts +4 -3
  56. package/dist/types/element/src/typeChecks.d.ts +19 -1
  57. package/dist/types/element/src/types.d.ts +15 -2
  58. package/dist/types/element/src/utils.d.ts +16 -6
  59. package/dist/types/element/src/zindex.d.ts +1 -1
  60. package/dist/types/excalidraw/actions/actionAddToLibrary.d.ts +39 -51
  61. package/dist/types/excalidraw/actions/actionBoundText.d.ts +26 -34
  62. package/dist/types/excalidraw/actions/actionCanvas.d.ts +175 -227
  63. package/dist/types/excalidraw/actions/actionClipboard.d.ts +78 -100
  64. package/dist/types/excalidraw/actions/actionCropEditor.d.ts +13 -17
  65. package/dist/types/excalidraw/actions/actionDeleteSelected.d.ts +39 -50
  66. package/dist/types/excalidraw/actions/actionElementLink.d.ts +12 -16
  67. package/dist/types/excalidraw/actions/actionElementLock.d.ts +41 -50
  68. package/dist/types/excalidraw/actions/actionEmbeddable.d.ts +13 -17
  69. package/dist/types/excalidraw/actions/actionExport.d.ts +127 -163
  70. package/dist/types/excalidraw/actions/actionFinalize.d.ts +73 -40
  71. package/dist/types/excalidraw/actions/actionFrame.d.ts +99 -115
  72. package/dist/types/excalidraw/actions/actionGroup.d.ts +26 -34
  73. package/dist/types/excalidraw/actions/actionHistory.d.ts +1 -2
  74. package/dist/types/excalidraw/actions/actionLinearEditor.d.ts +538 -18
  75. package/dist/types/excalidraw/actions/actionLink.d.ts +12 -16
  76. package/dist/types/excalidraw/actions/actionMenu.d.ts +36 -48
  77. package/dist/types/excalidraw/actions/actionNavigate.d.ts +25 -33
  78. package/dist/types/excalidraw/actions/actionProperties.d.ts +203 -255
  79. package/dist/types/excalidraw/actions/actionSelectAll.d.ts +13 -17
  80. package/dist/types/excalidraw/actions/actionStyles.d.ts +13 -17
  81. package/dist/types/excalidraw/actions/actionToggleGridMode.d.ts +13 -17
  82. package/dist/types/excalidraw/actions/actionToggleObjectsSnapMode.d.ts +13 -17
  83. package/dist/types/excalidraw/actions/actionToggleSearchMenu.d.ts +12 -189
  84. package/dist/types/excalidraw/actions/actionToggleShapeSwitch.d.ts +19 -0
  85. package/dist/types/excalidraw/actions/actionToggleStats.d.ts +13 -17
  86. package/dist/types/excalidraw/actions/actionToggleViewMode.d.ts +13 -17
  87. package/dist/types/excalidraw/actions/actionToggleZenMode.d.ts +13 -17
  88. package/dist/types/excalidraw/actions/types.d.ts +4 -3
  89. package/dist/types/excalidraw/appState.d.ts +19 -10
  90. package/dist/types/excalidraw/components/Actions.d.ts +0 -4
  91. package/dist/types/excalidraw/components/App.d.ts +30 -19
  92. package/dist/types/excalidraw/components/ButtonIcon.d.ts +1 -0
  93. package/dist/types/excalidraw/components/ColorPicker/ColorInput.d.ts +2 -1
  94. package/dist/types/excalidraw/components/ColorPicker/ColorPicker.d.ts +5 -1
  95. package/dist/types/excalidraw/components/ColorPicker/CustomColorList.d.ts +1 -1
  96. package/dist/types/excalidraw/components/ColorPicker/Picker.d.ts +2 -3
  97. package/dist/types/excalidraw/components/ColorPicker/PickerColorList.d.ts +2 -3
  98. package/dist/types/excalidraw/components/ColorPicker/ShadeList.d.ts +2 -2
  99. package/dist/types/excalidraw/components/ColorPicker/TopPicks.d.ts +1 -1
  100. package/dist/types/excalidraw/components/ColorPicker/colorPickerUtils.d.ts +1 -1
  101. package/dist/types/excalidraw/components/ColorPicker/keyboardNavHandlers.d.ts +1 -1
  102. package/dist/types/excalidraw/components/ConvertElementTypePopup.d.ts +23 -0
  103. package/dist/types/excalidraw/components/ElementLinkDialog.d.ts +4 -3
  104. package/dist/types/excalidraw/components/Ellipsify.d.ts +4 -0
  105. package/dist/types/excalidraw/components/{ButtonIconSelect.d.ts → RadioSelection.d.ts} +1 -1
  106. package/dist/types/excalidraw/components/Range.d.ts +3 -3
  107. package/dist/types/excalidraw/components/Stats/Angle.d.ts +1 -1
  108. package/dist/types/excalidraw/components/Stats/CanvasGrid.d.ts +1 -1
  109. package/dist/types/excalidraw/components/Stats/Collapsible.d.ts +2 -1
  110. package/dist/types/excalidraw/components/Stats/Dimension.d.ts +1 -1
  111. package/dist/types/excalidraw/components/Stats/DragInput.d.ts +12 -2
  112. package/dist/types/excalidraw/components/Stats/FontSize.d.ts +1 -1
  113. package/dist/types/excalidraw/components/Stats/MultiAngle.d.ts +1 -1
  114. package/dist/types/excalidraw/components/Stats/MultiDimension.d.ts +1 -1
  115. package/dist/types/excalidraw/components/Stats/MultiFontSize.d.ts +1 -1
  116. package/dist/types/excalidraw/components/Stats/MultiPosition.d.ts +1 -1
  117. package/dist/types/excalidraw/components/Stats/Position.d.ts +1 -1
  118. package/dist/types/excalidraw/components/Stats/utils.d.ts +4 -11
  119. package/dist/types/excalidraw/components/UnlockPopup.d.ts +8 -0
  120. package/dist/types/excalidraw/components/canvases/InteractiveCanvas.d.ts +1 -0
  121. package/dist/types/excalidraw/components/hyperlink/Hyperlink.d.ts +3 -2
  122. package/dist/types/excalidraw/components/hyperlink/helpers.d.ts +2 -1
  123. package/dist/types/excalidraw/components/icons.d.ts +3 -0
  124. package/dist/types/excalidraw/components/shapes.d.ts +1 -1
  125. package/dist/types/excalidraw/data/reconcile.d.ts +1 -0
  126. package/dist/types/excalidraw/data/restore.d.ts +6 -1
  127. package/dist/types/excalidraw/data/transform.d.ts +1 -1
  128. package/dist/types/excalidraw/editor-jotai.d.ts +6 -6
  129. package/dist/types/excalidraw/eraser/index.d.ts +0 -2
  130. package/dist/types/excalidraw/fonts/Fonts.d.ts +1 -1
  131. package/dist/types/excalidraw/history.d.ts +30 -22
  132. package/dist/types/excalidraw/hooks/useEmitter.d.ts +1 -1
  133. package/dist/types/excalidraw/index.d.ts +11 -10
  134. package/dist/types/excalidraw/lasso/index.d.ts +1 -0
  135. package/dist/types/excalidraw/lasso/utils.d.ts +2 -1
  136. package/dist/types/excalidraw/renderer/helpers.d.ts +7 -2
  137. package/dist/types/excalidraw/renderer/staticScene.d.ts +4 -1
  138. package/dist/types/excalidraw/scene/Renderer.d.ts +1 -2
  139. package/dist/types/excalidraw/scene/index.d.ts +2 -2
  140. package/dist/types/excalidraw/scene/scrollbars.d.ts +2 -3
  141. package/dist/types/excalidraw/scene/types.d.ts +2 -0
  142. package/dist/types/excalidraw/snapping.d.ts +2 -2
  143. package/dist/types/excalidraw/types.d.ts +34 -14
  144. package/dist/types/excalidraw/wysiwyg/textWysiwyg.d.ts +3 -1
  145. package/dist/types/math/src/angle.d.ts +2 -0
  146. package/dist/types/math/src/constants.d.ts +3 -0
  147. package/dist/types/math/src/curve.d.ts +34 -0
  148. package/dist/types/math/src/index.d.ts +1 -0
  149. package/dist/types/math/src/point.d.ts +1 -1
  150. package/dist/types/math/src/rectangle.d.ts +2 -0
  151. package/dist/types/math/src/vector.d.ts +8 -2
  152. package/dist/types/utils/src/bbox.d.ts +1 -1
  153. package/dist/types/utils/src/index.d.ts +1 -1
  154. package/dist/types/utils/src/withinBounds.d.ts +1 -1
  155. package/history.ts +147 -110
  156. package/package.json +12 -9
  157. package/dist/dev/chunk-KKJLIRJU.js +0 -7
  158. package/dist/dev/chunk-KKJLIRJU.js.map +0 -7
  159. package/dist/dev/chunk-LEJJ2YZY.js +0 -18711
  160. package/dist/dev/chunk-LEJJ2YZY.js.map +0 -7
  161. package/dist/dev/chunk-X3RYHLJU.js.map +0 -7
  162. package/dist/prod/chunk-IUH5AXLB.js +0 -12
  163. package/dist/prod/chunk-QUX7WTVH.js +0 -7
  164. package/dist/prod/chunk-RQK6WG4F.js +0 -33
  165. package/dist/prod/data/image-UQDATCXC.js +0 -1
  166. package/dist/types/element/src/Shape.d.ts +0 -17
  167. package/dist/types/element/src/ShapeCache.d.ts +0 -25
  168. package/dist/types/element/src/shapes.d.ts +0 -23
  169. package/dist/types/excalidraw/components/ButtonSelect.d.ts +0 -9
  170. package/dist/types/excalidraw/store.d.ts +0 -129
  171. package/dist/types/excalidraw/visualdebug.d.ts +0 -41
  172. package/dist/types/utils/src/collision.d.ts +0 -8
  173. /package/dist/dev/data/{image-U2IPNUKJ.js.map → image-WMAXQLTI.js.map} +0 -0
  174. /package/dist/dev/locales/{en-CKWC2GMK.js.map → en-SMAPCEOQ.js.map} +0 -0
@@ -93,12 +93,14 @@ export type ScrollBars = {
93
93
  y: number;
94
94
  width: number;
95
95
  height: number;
96
+ deltaMultiplier: number;
96
97
  } | null;
97
98
  vertical: {
98
99
  x: number;
99
100
  y: number;
100
101
  width: number;
101
102
  height: number;
103
+ deltaMultiplier: number;
102
104
  } | null;
103
105
  };
104
106
  export type ElementShape = Drawable | Drawable[] | null;
@@ -1,7 +1,7 @@
1
1
  import { type GlobalPoint } from "@excalidraw/math";
2
2
  import type { InclusiveRange } from "@excalidraw/math";
3
- import type { Bounds } from "@excalidraw/element/bounds";
4
- import type { MaybeTransformHandleType } from "@excalidraw/element/transformHandles";
3
+ import type { Bounds } from "@excalidraw/element";
4
+ import type { MaybeTransformHandleType } from "@excalidraw/element";
5
5
  import type { ElementsMap, ExcalidrawElement, NonDeletedExcalidrawElement } from "@excalidraw/element/types";
6
6
  import type { AppClassProperties, AppState, KeyboardModifiersObject } from "./types";
7
7
  export declare const getSnapDistance: (zoomValue: number) => number;
@@ -1,9 +1,10 @@
1
1
  import type { IMAGE_MIME_TYPES, UserIdleState, throttleRAF, MIME_TYPES } from "@excalidraw/common";
2
- import type { SuggestedBinding } from "@excalidraw/element/binding";
3
- import type { LinearElementEditor } from "@excalidraw/element/linearElementEditor";
4
- import type { MaybeTransformHandleType } from "@excalidraw/element/transformHandles";
5
- import type { PointerType, ExcalidrawLinearElement, NonDeletedExcalidrawElement, NonDeleted, TextAlign, ExcalidrawElement, GroupId, ExcalidrawBindableElement, Arrowhead, ChartType, FontFamilyValues, FileId, ExcalidrawImageElement, Theme, StrokeRoundness, ExcalidrawEmbeddableElement, ExcalidrawMagicFrameElement, ExcalidrawFrameLikeElement, ExcalidrawElementType, ExcalidrawIframeLikeElement, OrderedExcalidrawElement, ExcalidrawNonSelectionElement } from "@excalidraw/element/types";
2
+ import type { SuggestedBinding } from "@excalidraw/element";
3
+ import type { LinearElementEditor } from "@excalidraw/element";
4
+ import type { MaybeTransformHandleType } from "@excalidraw/element";
5
+ import type { PointerType, ExcalidrawLinearElement, NonDeletedExcalidrawElement, NonDeleted, TextAlign, ExcalidrawElement, GroupId, ExcalidrawBindableElement, Arrowhead, ChartType, FontFamilyValues, FileId, Theme, StrokeRoundness, ExcalidrawEmbeddableElement, ExcalidrawMagicFrameElement, ExcalidrawFrameLikeElement, ExcalidrawElementType, ExcalidrawIframeLikeElement, OrderedExcalidrawElement, ExcalidrawNonSelectionElement } from "@excalidraw/element/types";
6
6
  import type { Merge, MaybePromise, ValueOf, MakeBrand } from "@excalidraw/common/utility-types";
7
+ import type { CaptureUpdateActionType, DurableIncrement, EphemeralIncrement } from "@excalidraw/element";
7
8
  import type { Action } from "./actions/types";
8
9
  import type { Spreadsheet } from "./charts";
9
10
  import type { ClipboardData } from "./clipboard";
@@ -12,7 +13,6 @@ import type Library from "./data/library";
12
13
  import type { FileSystemHandle } from "./data/filesystem";
13
14
  import type { ContextMenuItems } from "./components/ContextMenu";
14
15
  import type { SnapLine } from "./snapping";
15
- import type { CaptureUpdateActionType } from "./store";
16
16
  import type { ImportedDataState } from "./data/types";
17
17
  import type { Language } from "./i18n";
18
18
  import type { isOverScrollBars } from "./scene/scrollbars";
@@ -113,7 +113,6 @@ type _CommonCanvasAppState = {
113
113
  offsetLeft: AppState["offsetLeft"];
114
114
  offsetTop: AppState["offsetTop"];
115
115
  theme: AppState["theme"];
116
- pendingImageElementId: AppState["pendingImageElementId"];
117
116
  };
118
117
  export type StaticCanvasAppState = Readonly<_CommonCanvasAppState & {
119
118
  shouldCacheIgnoreZoom: AppState["shouldCacheIgnoreZoom"];
@@ -130,7 +129,6 @@ export type StaticCanvasAppState = Readonly<_CommonCanvasAppState & {
130
129
  }>;
131
130
  export type InteractiveCanvasAppState = Readonly<_CommonCanvasAppState & {
132
131
  activeEmbeddable: AppState["activeEmbeddable"];
133
- editingLinearElement: AppState["editingLinearElement"];
134
132
  selectionElement: AppState["selectionElement"];
135
133
  selectedGroupIds: AppState["selectedGroupIds"];
136
134
  selectedLinearElement: AppState["selectedLinearElement"];
@@ -146,6 +144,7 @@ export type InteractiveCanvasAppState = Readonly<_CommonCanvasAppState & {
146
144
  isCropping: AppState["isCropping"];
147
145
  croppingElementId: AppState["croppingElementId"];
148
146
  searchMatches: AppState["searchMatches"];
147
+ activeLockedId: AppState["activeLockedId"];
149
148
  }>;
150
149
  export type ObservedAppState = ObservedStandaloneAppState & ObservedElementsAppState;
151
150
  export type ObservedStandaloneAppState = {
@@ -156,9 +155,13 @@ export type ObservedElementsAppState = {
156
155
  editingGroupId: AppState["editingGroupId"];
157
156
  selectedElementIds: AppState["selectedElementIds"];
158
157
  selectedGroupIds: AppState["selectedGroupIds"];
159
- editingLinearElementId: LinearElementEditor["elementId"] | null;
160
- selectedLinearElementId: LinearElementEditor["elementId"] | null;
158
+ selectedLinearElement: {
159
+ elementId: LinearElementEditor["elementId"];
160
+ isEditing: boolean;
161
+ } | null;
161
162
  croppingElementId: AppState["croppingElementId"];
163
+ lockedMultiSelections: AppState["lockedMultiSelections"];
164
+ activeLockedId: AppState["activeLockedId"];
162
165
  };
163
166
  export interface AppState {
164
167
  contextMenu: {
@@ -209,7 +212,6 @@ export interface AppState {
209
212
  * set when a new text is created or when an existing text is being edited
210
213
  */
211
214
  editingTextElement: NonDeletedExcalidrawElement | null;
212
- editingLinearElement: LinearElementEditor | null;
213
215
  activeTool: {
214
216
  /**
215
217
  * indicates a previous tool we should revert back to if we deselect the
@@ -324,8 +326,6 @@ export interface AppState {
324
326
  shown: true;
325
327
  data: Spreadsheet;
326
328
  };
327
- /** imageElement waiting to be placed on canvas */
328
- pendingImageElementId: ExcalidrawImageElement["id"] | null;
329
329
  showHyperlinkPopup: false | "info" | "editor";
330
330
  selectedLinearElement: LinearElementEditor | null;
331
331
  snapLines: readonly SnapLine[];
@@ -341,9 +341,18 @@ export interface AppState {
341
341
  /** image cropping */
342
342
  isCropping: boolean;
343
343
  croppingElementId: ExcalidrawElement["id"] | null;
344
- searchMatches: readonly SearchMatch[];
344
+ /** null if no search matches found / search closed */
345
+ searchMatches: Readonly<{
346
+ focusedId: ExcalidrawElement["id"] | null;
347
+ matches: readonly SearchMatch[];
348
+ }> | null;
349
+ /** the locked element/group that's active and shows unlock popup */
350
+ activeLockedId: string | null;
351
+ lockedMultiSelections: {
352
+ [groupId: string]: true;
353
+ };
345
354
  }
346
- type SearchMatch = {
355
+ export type SearchMatch = {
347
356
  id: string;
348
357
  focus: boolean;
349
358
  matchedLines: {
@@ -351,6 +360,7 @@ type SearchMatch = {
351
360
  offsetY: number;
352
361
  width: number;
353
362
  height: number;
363
+ showOnCanvas: boolean;
354
364
  }[];
355
365
  };
356
366
  export type UIAppState = Omit<AppState, "suggestedBindings" | "startBoundElement" | "cursorButton" | "scrollX" | "scrollY">;
@@ -403,6 +413,7 @@ export type OnUserFollowedPayload = {
403
413
  };
404
414
  export interface ExcalidrawProps {
405
415
  onChange?: (elements: readonly OrderedExcalidrawElement[], appState: AppState, files: BinaryFiles) => void;
416
+ onIncrement?: (event: DurableIncrement | EphemeralIncrement) => void;
406
417
  initialData?: (() => MaybePromise<ExcalidrawInitialDataState | null>) | MaybePromise<ExcalidrawInitialDataState | null>;
407
418
  excalidrawAPI?: (api: ExcalidrawImperativeAPI) => void;
408
419
  isCollaborating?: boolean;
@@ -459,6 +470,7 @@ export interface ExcalidrawProps {
459
470
  renderEmbeddable?: (element: NonDeleted<ExcalidrawEmbeddableElement>, appState: AppState) => JSX.Element | null;
460
471
  aiEnabled?: boolean;
461
472
  showDeprecatedFonts?: boolean;
473
+ renderScrollbars?: boolean;
462
474
  }
463
475
  export type SceneData = {
464
476
  elements?: ImportedDataState["elements"];
@@ -544,6 +556,7 @@ export type AppClassProperties = {
544
556
  visibleElements: App["visibleElements"];
545
557
  excalidrawContainerValue: App["excalidrawContainerValue"];
546
558
  onPointerUpEmitter: App["onPointerUpEmitter"];
559
+ updateEditorAtom: App["updateEditorAtom"];
547
560
  };
548
561
  export type PointerDownState = Readonly<{
549
562
  origin: Readonly<{
@@ -587,6 +600,10 @@ export type PointerDownState = Readonly<{
587
600
  x: number;
588
601
  y: number;
589
602
  } | null;
603
+ origin: {
604
+ x: number;
605
+ y: number;
606
+ };
590
607
  };
591
608
  eventListeners: {
592
609
  onMove: null | ReturnType<typeof throttleRAF>;
@@ -601,9 +618,11 @@ export type PointerDownState = Readonly<{
601
618
  export type UnsubscribeCallback = () => void;
602
619
  export interface ExcalidrawImperativeAPI {
603
620
  updateScene: InstanceType<typeof App>["updateScene"];
621
+ mutateElement: InstanceType<typeof App>["mutateElement"];
604
622
  updateLibrary: InstanceType<typeof Library>["updateLibrary"];
605
623
  resetScene: InstanceType<typeof App>["resetScene"];
606
624
  getSceneElementsIncludingDeleted: InstanceType<typeof App>["getSceneElementsIncludingDeleted"];
625
+ getSceneElementsMapIncludingDeleted: InstanceType<typeof App>["getSceneElementsMapIncludingDeleted"];
607
626
  history: {
608
627
  clear: InstanceType<typeof App>["resetHistory"];
609
628
  };
@@ -628,6 +647,7 @@ export interface ExcalidrawImperativeAPI {
628
647
  */
629
648
  updateFrameRendering: InstanceType<typeof App>["updateFrameRendering"];
630
649
  onChange: (callback: (elements: readonly ExcalidrawElement[], appState: AppState, files: BinaryFiles) => void) => UnsubscribeCallback;
650
+ onIncrement: (callback: (event: DurableIncrement | EphemeralIncrement) => void) => UnsubscribeCallback;
631
651
  onPointerDown: (callback: (activeTool: AppState["activeTool"], pointerDownState: PointerDownState, event: React.PointerEvent<HTMLElement>) => void) => UnsubscribeCallback;
632
652
  onPointerUp: (callback: (activeTool: AppState["activeTool"], pointerDownState: PointerDownState, event: PointerEvent) => void) => UnsubscribeCallback;
633
653
  onScrollChange: (callback: (scrollX: number, scrollY: number, zoom: Zoom) => void) => UnsubscribeCallback;
@@ -1,5 +1,6 @@
1
1
  import type { ExcalidrawElement, ExcalidrawTextElement } from "@excalidraw/element/types";
2
2
  import type App from "../components/App";
3
+ type SubmitHandler = () => void;
3
4
  export declare const textWysiwyg: ({ id, onChange, onSubmit, getViewportCoords, element, canvas, excalidrawContainer, app, autoSelect, }: {
4
5
  id: ExcalidrawElement["id"];
5
6
  /**
@@ -19,4 +20,5 @@ export declare const textWysiwyg: ({ id, onChange, onSubmit, getViewportCoords,
19
20
  excalidrawContainer: HTMLDivElement | null;
20
21
  app: App;
21
22
  autoSelect?: boolean | undefined;
22
- }) => void;
23
+ }) => SubmitHandler;
24
+ export {};
@@ -15,3 +15,5 @@ export declare function radiansToDegrees(degrees: Radians): Degrees;
15
15
  * @returns TRUE if the provided angle is a right angle
16
16
  */
17
17
  export declare function isRightAngleRads(rads: Radians): boolean;
18
+ export declare function radiansBetweenAngles(a: Radians, min: Radians, max: Radians): boolean;
19
+ export declare function radiansDifference(a: Radians, b: Radians): Radians;
@@ -0,0 +1,3 @@
1
+ export declare const PRECISION = 0.0001;
2
+ export declare const LegendreGaussN24TValues: number[];
3
+ export declare const LegendreGaussN24CValues: number[];
@@ -8,6 +8,7 @@ import type { Curve, GlobalPoint, LineSegment, LocalPoint } from "./types";
8
8
  * @returns
9
9
  */
10
10
  export declare function curve<Point extends GlobalPoint | LocalPoint>(a: Point, b: Point, c: Point, d: Point): Curve<Point>;
11
+ export declare const bezierEquation: <Point extends GlobalPoint | LocalPoint>(c: Curve<Point>, t: number) => Point;
11
12
  /**
12
13
  * Computes the intersection between a cubic spline and a line segment.
13
14
  */
@@ -38,3 +39,36 @@ export declare function curvePointDistance<Point extends GlobalPoint | LocalPoin
38
39
  * Determines if the parameter is a Curve
39
40
  */
40
41
  export declare function isCurve<P extends GlobalPoint | LocalPoint>(v: unknown): v is Curve<P>;
42
+ export declare function curveTangent<Point extends GlobalPoint | LocalPoint>([p0, p1, p2, p3]: Curve<Point>, t: number): import("./types").Vector;
43
+ export declare function curveCatmullRomQuadraticApproxPoints(points: GlobalPoint[], tension?: number): [GlobalPoint, GlobalPoint][] | undefined;
44
+ export declare function curveCatmullRomCubicApproxPoints<Point extends GlobalPoint | LocalPoint>(points: Point[], tension?: number): Curve<Point>[] | undefined;
45
+ export declare function curveOffsetPoints([p0, p1, p2, p3]: Curve<GlobalPoint>, offset: number, steps?: number): GlobalPoint[];
46
+ export declare function offsetPointsForQuadraticBezier(p0: GlobalPoint, p1: GlobalPoint, p2: GlobalPoint, offsetDist: number, steps?: number): GlobalPoint[];
47
+ /**
48
+ * Implementation based on Legendre-Gauss quadrature for more accurate arc
49
+ * length calculation.
50
+ *
51
+ * Reference: https://pomax.github.io/bezierinfo/#arclength
52
+ *
53
+ * @param c The curve to calculate the length of
54
+ * @returns The approximated length of the curve
55
+ */
56
+ export declare function curveLength<P extends GlobalPoint | LocalPoint>(c: Curve<P>): number;
57
+ /**
58
+ * Calculates the curve length from t=0 to t=parameter using the same
59
+ * Legendre-Gauss quadrature method used in curveLength
60
+ *
61
+ * @param c The curve to calculate the partial length for
62
+ * @param t The parameter value (0 to 1) to calculate length up to
63
+ * @returns The length of the curve from beginning to parameter t
64
+ */
65
+ export declare function curveLengthAtParameter<P extends GlobalPoint | LocalPoint>(c: Curve<P>, t: number): number;
66
+ /**
67
+ * Calculates the point at a specific percentage of a curve's total length
68
+ * using binary search for improved efficiency and accuracy.
69
+ *
70
+ * @param c The curve to calculate point on
71
+ * @param percent A value between 0 and 1 representing the percentage of the curve's length
72
+ * @returns The point at the specified percentage of curve length
73
+ */
74
+ export declare function curvePointAtLength<P extends GlobalPoint | LocalPoint>(c: Curve<P>, percent: number): P;
@@ -1,5 +1,6 @@
1
1
  export * from "./angle";
2
2
  export * from "./curve";
3
+ export * from "./ellipse";
3
4
  export * from "./line";
4
5
  export * from "./point";
5
6
  export * from "./polygon";
@@ -43,7 +43,7 @@ export declare function isPoint(p: unknown): p is LocalPoint | GlobalPoint;
43
43
  * @param b Point The second point to compare
44
44
  * @returns TRUE if the points are sufficiently close to each other
45
45
  */
46
- export declare function pointsEqual<Point extends GlobalPoint | LocalPoint>(a: Point, b: Point): boolean;
46
+ export declare function pointsEqual<Point extends GlobalPoint | LocalPoint>(a: Point, b: Point, tolerance?: number): boolean;
47
47
  /**
48
48
  * Rotate a point by [angle] radians.
49
49
  *
@@ -1,3 +1,5 @@
1
1
  import type { GlobalPoint, LineSegment, LocalPoint, Rectangle } from "./types";
2
2
  export declare function rectangle<P extends GlobalPoint | LocalPoint>(topLeft: P, bottomRight: P): Rectangle<P>;
3
+ export declare function rectangleFromNumberSequence<Point extends LocalPoint | GlobalPoint>(minX: number, minY: number, maxX: number, maxY: number): Rectangle<Point>;
3
4
  export declare function rectangleIntersectLineSegment<Point extends LocalPoint | GlobalPoint>(r: Rectangle<Point>, l: LineSegment<Point>): Point[];
5
+ export declare function rectangleIntersectRectangle<Point extends LocalPoint | GlobalPoint>(rectangle1: Rectangle<Point>, rectangle2: Rectangle<Point>): boolean;
@@ -12,9 +12,11 @@ export declare function vector(x: number, y: number, originX?: number, originY?:
12
12
  *
13
13
  * @param p The point to turn into a vector
14
14
  * @param origin The origin point in a given coordiante system
15
- * @returns The created vector from the point and the origin
15
+ * @param threshold The threshold to consider the vector as 'undefined'
16
+ * @param defaultValue The default value to return if the vector is 'undefined'
17
+ * @returns The created vector from the point and the origin or default
16
18
  */
17
- export declare function vectorFromPoint<Point extends GlobalPoint | LocalPoint>(p: Point, origin?: Point): Vector;
19
+ export declare function vectorFromPoint<Point extends GlobalPoint | LocalPoint>(p: Point, origin?: Point, threshold?: number, defaultValue?: Vector): Vector;
18
20
  /**
19
21
  * Cross product is a binary operation on two vectors in 2D space.
20
22
  * It results in a vector that is perpendicular to both vectors.
@@ -86,3 +88,7 @@ export declare function vectorMagnitude(v: Vector): number;
86
88
  * @returns The new normalized vector
87
89
  */
88
90
  export declare const vectorNormalize: (v: Vector) => Vector;
91
+ /**
92
+ * Calculate the right-hand normal of the vector.
93
+ */
94
+ export declare const vectorNormal: (v: Vector) => Vector;
@@ -1,5 +1,5 @@
1
1
  import { type GlobalPoint, type LocalPoint } from "@excalidraw/math";
2
- import type { Bounds } from "@excalidraw/element/bounds";
2
+ import type { Bounds } from "@excalidraw/element";
3
3
  export type LineSegment<P extends LocalPoint | GlobalPoint> = [P, P];
4
4
  export declare function getBBox<P extends LocalPoint | GlobalPoint>(line: LineSegment<P>): Bounds;
5
5
  export declare function doBBoxesIntersect(a: Bounds, b: Bounds): boolean;
@@ -1,4 +1,4 @@
1
1
  export * from "./export";
2
2
  export * from "./withinBounds";
3
3
  export * from "./bbox";
4
- export { getCommonBounds } from "@excalidraw/element/bounds";
4
+ export { getCommonBounds } from "@excalidraw/element";
@@ -1,4 +1,4 @@
1
- import type { Bounds } from "@excalidraw/element/bounds";
1
+ import type { Bounds } from "@excalidraw/element";
2
2
  import type { ExcalidrawElement, NonDeletedExcalidrawElement } from "@excalidraw/element/types";
3
3
  type Element = NonDeletedExcalidrawElement;
4
4
  type Elements = readonly NonDeletedExcalidrawElement[];
package/history.ts CHANGED
@@ -1,12 +1,84 @@
1
- import type { SceneElementsMap } from "@excalidraw/element/types";
1
+ import { Emitter } from "@excalidraw/common";
2
+
3
+ import {
4
+ CaptureUpdateAction,
5
+ StoreChange,
6
+ StoreDelta,
7
+ } from "@excalidraw/element";
8
+
9
+ import type { StoreSnapshot, Store } from "@excalidraw/element";
2
10
 
3
- import { Emitter } from "./emitter";
11
+ import type { SceneElementsMap } from "@excalidraw/element/types";
4
12
 
5
- import type { AppStateChange, ElementsChange } from "./change";
6
- import type { Snapshot } from "./store";
7
13
  import type { AppState } from "./types";
8
14
 
9
- type HistoryStack = HistoryEntry[];
15
+ export class HistoryDelta extends StoreDelta {
16
+ /**
17
+ * Apply the delta to the passed elements and appState, does not modify the snapshot.
18
+ */
19
+ public applyTo(
20
+ elements: SceneElementsMap,
21
+ appState: AppState,
22
+ snapshot: StoreSnapshot,
23
+ ): [SceneElementsMap, AppState, boolean] {
24
+ const [nextElements, elementsContainVisibleChange] = this.elements.applyTo(
25
+ elements,
26
+ // used to fallback into local snapshot in case we couldn't apply the delta
27
+ // due to a missing (force deleted) elements in the scene
28
+ snapshot.elements,
29
+ // we don't want to apply the `version` and `versionNonce` properties for history
30
+ // as we always need to end up with a new version due to collaboration,
31
+ // approaching each undo / redo as a new user action
32
+ {
33
+ excludedProperties: new Set(["version", "versionNonce"]),
34
+ },
35
+ );
36
+
37
+ const [nextAppState, appStateContainsVisibleChange] = this.appState.applyTo(
38
+ appState,
39
+ nextElements,
40
+ );
41
+
42
+ const appliedVisibleChanges =
43
+ elementsContainVisibleChange || appStateContainsVisibleChange;
44
+
45
+ return [nextElements, nextAppState, appliedVisibleChanges];
46
+ }
47
+
48
+ /**
49
+ * Overriding once to avoid type casting everywhere.
50
+ */
51
+ public static override calculate(
52
+ prevSnapshot: StoreSnapshot,
53
+ nextSnapshot: StoreSnapshot,
54
+ ) {
55
+ return super.calculate(prevSnapshot, nextSnapshot) as HistoryDelta;
56
+ }
57
+
58
+ /**
59
+ * Overriding once to avoid type casting everywhere.
60
+ */
61
+ public static override inverse(delta: StoreDelta): HistoryDelta {
62
+ return super.inverse(delta) as HistoryDelta;
63
+ }
64
+
65
+ /**
66
+ * Overriding once to avoid type casting everywhere.
67
+ */
68
+ public static override applyLatestChanges(
69
+ delta: StoreDelta,
70
+ prevElements: SceneElementsMap,
71
+ nextElements: SceneElementsMap,
72
+ modifierOptions?: "deleted" | "inserted",
73
+ ) {
74
+ return super.applyLatestChanges(
75
+ delta,
76
+ prevElements,
77
+ nextElements,
78
+ modifierOptions,
79
+ ) as HistoryDelta;
80
+ }
81
+ }
10
82
 
11
83
  export class HistoryChangedEvent {
12
84
  constructor(
@@ -20,8 +92,8 @@ export class History {
20
92
  [HistoryChangedEvent]
21
93
  >();
22
94
 
23
- private readonly undoStack: HistoryStack = [];
24
- private readonly redoStack: HistoryStack = [];
95
+ public readonly undoStack: HistoryDelta[] = [];
96
+ public readonly redoStack: HistoryDelta[] = [];
25
97
 
26
98
  public get isUndoStackEmpty() {
27
99
  return this.undoStack.length === 0;
@@ -31,98 +103,119 @@ export class History {
31
103
  return this.redoStack.length === 0;
32
104
  }
33
105
 
106
+ constructor(private readonly store: Store) {}
107
+
34
108
  public clear() {
35
109
  this.undoStack.length = 0;
36
110
  this.redoStack.length = 0;
37
111
  }
38
112
 
39
113
  /**
40
- * Record a local change which will go into the history
114
+ * Record a non-empty local durable increment, which will go into the undo stack..
115
+ * Do not re-record history entries, which were already pushed to undo / redo stack, as part of history action.
41
116
  */
42
- public record(
43
- elementsChange: ElementsChange,
44
- appStateChange: AppStateChange,
45
- ) {
46
- const entry = HistoryEntry.create(appStateChange, elementsChange);
117
+ public record(delta: StoreDelta) {
118
+ if (delta.isEmpty() || delta instanceof HistoryDelta) {
119
+ return;
120
+ }
47
121
 
48
- if (!entry.isEmpty()) {
49
- // we have the latest changes, no need to `applyLatest`, which is done within `History.push`
50
- this.undoStack.push(entry.inverse());
122
+ // construct history entry, so once it's emitted, it's not recorded again
123
+ const historyDelta = HistoryDelta.inverse(delta);
51
124
 
52
- if (!entry.elementsChange.isEmpty()) {
53
- // don't reset redo stack on local appState changes,
54
- // as a simple click (unselect) could lead to losing all the redo entries
55
- // only reset on non empty elements changes!
56
- this.redoStack.length = 0;
57
- }
125
+ this.undoStack.push(historyDelta);
58
126
 
59
- this.onHistoryChangedEmitter.trigger(
60
- new HistoryChangedEvent(this.isUndoStackEmpty, this.isRedoStackEmpty),
61
- );
127
+ if (!historyDelta.elements.isEmpty()) {
128
+ // don't reset redo stack on local appState changes,
129
+ // as a simple click (unselect) could lead to losing all the redo entries
130
+ // only reset on non empty elements changes!
131
+ this.redoStack.length = 0;
62
132
  }
133
+
134
+ this.onHistoryChangedEmitter.trigger(
135
+ new HistoryChangedEvent(this.isUndoStackEmpty, this.isRedoStackEmpty),
136
+ );
63
137
  }
64
138
 
65
- public undo(
66
- elements: SceneElementsMap,
67
- appState: AppState,
68
- snapshot: Readonly<Snapshot>,
69
- ) {
139
+ public undo(elements: SceneElementsMap, appState: AppState) {
70
140
  return this.perform(
71
141
  elements,
72
142
  appState,
73
- snapshot,
74
143
  () => History.pop(this.undoStack),
75
- (entry: HistoryEntry) => History.push(this.redoStack, entry, elements),
144
+ (entry: HistoryDelta) => History.push(this.redoStack, entry),
76
145
  );
77
146
  }
78
147
 
79
- public redo(
80
- elements: SceneElementsMap,
81
- appState: AppState,
82
- snapshot: Readonly<Snapshot>,
83
- ) {
148
+ public redo(elements: SceneElementsMap, appState: AppState) {
84
149
  return this.perform(
85
150
  elements,
86
151
  appState,
87
- snapshot,
88
152
  () => History.pop(this.redoStack),
89
- (entry: HistoryEntry) => History.push(this.undoStack, entry, elements),
153
+ (entry: HistoryDelta) => History.push(this.undoStack, entry),
90
154
  );
91
155
  }
92
156
 
93
157
  private perform(
94
158
  elements: SceneElementsMap,
95
159
  appState: AppState,
96
- snapshot: Readonly<Snapshot>,
97
- pop: () => HistoryEntry | null,
98
- push: (entry: HistoryEntry) => void,
160
+ pop: () => HistoryDelta | null,
161
+ push: (entry: HistoryDelta) => void,
99
162
  ): [SceneElementsMap, AppState] | void {
100
163
  try {
101
- let historyEntry = pop();
164
+ let historyDelta = pop();
102
165
 
103
- if (historyEntry === null) {
166
+ if (historyDelta === null) {
104
167
  return;
105
168
  }
106
169
 
170
+ const action = CaptureUpdateAction.IMMEDIATELY;
171
+
172
+ let prevSnapshot = this.store.snapshot;
173
+
107
174
  let nextElements = elements;
108
175
  let nextAppState = appState;
109
176
  let containsVisibleChange = false;
110
177
 
111
- // iterate through the history entries in case they result in no visible changes
112
- while (historyEntry) {
178
+ // iterate through the history entries in case ;they result in no visible changes
179
+ while (historyDelta) {
113
180
  try {
114
181
  [nextElements, nextAppState, containsVisibleChange] =
115
- historyEntry.applyTo(nextElements, nextAppState, snapshot);
182
+ historyDelta.applyTo(nextElements, nextAppState, prevSnapshot);
183
+
184
+ const prevElements = prevSnapshot.elements;
185
+ const nextSnapshot = prevSnapshot.maybeClone(
186
+ action,
187
+ nextElements,
188
+ nextAppState,
189
+ );
190
+
191
+ const change = StoreChange.create(prevSnapshot, nextSnapshot);
192
+ const delta = HistoryDelta.applyLatestChanges(
193
+ historyDelta,
194
+ prevElements,
195
+ nextElements,
196
+ );
197
+
198
+ if (!delta.isEmpty()) {
199
+ // schedule immediate capture, so that it's emitted for the sync purposes
200
+ this.store.scheduleMicroAction({
201
+ action,
202
+ change,
203
+ delta,
204
+ });
205
+
206
+ historyDelta = delta;
207
+ }
208
+
209
+ prevSnapshot = nextSnapshot;
116
210
  } finally {
117
- // make sure to always push / pop, even if the increment is corrupted
118
- push(historyEntry);
211
+ push(historyDelta);
119
212
  }
120
213
 
121
214
  if (containsVisibleChange) {
122
215
  break;
123
216
  }
124
217
 
125
- historyEntry = pop();
218
+ historyDelta = pop();
126
219
  }
127
220
 
128
221
  return [nextElements, nextAppState];
@@ -135,7 +228,7 @@ export class History {
135
228
  }
136
229
  }
137
230
 
138
- private static pop(stack: HistoryStack): HistoryEntry | null {
231
+ private static pop(stack: HistoryDelta[]): HistoryDelta | null {
139
232
  if (!stack.length) {
140
233
  return null;
141
234
  }
@@ -149,64 +242,8 @@ export class History {
149
242
  return null;
150
243
  }
151
244
 
152
- private static push(
153
- stack: HistoryStack,
154
- entry: HistoryEntry,
155
- prevElements: SceneElementsMap,
156
- ) {
157
- const updatedEntry = entry.inverse().applyLatestChanges(prevElements);
158
- return stack.push(updatedEntry);
159
- }
160
- }
161
-
162
- export class HistoryEntry {
163
- private constructor(
164
- public readonly appStateChange: AppStateChange,
165
- public readonly elementsChange: ElementsChange,
166
- ) {}
167
-
168
- public static create(
169
- appStateChange: AppStateChange,
170
- elementsChange: ElementsChange,
171
- ) {
172
- return new HistoryEntry(appStateChange, elementsChange);
173
- }
174
-
175
- public inverse(): HistoryEntry {
176
- return new HistoryEntry(
177
- this.appStateChange.inverse(),
178
- this.elementsChange.inverse(),
179
- );
180
- }
181
-
182
- public applyTo(
183
- elements: SceneElementsMap,
184
- appState: AppState,
185
- snapshot: Readonly<Snapshot>,
186
- ): [SceneElementsMap, AppState, boolean] {
187
- const [nextElements, elementsContainVisibleChange] =
188
- this.elementsChange.applyTo(elements, snapshot.elements);
189
-
190
- const [nextAppState, appStateContainsVisibleChange] =
191
- this.appStateChange.applyTo(appState, nextElements);
192
-
193
- const appliedVisibleChanges =
194
- elementsContainVisibleChange || appStateContainsVisibleChange;
195
-
196
- return [nextElements, nextAppState, appliedVisibleChanges];
197
- }
198
-
199
- /**
200
- * Apply latest (remote) changes to the history entry, creates new instance of `HistoryEntry`.
201
- */
202
- public applyLatestChanges(elements: SceneElementsMap): HistoryEntry {
203
- const updatedElementsChange =
204
- this.elementsChange.applyLatestChanges(elements);
205
-
206
- return HistoryEntry.create(this.appStateChange, updatedElementsChange);
207
- }
208
-
209
- public isEmpty(): boolean {
210
- return this.appStateChange.isEmpty() && this.elementsChange.isEmpty();
245
+ private static push(stack: HistoryDelta[], entry: HistoryDelta) {
246
+ const inversedEntry = HistoryDelta.inverse(entry);
247
+ return stack.push(inversedEntry);
211
248
  }
212
249
  }