@excalidraw/element 0.18.0-063e025 → 0.18.0-1118751

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 (154) hide show
  1. package/dist/dev/index.js +13047 -9808
  2. package/dist/dev/index.js.map +4 -4
  3. package/dist/prod/index.js +19 -19
  4. package/dist/types/common/src/colors.d.ts +22 -0
  5. package/dist/types/common/src/constants.d.ts +54 -0
  6. package/dist/types/common/src/keys.d.ts +4 -0
  7. package/dist/types/common/src/points.d.ts +1 -1
  8. package/dist/types/common/src/random.d.ts +7 -0
  9. package/dist/types/common/src/utils.d.ts +1 -1
  10. package/dist/types/element/src/Scene.d.ts +1 -1
  11. package/dist/types/element/src/arrowEndpointText.d.ts +49 -0
  12. package/dist/types/element/src/arrows/focus.d.ts +5 -2
  13. package/dist/types/element/src/binding.d.ts +15 -8
  14. package/dist/types/element/src/bucketFill.d.ts +110 -0
  15. package/dist/types/element/src/collision.d.ts +8 -5
  16. package/dist/types/element/src/comparisons.d.ts +7 -5
  17. package/dist/types/element/src/convertToShape.d.ts +23 -0
  18. package/dist/types/element/src/delta.d.ts +23 -1
  19. package/dist/types/element/src/dragElements.d.ts +27 -0
  20. package/dist/types/element/src/duplicate.d.ts +60 -0
  21. package/dist/types/element/src/flowchart.d.ts +10 -6
  22. package/dist/types/element/src/frame.d.ts +2 -2
  23. package/dist/types/element/src/groups.d.ts +1 -1
  24. package/dist/types/element/src/index.d.ts +4 -0
  25. package/dist/types/element/src/linearElementEditor.d.ts +17 -0
  26. package/dist/types/element/src/mutateElement.d.ts +1 -1
  27. package/dist/types/element/src/newElement.d.ts +37 -2
  28. package/dist/types/element/src/renderElement.d.ts +21 -4
  29. package/dist/types/element/src/selection.d.ts +1 -1
  30. package/dist/types/element/src/shape.d.ts +27 -1
  31. package/dist/types/element/src/sizeHelpers.d.ts +6 -0
  32. package/dist/types/element/src/sortElements.d.ts +10 -0
  33. package/dist/types/element/src/stickyNote.d.ts +183 -0
  34. package/dist/types/element/src/textElement.d.ts +7 -3
  35. package/dist/types/element/src/transform.d.ts +25 -6
  36. package/dist/types/element/src/typeChecks.d.ts +3 -2
  37. package/dist/types/element/src/types.d.ts +35 -6
  38. package/dist/types/element/src/utils.d.ts +15 -4
  39. package/dist/types/element/src/zindex.d.ts +1 -1
  40. package/dist/types/excalidraw/actions/actionAddToLibrary.d.ts +48 -9
  41. package/dist/types/excalidraw/actions/actionAlign.d.ts +6 -6
  42. package/dist/types/excalidraw/actions/actionBoundText.d.ts +32 -6
  43. package/dist/types/excalidraw/actions/actionCanvas.d.ts +173 -576
  44. package/dist/types/excalidraw/actions/actionClipboard.d.ts +32 -6
  45. package/dist/types/excalidraw/actions/actionCropEditor.d.ts +16 -3
  46. package/dist/types/excalidraw/actions/actionDeleteSelected.d.ts +50 -10
  47. package/dist/types/excalidraw/actions/actionDeselect.d.ts +13 -3
  48. package/dist/types/excalidraw/actions/actionDistribute.d.ts +2 -2
  49. package/dist/types/excalidraw/actions/actionElementLink.d.ts +16 -3
  50. package/dist/types/excalidraw/actions/actionElementLock.d.ts +32 -6
  51. package/dist/types/excalidraw/actions/actionExport.d.ts +34 -8
  52. package/dist/types/excalidraw/actions/actionFinalize.d.ts +1 -0
  53. package/dist/types/excalidraw/actions/actionFrame.d.ts +99 -185
  54. package/dist/types/excalidraw/actions/actionGroup.d.ts +33 -7
  55. package/dist/types/excalidraw/actions/actionLinearEditor.d.ts +68 -4
  56. package/dist/types/excalidraw/actions/actionLink.d.ts +16 -3
  57. package/dist/types/excalidraw/actions/actionMenu.d.ts +16 -3
  58. package/dist/types/excalidraw/actions/actionProperties.d.ts +45 -12
  59. package/dist/types/excalidraw/actions/actionSelectAll.d.ts +16 -3
  60. package/dist/types/excalidraw/actions/actionStyles.d.ts +17 -4
  61. package/dist/types/excalidraw/actions/actionTextAutoResize.d.ts +1 -1
  62. package/dist/types/excalidraw/actions/actionToggleArrowBinding.d.ts +16 -3
  63. package/dist/types/excalidraw/actions/actionToggleGridMode.d.ts +16 -3
  64. package/dist/types/excalidraw/actions/actionToggleMidpointSnapping.d.ts +16 -3
  65. package/dist/types/excalidraw/actions/actionToggleObjectsSnapMode.d.ts +16 -3
  66. package/dist/types/excalidraw/actions/actionToggleSearchMenu.d.ts +16 -3
  67. package/dist/types/excalidraw/actions/actionToggleStats.d.ts +16 -3
  68. package/dist/types/excalidraw/actions/actionToggleViewMode.d.ts +17 -4
  69. package/dist/types/excalidraw/actions/actionToggleZenMode.d.ts +16 -3
  70. package/dist/types/excalidraw/actions/colorTargets.d.ts +39 -0
  71. package/dist/types/excalidraw/actions/index.d.ts +1 -2
  72. package/dist/types/excalidraw/actions/manager.d.ts +1 -0
  73. package/dist/types/excalidraw/actions/shortcuts.d.ts +1 -1
  74. package/dist/types/excalidraw/actions/types.d.ts +5 -1
  75. package/dist/types/excalidraw/appState.d.ts +26 -5
  76. package/dist/types/excalidraw/components/Actions.d.ts +16 -10
  77. package/dist/types/excalidraw/components/App.arrowText.d.ts +104 -0
  78. package/dist/types/excalidraw/components/App.bucketFill.d.ts +48 -0
  79. package/dist/types/excalidraw/components/App.cursor.d.ts +38 -0
  80. package/dist/types/excalidraw/components/App.d.ts +468 -99
  81. package/dist/types/excalidraw/components/App.drawshape.d.ts +55 -0
  82. package/dist/types/excalidraw/components/App.duplicate.d.ts +51 -0
  83. package/dist/types/excalidraw/components/App.flowchart.d.ts +21 -0
  84. package/dist/types/excalidraw/components/App.pan.d.ts +54 -0
  85. package/dist/types/excalidraw/components/App.toolDrag.d.ts +63 -0
  86. package/dist/types/excalidraw/components/App.viewport.d.ts +73 -0
  87. package/dist/types/excalidraw/components/App.wheel.d.ts +26 -0
  88. package/dist/types/excalidraw/components/ColorPicker/ColorPicker.d.ts +8 -2
  89. package/dist/types/excalidraw/components/ColorPicker/CustomColorList.d.ts +3 -1
  90. package/dist/types/excalidraw/components/ColorPicker/Picker.d.ts +5 -1
  91. package/dist/types/excalidraw/components/ColorPicker/PickerColorList.d.ts +9 -2
  92. package/dist/types/excalidraw/components/ColorPicker/ShadeList.d.ts +4 -2
  93. package/dist/types/excalidraw/components/ColorPicker/TopPicks.d.ts +8 -1
  94. package/dist/types/excalidraw/components/ColorPicker/colorTopPicksDnD.d.ts +11 -0
  95. package/dist/types/excalidraw/components/ColorPicker/keyboardNavHandlers.d.ts +2 -1
  96. package/dist/types/excalidraw/components/FontPicker/FontPicker.d.ts +4 -1
  97. package/dist/types/excalidraw/components/FontPicker/FontPickerList.d.ts +6 -1
  98. package/dist/types/excalidraw/components/FontPicker/fontTopPicksDnD.d.ts +12 -0
  99. package/dist/types/excalidraw/components/IconButton.d.ts +48 -0
  100. package/dist/types/excalidraw/components/LaserPointerButton.d.ts +2 -4
  101. package/dist/types/excalidraw/components/LayerUI.d.ts +5 -2
  102. package/dist/types/excalidraw/components/LockButton.d.ts +3 -4
  103. package/dist/types/excalidraw/components/MagicButton.d.ts +0 -2
  104. package/dist/types/excalidraw/components/MobileMenu.d.ts +4 -4
  105. package/dist/types/excalidraw/components/MobileToolbar.d.ts +9 -0
  106. package/dist/types/excalidraw/components/PenModeButton.d.ts +2 -5
  107. package/dist/types/excalidraw/components/Popover.d.ts +1 -3
  108. package/dist/types/excalidraw/components/{ButtonIcon.d.ts → RadioButton.d.ts} +2 -5
  109. package/dist/types/excalidraw/components/ToolPopover.d.ts +3 -6
  110. package/dist/types/excalidraw/components/Toolbar.d.ts +11 -0
  111. package/dist/types/excalidraw/components/Tools.d.ts +151 -0
  112. package/dist/types/excalidraw/components/TopPicksDnD/TopPicksContextMenu.d.ts +14 -0
  113. package/dist/types/excalidraw/components/TopPicksDnD/TopPicksTip.d.ts +11 -0
  114. package/dist/types/excalidraw/components/TopPicksDnD/topPicksDnD.d.ts +58 -0
  115. package/dist/types/excalidraw/components/UserList.d.ts +3 -2
  116. package/dist/types/excalidraw/components/ViewportStatusFrame/ViewportStatusFrame.d.ts +11 -0
  117. package/dist/types/excalidraw/components/canvases/InteractiveCanvas.d.ts +2 -0
  118. package/dist/types/excalidraw/components/canvases/NewElementCanvas.d.ts +2 -0
  119. package/dist/types/excalidraw/components/footer/Footer.d.ts +3 -1
  120. package/dist/types/excalidraw/components/icons.d.ts +5 -1
  121. package/dist/types/excalidraw/components/main-menu/DefaultItems.d.ts +2 -1
  122. package/dist/types/excalidraw/components/positionElementBesideCursor.d.ts +26 -0
  123. package/dist/types/excalidraw/components/shapeActionPredicates.d.ts +39 -0
  124. package/dist/types/excalidraw/data/blob.d.ts +36 -10
  125. package/dist/types/excalidraw/data/json.d.ts +18 -5
  126. package/dist/types/excalidraw/drawShapeTrail.d.ts +16 -0
  127. package/dist/types/excalidraw/fonts/Fonts.d.ts +3 -2
  128. package/dist/types/excalidraw/hooks/useTextEditorFocus.d.ts +5 -5
  129. package/dist/types/excalidraw/lasso/utils.d.ts +2 -0
  130. package/dist/types/excalidraw/renderOverrides.d.ts +9 -0
  131. package/dist/types/excalidraw/renderer/helpers.d.ts +25 -0
  132. package/dist/types/excalidraw/renderer/interactiveScene.d.ts +1 -1
  133. package/dist/types/excalidraw/scene/Renderer.d.ts +64 -2
  134. package/dist/types/excalidraw/scene/index.d.ts +1 -1
  135. package/dist/types/excalidraw/scene/types.d.ts +6 -1
  136. package/dist/types/excalidraw/types.d.ts +341 -21
  137. package/dist/types/excalidraw/viewport.d.ts +31 -66
  138. package/dist/types/laser-pointer/src/state.d.ts +1 -0
  139. package/dist/types/math/src/curve.d.ts +19 -12
  140. package/dist/types/math/src/index.d.ts +1 -0
  141. package/dist/types/math/src/pca.d.ts +79 -0
  142. package/dist/types/math/src/polygon.d.ts +25 -1
  143. package/dist/types/math/src/segment.d.ts +6 -0
  144. package/dist/types/utils/src/export.d.ts +1 -0
  145. package/dist/types/utils/src/shape.d.ts +2 -2
  146. package/package.json +4 -4
  147. package/dist/types/excalidraw/actions/actionEmbeddable.d.ts +0 -173
  148. package/dist/types/excalidraw/components/FollowMode/FollowMode.d.ts +0 -10
  149. package/dist/types/excalidraw/components/HandButton.d.ts +0 -10
  150. package/dist/types/excalidraw/components/MobileToolBar.d.ts +0 -10
  151. package/dist/types/excalidraw/components/ToolButton.d.ts +0 -49
  152. package/dist/types/excalidraw/components/shapes.d.ts +0 -270
  153. package/dist/types/excalidraw/cursor.d.ts +0 -5
  154. package/dist/types/excalidraw/scene/zoom.d.ts +0 -12
@@ -1,9 +1,9 @@
1
1
  import type { IMAGE_MIME_TYPES, UserIdleState, throttleRAF, MIME_TYPES, EditorInterface, StrokeWidthKey } from "@excalidraw/common";
2
2
  import type { LinearElementEditor } from "@excalidraw/element";
3
3
  import type { MaybeTransformHandleType } from "@excalidraw/element";
4
- import type { PointerType, ExcalidrawLinearElement, NonDeletedExcalidrawElement, NonDeleted, TextAlign, ExcalidrawElement, GroupId, ExcalidrawBindableElement, Arrowhead, FontFamilyValues, FileId, Theme, StrokeRoundness, ExcalidrawEmbeddableElement, ExcalidrawMagicFrameElement, ExcalidrawFrameLikeElement, ExcalidrawElementType, ExcalidrawIframeLikeElement, OrderedExcalidrawElement, ExcalidrawNonSelectionElement, BindMode, ExcalidrawTextElement, StrokeVariability } from "@excalidraw/element/types";
4
+ import type { PointerType, ExcalidrawLinearElement, NonDeletedExcalidrawElement, NonDeleted, TextAlign, ExcalidrawElement, GroupId, ExcalidrawBindableElement, ExcalidrawArrowElement, Arrowhead, FontFamilyValues, FileId, Theme, StrokeRoundness, ExcalidrawEmbeddableElement, ExcalidrawMagicFrameElement, ExcalidrawFrameLikeElement, ExcalidrawElementType, ExcalidrawIframeLikeElement, OrderedExcalidrawElement, ExcalidrawNonSelectionElement, BindMode, ExcalidrawTextElement, StrokeVariability } from "@excalidraw/element/types";
5
5
  import type { Merge, MaybePromise, ValueOf, MakeBrand } from "@excalidraw/common/utility-types";
6
- import type { CaptureUpdateActionType, DurableIncrement, EphemeralIncrement } from "@excalidraw/element";
6
+ import type { CaptureUpdateActionType, DurableIncrement, EphemeralIncrement, OnDuplicateData } from "@excalidraw/element";
7
7
  import type { GlobalPoint } from "@excalidraw/math";
8
8
  import type { Action } from "./actions/types";
9
9
  import type { Spreadsheet } from "./charts";
@@ -85,7 +85,7 @@ export type BinaryFileData = {
85
85
  };
86
86
  export type BinaryFileMetadata = Omit<BinaryFileData, "dataURL">;
87
87
  export type BinaryFiles = Record<ExcalidrawElement["id"], BinaryFileData>;
88
- export type ToolType = "selection" | "lasso" | "rectangle" | "diamond" | "ellipse" | "arrow" | "line" | "freedraw" | "text" | "image" | "eraser" | "hand" | "frame" | "magicframe" | "embeddable" | "laser";
88
+ export type ToolType = "selection" | "lasso" | "rectangle" | "diamond" | "ellipse" | "arrow" | "line" | "freedraw" | "text" | "image" | "eraser" | "hand" | "frame" | "magicframe" | "stickynote" | "embeddable" | "laser" | "autoshape" | "bucketfill";
89
89
  export type ElementOrToolType = ExcalidrawElementType | ToolType | "custom";
90
90
  export type ActiveTool = {
91
91
  type: ToolType;
@@ -139,7 +139,9 @@ export type InteractiveCanvasAppState = Readonly<_CommonCanvasAppState & {
139
139
  newElement: AppState["newElement"];
140
140
  isBindingEnabled: AppState["isBindingEnabled"];
141
141
  isMidpointSnappingEnabled: AppState["isMidpointSnappingEnabled"];
142
+ gridModeEnabled: AppState["gridModeEnabled"];
142
143
  suggestedBinding: AppState["suggestedBinding"];
144
+ hoveredArrowTextAnchor: AppState["hoveredArrowTextAnchor"];
143
145
  isRotating: AppState["isRotating"];
144
146
  elementsToHighlight: AppState["elementsToHighlight"];
145
147
  collaborators: AppState["collaborators"];
@@ -174,6 +176,11 @@ export type ObservedElementsAppState = {
174
176
  activeLockedId: AppState["activeLockedId"];
175
177
  };
176
178
  export type BoxSelectionMode = "contain" | "overlap";
179
+ /**
180
+ * The pointing device the wheel mappings are tuned for. `auto` is reserved
181
+ * for detecting it from the wheel events; see `resolveInputDevice`.
182
+ */
183
+ export type InputDevice = "auto" | "mouse" | "trackpad";
177
184
  /**
178
185
  * A box, in scene coordinates, that pan & zoom are constrained to.
179
186
  *
@@ -253,6 +260,14 @@ export interface AppState {
253
260
  bindingPreference: "enabled" | "disabled";
254
261
  /** user preference whether arrow snap to midpoints while binding */
255
262
  isMidpointSnappingEnabled: boolean;
263
+ /**
264
+ * user preference for what the wheel does: with a `trackpad` a plain wheel
265
+ * pans; with a `mouse` a plain wheel zooms. Ctrl/cmd+wheel (how a pinch is
266
+ * delivered) zooms with either device. Shift+wheel pans horizontally;
267
+ * ctrl/cmd+shift+wheel pans vertically. `auto` resolves to `trackpad` until
268
+ * device detection exists — see `resolveInputDevice`
269
+ */
270
+ inputDevice: InputDevice;
256
271
  /**
257
272
  * The bindable element the UI highlights for the user when an arrow is
258
273
  * dragged or otherwise its endpoint being close to said element.
@@ -261,6 +276,15 @@ export interface AppState {
261
276
  element: NonDeleted<ExcalidrawBindableElement>;
262
277
  midPoint?: GlobalPoint;
263
278
  } | null;
279
+ /**
280
+ * Where on a hovered arrow the text tool would attach text if clicked —
281
+ * a free endpoint (binds the arrow to a new text element positioned against
282
+ * that endpoint) or the arrow's midpoint (adds a label bound to the arrow).
283
+ */
284
+ hoveredArrowTextAnchor: {
285
+ elementId: ExcalidrawArrowElement["id"];
286
+ anchor: "start" | "end" | "label";
287
+ } | null;
264
288
  frameToHighlight: NonDeleted<ExcalidrawFrameLikeElement> | null;
265
289
  frameRendering: {
266
290
  enabled: boolean;
@@ -268,7 +292,10 @@ export interface AppState {
268
292
  outline: boolean;
269
293
  clip: boolean;
270
294
  };
271
- editingFrame: string | null;
295
+ /**
296
+ * frame-like element whose name is currently being edited
297
+ */
298
+ editingFrame: ExcalidrawFrameLikeElement["id"] | null;
272
299
  elementsToHighlight: readonly NonDeletedExcalidrawElement[] | null;
273
300
  /**
274
301
  * set when a new text is created or when an existing text is being edited
@@ -294,6 +321,8 @@ export interface AppState {
294
321
  exportWithDarkMode: boolean;
295
322
  exportScale: number;
296
323
  currentItemStrokeColor: string;
324
+ currentItemStickynoteStrokeColor: string;
325
+ currentItemStickynoteBackgroundColor: string;
297
326
  currentItemBackgroundColor: string;
298
327
  currentItemFillStyle: ExcalidrawElement["fillStyle"];
299
328
  currentItemStrokeWidthKey: StrokeWidthKey;
@@ -400,10 +429,6 @@ export interface AppState {
400
429
  y: number;
401
430
  } | null;
402
431
  objectsSnapModeEnabled: boolean;
403
- /** the user's socket id & username who is being followed on the canvas */
404
- userToFollow: UserToFollow | null;
405
- /** the socket ids of the users following the current user */
406
- followedBy: Set<SocketId>;
407
432
  /** image cropping */
408
433
  isCropping: boolean;
409
434
  croppingElementId: ExcalidrawElement["id"] | null;
@@ -418,6 +443,23 @@ export interface AppState {
418
443
  [groupId: string]: true;
419
444
  };
420
445
  bindMode: BindMode;
446
+ /** user-customized color-picker top picks (pinned via drag & drop from the
447
+ * color picker popup). `null` means no customization (defaults, or
448
+ * host-supplied `topPicks`, are used). Kept per picker. */
449
+ colorTopPicks: {
450
+ elementStroke: readonly string[] | null;
451
+ elementBackground: readonly string[] | null;
452
+ /** the bucket-fill tool keeps a list separate from `elementBackground`
453
+ * even though both drive `currentItemBackgroundColor` (its defaults and
454
+ * use case differ — no transparent) */
455
+ bucketFill: readonly string[] | null;
456
+ /** sticky notes are their own color domain (own defaults, own picks) */
457
+ stickyNoteStroke: readonly string[] | null;
458
+ stickyNoteBackground: readonly string[] | null;
459
+ };
460
+ /** user-customized font-picker top picks (pinned via drag & drop from the
461
+ * font picker popup). `null` means no customization (defaults are used) */
462
+ fontTopPicks: readonly FontFamilyValues[] | null;
421
463
  }
422
464
  export type SearchMatch = {
423
465
  id: string;
@@ -430,7 +472,7 @@ export type SearchMatch = {
430
472
  showOnCanvas: boolean;
431
473
  }[];
432
474
  };
433
- export type UIAppState = Omit<AppState, "cursorButton" | "scrollX" | "scrollY" | "zoom" | "shouldCacheIgnoreZoom" | "snapLines" | "originSnapOffset" | "suggestedBinding" | "frameToHighlight" | "elementsToHighlight">;
475
+ export type UIAppState = Omit<AppState, "cursorButton" | "scrollX" | "scrollY" | "zoom" | "shouldCacheIgnoreZoom" | "snapLines" | "originSnapOffset" | "suggestedBinding" | "hoveredArrowTextAnchor" | "frameToHighlight" | "elementsToHighlight">;
434
476
  export type NormalizedZoomValue = number & {
435
477
  _brand: "normalizedZoom";
436
478
  };
@@ -481,13 +523,160 @@ export type OnUserFollowedPayload = {
481
523
  userToFollow: UserToFollow;
482
524
  action: "FOLLOW" | "UNFOLLOW";
483
525
  };
526
+ export type ViewportStatusFrame = {
527
+ /** the badge (bottom-center pill) */
528
+ label?: {
529
+ label: React.ReactNode;
530
+ icon?: React.ReactNode;
531
+ /** badge background; defaults to var(--color-primary-hover) */
532
+ background?: string;
533
+ /** badge text color; defaults to var(--color-primary-light) */
534
+ color?: string;
535
+ /** makes the badge label interactive */
536
+ onClick?: () => void;
537
+ /** renders a close button when set */
538
+ onClose?: () => void;
539
+ };
540
+ /** viewport-edge border: CSS color, or `false` for none */
541
+ border: false | string;
542
+ };
484
543
  export type OnExportProgress = {
485
544
  type: "progress";
486
545
  message?: React.ReactNode;
487
546
  /** 0-1 range */
488
547
  progress?: number;
489
548
  };
549
+ export type InteractionConfig = {
550
+ /**
551
+ * Interactions that stay enabled while the editor is otherwise
552
+ * non-interactive. Opt-in: anything omitted or `false` is disabled.
553
+ */
554
+ enabled?: {
555
+ /**
556
+ * Element links render their link icon and stay clickable — clicking
557
+ * anywhere on a linked element opens the link, same as in view mode.
558
+ * When disabled, link icons are not rendered at all.
559
+ *
560
+ * @default false
561
+ */
562
+ links?: boolean;
563
+ /**
564
+ * Embeddable & iframe elements stay interactive — hovering & clicking
565
+ * activates them so their content can be used, same as in view mode.
566
+ *
567
+ * @default false
568
+ */
569
+ embeds?: boolean;
570
+ /**
571
+ * Umbrella for all interactive content on canvas — shorthand for
572
+ * enabling `links` & `embeds` (and future interactive content kinds)
573
+ * together. Additive: `interactiveContent: true` enables them
574
+ * regardless of their individual values.
575
+ *
576
+ * @default false
577
+ */
578
+ interactiveContent?: boolean;
579
+ /**
580
+ * Canvas navigation — panning (pointer drag, wheel, PageUp/PageDown)
581
+ * and zooming (ctrl/cmd + wheel, pinch, and the canvas zoom &
582
+ * zoom-to-fit shortcuts: ctrl/cmd +/-/0, shift+1/2/3), same as in view
583
+ * mode. Respects `appState.scrollConstraints` if set, so it composes
584
+ * with viewport locking. The rest of the keyboard stays disabled. Note
585
+ * the editor consumes wheel & touch input again when enabled, so the
586
+ * page no longer scrolls over the editor.
587
+ *
588
+ * @default false
589
+ */
590
+ navigation?: boolean;
591
+ /**
592
+ * Whether the browser's own zoom remains available over the editor —
593
+ * ctrl/cmd + wheel, pinch, and (while the editor has focus)
594
+ * ctrl/cmd +/-/0 shortcuts. Prevented by default, mirroring the
595
+ * interactive editor. Regular page scrolling stays available either way.
596
+ * With `navigation` enabled, the zoom input (wheel, pinch, keyboard
597
+ * shortcuts) zooms the canvas instead either way, making this moot.
598
+ *
599
+ * @default false
600
+ */
601
+ browserZoom?: boolean;
602
+ /**
603
+ * Tools that stay user-driven while the editor is otherwise
604
+ * non-interactive: pointer input keeps driving the listed tool when it's
605
+ * the active tool. Does not enable user-driven tool *switching* — the
606
+ * keyboard stays disabled and tool selection remains host-driven
607
+ * (`ExcalidrawAPI.setActiveTool`).
608
+ *
609
+ * Composes with `navigation`: the enabled tool wins the primary-pointer
610
+ * drag, while wheel input (and wheel-button drag) still pans/zooms.
611
+ */
612
+ tools?: {
613
+ /**
614
+ * The laser pointer stays usable — pointer strokes draw laser trails
615
+ * and pointer positions keep broadcasting via `onPointerUpdate`, so
616
+ * e.g. collaborators see a presenter's laser & cursor.
617
+ *
618
+ * @default false
619
+ */
620
+ laser?: boolean;
621
+ /**
622
+ * Custom tools (`activeTool.type === "custom"`) stay usable — the
623
+ * editor keeps dispatching `onPointerDown` / `onPointerUp` for them.
624
+ * Tool behavior is host-implemented; activate custom tools with
625
+ * `locked: true` or they revert to the selection tool (and go inert)
626
+ * after the first pointer interaction.
627
+ *
628
+ * @default false
629
+ */
630
+ custom?: boolean;
631
+ };
632
+ };
633
+ };
634
+ export type UIConfig = {
635
+ /**
636
+ * Default UI controls that stay enabled while the rest of Excalidraw's
637
+ * default UI is hidden. Opt-in: anything omitted or `false` is disabled.
638
+ */
639
+ enabled: {
640
+ /**
641
+ * The zoom-out, reset-zoom, and zoom-in controls.
642
+ *
643
+ * @default false
644
+ */
645
+ zoom?: boolean;
646
+ /**
647
+ * The button shown when the viewport is scrolled away from all content.
648
+ *
649
+ * @default false
650
+ */
651
+ scrollBackToContent?: boolean;
652
+ };
653
+ };
654
+ /** Supported visual changes. Geometry, content, bindings and styles are not overridable. */
655
+ export type ElementRenderOverride = Readonly<{
656
+ /** Absolute render opacity (0–100, clamped). Omitted: use element.opacity. */
657
+ opacity?: number;
658
+ /** Translation in scene units. Bound labels inherit their container's offset and ignore this field. */
659
+ offset?: Readonly<{
660
+ x: number;
661
+ y: number;
662
+ }>;
663
+ }>;
664
+ /** see {@link ExcalidrawImperativeAPI.setElementRenderOverrides} for details */
665
+ export type ElementRenderOverrides = ReadonlyMap<ExcalidrawElement["id"], ElementRenderOverride>;
666
+ /** The translation part of a snapshot: only the entries that carry an offset. */
667
+ export type ElementRenderOffsets = ReadonlyMap<ExcalidrawElement["id"], NonNullable<ElementRenderOverride["offset"]>>;
490
668
  export interface ExcalidrawProps {
669
+ className?: string;
670
+ /**
671
+ * Document that owns Excalidraw's mounted DOM.
672
+ *
673
+ * Set only when it differs from the global `document`, such as when code
674
+ * executing in a parent window mounts Excalidraw into an iframe document.
675
+ * The value must remain stable for the editor's lifetime.
676
+ *
677
+ * @default document
678
+ */
679
+ ownerDocument?: Document;
491
680
  onChange?: (elements: readonly OrderedExcalidrawElement[], appState: AppState, files: BinaryFiles) => void;
492
681
  onThemeChange?: (theme: Theme | "system") => void;
493
682
  /**
@@ -533,15 +722,95 @@ export interface ExcalidrawProps {
533
722
  *
534
723
  * Returned elements will be used in place of the next elements
535
724
  * (you should return all elements, including deleted, and not mutate
536
- * the element if changes are made)
725
+ * the element if changes are made).
726
+ *
727
+ * The duplicates are the elements in `nextElements` which are not in
728
+ * `prevElements` (see also `data.duplicateElements`). When pasting or
729
+ * inserting onto a frame, their `frameId` is already set. To change a
730
+ * duplicate, return a new object with the same `id`. It is shallow-merged
731
+ * into the duplicate (omitted properties are kept), and your changes are
732
+ * part of the duplication itself (same undo entry, same durable increment).
733
+ *
734
+ * To prevent an element from being duplicated, omit its duplicate from the
735
+ * returned array. References to it from the remaining duplicates are
736
+ * cleared, and a bound text isn't duplicated without its container. To
737
+ * prevent the duplication as a whole, return `false`. If no duplicate
738
+ * remains, the duplication is cancelled and the returned elements are
739
+ * ignored (alt-drag then moves the original elements instead).
537
740
  */
538
741
  onDuplicate?: (nextElements: readonly ExcalidrawElement[],
539
742
  /** excludes the duplicated elements */
540
- prevElements: readonly ExcalidrawElement[]) => ExcalidrawElement[] | void;
743
+ prevElements: readonly ExcalidrawElement[],
744
+ /** lookups covering just the elements taking part in the duplication */
745
+ data: OnDuplicateData) => ExcalidrawElement[] | void | false;
541
746
  renderTopLeftUI?: (isMobile: boolean, appState: UIAppState) => JSX.Element | null;
542
747
  renderTopRightUI?: (isMobile: boolean, appState: UIAppState) => JSX.Element | null;
543
748
  langCode?: Language["code"];
544
749
  viewModeEnabled?: boolean;
750
+ /**
751
+ * Whether the editor accepts user input (pointer, keyboard, wheel, touch,
752
+ * clipboard, drag&drop). When `false`, the scene still renders and reacts
753
+ * to programmatic updates (imperative API), but the user cannot affect it
754
+ * in any way. Implies view mode.
755
+ *
756
+ * Pass a config object to keep specific interactions enabled while the
757
+ * editor is otherwise non-interactive (see `InteractionConfig`):
758
+ *
759
+ * ```tsx
760
+ * <Excalidraw interaction={{ enabled: { links: true } }} />
761
+ * ```
762
+ *
763
+ * @default true
764
+ */
765
+ interaction?: boolean | InteractionConfig;
766
+ /**
767
+ * Whether Excalidraw's default UI is rendered — toolbar, default menus,
768
+ * footer controls, sidebars, and canvas popups. Host UI passed through
769
+ * children (including exported components such as `MainMenu` and `Footer`)
770
+ * or render props continues to render, together with any supporting dialogs
771
+ * it opens.
772
+ *
773
+ * Canvas content (elements, text editing surface, frame names, embeds) still
774
+ * renders, and the editor remains interactive unless `interaction` is set to
775
+ * `false`.
776
+ *
777
+ * Pass a config object to keep specific default controls rendered while the
778
+ * rest of the default UI is hidden (see `UIConfig`):
779
+ *
780
+ * ```tsx
781
+ * <Excalidraw ui={{ enabled: { zoom: true } }} />
782
+ * ```
783
+ *
784
+ * NOTE: this is WIP and what default UI is/is not rendered when ui=false
785
+ * may yet change.
786
+ *
787
+ * @default true
788
+ */
789
+ ui?: boolean | UIConfig;
790
+ /**
791
+ * Forces the active editor tool (controlled). While set, user- and
792
+ * API-driven tool switching is ignored — `setActiveTool` refuses with a
793
+ * console warning, non-forced toolbar buttons render disabled — and the
794
+ * editor snaps back if internal flows reset the tool. The forced tool
795
+ * behaves as if locked (see the tool lock / padlock): it doesn't revert to
796
+ * the selection tool after use, and elements drawn with it aren't
797
+ * auto-selected — without mutating `appState.activeTool.locked`, so the
798
+ * user's persisted padlock preference stays untouched. Unset to return
799
+ * tool control to the editor (the current tool stays active).
800
+ *
801
+ * The forced tool must be activatable to take effect: not disabled via
802
+ * `UIOptions.tools`, and — while the editor is non-interactive — allowed
803
+ * via `interaction.enabled.tools`. Otherwise the editor stays on (or, when
804
+ * non-interactive, resets to) the `selection` tool, and the forced tool is
805
+ * applied once it becomes activatable. `image` cannot be forced (its
806
+ * activation opens the file picker).
807
+ */
808
+ activeTool?: {
809
+ type: Exclude<ToolType, "image">;
810
+ } | {
811
+ type: "custom";
812
+ customType: string;
813
+ };
545
814
  zenModeEnabled?: boolean;
546
815
  gridModeEnabled?: boolean;
547
816
  objectsSnapModeEnabled?: boolean;
@@ -573,6 +842,21 @@ export interface ExcalidrawProps {
573
842
  aiEnabled?: boolean;
574
843
  showDeprecatedFonts?: boolean;
575
844
  renderScrollbars?: boolean;
845
+ viewportStatusFrame?: ViewportStatusFrame | null;
846
+ /**
847
+ * Rendered inside the UserList "who's here" dropdown (desktop) and inline
848
+ * in the mobile menu's collaborators section, below a divider. Accepts a
849
+ * render function — called with `isMobile` so hosts can render different
850
+ * UI for each surface — in addition to a plain node.
851
+ */
852
+ currentUserControls?: React.ReactNode | ((isMobile: boolean) => React.ReactNode);
853
+ /**
854
+ * The user being followed on the canvas, if any. Controlled by the host —
855
+ * the editor never sets it; it emits follow/unfollow intents via
856
+ * `onUserFollow` (prop or imperative API) and renders the followed
857
+ * user's avatar highlight from this value.
858
+ */
859
+ userToFollow?: UserToFollow | null;
576
860
  /**
577
861
  * Called before exporting to a file.
578
862
  *
@@ -598,7 +882,8 @@ export interface ExcalidrawProps {
598
882
  }) => MaybePromise<void> | AsyncGenerator<OnExportProgress, void>;
599
883
  }
600
884
  export type SceneData = {
601
- elements?: ImportedDataState["elements"];
885
+ /** Expects normalized elements; restore imported data before updating the scene. */
886
+ elements?: readonly ExcalidrawElement[] | null;
602
887
  appState?: ImportedDataState["appState"];
603
888
  collaborators?: Map<SocketId, Collaborator>;
604
889
  captureUpdate?: CaptureUpdateActionType;
@@ -658,6 +943,8 @@ export type AppProps = Merge<ExcalidrawProps, {
658
943
  export type AppClassProperties = {
659
944
  props: AppProps;
660
945
  state: AppState;
946
+ readonly ownerDocument: Document;
947
+ readonly ownerWindow: Window & typeof globalThis;
661
948
  api: App["api"];
662
949
  sessionExportThemeOverride: App["sessionExportThemeOverride"];
663
950
  interactiveCanvas: HTMLCanvasElement | null;
@@ -678,8 +965,7 @@ export type AppClassProperties = {
678
965
  id: App["id"];
679
966
  onInsertElements: App["onInsertElements"];
680
967
  onExportImage: App["onExportImage"];
681
- lastViewportPosition: App["lastViewportPosition"];
682
- setViewport: App["setViewport"];
968
+ viewport: App["viewport"];
683
969
  addFiles: App["addFiles"];
684
970
  addElementsFromPasteOrLibrary: App["addElementsFromPasteOrLibrary"];
685
971
  togglePenMode: App["togglePenMode"];
@@ -690,11 +976,18 @@ export type AppClassProperties = {
690
976
  onMagicframeToolSelect: App["onMagicframeToolSelect"];
691
977
  getName: App["getName"];
692
978
  dismissLinearEditor: App["dismissLinearEditor"];
693
- flowChartCreator: App["flowChartCreator"];
979
+ flowchart: App["flowchart"];
980
+ drawShape: App["drawShape"];
981
+ arrowText: App["arrowText"];
982
+ cursor: App["cursor"];
983
+ bucketFill: App["bucketFill"];
984
+ duplicate: App["duplicate"];
985
+ toolDrag: App["toolDrag"];
986
+ activeResizeHandle: App["activeResizeHandle"];
987
+ isToolLocked: App["isToolLocked"];
694
988
  getEffectiveGridSize: App["getEffectiveGridSize"];
695
989
  setPlugins: App["setPlugins"];
696
990
  plugins: App["plugins"];
697
- getViewportOffsets: App["getViewportOffsets"];
698
991
  visibleElements: App["visibleElements"];
699
992
  excalidrawContainerValue: App["excalidrawContainerValue"];
700
993
  onPointerUpEmitter: App["onPointerUpEmitter"];
@@ -703,8 +996,13 @@ export type AppClassProperties = {
703
996
  onEvent: App["onEvent"];
704
997
  onStateChange: App["onStateChange"];
705
998
  lastPointerMoveCoords: App["lastPointerMoveCoords"];
999
+ lastPointerMoveEvent: App["lastPointerMoveEvent"];
706
1000
  bindModeHandler: App["bindModeHandler"];
1001
+ emitUserFollowIntent: App["emitUserFollowIntent"];
1002
+ requestUnfollow: App["requestUnfollow"];
707
1003
  setAppState: App["setAppState"];
1004
+ isInteractionEnabled: App["isInteractionEnabled"];
1005
+ isNavigationEnabled: App["isNavigationEnabled"];
708
1006
  };
709
1007
  export type PointerDownState = Readonly<{
710
1008
  origin: Readonly<{
@@ -740,6 +1038,7 @@ export type PointerDownState = Readonly<{
740
1038
  wasAddedToSelection: boolean;
741
1039
  hasBeenDuplicated: boolean;
742
1040
  hasHitCommonBoundingBoxOfSelectedElements: boolean;
1041
+ arrowLabel: boolean;
743
1042
  };
744
1043
  withCmdOrCtrl: boolean;
745
1044
  drag: {
@@ -791,16 +1090,32 @@ export interface ExcalidrawImperativeAPI {
791
1090
  getAppState: () => InstanceType<typeof App>["state"];
792
1091
  getFiles: () => InstanceType<typeof App>["files"];
793
1092
  getName: InstanceType<typeof App>["getName"];
794
- setViewport: InstanceType<typeof App>["setViewport"];
795
- getViewportOffsets: InstanceType<typeof App>["getViewportOffsets"];
1093
+ setViewport: InstanceType<typeof App>["viewport"]["setViewport"];
1094
+ getViewportOffsets: InstanceType<typeof App>["viewport"]["getOffsets"];
1095
+ /**
1096
+ * Atomically replaces all transient visual overrides. Values are copied;
1097
+ * omitted IDs/fields use document values, except for inherited label offsets.
1098
+ * null clears the snapshot.
1099
+ * Repaints without document changes, history entries or onChange events;
1100
+ * an equivalent snapshot may still repaint (clearing an already clear
1101
+ * snapshot does not), so submit only when something changed.
1102
+ * Finite opacity is clamped to 0–100; non-finite values reject the snapshot.
1103
+ * Unknown/deleted IDs are ignored when rendering. Reset/unmount clears it.
1104
+ * Bound labels inherit their container's offset; offsets targeting them are
1105
+ * ignored. Label opacity remains independent. Target frame children explicitly.
1106
+ * Frame opacity still multiplies child opacity. Decorations follow their owner.
1107
+ * Exports and interactive geometry (hit tests, selection, editing) use document
1108
+ * values, including while authoring an animation preview in edit mode.
1109
+ */
1110
+ setElementRenderOverrides: InstanceType<typeof App>["setElementRenderOverrides"];
796
1111
  registerAction: (action: Action) => void;
797
1112
  refresh: InstanceType<typeof App>["refresh"];
798
1113
  setToast: InstanceType<typeof App>["setToast"];
799
1114
  addFiles: (data: BinaryFileData[]) => void;
800
1115
  id: string;
801
1116
  setActiveTool: InstanceType<typeof App>["setActiveTool"];
802
- setCursor: InstanceType<typeof App>["setCursor"];
803
- resetCursor: InstanceType<typeof App>["resetCursor"];
1117
+ setCursor: InstanceType<typeof App>["cursor"]["set"];
1118
+ resetCursor: InstanceType<typeof App>["cursor"]["reset"];
804
1119
  toggleSidebar: InstanceType<typeof App>["toggleSidebar"];
805
1120
  getEditorInterface: () => EditorInterface;
806
1121
  /**
@@ -823,7 +1138,6 @@ export type FrameNameBounds = {
823
1138
  y: number;
824
1139
  width: number;
825
1140
  height: number;
826
- angle: number;
827
1141
  };
828
1142
  export type FrameNameBoundsCache = {
829
1143
  get: (frameElement: ExcalidrawFrameLikeElement | ExcalidrawMagicFrameElement) => FrameNameBounds | null;
@@ -848,6 +1162,12 @@ export type NullableGridSize = (AppState["gridSize"] & MakeBrand<"NullableGridSi
848
1162
  export type GenerateDiagramToCode = (props: {
849
1163
  frame: NonDeleted<ExcalidrawMagicFrameElement>;
850
1164
  children: readonly NonDeletedExcalidrawElement[];
1165
+ /**
1166
+ * Optional streaming hook. Call with the accumulated response text as it
1167
+ * streams in so the editor can progressively render the partial HTML
1168
+ * inside the generated frame.
1169
+ */
1170
+ onPartial?: (html: string) => void;
851
1171
  }) => MaybePromise<{
852
1172
  html: string;
853
1173
  }>;