@excalidraw/math 0.18.0-4e758db → 0.18.0-4f68076

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 (80) hide show
  1. package/dist/dev/index.js +8 -2
  2. package/dist/dev/index.js.map +2 -2
  3. package/dist/prod/index.js +1 -1
  4. package/dist/types/common/src/constants.d.ts +10 -0
  5. package/dist/types/common/src/utils.d.ts +5 -0
  6. package/dist/types/element/src/binding.d.ts +13 -7
  7. package/dist/types/element/src/collision.d.ts +14 -5
  8. package/dist/types/element/src/duplicate.d.ts +60 -0
  9. package/dist/types/element/src/index.d.ts +1 -0
  10. package/dist/types/element/src/listMarker.d.ts +34 -0
  11. package/dist/types/element/src/newElement.d.ts +15 -1
  12. package/dist/types/element/src/renderElement.d.ts +21 -4
  13. package/dist/types/element/src/shape.d.ts +15 -1
  14. package/dist/types/element/src/textElement.d.ts +7 -0
  15. package/dist/types/element/src/utils.d.ts +8 -1
  16. package/dist/types/element/src/zindex.d.ts +1 -1
  17. package/dist/types/excalidraw/actions/actionAddToLibrary.d.ts +30 -3
  18. package/dist/types/excalidraw/actions/actionBoundText.d.ts +20 -2
  19. package/dist/types/excalidraw/actions/actionCanvas.d.ts +70 -7
  20. package/dist/types/excalidraw/actions/actionClipboard.d.ts +20 -2
  21. package/dist/types/excalidraw/actions/actionCropEditor.d.ts +10 -1
  22. package/dist/types/excalidraw/actions/actionDeleteSelected.d.ts +30 -3
  23. package/dist/types/excalidraw/actions/actionDeselect.d.ts +13 -1
  24. package/dist/types/excalidraw/actions/actionElementLink.d.ts +10 -1
  25. package/dist/types/excalidraw/actions/actionElementLock.d.ts +20 -2
  26. package/dist/types/excalidraw/actions/actionExport.d.ts +20 -2
  27. package/dist/types/excalidraw/actions/actionFrame.d.ts +30 -3
  28. package/dist/types/excalidraw/actions/actionGroup.d.ts +20 -2
  29. package/dist/types/excalidraw/actions/actionLinearEditor.d.ts +10 -1
  30. package/dist/types/excalidraw/actions/actionLink.d.ts +10 -1
  31. package/dist/types/excalidraw/actions/actionMenu.d.ts +10 -1
  32. package/dist/types/excalidraw/actions/actionProperties.d.ts +20 -2
  33. package/dist/types/excalidraw/actions/actionSelectAll.d.ts +10 -1
  34. package/dist/types/excalidraw/actions/actionStyles.d.ts +10 -1
  35. package/dist/types/excalidraw/actions/actionToggleArrowBinding.d.ts +10 -1
  36. package/dist/types/excalidraw/actions/actionToggleGridMode.d.ts +10 -1
  37. package/dist/types/excalidraw/actions/actionToggleMidpointSnapping.d.ts +10 -1
  38. package/dist/types/excalidraw/actions/actionToggleObjectsSnapMode.d.ts +10 -1
  39. package/dist/types/excalidraw/actions/actionToggleSearchMenu.d.ts +10 -1
  40. package/dist/types/excalidraw/actions/actionToggleShowHints.d.ts +197 -0
  41. package/dist/types/excalidraw/actions/actionToggleStats.d.ts +10 -1
  42. package/dist/types/excalidraw/actions/actionToggleViewMode.d.ts +10 -1
  43. package/dist/types/excalidraw/actions/actionToggleZenMode.d.ts +10 -1
  44. package/dist/types/excalidraw/actions/index.d.ts +1 -0
  45. package/dist/types/excalidraw/actions/types.d.ts +1 -1
  46. package/dist/types/excalidraw/appState.d.ts +2 -0
  47. package/dist/types/excalidraw/components/App.arrowText.d.ts +5 -39
  48. package/dist/types/excalidraw/components/App.clipboard.d.ts +31 -0
  49. package/dist/types/excalidraw/components/App.d.ts +82 -262
  50. package/dist/types/excalidraw/components/App.duplicate.d.ts +101 -0
  51. package/dist/types/excalidraw/components/App.modifiers.d.ts +38 -0
  52. package/dist/types/excalidraw/components/App.pan.d.ts +62 -0
  53. package/dist/types/excalidraw/components/App.selectionTool.d.ts +57 -0
  54. package/dist/types/excalidraw/components/App.text.d.ts +146 -0
  55. package/dist/types/excalidraw/components/App.textTool.d.ts +140 -0
  56. package/dist/types/excalidraw/components/App.viewport.d.ts +41 -1
  57. package/dist/types/excalidraw/components/App.wheel.d.ts +3 -10
  58. package/dist/types/excalidraw/components/ColorPicker/Picker.d.ts +2 -0
  59. package/dist/types/excalidraw/components/ColorPicker/colorTopPicksDnD.d.ts +11 -0
  60. package/dist/types/excalidraw/components/FileDropOverlay.d.ts +2 -0
  61. package/dist/types/excalidraw/components/FontPicker/FontPicker.d.ts +4 -1
  62. package/dist/types/excalidraw/components/FontPicker/FontPickerList.d.ts +6 -1
  63. package/dist/types/excalidraw/components/FontPicker/fontTopPicksDnD.d.ts +12 -0
  64. package/dist/types/excalidraw/components/LibraryMenuSection.d.ts +6 -2
  65. package/dist/types/excalidraw/components/LibraryUnit.d.ts +7 -2
  66. package/dist/types/excalidraw/components/Tooltip.d.ts +15 -1
  67. package/dist/types/excalidraw/components/TopPicksDnD/TopPicksContextMenu.d.ts +14 -0
  68. package/dist/types/excalidraw/components/TopPicksDnD/TopPicksTip.d.ts +11 -0
  69. package/dist/types/excalidraw/components/TopPicksDnD/topPicksDnD.d.ts +58 -0
  70. package/dist/types/excalidraw/components/main-menu/DefaultItems.d.ts +1 -0
  71. package/dist/types/excalidraw/data/blob.d.ts +20 -2
  72. package/dist/types/excalidraw/data/json.d.ts +10 -1
  73. package/dist/types/excalidraw/renderOverrides.d.ts +9 -0
  74. package/dist/types/excalidraw/scene/Renderer.d.ts +14 -1
  75. package/dist/types/excalidraw/scene/types.d.ts +2 -1
  76. package/dist/types/excalidraw/types.d.ts +92 -19
  77. package/dist/types/excalidraw/viewport.d.ts +23 -1
  78. package/dist/types/excalidraw/wysiwyg/textWysiwyg.d.ts +12 -1
  79. package/package.json +2 -2
  80. package/dist/types/excalidraw/components/ColorPicker/topPicksDnD.d.ts +0 -31
@@ -0,0 +1,11 @@
1
+ /**
2
+ * "drag to pin" hint shown in a picker popup whose top picks are
3
+ * customizable — with a reset link while the picks are customized
4
+ */
5
+ export declare const TopPicksTip: ({ className, tip, onReset, resetTitle, }: {
6
+ className?: string;
7
+ tip: string;
8
+ /** present only while the top picks are customized */
9
+ onReset?: () => void;
10
+ resetTitle: string;
11
+ }) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,58 @@
1
+ import "./TopPicksDnD.scss";
2
+ type DragOrigin = {
3
+ kind: "source";
4
+ } | {
5
+ kind: "pick";
6
+ index: number;
7
+ };
8
+ export type TopPicksDragState<T> = {
9
+ value: T;
10
+ origin: DragOrigin;
11
+ /** hovered strip slot — the slot to replace (source drags) or the final
12
+ * position (pick reorders). null while the pointer is outside the strip */
13
+ overIndex: number | null;
14
+ /** index of an already-pinned identical value that blocks the drop */
15
+ duplicateIndex: number | null;
16
+ /** signed distance between strip slot centers (for reorder preview) */
17
+ slotSpan: number;
18
+ } | null;
19
+ export type TopPicksGhost = {
20
+ /** the ghost's visual. Rendered into `document.body` — outside the
21
+ * editor's CSS scope, so theme-dependent styling must be resolved from the
22
+ * rendered DOM (computed styles) rather than CSS variables */
23
+ content: HTMLElement;
24
+ /** where the ghost spawns (its size) and flies back to on cancel */
25
+ rect: DOMRect;
26
+ };
27
+ /** called on pointerdown (the source may not stay mounted until the drag
28
+ * activates), for every potential drag — keep it cheap */
29
+ export type CreateTopPicksGhost<T> = (args: {
30
+ value: T;
31
+ /** the element the drag started on */
32
+ sourceEl: HTMLElement;
33
+ /** the registered strip */
34
+ stripEl: HTMLElement;
35
+ }) => TopPicksGhost;
36
+ export type TopPicksDnD<T> = {
37
+ dragState: TopPicksDragState<T>;
38
+ startSourceDrag: (event: React.PointerEvent, value: T | null) => void;
39
+ startPickDrag: (event: React.PointerEvent, index: number, value: T) => void;
40
+ setStripEl: (el: HTMLDivElement | null) => void;
41
+ };
42
+ /**
43
+ * live preview of the reorder result — the translation (px) moving the pick
44
+ * at `index` to the slot it would occupy if dropped right now
45
+ */
46
+ export declare const getTopPickReorderOffset: (dragState: TopPicksDragState<unknown>, index: number) => number;
47
+ /** "marching ants" outline hinting that the strip accepts the drop — SVG
48
+ * because CSS dashed outlines/borders can't animate their dash offset */
49
+ export declare const TopPicksDnDOutline: () => import("react/jsx-runtime").JSX.Element;
50
+ export declare const useTopPicksDnD: <T>({ enabled, picks, onPicksChange, isSamePick, createGhost, }: {
51
+ enabled: boolean;
52
+ picks: readonly T[];
53
+ onPicksChange: (picks: T[]) => void;
54
+ /** value-equality — pins identical to an existing pick are refused */
55
+ isSamePick?: (a: T, b: T) => boolean;
56
+ createGhost: CreateTopPicksGhost<T>;
57
+ }) => TopPicksDnD<T>;
58
+ export {};
@@ -78,6 +78,7 @@ export declare const Preferences: {
78
78
  ToggleSnapMode: () => import("react/jsx-runtime").JSX.Element;
79
79
  ToggleArrowBinding: () => import("react/jsx-runtime").JSX.Element;
80
80
  ToggleMidpointSnapping: () => import("react/jsx-runtime").JSX.Element;
81
+ ToggleShowHints: () => import("react/jsx-runtime").JSX.Element;
81
82
  ToggleGridMode: () => import("react/jsx-runtime").JSX.Element;
82
83
  ToggleZenMode: () => import("react/jsx-runtime").JSX.Element;
83
84
  ToggleViewMode: () => import("react/jsx-runtime").JSX.Element | null;
@@ -78,7 +78,14 @@ fileHandle?: FileSystemFileHandle | null) => Promise<{
78
78
  element: import("@excalidraw/element/types").NonDeleted<import("@excalidraw/element/types").ExcalidrawBindableElement>;
79
79
  midPoint?: import("@excalidraw/math").GlobalPoint;
80
80
  } | null;
81
- hoveredArrowTextAnchor: {
81
+ textToolHover: {
82
+ type: "text";
83
+ elementId: ExcalidrawElement["id"];
84
+ } | {
85
+ type: "container";
86
+ elementId: ExcalidrawElement["id"];
87
+ } | {
88
+ type: "arrow";
82
89
  elementId: import("@excalidraw/element/types").ExcalidrawArrowElement["id"];
83
90
  anchor: "start" | "end" | "label";
84
91
  } | null;
@@ -114,6 +121,7 @@ fileHandle?: FileSystemFileHandle | null) => Promise<{
114
121
  resizingElement: import("@excalidraw/element/types").NonDeletedExcalidrawElement | null;
115
122
  boxSelectionMode: import("../types").BoxSelectionMode;
116
123
  bindingPreference: "enabled" | "disabled";
124
+ showHints: boolean;
117
125
  inputDevice: import("../types").InputDevice;
118
126
  editingFrame: import("@excalidraw/element/types").ExcalidrawFrameLikeElement["id"] | null;
119
127
  preferredSelectionTool: {
@@ -185,6 +193,7 @@ fileHandle?: FileSystemFileHandle | null) => Promise<{
185
193
  stickyNoteStroke: readonly string[] | null;
186
194
  stickyNoteBackground: readonly string[] | null;
187
195
  };
196
+ fontTopPicks: readonly import("@excalidraw/element/types").FontFamilyValues[] | null;
188
197
  };
189
198
  files: import("../types").BinaryFiles;
190
199
  };
@@ -257,7 +266,14 @@ fileHandle?: FileSystemFileHandle | null) => Promise<{
257
266
  element: import("@excalidraw/element/types").NonDeleted<import("@excalidraw/element/types").ExcalidrawBindableElement>;
258
267
  midPoint?: import("@excalidraw/math").GlobalPoint;
259
268
  } | null;
260
- hoveredArrowTextAnchor: {
269
+ textToolHover: {
270
+ type: "text";
271
+ elementId: ExcalidrawElement["id"];
272
+ } | {
273
+ type: "container";
274
+ elementId: ExcalidrawElement["id"];
275
+ } | {
276
+ type: "arrow";
261
277
  elementId: import("@excalidraw/element/types").ExcalidrawArrowElement["id"];
262
278
  anchor: "start" | "end" | "label";
263
279
  } | null;
@@ -293,6 +309,7 @@ fileHandle?: FileSystemFileHandle | null) => Promise<{
293
309
  resizingElement: import("@excalidraw/element/types").NonDeletedExcalidrawElement | null;
294
310
  boxSelectionMode: import("../types").BoxSelectionMode;
295
311
  bindingPreference: "enabled" | "disabled";
312
+ showHints: boolean;
296
313
  inputDevice: import("../types").InputDevice;
297
314
  editingFrame: import("@excalidraw/element/types").ExcalidrawFrameLikeElement["id"] | null;
298
315
  preferredSelectionTool: {
@@ -364,6 +381,7 @@ fileHandle?: FileSystemFileHandle | null) => Promise<{
364
381
  stickyNoteStroke: readonly string[] | null;
365
382
  stickyNoteBackground: readonly string[] | null;
366
383
  };
384
+ fontTopPicks: readonly import("@excalidraw/element/types").FontFamilyValues[] | null;
367
385
  };
368
386
  files: import("../types").BinaryFiles;
369
387
  }>;
@@ -76,7 +76,14 @@ export declare const loadFromJSON: (localAppState: AppState, localElements: read
76
76
  element: import("@excalidraw/element/types").NonDeleted<import("@excalidraw/element/types").ExcalidrawBindableElement>;
77
77
  midPoint?: import("@excalidraw/math").GlobalPoint;
78
78
  } | null;
79
- hoveredArrowTextAnchor: {
79
+ textToolHover: {
80
+ type: "text";
81
+ elementId: ExcalidrawElement["id"];
82
+ } | {
83
+ type: "container";
84
+ elementId: ExcalidrawElement["id"];
85
+ } | {
86
+ type: "arrow";
80
87
  elementId: import("@excalidraw/element/types").ExcalidrawArrowElement["id"];
81
88
  anchor: "start" | "end" | "label";
82
89
  } | null;
@@ -112,6 +119,7 @@ export declare const loadFromJSON: (localAppState: AppState, localElements: read
112
119
  resizingElement: import("@excalidraw/element/types").NonDeletedExcalidrawElement | null;
113
120
  boxSelectionMode: import("../types").BoxSelectionMode;
114
121
  bindingPreference: "enabled" | "disabled";
122
+ showHints: boolean;
115
123
  inputDevice: import("../types").InputDevice;
116
124
  editingFrame: import("@excalidraw/element/types").ExcalidrawFrameLikeElement["id"] | null;
117
125
  preferredSelectionTool: {
@@ -183,6 +191,7 @@ export declare const loadFromJSON: (localAppState: AppState, localElements: read
183
191
  stickyNoteStroke: readonly string[] | null;
184
192
  stickyNoteBackground: readonly string[] | null;
185
193
  };
194
+ fontTopPicks: readonly import("@excalidraw/element/types").FontFamilyValues[] | null;
186
195
  };
187
196
  files: BinaryFiles;
188
197
  }>;
@@ -0,0 +1,9 @@
1
+ import type { ElementRenderOffsets, ElementRenderOverrides } from "./types";
2
+ /** Validate and copy before publishing, so a rejected snapshot changes nothing. */
3
+ export declare const copyElementRenderOverrides: (overrides: ElementRenderOverrides | null) => ElementRenderOverrides;
4
+ /**
5
+ * Extracts the offsets of a snapshot, returning `previous` when they are the
6
+ * same. Visibility is memoized on this map's identity, so a snapshot that only
7
+ * changes opacities (a fade) never re-runs viewport geometry.
8
+ */
9
+ export declare const getElementRenderOffsets: (overrides: ElementRenderOverrides, previous: ElementRenderOffsets) => ElementRenderOffsets;
@@ -1,7 +1,7 @@
1
1
  import type { NonDeletedExcalidrawElement } from "@excalidraw/element/types";
2
2
  import type { Scene } from "@excalidraw/element";
3
3
  import type { RenderableElementsMap } from "./types";
4
- import type { AppState } from "../types";
4
+ import type { AppState, ElementRenderOffsets } from "../types";
5
5
  type GetRenderableElementsOpts = {
6
6
  zoom: AppState["zoom"];
7
7
  offsetLeft: AppState["offsetLeft"];
@@ -19,6 +19,19 @@ type GetRenderableElementsOpts = {
19
19
  export declare class Renderer {
20
20
  private scene;
21
21
  constructor(scene: Scene);
22
+ /**
23
+ * Adjusts the document-visible set for render-override translations: an
24
+ * element leaves it when its offset moves it out of view and enters it when
25
+ * its offset brings it in; everything else keeps its document visibility.
26
+ * Only translated elements go through viewport geometry. The result is
27
+ * memoized on the offsets' identity so that opacity-only snapshots don't
28
+ * reach it at all.
29
+ */
30
+ getVisibleElementsWithRenderOffsets(visibleElements: readonly NonDeletedExcalidrawElement[], elementsMap: RenderableElementsMap, appState: AppState, offsets: ElementRenderOffsets): readonly NonDeletedExcalidrawElement[];
31
+ private _getVisibleElementsWithRenderOffsets;
32
+ /** the document-visible elements as a set, cached per visible array */
33
+ private visibleSets;
34
+ private getVisibleSet;
22
35
  private getVisibleCanvasElements;
23
36
  private getRenderableElementsMap;
24
37
  private sortSelectedElementsIntoHighlightedFrame;
@@ -1,7 +1,7 @@
1
1
  import type { UserIdleState, EditorInterface } from "@excalidraw/common";
2
2
  import type { ExcalidrawElement, NonDeletedElementsMap, NonDeletedExcalidrawElement, NonDeletedSceneElementsMap } from "@excalidraw/element/types";
3
3
  import type { MakeBrand } from "@excalidraw/common/utility-types";
4
- import type { AppClassProperties, AppState, EmbedsValidationStatus, ElementsPendingErasure, InteractiveCanvasAppState, StaticCanvasAppState, SocketId, PendingExcalidrawElements } from "../types";
4
+ import type { AppClassProperties, AppState, EmbedsValidationStatus, ElementRenderOverrides, ElementsPendingErasure, InteractiveCanvasAppState, StaticCanvasAppState, SocketId, PendingExcalidrawElements } from "../types";
5
5
  import type { RoughCanvas } from "roughjs/bin/canvas";
6
6
  import type { Drawable } from "roughjs/bin/core";
7
7
  export type RenderableElementsMap = NonDeletedElementsMap & MakeBrand<"RenderableElementsMap">;
@@ -19,6 +19,7 @@ export type StaticCanvasRenderConfig = {
19
19
  elementsPendingErasure: ElementsPendingErasure;
20
20
  pendingFlowchartNodes: PendingExcalidrawElements | null;
21
21
  theme: AppState["theme"];
22
+ elementRenderOverrides?: ElementRenderOverrides;
22
23
  };
23
24
  export type SVGRenderConfig = {
24
25
  offsetX: number;
@@ -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
- import type { MaybeTransformHandleType } from "@excalidraw/element";
3
+ import type { ListMarkerAdvance, MaybeTransformHandleType } from "@excalidraw/element";
4
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";
@@ -141,7 +141,7 @@ export type InteractiveCanvasAppState = Readonly<_CommonCanvasAppState & {
141
141
  isMidpointSnappingEnabled: AppState["isMidpointSnappingEnabled"];
142
142
  gridModeEnabled: AppState["gridModeEnabled"];
143
143
  suggestedBinding: AppState["suggestedBinding"];
144
- hoveredArrowTextAnchor: AppState["hoveredArrowTextAnchor"];
144
+ textToolHover: AppState["textToolHover"];
145
145
  isRotating: AppState["isRotating"];
146
146
  elementsToHighlight: AppState["elementsToHighlight"];
147
147
  collaborators: AppState["collaborators"];
@@ -260,11 +260,14 @@ export interface AppState {
260
260
  bindingPreference: "enabled" | "disabled";
261
261
  /** user preference whether arrow snap to midpoints while binding */
262
262
  isMidpointSnappingEnabled: boolean;
263
+ /** user preference whether to show contextual hints above the toolbar */
264
+ showHints: boolean;
263
265
  /**
264
266
  * user preference for what the wheel does: with a `trackpad` a plain wheel
265
- * pans and ctrl/cmd+wheel (how a pinch is delivered) zooms; with a `mouse`
266
- * a plain wheel zooms and ctrl/cmd+wheel pans vertically. `auto` resolves
267
- * to `trackpad` until device detection exists — see `resolveInputDevice`
267
+ * pans; with a `mouse` a plain wheel zooms. Ctrl/cmd+wheel (how a pinch is
268
+ * delivered) zooms with either device. Shift+wheel pans horizontally;
269
+ * ctrl/cmd+shift+wheel pans vertically. `auto` resolves to `trackpad` until
270
+ * device detection exists — see `resolveInputDevice`
268
271
  */
269
272
  inputDevice: InputDevice;
270
273
  /**
@@ -276,11 +279,20 @@ export interface AppState {
276
279
  midPoint?: GlobalPoint;
277
280
  } | null;
278
281
  /**
279
- * Where on a hovered arrow the text tool would attach text if clicked —
280
- * a free endpoint (binds the arrow to a new text element positioned against
281
- * that endpoint) or the arrow's midpoint (adds a label bound to the arrow).
282
+ * What a text-tool click at the hovered position would act on — the text
283
+ * it would edit, the empty container it would label, or the arrow anchor
284
+ * (a free endpoint, or the midpoint for a label) it would attach text to.
285
+ * `null` when the click would create free text, or the tool isn't active.
286
+ * Drives the hover affordance only.
282
287
  */
283
- hoveredArrowTextAnchor: {
288
+ textToolHover: {
289
+ type: "text";
290
+ elementId: ExcalidrawElement["id"];
291
+ } | {
292
+ type: "container";
293
+ elementId: ExcalidrawElement["id"];
294
+ } | {
295
+ type: "arrow";
284
296
  elementId: ExcalidrawArrowElement["id"];
285
297
  anchor: "start" | "end" | "label";
286
298
  } | null;
@@ -295,6 +307,10 @@ export interface AppState {
295
307
  * frame-like element whose name is currently being edited
296
308
  */
297
309
  editingFrame: ExcalidrawFrameLikeElement["id"] | null;
310
+ /**
311
+ * Elements the UI highlights with a bounding-box outline — those that
312
+ * would get added to a frame being dragged/resized.
313
+ */
298
314
  elementsToHighlight: readonly NonDeletedExcalidrawElement[] | null;
299
315
  /**
300
316
  * set when a new text is created or when an existing text is being edited
@@ -456,6 +472,9 @@ export interface AppState {
456
472
  stickyNoteStroke: readonly string[] | null;
457
473
  stickyNoteBackground: readonly string[] | null;
458
474
  };
475
+ /** user-customized font-picker top picks (pinned via drag & drop from the
476
+ * font picker popup). `null` means no customization (defaults are used) */
477
+ fontTopPicks: readonly FontFamilyValues[] | null;
459
478
  }
460
479
  export type SearchMatch = {
461
480
  id: string;
@@ -468,7 +487,7 @@ export type SearchMatch = {
468
487
  showOnCanvas: boolean;
469
488
  }[];
470
489
  };
471
- export type UIAppState = Omit<AppState, "cursorButton" | "scrollX" | "scrollY" | "zoom" | "shouldCacheIgnoreZoom" | "snapLines" | "originSnapOffset" | "suggestedBinding" | "hoveredArrowTextAnchor" | "frameToHighlight" | "elementsToHighlight">;
490
+ export type UIAppState = Omit<AppState, "cursorButton" | "scrollX" | "scrollY" | "zoom" | "shouldCacheIgnoreZoom" | "snapLines" | "originSnapOffset" | "suggestedBinding" | "textToolHover" | "frameToHighlight" | "elementsToHighlight">;
472
491
  export type NormalizedZoomValue = number & {
473
492
  _brand: "normalizedZoom";
474
493
  };
@@ -647,6 +666,20 @@ export type UIConfig = {
647
666
  scrollBackToContent?: boolean;
648
667
  };
649
668
  };
669
+ /** Supported visual changes. Geometry, content, bindings and styles are not overridable. */
670
+ export type ElementRenderOverride = Readonly<{
671
+ /** Absolute render opacity (0–100, clamped). Omitted: use element.opacity. */
672
+ opacity?: number;
673
+ /** Translation in scene units. Bound labels inherit their container's offset and ignore this field. */
674
+ offset?: Readonly<{
675
+ x: number;
676
+ y: number;
677
+ }>;
678
+ }>;
679
+ /** see {@link ExcalidrawImperativeAPI.setElementRenderOverrides} for details */
680
+ export type ElementRenderOverrides = ReadonlyMap<ExcalidrawElement["id"], ElementRenderOverride>;
681
+ /** The translation part of a snapshot: only the entries that carry an offset. */
682
+ export type ElementRenderOffsets = ReadonlyMap<ExcalidrawElement["id"], NonNullable<ElementRenderOverride["offset"]>>;
650
683
  export interface ExcalidrawProps {
651
684
  className?: string;
652
685
  /**
@@ -704,11 +737,27 @@ export interface ExcalidrawProps {
704
737
  *
705
738
  * Returned elements will be used in place of the next elements
706
739
  * (you should return all elements, including deleted, and not mutate
707
- * the element if changes are made)
740
+ * the element if changes are made).
741
+ *
742
+ * The duplicates are the elements in `nextElements` which are not in
743
+ * `prevElements` (see also `data.duplicateElements`). When pasting or
744
+ * inserting onto a frame, their `frameId` is already set. To change a
745
+ * duplicate, return a new object with the same `id`. It is shallow-merged
746
+ * into the duplicate (omitted properties are kept), and your changes are
747
+ * part of the duplication itself (same undo entry, same durable increment).
748
+ *
749
+ * To prevent an element from being duplicated, omit its duplicate from the
750
+ * returned array. References to it from the remaining duplicates are
751
+ * cleared, and a bound text isn't duplicated without its container. To
752
+ * prevent the duplication as a whole, return `false`. If no duplicate
753
+ * remains, the duplication is cancelled and the returned elements are
754
+ * ignored (alt-drag then moves the original elements instead).
708
755
  */
709
756
  onDuplicate?: (nextElements: readonly ExcalidrawElement[],
710
757
  /** excludes the duplicated elements */
711
- prevElements: readonly ExcalidrawElement[]) => ExcalidrawElement[] | void;
758
+ prevElements: readonly ExcalidrawElement[],
759
+ /** lookups covering just the elements taking part in the duplication */
760
+ data: OnDuplicateData) => ExcalidrawElement[] | void | false;
712
761
  renderTopLeftUI?: (isMobile: boolean, appState: UIAppState) => JSX.Element | null;
713
762
  renderTopRightUI?: (isMobile: boolean, appState: UIAppState) => JSX.Element | null;
714
763
  langCode?: Language["code"];
@@ -927,7 +976,7 @@ export type AppClassProperties = {
927
976
  scene: App["scene"];
928
977
  syncActionResult: App["syncActionResult"];
929
978
  fonts: App["fonts"];
930
- pasteFromClipboard: App["pasteFromClipboard"];
979
+ clipboard: App["clipboard"];
931
980
  id: App["id"];
932
981
  onInsertElements: App["onInsertElements"];
933
982
  onExportImage: App["onExportImage"];
@@ -945,10 +994,14 @@ export type AppClassProperties = {
945
994
  flowchart: App["flowchart"];
946
995
  drawShape: App["drawShape"];
947
996
  arrowText: App["arrowText"];
997
+ textTool: App["textTool"];
948
998
  cursor: App["cursor"];
949
999
  bucketFill: App["bucketFill"];
1000
+ duplicate: App["duplicate"];
950
1001
  toolDrag: App["toolDrag"];
951
1002
  activeResizeHandle: App["activeResizeHandle"];
1003
+ selectionTool: App["selectionTool"];
1004
+ modifiers: App["modifiers"];
952
1005
  isToolLocked: App["isToolLocked"];
953
1006
  getEffectiveGridSize: App["getEffectiveGridSize"];
954
1007
  setPlugins: App["setPlugins"];
@@ -1001,7 +1054,10 @@ export type PointerDownState = Readonly<{
1001
1054
  element: NonDeleted<ExcalidrawElement> | null;
1002
1055
  allHitElements: NonDeleted<ExcalidrawElement>[];
1003
1056
  wasAddedToSelection: boolean;
1057
+ cycleTarget: NonDeleted<ExcalidrawElement> | null;
1004
1058
  hasBeenDuplicated: boolean;
1059
+ advancedListMarkers: readonly ListMarkerAdvance[];
1060
+ editedTextId: ExcalidrawTextElement["id"] | null;
1005
1061
  hasHitCommonBoundingBoxOfSelectedElements: boolean;
1006
1062
  arrowLabel: boolean;
1007
1063
  };
@@ -1057,6 +1113,22 @@ export interface ExcalidrawImperativeAPI {
1057
1113
  getName: InstanceType<typeof App>["getName"];
1058
1114
  setViewport: InstanceType<typeof App>["viewport"]["setViewport"];
1059
1115
  getViewportOffsets: InstanceType<typeof App>["viewport"]["getOffsets"];
1116
+ /**
1117
+ * Atomically replaces all transient visual overrides. Values are copied;
1118
+ * omitted IDs/fields use document values, except for inherited label offsets.
1119
+ * null clears the snapshot.
1120
+ * Repaints without document changes, history entries or onChange events;
1121
+ * an equivalent snapshot may still repaint (clearing an already clear
1122
+ * snapshot does not), so submit only when something changed.
1123
+ * Finite opacity is clamped to 0–100; non-finite values reject the snapshot.
1124
+ * Unknown/deleted IDs are ignored when rendering. Reset/unmount clears it.
1125
+ * Bound labels inherit their container's offset; offsets targeting them are
1126
+ * ignored. Label opacity remains independent. Target frame children explicitly.
1127
+ * Frame opacity still multiplies child opacity. Decorations follow their owner.
1128
+ * Exports and interactive geometry (hit tests, selection, editing) use document
1129
+ * values, including while authoring an animation preview in edit mode.
1130
+ */
1131
+ setElementRenderOverrides: InstanceType<typeof App>["setElementRenderOverrides"];
1060
1132
  registerAction: (action: Action) => void;
1061
1133
  refresh: InstanceType<typeof App>["refresh"];
1062
1134
  setToast: InstanceType<typeof App>["setToast"];
@@ -1219,9 +1291,10 @@ export type ViewportOffsets = Offsets & {
1219
1291
  /**
1220
1292
  * Value of the `data-viewport-ui-name` attribute, identifying a
1221
1293
  * conditionally-rendered surface (marked with `data-viewport-ui`) so that
1222
- * `getViewportOffsets` can reserve space for it while it's hidden (see the
1223
- * `reserve` option). Whenever a named surface is rendered, its measured
1224
- * footprint is remembered; reserving uses that remembered footprint, or an
1225
- * approximate default if the surface hasn't been rendered yet.
1294
+ * it can be measured on its own, and so that `getViewportOffsets` can
1295
+ * reserve space for it while it's hidden (see the `reserve` option).
1296
+ * Whenever a named surface is rendered, its measured footprint is
1297
+ * remembered; reserving uses that remembered footprint, or an approximate
1298
+ * default if the surface hasn't been rendered yet.
1226
1299
  */
1227
- export type ViewportUIName = "sidebar" | "stylesPanel";
1300
+ export type ViewportUIName = "sidebar" | "stylesPanel" | "stats";
@@ -108,12 +108,20 @@ export declare const zoomToFitBounds: ({ bounds, appState, canvasOffsets, fit, m
108
108
  boxSelectionMode: import("./types").BoxSelectionMode;
109
109
  bindingPreference: "enabled" | "disabled";
110
110
  isMidpointSnappingEnabled: boolean;
111
+ showHints: boolean;
111
112
  inputDevice: import("./types").InputDevice;
112
113
  suggestedBinding: {
113
114
  element: import("@excalidraw/element/types").NonDeleted<import("@excalidraw/element/types").ExcalidrawBindableElement>;
114
115
  midPoint?: import("@excalidraw/math").GlobalPoint;
115
116
  } | null;
116
- hoveredArrowTextAnchor: {
117
+ textToolHover: {
118
+ type: "text";
119
+ elementId: ExcalidrawElement["id"];
120
+ } | {
121
+ type: "container";
122
+ elementId: ExcalidrawElement["id"];
123
+ } | {
124
+ type: "arrow";
117
125
  elementId: import("@excalidraw/element/types").ExcalidrawArrowElement["id"];
118
126
  anchor: "start" | "end" | "label";
119
127
  } | null;
@@ -254,6 +262,7 @@ export declare const zoomToFitBounds: ({ bounds, appState, canvasOffsets, fit, m
254
262
  stickyNoteStroke: readonly string[] | null;
255
263
  stickyNoteBackground: readonly string[] | null;
256
264
  };
265
+ fontTopPicks: readonly import("@excalidraw/element/types").FontFamilyValues[] | null;
257
266
  };
258
267
  captureUpdate: "EVENTUALLY";
259
268
  };
@@ -273,6 +282,19 @@ export declare const centerScrollOn: ({ scenePoint, viewportDimensions, zoom, of
273
282
  scrollX: number;
274
283
  scrollY: number;
275
284
  };
285
+ /**
286
+ * The scroll that brings `bounds` into the viewport — less `offsets` (screen
287
+ * px: UI covering its edges, room to leave) — by the least movement, keeping
288
+ * the zoom; `null` when they're in view already. Along an axis where they
289
+ * don't fit, their start (left / top) is brought in instead, or, with
290
+ * `tooLarge: "leave"`, that axis keeps its scroll.
291
+ */
292
+ export declare const scrollBoundsIntoView: ({ bounds: [x1, y1, x2, y2], appState: { scrollX, scrollY, zoom, width, height }, offsets, tooLarge, }: {
293
+ bounds: Bounds;
294
+ appState: Pick<AppState, "scrollX" | "scrollY" | "zoom" | "width" | "height">;
295
+ offsets?: Offsets;
296
+ tooLarge?: "alignStart" | "leave";
297
+ }) => Pick<AppState, "scrollX" | "scrollY"> | null;
276
298
  export declare const getScrollToContentState: (elements: readonly ExcalidrawElement[], appState: AppState) => {
277
299
  scrollX: number;
278
300
  scrollY: number;
@@ -1,7 +1,13 @@
1
1
  import type { ExcalidrawTextElement } from "@excalidraw/element/types";
2
2
  import type App from "../components/App";
3
+ /**
4
+ * How much further than the browser's caret reveal the canvas pans, in
5
+ * screen px: text typed past the viewport's edge comes back with this much
6
+ * room to spare, instead of flush against the edge.
7
+ */
8
+ export declare const CARET_FOLLOW_PADDING = 5;
3
9
  type SubmitHandler = () => void;
4
- export declare const textWysiwyg: ({ onChange, onSubmit, getViewportCoords, element, canvas, excalidrawContainer, app, autoSelect, initialCaretSceneCoords, }: {
10
+ export declare const textWysiwyg: ({ onChange, onSubmit, getViewportCoords, element, canvas, excalidrawContainer, app, autoSelect, initialCaretSceneCoords, initialSelection, }: {
5
11
  /**
6
12
  * textWysiwyg only deals with `originalText`
7
13
  *
@@ -23,5 +29,10 @@ export declare const textWysiwyg: ({ onChange, onSubmit, getViewportCoords, elem
23
29
  x: number;
24
30
  y: number;
25
31
  } | null;
32
+ /** range of `originalText` to select (takes precedence over the caret) */
33
+ initialSelection?: {
34
+ start: number;
35
+ end: number;
36
+ } | null;
26
37
  }) => SubmitHandler;
27
38
  export {};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@excalidraw/math",
3
- "version": "0.18.0-4e758db",
3
+ "version": "0.18.0-4f68076",
4
4
  "type": "module",
5
5
  "types": "./dist/types/math/src/index.d.ts",
6
6
  "main": "./dist/prod/index.js",
@@ -61,6 +61,6 @@
61
61
  "build:esm": "rimraf dist && node ../../scripts/buildBase.js && yarn gen:types"
62
62
  },
63
63
  "dependencies": {
64
- "@excalidraw/common": "0.18.0-4e758db"
64
+ "@excalidraw/common": "0.18.0-4f68076"
65
65
  }
66
66
  }
@@ -1,31 +0,0 @@
1
- type DragOrigin = {
2
- kind: "swatch";
3
- } | {
4
- kind: "pick";
5
- index: number;
6
- };
7
- export type TopPicksDragState = {
8
- color: string;
9
- origin: DragOrigin;
10
- /** hovered strip slot — the slot to replace (swatch drags) or the final
11
- * position (pick reorders). null while the pointer is outside the strip */
12
- overIndex: number | null;
13
- /** index of an already-pinned identical color that blocks the drop */
14
- duplicateIndex: number | null;
15
- /** signed distance between strip slot centers (for reorder preview) */
16
- slotSpan: number;
17
- } | null;
18
- export type ColorPickerDnD = {
19
- dragState: TopPicksDragState;
20
- startSwatchDrag: (event: React.PointerEvent, color: string | null) => void;
21
- startPickDrag: (event: React.PointerEvent, index: number, color: string) => void;
22
- setStripEl: (el: HTMLDivElement | null) => void;
23
- };
24
- export declare const ColorPickerDnDContext: import("react").Context<ColorPickerDnD | null>;
25
- export declare const useColorPickerDnD: () => ColorPickerDnD | null;
26
- export declare const useTopPicksDnD: ({ enabled, picks, onPicksChange, }: {
27
- enabled: boolean;
28
- picks: readonly string[];
29
- onPicksChange: (picks: string[]) => void;
30
- }) => ColorPickerDnD;
31
- export {};