@zsviczian/excalidraw 0.17.6-4 → 0.17.6-5

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 (41) hide show
  1. package/dist/excalidraw.development.js +50 -28
  2. package/dist/excalidraw.production.min.js +1 -1
  3. package/package.json +1 -1
  4. package/types/excalidraw/actions/actionAddToLibrary.d.ts +6 -0
  5. package/types/excalidraw/actions/actionBoundText.d.ts +4 -0
  6. package/types/excalidraw/actions/actionCanvas.d.ts +28 -0
  7. package/types/excalidraw/actions/actionClipboard.d.ts +12 -0
  8. package/types/excalidraw/actions/actionCropEditor.d.ts +216 -0
  9. package/types/excalidraw/actions/actionDeleteSelected.d.ts +6 -0
  10. package/types/excalidraw/actions/actionElementLock.d.ts +4 -0
  11. package/types/excalidraw/actions/actionExport.d.ts +18 -0
  12. package/types/excalidraw/actions/actionFinalize.d.ts +4 -0
  13. package/types/excalidraw/actions/actionFrame.d.ts +8 -0
  14. package/types/excalidraw/actions/actionGroup.d.ts +4 -0
  15. package/types/excalidraw/actions/actionLinearEditor.d.ts +2 -0
  16. package/types/excalidraw/actions/actionLink.d.ts +2 -0
  17. package/types/excalidraw/actions/actionMenu.d.ts +6 -0
  18. package/types/excalidraw/actions/actionNavigate.d.ts +4 -0
  19. package/types/excalidraw/actions/actionProperties.d.ts +30 -0
  20. package/types/excalidraw/actions/actionSelectAll.d.ts +2 -0
  21. package/types/excalidraw/actions/actionStyles.d.ts +2 -0
  22. package/types/excalidraw/actions/actionToggleGridMode.d.ts +2 -0
  23. package/types/excalidraw/actions/actionToggleObjectsSnapMode.d.ts +2 -0
  24. package/types/excalidraw/actions/actionToggleSearchMenu.d.ts +4 -0
  25. package/types/excalidraw/actions/actionToggleStats.d.ts +2 -0
  26. package/types/excalidraw/actions/actionToggleViewMode.d.ts +2 -0
  27. package/types/excalidraw/actions/actionToggleZenMode.d.ts +2 -0
  28. package/types/excalidraw/actions/index.d.ts +1 -0
  29. package/types/excalidraw/actions/types.d.ts +1 -1
  30. package/types/excalidraw/change.d.ts +2 -2
  31. package/types/excalidraw/components/App.d.ts +10 -3
  32. package/types/excalidraw/components/icons.d.ts +1 -0
  33. package/types/excalidraw/element/cropElement.d.ts +14 -0
  34. package/types/excalidraw/element/embeddable.d.ts +2 -0
  35. package/types/excalidraw/element/newElement.d.ts +1 -0
  36. package/types/excalidraw/element/transformHandles.d.ts +1 -1
  37. package/types/excalidraw/element/types.d.ts +10 -0
  38. package/types/excalidraw/scene/comparisons.d.ts +1 -0
  39. package/types/excalidraw/types.d.ts +7 -0
  40. package/types/math/utils.d.ts +1 -0
  41. package/types/math/vector.d.ts +4 -0
@@ -191,6 +191,8 @@ export declare const actionToggleCanvasMenu: {
191
191
  objectsSnapModeEnabled: boolean;
192
192
  userToFollow: import("../types").UserToFollow | null;
193
193
  followedBy: Set<import("../types").SocketId>;
194
+ isCropping: boolean;
195
+ croppingElementId: string | null;
194
196
  searchMatches: readonly {
195
197
  id: string;
196
198
  focus: boolean;
@@ -401,6 +403,8 @@ export declare const actionToggleEditMenu: {
401
403
  objectsSnapModeEnabled: boolean;
402
404
  userToFollow: import("../types").UserToFollow | null;
403
405
  followedBy: Set<import("../types").SocketId>;
406
+ isCropping: boolean;
407
+ croppingElementId: string | null;
404
408
  searchMatches: readonly {
405
409
  id: string;
406
410
  focus: boolean;
@@ -609,6 +613,8 @@ export declare const actionShortcuts: {
609
613
  objectsSnapModeEnabled: boolean;
610
614
  userToFollow: import("../types").UserToFollow | null;
611
615
  followedBy: Set<import("../types").SocketId>;
616
+ isCropping: boolean;
617
+ croppingElementId: string | null;
612
618
  searchMatches: readonly {
613
619
  id: string;
614
620
  focus: boolean;
@@ -193,6 +193,8 @@ export declare const actionGoToCollaborator: {
193
193
  } | null;
194
194
  objectsSnapModeEnabled: boolean;
195
195
  followedBy: Set<import("../types").SocketId>;
196
+ isCropping: boolean;
197
+ croppingElementId: string | null;
196
198
  searchMatches: readonly {
197
199
  id: string;
198
200
  focus: boolean;
@@ -395,6 +397,8 @@ export declare const actionGoToCollaborator: {
395
397
  } | null;
396
398
  objectsSnapModeEnabled: boolean;
397
399
  followedBy: Set<import("../types").SocketId>;
400
+ isCropping: boolean;
401
+ croppingElementId: string | null;
398
402
  searchMatches: readonly {
399
403
  id: string;
400
404
  focus: boolean;
@@ -213,6 +213,8 @@ export declare const actionChangeFillStyle: {
213
213
  objectsSnapModeEnabled: boolean;
214
214
  userToFollow: import("../types").UserToFollow | null;
215
215
  followedBy: Set<import("../types").SocketId>;
216
+ isCropping: boolean;
217
+ croppingElementId: string | null;
216
218
  searchMatches: readonly {
217
219
  id: string;
218
220
  focus: boolean;
@@ -422,6 +424,8 @@ export declare const actionChangeStrokeWidth: {
422
424
  objectsSnapModeEnabled: boolean;
423
425
  userToFollow: import("../types").UserToFollow | null;
424
426
  followedBy: Set<import("../types").SocketId>;
427
+ isCropping: boolean;
428
+ croppingElementId: string | null;
425
429
  searchMatches: readonly {
426
430
  id: string;
427
431
  focus: boolean;
@@ -631,6 +635,8 @@ export declare const actionChangeSloppiness: {
631
635
  objectsSnapModeEnabled: boolean;
632
636
  userToFollow: import("../types").UserToFollow | null;
633
637
  followedBy: Set<import("../types").SocketId>;
638
+ isCropping: boolean;
639
+ croppingElementId: string | null;
634
640
  searchMatches: readonly {
635
641
  id: string;
636
642
  focus: boolean;
@@ -840,6 +846,8 @@ export declare const actionChangeStrokeStyle: {
840
846
  objectsSnapModeEnabled: boolean;
841
847
  userToFollow: import("../types").UserToFollow | null;
842
848
  followedBy: Set<import("../types").SocketId>;
849
+ isCropping: boolean;
850
+ croppingElementId: string | null;
843
851
  searchMatches: readonly {
844
852
  id: string;
845
853
  focus: boolean;
@@ -1049,6 +1057,8 @@ export declare const actionChangeOpacity: {
1049
1057
  objectsSnapModeEnabled: boolean;
1050
1058
  userToFollow: import("../types").UserToFollow | null;
1051
1059
  followedBy: Set<import("../types").SocketId>;
1060
+ isCropping: boolean;
1061
+ croppingElementId: string | null;
1052
1062
  searchMatches: readonly {
1053
1063
  id: string;
1054
1064
  focus: boolean;
@@ -1259,6 +1269,8 @@ export declare const actionChangeFontSize: {
1259
1269
  objectsSnapModeEnabled: boolean;
1260
1270
  userToFollow: import("../types").UserToFollow | null;
1261
1271
  followedBy: Set<import("../types").SocketId>;
1272
+ isCropping: boolean;
1273
+ croppingElementId: string | null;
1262
1274
  searchMatches: readonly {
1263
1275
  id: string;
1264
1276
  focus: boolean;
@@ -1469,6 +1481,8 @@ export declare const actionDecreaseFontSize: {
1469
1481
  objectsSnapModeEnabled: boolean;
1470
1482
  userToFollow: import("../types").UserToFollow | null;
1471
1483
  followedBy: Set<import("../types").SocketId>;
1484
+ isCropping: boolean;
1485
+ croppingElementId: string | null;
1472
1486
  searchMatches: readonly {
1473
1487
  id: string;
1474
1488
  focus: boolean;
@@ -1679,6 +1693,8 @@ export declare const actionIncreaseFontSize: {
1679
1693
  objectsSnapModeEnabled: boolean;
1680
1694
  userToFollow: import("../types").UserToFollow | null;
1681
1695
  followedBy: Set<import("../types").SocketId>;
1696
+ isCropping: boolean;
1697
+ croppingElementId: string | null;
1682
1698
  searchMatches: readonly {
1683
1699
  id: string;
1684
1700
  focus: boolean;
@@ -1887,6 +1903,8 @@ export declare const actionChangeFontFamily: {
1887
1903
  objectsSnapModeEnabled: boolean;
1888
1904
  userToFollow: import("../types").UserToFollow | null;
1889
1905
  followedBy: Set<import("../types").SocketId>;
1906
+ isCropping: boolean;
1907
+ croppingElementId: string | null;
1890
1908
  searchMatches: readonly {
1891
1909
  id: string;
1892
1910
  focus: boolean;
@@ -2087,6 +2105,8 @@ export declare const actionChangeFontFamily: {
2087
2105
  objectsSnapModeEnabled: boolean;
2088
2106
  userToFollow: import("../types").UserToFollow | null;
2089
2107
  followedBy: Set<import("../types").SocketId>;
2108
+ isCropping: boolean;
2109
+ croppingElementId: string | null;
2090
2110
  searchMatches: readonly {
2091
2111
  id: string;
2092
2112
  focus: boolean;
@@ -2296,6 +2316,8 @@ export declare const actionChangeTextAlign: {
2296
2316
  objectsSnapModeEnabled: boolean;
2297
2317
  userToFollow: import("../types").UserToFollow | null;
2298
2318
  followedBy: Set<import("../types").SocketId>;
2319
+ isCropping: boolean;
2320
+ croppingElementId: string | null;
2299
2321
  searchMatches: readonly {
2300
2322
  id: string;
2301
2323
  focus: boolean;
@@ -2507,6 +2529,8 @@ export declare const actionChangeVerticalAlign: {
2507
2529
  objectsSnapModeEnabled: boolean;
2508
2530
  userToFollow: import("../types").UserToFollow | null;
2509
2531
  followedBy: Set<import("../types").SocketId>;
2532
+ isCropping: boolean;
2533
+ croppingElementId: string | null;
2510
2534
  searchMatches: readonly {
2511
2535
  id: string;
2512
2536
  focus: boolean;
@@ -2716,6 +2740,8 @@ export declare const actionChangeRoundness: {
2716
2740
  objectsSnapModeEnabled: boolean;
2717
2741
  userToFollow: import("../types").UserToFollow | null;
2718
2742
  followedBy: Set<import("../types").SocketId>;
2743
+ isCropping: boolean;
2744
+ croppingElementId: string | null;
2719
2745
  searchMatches: readonly {
2720
2746
  id: string;
2721
2747
  focus: boolean;
@@ -2928,6 +2954,8 @@ export declare const actionChangeArrowhead: {
2928
2954
  objectsSnapModeEnabled: boolean;
2929
2955
  userToFollow: import("../types").UserToFollow | null;
2930
2956
  followedBy: Set<import("../types").SocketId>;
2957
+ isCropping: boolean;
2958
+ croppingElementId: string | null;
2931
2959
  searchMatches: readonly {
2932
2960
  id: string;
2933
2961
  focus: boolean;
@@ -3137,6 +3165,8 @@ export declare const actionChangeArrowType: {
3137
3165
  objectsSnapModeEnabled: boolean;
3138
3166
  userToFollow: import("../types").UserToFollow | null;
3139
3167
  followedBy: Set<import("../types").SocketId>;
3168
+ isCropping: boolean;
3169
+ croppingElementId: string | null;
3140
3170
  searchMatches: readonly {
3141
3171
  id: string;
3142
3172
  focus: boolean;
@@ -195,6 +195,8 @@ export declare const actionSelectAll: {
195
195
  objectsSnapModeEnabled: boolean;
196
196
  userToFollow: import("../types").UserToFollow | null;
197
197
  followedBy: Set<import("../types").SocketId>;
198
+ isCropping: boolean;
199
+ croppingElementId: string | null;
198
200
  searchMatches: readonly {
199
201
  id: string;
200
202
  focus: boolean;
@@ -191,6 +191,8 @@ export declare const actionCopyStyles: {
191
191
  objectsSnapModeEnabled: boolean;
192
192
  userToFollow: import("../types").UserToFollow | null;
193
193
  followedBy: Set<import("../types").SocketId>;
194
+ isCropping: boolean;
195
+ croppingElementId: string | null;
194
196
  searchMatches: readonly {
195
197
  id: string;
196
198
  focus: boolean;
@@ -196,6 +196,8 @@ export declare const actionToggleGridMode: {
196
196
  } | null;
197
197
  userToFollow: import("../types").UserToFollow | null;
198
198
  followedBy: Set<import("../types").SocketId>;
199
+ isCropping: boolean;
200
+ croppingElementId: string | null;
199
201
  searchMatches: readonly {
200
202
  id: string;
201
203
  focus: boolean;
@@ -194,6 +194,8 @@ export declare const actionToggleObjectsSnapMode: {
194
194
  } | null;
195
195
  userToFollow: import("../types").UserToFollow | null;
196
196
  followedBy: Set<import("../types").SocketId>;
197
+ isCropping: boolean;
198
+ croppingElementId: string | null;
197
199
  searchMatches: readonly {
198
200
  id: string;
199
201
  focus: boolean;
@@ -194,6 +194,8 @@ export declare const actionToggleSearchMenu: {
194
194
  objectsSnapModeEnabled: boolean;
195
195
  userToFollow: import("../types").UserToFollow | null;
196
196
  followedBy: Set<import("../types").SocketId>;
197
+ isCropping: boolean;
198
+ croppingElementId: string | null;
197
199
  searchMatches: readonly {
198
200
  id: string;
199
201
  focus: boolean;
@@ -386,6 +388,8 @@ export declare const actionToggleSearchMenu: {
386
388
  objectsSnapModeEnabled: boolean;
387
389
  userToFollow: import("../types").UserToFollow | null;
388
390
  followedBy: Set<import("../types").SocketId>;
391
+ isCropping: boolean;
392
+ croppingElementId: string | null;
389
393
  searchMatches: readonly {
390
394
  id: string;
391
395
  focus: boolean;
@@ -195,6 +195,8 @@ export declare const actionToggleStats: {
195
195
  objectsSnapModeEnabled: boolean;
196
196
  userToFollow: import("../types").UserToFollow | null;
197
197
  followedBy: Set<import("../types").SocketId>;
198
+ isCropping: boolean;
199
+ croppingElementId: string | null;
198
200
  searchMatches: readonly {
199
201
  id: string;
200
202
  focus: boolean;
@@ -195,6 +195,8 @@ export declare const actionToggleViewMode: {
195
195
  objectsSnapModeEnabled: boolean;
196
196
  userToFollow: import("../types").UserToFollow | null;
197
197
  followedBy: Set<import("../types").SocketId>;
198
+ isCropping: boolean;
199
+ croppingElementId: string | null;
198
200
  searchMatches: readonly {
199
201
  id: string;
200
202
  focus: boolean;
@@ -195,6 +195,8 @@ export declare const actionToggleZenMode: {
195
195
  objectsSnapModeEnabled: boolean;
196
196
  userToFollow: import("../types").UserToFollow | null;
197
197
  followedBy: Set<import("../types").SocketId>;
198
+ isCropping: boolean;
199
+ croppingElementId: string | null;
198
200
  searchMatches: readonly {
199
201
  id: string;
200
202
  focus: boolean;
@@ -24,3 +24,4 @@ export { actionLink } from "./actionLink";
24
24
  export { actionToggleElementLock } from "./actionElementLock";
25
25
  export { actionToggleLinearEditor } from "./actionLinearEditor";
26
26
  export { actionToggleSearchMenu } from "./actionToggleSearchMenu";
27
+ export { actionToggleCropEditor } from "./actionCropEditor";
@@ -14,7 +14,7 @@ export type ActionResult = {
14
14
  type ActionFn = (elements: readonly OrderedExcalidrawElement[], appState: Readonly<AppState>, formData: any, app: AppClassProperties) => ActionResult | Promise<ActionResult>;
15
15
  export type UpdaterFn = (res: ActionResult) => void;
16
16
  export type ActionFilterFn = (action: Action) => void;
17
- export type ActionName = "copy" | "cut" | "paste" | "copyAsPng" | "copyAsSvg" | "copyText" | "sendBackward" | "bringForward" | "sendToBack" | "bringToFront" | "copyStyles" | "selectAll" | "pasteStyles" | "gridMode" | "zenMode" | "objectsSnapMode" | "stats" | "changeStrokeColor" | "changeBackgroundColor" | "changeFillStyle" | "changeStrokeWidth" | "changeStrokeShape" | "changeSloppiness" | "changeStrokeStyle" | "changeArrowhead" | "changeArrowType" | "changeOpacity" | "changeFontSize" | "toggleCanvasMenu" | "toggleEditMenu" | "undo" | "redo" | "finalize" | "changeProjectName" | "changeExportBackground" | "changeExportEmbedScene" | "changeExportScale" | "saveToActiveFile" | "saveFileToDisk" | "loadScene" | "duplicateSelection" | "deleteSelectedElements" | "changeViewBackgroundColor" | "clearCanvas" | "zoomIn" | "zoomOut" | "resetZoom" | "zoomToFit" | "zoomToFitSelection" | "zoomToFitSelectionInViewport" | "changeFontFamily" | "changeTextAlign" | "changeVerticalAlign" | "toggleFullScreen" | "toggleShortcuts" | "group" | "ungroup" | "goToCollaborator" | "addToLibrary" | "changeRoundness" | "alignTop" | "alignBottom" | "alignLeft" | "alignRight" | "alignVerticallyCentered" | "alignHorizontallyCentered" | "distributeHorizontally" | "distributeVertically" | "flipHorizontal" | "flipVertical" | "viewMode" | "exportWithDarkMode" | "toggleTheme" | "increaseFontSize" | "decreaseFontSize" | "unbindText" | "hyperlink" | "bindText" | "unlockAllElements" | "toggleElementLock" | "toggleLinearEditor" | "toggleEraserTool" | "toggleHandTool" | "selectAllElementsInFrame" | "removeAllElementsFromFrame" | "updateFrameRendering" | "setFrameAsActiveTool" | "setEmbeddableAsActiveTool" | "createContainerFromText" | "wrapTextInContainer" | "toggleLaserPointerTool" | "commandPalette" | "autoResize" | "elementStats" | "searchMenu";
17
+ export type ActionName = "copy" | "cut" | "paste" | "copyAsPng" | "copyAsSvg" | "copyText" | "sendBackward" | "bringForward" | "sendToBack" | "bringToFront" | "copyStyles" | "selectAll" | "pasteStyles" | "gridMode" | "zenMode" | "objectsSnapMode" | "stats" | "changeStrokeColor" | "changeBackgroundColor" | "changeFillStyle" | "changeStrokeWidth" | "changeStrokeShape" | "changeSloppiness" | "changeStrokeStyle" | "changeArrowhead" | "changeArrowType" | "changeOpacity" | "changeFontSize" | "toggleCanvasMenu" | "toggleEditMenu" | "undo" | "redo" | "finalize" | "changeProjectName" | "changeExportBackground" | "changeExportEmbedScene" | "changeExportScale" | "saveToActiveFile" | "saveFileToDisk" | "loadScene" | "duplicateSelection" | "deleteSelectedElements" | "changeViewBackgroundColor" | "clearCanvas" | "zoomIn" | "zoomOut" | "resetZoom" | "zoomToFit" | "zoomToFitSelection" | "zoomToFitSelectionInViewport" | "changeFontFamily" | "changeTextAlign" | "changeVerticalAlign" | "toggleFullScreen" | "toggleShortcuts" | "group" | "ungroup" | "goToCollaborator" | "addToLibrary" | "changeRoundness" | "alignTop" | "alignBottom" | "alignLeft" | "alignRight" | "alignVerticallyCentered" | "alignHorizontallyCentered" | "distributeHorizontally" | "distributeVertically" | "flipHorizontal" | "flipVertical" | "viewMode" | "exportWithDarkMode" | "toggleTheme" | "increaseFontSize" | "decreaseFontSize" | "unbindText" | "hyperlink" | "bindText" | "unlockAllElements" | "toggleElementLock" | "toggleLinearEditor" | "toggleEraserTool" | "toggleHandTool" | "selectAllElementsInFrame" | "removeAllElementsFromFrame" | "updateFrameRendering" | "setFrameAsActiveTool" | "setEmbeddableAsActiveTool" | "createContainerFromText" | "wrapTextInContainer" | "toggleLaserPointerTool" | "commandPalette" | "autoResize" | "elementStats" | "searchMenu" | "cropEditor";
18
18
  export type PanelComponentProps = {
19
19
  elements: readonly ExcalidrawElement[];
20
20
  appState: AppState;
@@ -1,5 +1,5 @@
1
1
  import type { ElementUpdate } from "./element/mutateElement";
2
- import type { OrderedExcalidrawElement, SceneElementsMap } from "./element/types";
2
+ import type { ExcalidrawElement, Ordered, OrderedExcalidrawElement, SceneElementsMap } from "./element/types";
3
3
  import type { AppState, ObservedAppState } from "./types";
4
4
  import type { ValueOf } from "./utility-types";
5
5
  /**
@@ -116,7 +116,7 @@ export declare class AppStateChange implements Change<AppState> {
116
116
  private static stripElementsProps;
117
117
  private static stripStandaloneProps;
118
118
  }
119
- type ElementPartial = Omit<ElementUpdate<OrderedExcalidrawElement>, "seed">;
119
+ type ElementPartial<T extends ExcalidrawElement = ExcalidrawElement> = Omit<ElementUpdate<Ordered<T>>, "seed">;
120
120
  /**
121
121
  * Elements change is a low level primitive to capture a change between two sets of elements.
122
122
  * It does so by encapsulating forward and backward `Delta`s, allowing to time-travel in both directions.
@@ -5,7 +5,7 @@ import type { ActionResult } from "../actions/types";
5
5
  import { type EXPORT_IMAGE_TYPES } from "../constants";
6
6
  import type { ExportedElements } from "../data";
7
7
  import { LinearElementEditor } from "../element/linearElementEditor";
8
- import type { ExcalidrawElement, ExcalidrawLinearElement, NonDeleted, NonDeletedExcalidrawElement, ExcalidrawFrameLikeElement, ExcalidrawIframeElement, ExcalidrawEmbeddableElement, Ordered } from "../element/types";
8
+ import type { ExcalidrawElement, ExcalidrawLinearElement, NonDeleted, InitializedExcalidrawImageElement, ExcalidrawImageElement, NonDeletedExcalidrawElement, ExcalidrawFrameLikeElement, ExcalidrawIframeElement, ExcalidrawEmbeddableElement, Ordered } from "../element/types";
9
9
  import { History } from "../history";
10
10
  import Scene from "../scene/Scene";
11
11
  import type { AppClassProperties, AppProps, AppState, ExcalidrawImperativeAPI, BinaryFiles, LibraryItems, SceneData, Device, FrameNameBoundsCache, SidebarName, SidebarTabName, ToolType, OnUserFollowedPayload, GenerateDiagramToCode, NullableGridSize, Offsets } from "../types";
@@ -86,6 +86,10 @@ declare class App extends React.Component<AppProps, AppState> {
86
86
  lastPointerDownEvent: React.PointerEvent<HTMLElement> | null;
87
87
  lastPointerUpEvent: React.PointerEvent<HTMLElement> | PointerEvent | null;
88
88
  lastPointerMoveEvent: PointerEvent | null;
89
+ lastPointerMoveCoords: {
90
+ x: number;
91
+ y: number;
92
+ } | null;
89
93
  lastViewportPosition: {
90
94
  x: number;
91
95
  y: number;
@@ -426,6 +430,8 @@ declare class App extends React.Component<AppProps, AppState> {
426
430
  private getTextBindableContainerAtPosition;
427
431
  private startTextEditing;
428
432
  private debounceDoubleClickTimestamp;
433
+ private startImageCropping;
434
+ private finishImageCropping;
429
435
  private handleCanvasDoubleClick;
430
436
  private getElementLinkAtPosition;
431
437
  private redirectToLink;
@@ -486,10 +492,10 @@ declare class App extends React.Component<AppProps, AppState> {
486
492
  /**
487
493
  * inserts image into elements array and rerenders
488
494
  */
489
- private insertImageElement;
495
+ insertImageElement: (imageElement: ExcalidrawImageElement, imageFile: File, showCursorImagePreview?: boolean) => Promise<NonDeleted<InitializedExcalidrawImageElement> | null | undefined>;
490
496
  private setImagePreviewCursor;
491
497
  private onImageAction;
492
- private initializeImageDimensions;
498
+ initializeImageDimensions: (imageElement: ExcalidrawImageElement, forceNaturalSize?: boolean) => void;
493
499
  /** updates image cache, refreshing updated elements and/or setting status
494
500
  to error for images that fail during <img> element creation */
495
501
  private updateImageCache;
@@ -508,6 +514,7 @@ declare class App extends React.Component<AppProps, AppState> {
508
514
  loadFileToCanvas: (file: File, fileHandle: FileSystemHandle | null) => Promise<void>;
509
515
  private handleCanvasContextMenu;
510
516
  private maybeDragNewGenericElement;
517
+ private maybeHandleCrop;
511
518
  private maybeHandleResize;
512
519
  private getContextMenuItems;
513
520
  private handleWheel;
@@ -209,4 +209,5 @@ export declare const roundArrowIcon: JSX.Element;
209
209
  export declare const collapseDownIcon: JSX.Element;
210
210
  export declare const collapseUpIcon: JSX.Element;
211
211
  export declare const upIcon: JSX.Element;
212
+ export declare const cropIcon: JSX.Element;
212
213
  export {};
@@ -0,0 +1,14 @@
1
+ import type { TransformHandleType } from "./transformHandles";
2
+ import type { ElementsMap, ExcalidrawImageElement, ImageCrop } from "./types";
3
+ export declare const cropElement: (element: ExcalidrawImageElement, transformHandle: TransformHandleType, naturalWidth: number, naturalHeight: number, pointerX: number, pointerY: number, widthAspectRatio?: number) => {
4
+ x: number;
5
+ y: number;
6
+ width: number;
7
+ height: number;
8
+ crop: ImageCrop | null;
9
+ };
10
+ export declare const getUncroppedImageElement: (element: ExcalidrawImageElement, elementsMap: ElementsMap) => ExcalidrawImageElement;
11
+ export declare const getUncroppedWidthAndHeight: (element: ExcalidrawImageElement) => {
12
+ width: number;
13
+ height: number;
14
+ };
@@ -200,6 +200,8 @@ export declare const actionSetEmbeddableAsActiveTool: {
200
200
  objectsSnapModeEnabled: boolean;
201
201
  userToFollow: import("../types").UserToFollow | null;
202
202
  followedBy: Set<import("../types").SocketId>;
203
+ isCropping: boolean;
204
+ croppingElementId: string | null;
203
205
  searchMatches: readonly {
204
206
  id: string;
205
207
  focus: boolean;
@@ -58,6 +58,7 @@ export declare const newImageElement: (opts: {
58
58
  status?: ExcalidrawImageElement["status"];
59
59
  fileId?: ExcalidrawImageElement["fileId"];
60
60
  scale?: ExcalidrawImageElement["scale"];
61
+ crop?: ExcalidrawImageElement["crop"];
61
62
  } & ElementConstructorOpts) => NonDeleted<ExcalidrawImageElement>;
62
63
  /**
63
64
  * Clones ExcalidrawElement data structure. Does not regenerate id, nonce, or
@@ -40,7 +40,7 @@ export declare const getTransformHandlesFromCoords: ([x1, y1, x2, y2, cx, cy]: [
40
40
  sw?: boolean | undefined;
41
41
  se?: boolean | undefined;
42
42
  rotation?: boolean | undefined;
43
- }, margin?: number) => TransformHandles;
43
+ }, margin?: number, spacing?: number) => TransformHandles;
44
44
  export declare const getTransformHandles: (element: ExcalidrawElement, zoom: Zoom, elementsMap: ElementsMap, pointerType?: PointerType, omitSides?: {
45
45
  e?: boolean | undefined;
46
46
  s?: boolean | undefined;
@@ -120,6 +120,14 @@ export type IframeData = ({
120
120
  type: "document";
121
121
  srcdoc: (theme: Theme) => string;
122
122
  }));
123
+ export type ImageCrop = {
124
+ x: number;
125
+ y: number;
126
+ width: number;
127
+ height: number;
128
+ naturalWidth: number;
129
+ naturalHeight: number;
130
+ };
123
131
  export type ExcalidrawImageElement = _ExcalidrawElementBase & Readonly<{
124
132
  type: "image";
125
133
  fileId: FileId | null;
@@ -127,6 +135,8 @@ export type ExcalidrawImageElement = _ExcalidrawElementBase & Readonly<{
127
135
  status: "pending" | "saved" | "error";
128
136
  /** X and Y scale factors <-1, 1>, used for image axis flipping */
129
137
  scale: [number, number];
138
+ /** whether an element is cropped */
139
+ crop: ImageCrop | null;
130
140
  }>;
131
141
  export type InitializedExcalidrawImageElement = MarkNonNullable<ExcalidrawImageElement, "fileId">;
132
142
  export type ExcalidrawFrameElement = _ExcalidrawElementBase & {
@@ -289,6 +289,7 @@ export declare const getElementAtPosition: (elements: readonly NonDeletedExcalid
289
289
  fileId: import("../element/types").FileId | null;
290
290
  status: "pending" | "saved" | "error";
291
291
  scale: [number, number];
292
+ crop: import("../element/types").ImageCrop | null;
292
293
  }> & {
293
294
  isDeleted: boolean;
294
295
  }) | (Readonly<{
@@ -123,6 +123,7 @@ export type StaticCanvasAppState = Readonly<_CommonCanvasAppState & {
123
123
  gridColor: AppState["gridColor"];
124
124
  frameColor: AppState["frameColor"];
125
125
  currentHoveredFontFamily: AppState["currentHoveredFontFamily"];
126
+ croppingElementId: AppState["croppingElementId"];
126
127
  }>;
127
128
  export type InteractiveCanvasAppState = Readonly<_CommonCanvasAppState & {
128
129
  activeEmbeddable: AppState["activeEmbeddable"];
@@ -141,6 +142,8 @@ export type InteractiveCanvasAppState = Readonly<_CommonCanvasAppState & {
141
142
  editingTextElement: AppState["editingTextElement"];
142
143
  gridColor: AppState["gridColor"];
143
144
  highlightSearchResult: AppState["highlightSearchResult"];
145
+ isCropping: AppState["isCropping"];
146
+ croppingElementId: AppState["croppingElementId"];
144
147
  searchMatches: AppState["searchMatches"];
145
148
  }>;
146
149
  export type ObservedAppState = ObservedStandaloneAppState & ObservedElementsAppState;
@@ -154,6 +157,7 @@ export type ObservedElementsAppState = {
154
157
  selectedGroupIds: AppState["selectedGroupIds"];
155
158
  editingLinearElementId: LinearElementEditor["elementId"] | null;
156
159
  selectedLinearElementId: LinearElementEditor["elementId"] | null;
160
+ croppingElementId: AppState["croppingElementId"];
157
161
  };
158
162
  export interface AppState {
159
163
  contextMenu: {
@@ -358,6 +362,9 @@ export interface AppState {
358
362
  userToFollow: UserToFollow | null;
359
363
  /** the socket ids of the users following the current user */
360
364
  followedBy: Set<SocketId>;
365
+ /** image cropping */
366
+ isCropping: boolean;
367
+ croppingElementId: ExcalidrawElement["id"] | null;
361
368
  searchMatches: readonly SearchMatch[];
362
369
  }
363
370
  type SearchMatch = {
@@ -4,3 +4,4 @@ export declare const round: (value: number, precision: number, func?: "round" |
4
4
  export declare const roundToStep: (value: number, step: number, func?: "round" | "floor" | "ceil") => number;
5
5
  export declare const average: (a: number, b: number) => number;
6
6
  export declare const isFiniteNumber: (value: any) => value is number;
7
+ export declare const isCloseTo: (a: number, b: number, precision?: number) => boolean;
@@ -86,3 +86,7 @@ export declare function vectorMagnitude(v: Vector): number;
86
86
  * @returns The new normalized vector
87
87
  */
88
88
  export declare const vectorNormalize: (v: Vector) => Vector;
89
+ /**
90
+ * Project the first vector onto the second vector
91
+ */
92
+ export declare const vectorProjection: (a: Vector, b: Vector) => Vector;