chore: release @excalidraw/excalidraw@18.0.0 🎉 (#9127)

This commit is contained in:
Marcel Mraz
2025-02-28 16:49:09 +01:00
committed by GitHub
parent 392118bf26
commit ecef5d12f4
232 changed files with 3412 additions and 2851 deletions
@@ -3,7 +3,7 @@ import { deepCopyElement } from "../element/newElement";
import { randomId } from "../random";
import { t } from "../i18n";
import { LIBRARY_DISABLED_TYPES } from "../constants";
import { StoreAction } from "../store";
import { CaptureUpdateAction } from "../store";
export const actionAddToLibrary = register({
name: "addToLibrary",
@@ -18,7 +18,7 @@ export const actionAddToLibrary = register({
for (const type of LIBRARY_DISABLED_TYPES) {
if (selectedElements.some((element) => element.type === type)) {
return {
storeAction: StoreAction.NONE,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
appState: {
...appState,
errorMessage: t(`errors.libraryElementTypeError.${type}`),
@@ -42,7 +42,7 @@ export const actionAddToLibrary = register({
})
.then(() => {
return {
storeAction: StoreAction.NONE,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
appState: {
...appState,
toast: { message: t("toast.addedToLibrary") },
@@ -51,7 +51,7 @@ export const actionAddToLibrary = register({
})
.catch((error) => {
return {
storeAction: StoreAction.NONE,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
appState: {
...appState,
errorMessage: error.message,
+7 -7
View File
@@ -16,7 +16,7 @@ import { updateFrameMembershipOfSelectedElements } from "../frame";
import { t } from "../i18n";
import { KEYS } from "../keys";
import { isSomeElementSelected } from "../scene";
import { StoreAction } from "../store";
import { CaptureUpdateAction } from "../store";
import type { AppClassProperties, AppState, UIAppState } from "../types";
import { arrayToMap, getShortcutKey } from "../utils";
import { register } from "./register";
@@ -72,7 +72,7 @@ export const actionAlignTop = register({
position: "start",
axis: "y",
}),
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
},
keyTest: (event) =>
@@ -106,7 +106,7 @@ export const actionAlignBottom = register({
position: "end",
axis: "y",
}),
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
},
keyTest: (event) =>
@@ -140,7 +140,7 @@ export const actionAlignLeft = register({
position: "start",
axis: "x",
}),
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
},
keyTest: (event) =>
@@ -174,7 +174,7 @@ export const actionAlignRight = register({
position: "end",
axis: "x",
}),
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
},
keyTest: (event) =>
@@ -208,7 +208,7 @@ export const actionAlignVerticallyCentered = register({
position: "center",
axis: "y",
}),
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
},
PanelComponent: ({ elements, appState, updateData, app }) => (
@@ -238,7 +238,7 @@ export const actionAlignHorizontallyCentered = register({
position: "center",
axis: "x",
}),
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
},
PanelComponent: ({ elements, appState, updateData, app }) => (
@@ -33,7 +33,7 @@ import type { Mutable } from "../utility-types";
import { arrayToMap, getFontString } from "../utils";
import { register } from "./register";
import { syncMovedIndices } from "../fractionalIndex";
import { StoreAction } from "../store";
import { CaptureUpdateAction } from "../store";
import { measureText } from "../element/textMeasurements";
export const actionUnbindText = register({
@@ -86,7 +86,7 @@ export const actionUnbindText = register({
return {
elements,
appState,
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
},
});
@@ -163,7 +163,7 @@ export const actionBindText = register({
return {
elements: pushTextAboveContainer(elements, container, textElement),
appState: { ...appState, selectedElementIds: { [container.id]: true } },
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
},
});
@@ -323,7 +323,7 @@ export const actionWrapTextInContainer = register({
...appState,
selectedElementIds: containerIds,
},
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
},
});
+13 -13
View File
@@ -37,8 +37,8 @@ import {
import { DEFAULT_CANVAS_BACKGROUND_PICKS } from "../colors";
import type { SceneBounds } from "../element/bounds";
import { setCursor } from "../cursor";
import { StoreAction } from "../store";
import { clamp, roundToStep } from "../../math";
import { CaptureUpdateAction } from "../store";
import { clamp, roundToStep } from "@excalidraw/math";
export const actionChangeViewBackgroundColor = register({
name: "changeViewBackgroundColor",
@@ -54,9 +54,9 @@ export const actionChangeViewBackgroundColor = register({
perform: (_, appState, value) => {
return {
appState: { ...appState, ...value },
storeAction: !!value.viewBackgroundColor
? StoreAction.CAPTURE
: StoreAction.NONE,
captureUpdate: !!value.viewBackgroundColor
? CaptureUpdateAction.IMMEDIATELY
: CaptureUpdateAction.EVENTUALLY,
};
},
PanelComponent: ({ elements, appState, updateData, appProps }) => {
@@ -115,7 +115,7 @@ export const actionClearCanvas = register({
? { ...appState.activeTool, type: "selection" }
: appState.activeTool,
},
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
},
});
@@ -140,7 +140,7 @@ export const actionZoomIn = register({
),
userToFollow: null,
},
storeAction: StoreAction.NONE,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
};
},
PanelComponent: ({ updateData, appState }) => (
@@ -181,7 +181,7 @@ export const actionZoomOut = register({
),
userToFollow: null,
},
storeAction: StoreAction.NONE,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
};
},
PanelComponent: ({ updateData, appState }) => (
@@ -222,7 +222,7 @@ export const actionResetZoom = register({
),
userToFollow: null,
},
storeAction: StoreAction.NONE,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
};
},
PanelComponent: ({ updateData, appState }) => (
@@ -341,7 +341,7 @@ export const zoomToFitBounds = ({
scrollY: centerScroll.scrollY,
zoom: { value: newZoomValue },
},
storeAction: StoreAction.NONE,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
};
};
@@ -472,7 +472,7 @@ export const actionToggleTheme = register({
theme:
value || (appState.theme === THEME.LIGHT ? THEME.DARK : THEME.LIGHT),
},
storeAction: StoreAction.NONE,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
};
},
keyTest: (event) => event.altKey && event.shiftKey && event.code === CODES.D,
@@ -510,7 +510,7 @@ export const actionToggleEraserTool = register({
activeEmbeddable: null,
activeTool,
},
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
},
keyTest: (event) => event.key === KEYS.E,
@@ -549,7 +549,7 @@ export const actionToggleHandTool = register({
activeEmbeddable: null,
activeTool,
},
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
},
keyTest: (event) =>
+14 -14
View File
@@ -14,7 +14,7 @@ import { getTextFromElements, isTextElement } from "../element";
import { t } from "../i18n";
import { isFirefox } from "../constants";
import { DuplicateIcon, cutIcon, pngIcon, svgIcon } from "../components/icons";
import { StoreAction } from "../store";
import { CaptureUpdateAction } from "../store";
export const actionCopy = register({
name: "copy",
@@ -32,7 +32,7 @@ export const actionCopy = register({
await copyToClipboard(elementsToCopy, app.files, event);
} catch (error: any) {
return {
storeAction: StoreAction.NONE,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
appState: {
...appState,
errorMessage: error.message,
@@ -41,7 +41,7 @@ export const actionCopy = register({
}
return {
storeAction: StoreAction.NONE,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
};
},
// don't supply a shortcut since we handle this conditionally via onCopy event
@@ -67,7 +67,7 @@ export const actionPaste = register({
if (isFirefox) {
return {
storeAction: StoreAction.NONE,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
appState: {
...appState,
errorMessage: t("hints.firefox_clipboard_write"),
@@ -76,7 +76,7 @@ export const actionPaste = register({
}
return {
storeAction: StoreAction.NONE,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
appState: {
...appState,
errorMessage: t("errors.asyncPasteFailedOnRead"),
@@ -89,7 +89,7 @@ export const actionPaste = register({
} catch (error: any) {
console.error(error);
return {
storeAction: StoreAction.NONE,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
appState: {
...appState,
errorMessage: t("errors.asyncPasteFailedOnParse"),
@@ -98,7 +98,7 @@ export const actionPaste = register({
}
return {
storeAction: StoreAction.NONE,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
};
},
// don't supply a shortcut since we handle this conditionally via onCopy event
@@ -125,7 +125,7 @@ export const actionCopyAsSvg = register({
perform: async (elements, appState, _data, app) => {
if (!app.canvas) {
return {
storeAction: StoreAction.NONE,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
};
}
@@ -167,7 +167,7 @@ export const actionCopyAsSvg = register({
}),
},
},
storeAction: StoreAction.NONE,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
};
} catch (error: any) {
console.error(error);
@@ -175,7 +175,7 @@ export const actionCopyAsSvg = register({
appState: {
errorMessage: error.message,
},
storeAction: StoreAction.NONE,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
};
}
},
@@ -193,7 +193,7 @@ export const actionCopyAsPng = register({
perform: async (elements, appState, _data, app) => {
if (!app.canvas) {
return {
storeAction: StoreAction.NONE,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
};
}
const selectedElements = app.scene.getSelectedElements({
@@ -227,7 +227,7 @@ export const actionCopyAsPng = register({
}),
},
},
storeAction: StoreAction.NONE,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
};
} catch (error: any) {
console.error(error);
@@ -236,7 +236,7 @@ export const actionCopyAsPng = register({
...appState,
errorMessage: error.message,
},
storeAction: StoreAction.NONE,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
};
}
},
@@ -263,7 +263,7 @@ export const copyText = register({
throw new Error(t("errors.copyToSystemClipboardFailed"));
}
return {
storeAction: StoreAction.NONE,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
};
},
predicate: (elements, appState, _, app) => {
@@ -1,6 +1,6 @@
import { register } from "./register";
import { cropIcon } from "../components/icons";
import { StoreAction } from "../store";
import { CaptureUpdateAction } from "../store";
import { ToolButton } from "../components/ToolButton";
import { t } from "../i18n";
import { isImageElement } from "../element/typeChecks";
@@ -25,7 +25,7 @@ export const actionToggleCropEditor = register({
isCropping: false,
croppingElementId: selectedElement.id,
},
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
},
predicate: (elements, appState, _, app) => {
@@ -17,7 +17,7 @@ import {
} from "../element/typeChecks";
import { updateActiveTool } from "../utils";
import { TrashIcon } from "../components/icons";
import { StoreAction } from "../store";
import { CaptureUpdateAction } from "../store";
import { getContainerElement } from "../element/textElement";
import { getFrameChildren } from "../frame";
@@ -233,7 +233,7 @@ export const actionDeleteSelected = register({
...nextAppState,
editingLinearElement: null,
},
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
}
@@ -265,7 +265,7 @@ export const actionDeleteSelected = register({
: [0],
},
},
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
}
@@ -287,12 +287,12 @@ export const actionDeleteSelected = register({
multiElement: null,
activeEmbeddable: null,
},
storeAction: isSomeElementSelected(
captureUpdate: isSomeElementSelected(
getNonDeletedElements(elements),
appState,
)
? StoreAction.CAPTURE
: StoreAction.NONE,
? CaptureUpdateAction.IMMEDIATELY
: CaptureUpdateAction.EVENTUALLY,
};
},
keyTest: (event, appState, elements) =>
@@ -12,7 +12,7 @@ import { updateFrameMembershipOfSelectedElements } from "../frame";
import { t } from "../i18n";
import { CODES, KEYS } from "../keys";
import { isSomeElementSelected } from "../scene";
import { StoreAction } from "../store";
import { CaptureUpdateAction } from "../store";
import type { AppClassProperties, AppState } from "../types";
import { arrayToMap, getShortcutKey } from "../utils";
import { register } from "./register";
@@ -60,7 +60,7 @@ export const distributeHorizontally = register({
space: "between",
axis: "x",
}),
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
},
keyTest: (event) =>
@@ -91,7 +91,7 @@ export const distributeVertically = register({
space: "between",
axis: "y",
}),
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
},
keyTest: (event) =>
@@ -42,7 +42,7 @@ import {
excludeElementsInFramesFromSelection,
getSelectedElements,
} from "../scene/selection";
import { StoreAction } from "../store";
import { CaptureUpdateAction } from "../store";
export const actionDuplicateSelection = register({
name: "duplicateSelection",
@@ -62,7 +62,7 @@ export const actionDuplicateSelection = register({
return {
elements,
appState: newAppState,
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
} catch {
return false;
@@ -83,7 +83,7 @@ export const actionDuplicateSelection = register({
return {
...nextState,
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
},
keyTest: (event) => event[KEYS.CTRL_OR_CMD] && event.key === KEYS.D,
@@ -7,7 +7,7 @@ import {
} from "../element/elementLink";
import { t } from "../i18n";
import { getSelectedElements } from "../scene";
import { StoreAction } from "../store";
import { CaptureUpdateAction } from "../store";
import { register } from "./register";
export const actionCopyElementLink = register({
@@ -42,14 +42,14 @@ export const actionCopyElementLink = register({
closable: true,
},
},
storeAction: StoreAction.NONE,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
};
}
return {
appState,
elements,
app,
storeAction: StoreAction.NONE,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
};
}
} catch (error: any) {
@@ -60,7 +60,7 @@ export const actionCopyElementLink = register({
appState,
elements,
app,
storeAction: StoreAction.NONE,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
};
},
predicate: (elements, appState) =>
@@ -78,7 +78,12 @@ export const actionLinkToElement = register({
selectedElements.length !== 1 ||
!canCreateLinkFromElements(selectedElements)
) {
return { elements, appState, app, storeAction: StoreAction.NONE };
return {
elements,
appState,
app,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
};
}
return {
@@ -89,7 +94,7 @@ export const actionLinkToElement = register({
sourceElementId: getSelectedElements(elements, appState)[0].id,
},
},
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
},
predicate: (elements, appState, appProps, app) => {
@@ -4,7 +4,7 @@ import { isFrameLikeElement } from "../element/typeChecks";
import type { ExcalidrawElement } from "../element/types";
import { KEYS } from "../keys";
import { getSelectedElements } from "../scene";
import { StoreAction } from "../store";
import { CaptureUpdateAction } from "../store";
import { arrayToMap } from "../utils";
import { register } from "./register";
@@ -67,7 +67,7 @@ export const actionToggleElementLock = register({
? null
: appState.selectedLinearElement,
},
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
},
keyTest: (event, appState, elements, app) => {
@@ -112,7 +112,7 @@ export const actionUnlockAllElements = register({
lockedElements.map((el) => [el.id, true]),
),
},
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
},
label: "labels.elementLock.unlockAll",
+12 -12
View File
@@ -19,7 +19,7 @@ import { nativeFileSystemSupported } from "../data/filesystem";
import type { Theme } from "../element/types";
import "../components/ToolIcon.scss";
import { StoreAction } from "../store";
import { CaptureUpdateAction } from "../store";
export const actionChangeProjectName = register({
name: "changeProjectName",
@@ -28,7 +28,7 @@ export const actionChangeProjectName = register({
perform: (_elements, appState, value) => {
return {
appState: { ...appState, name: value },
storeAction: StoreAction.NONE,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
};
},
PanelComponent: ({ appState, updateData, appProps, data, app }) => (
@@ -48,7 +48,7 @@ export const actionChangeExportScale = register({
perform: (_elements, appState, value) => {
return {
appState: { ...appState, exportScale: value },
storeAction: StoreAction.NONE,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
};
},
PanelComponent: ({ elements: allElements, appState, updateData }) => {
@@ -98,7 +98,7 @@ export const actionChangeExportBackground = register({
perform: (_elements, appState, value) => {
return {
appState: { ...appState, exportBackground: value },
storeAction: StoreAction.NONE,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
};
},
PanelComponent: ({ appState, updateData }) => (
@@ -118,7 +118,7 @@ export const actionChangeExportEmbedScene = register({
perform: (_elements, appState, value) => {
return {
appState: { ...appState, exportEmbedScene: value },
storeAction: StoreAction.NONE,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
};
},
PanelComponent: ({ appState, updateData }) => (
@@ -160,7 +160,7 @@ export const actionSaveToActiveFile = register({
: await saveAsJSON(elements, appState, app.files, app.getName());
return {
storeAction: StoreAction.NONE,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
appState: {
...appState,
fileHandle,
@@ -182,7 +182,7 @@ export const actionSaveToActiveFile = register({
} else {
console.warn(error);
}
return { storeAction: StoreAction.NONE };
return { captureUpdate: CaptureUpdateAction.EVENTUALLY };
}
},
keyTest: (event) =>
@@ -207,7 +207,7 @@ export const actionSaveFileToDisk = register({
app.getName(),
);
return {
storeAction: StoreAction.NONE,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
appState: {
...appState,
openDialog: null,
@@ -221,7 +221,7 @@ export const actionSaveFileToDisk = register({
} else {
console.warn(error);
}
return { storeAction: StoreAction.NONE };
return { captureUpdate: CaptureUpdateAction.EVENTUALLY };
}
},
keyTest: (event) =>
@@ -260,7 +260,7 @@ export const actionLoadScene = register({
elements: loadedElements,
appState: loadedAppState,
files,
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
} catch (error: any) {
if (error?.name === "AbortError") {
@@ -271,7 +271,7 @@ export const actionLoadScene = register({
elements,
appState: { ...appState, errorMessage: error.message },
files: app.files,
storeAction: StoreAction.NONE,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
};
}
},
@@ -285,7 +285,7 @@ export const actionExportWithDarkMode = register({
perform: (_elements, appState, value) => {
return {
appState: { ...appState, exportWithDarkMode: value },
storeAction: StoreAction.NONE,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
};
},
PanelComponent: ({ appState, updateData }) => (
@@ -14,8 +14,8 @@ import {
import { isBindingElement, isLinearElement } from "../element/typeChecks";
import type { AppState } from "../types";
import { resetCursor } from "../cursor";
import { StoreAction } from "../store";
import { pointFrom } from "../../math";
import { CaptureUpdateAction } from "../store";
import { pointFrom } from "@excalidraw/math";
import { isPathALoop } from "../shapes";
export const actionFinalize = register({
@@ -52,7 +52,7 @@ export const actionFinalize = register({
cursorButton: "up",
editingLinearElement: null,
},
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
}
}
@@ -199,7 +199,7 @@ export const actionFinalize = register({
pendingImageElementId: null,
},
// TODO: #7348 we should not capture everything, but if we don't, it leads to incosistencies -> revisit
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
},
keyTest: (event, appState) =>
@@ -2,7 +2,7 @@ import React from "react";
import { Excalidraw } from "../index";
import { render } from "../tests/test-utils";
import { API } from "../tests/helpers/api";
import { pointFrom } from "../../math";
import { pointFrom } from "@excalidraw/math";
import { actionFlipHorizontal, actionFlipVertical } from "./actionFlip";
const { h } = window;
+3 -3
View File
@@ -18,7 +18,7 @@ import {
} from "../element/binding";
import { updateFrameMembershipOfSelectedElements } from "../frame";
import { flipHorizontal, flipVertical } from "../components/icons";
import { StoreAction } from "../store";
import { CaptureUpdateAction } from "../store";
import {
isArrowElement,
isElbowArrow,
@@ -47,7 +47,7 @@ export const actionFlipHorizontal = register({
app,
),
appState,
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
},
keyTest: (event) => event.shiftKey && event.code === CODES.H,
@@ -72,7 +72,7 @@ export const actionFlipVertical = register({
app,
),
appState,
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
},
keyTest: (event) =>
+8 -8
View File
@@ -9,7 +9,7 @@ import { setCursorForShape } from "../cursor";
import { register } from "./register";
import { isFrameLikeElement } from "../element/typeChecks";
import { frameToolIcon } from "../components/icons";
import { StoreAction } from "../store";
import { CaptureUpdateAction } from "../store";
import { getSelectedElements } from "../scene";
import { newFrameElement } from "../element/newElement";
import { getElementsInGroup } from "../groups";
@@ -49,14 +49,14 @@ export const actionSelectAllElementsInFrame = register({
return acc;
}, {} as Record<ExcalidrawElement["id"], true>),
},
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
}
return {
elements,
appState,
storeAction: StoreAction.NONE,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
};
},
predicate: (elements, appState, _, app) =>
@@ -80,14 +80,14 @@ export const actionRemoveAllElementsFromFrame = register({
[selectedElement.id]: true,
},
},
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
}
return {
elements,
appState,
storeAction: StoreAction.NONE,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
};
},
predicate: (elements, appState, _, app) =>
@@ -109,7 +109,7 @@ export const actionupdateFrameRendering = register({
enabled: !appState.frameRendering.enabled,
},
},
storeAction: StoreAction.NONE,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
};
},
checked: (appState: AppState) => appState.frameRendering.enabled,
@@ -139,7 +139,7 @@ export const actionSetFrameAsActiveTool = register({
type: "frame",
}),
},
storeAction: StoreAction.NONE,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
};
},
keyTest: (event) =>
@@ -208,7 +208,7 @@ export const actionWrapSelectionInFrame = register({
appState: {
selectedElementIds: { [frame.id]: true },
},
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
},
});
+18 -6
View File
@@ -34,7 +34,7 @@ import {
replaceAllElementsInFrame,
} from "../frame";
import { syncMovedIndices } from "../fractionalIndex";
import { StoreAction } from "../store";
import { CaptureUpdateAction } from "../store";
const allElementsInSameGroup = (elements: readonly ExcalidrawElement[]) => {
if (elements.length >= 2) {
@@ -84,7 +84,11 @@ export const actionGroup = register({
);
if (selectedElements.length < 2) {
// nothing to group
return { appState, elements, storeAction: StoreAction.NONE };
return {
appState,
elements,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
};
}
// if everything is already grouped into 1 group, there is nothing to do
const selectedGroupIds = getSelectedGroupIds(appState);
@@ -104,7 +108,11 @@ export const actionGroup = register({
]);
if (combinedSet.size === elementIdsInGroup.size) {
// no incremental ids in the selected ids
return { appState, elements, storeAction: StoreAction.NONE };
return {
appState,
elements,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
};
}
}
@@ -170,7 +178,7 @@ export const actionGroup = register({
),
},
elements: reorderedElements,
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
},
predicate: (elements, appState, _, app) =>
@@ -200,7 +208,11 @@ export const actionUngroup = register({
const elementsMap = arrayToMap(elements);
if (groupIds.length === 0) {
return { appState, elements, storeAction: StoreAction.NONE };
return {
appState,
elements,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
};
}
let nextElements = [...elements];
@@ -273,7 +285,7 @@ export const actionUngroup = register({
return {
appState: { ...appState, ...updateAppState },
elements: nextElements,
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
},
keyTest: (event) =>
@@ -10,7 +10,7 @@ import { arrayToMap } from "../utils";
import { isWindows } from "../constants";
import type { SceneElementsMap } from "../element/types";
import type { Store } from "../store";
import { StoreAction } from "../store";
import { CaptureUpdateAction } from "../store";
import { useEmitter } from "../hooks/useEmitter";
const executeHistoryAction = (
@@ -30,7 +30,7 @@ const executeHistoryAction = (
const result = updater();
if (!result) {
return { storeAction: StoreAction.NONE };
return { captureUpdate: CaptureUpdateAction.EVENTUALLY };
}
const [nextElementsMap, nextAppState] = result;
@@ -39,11 +39,11 @@ const executeHistoryAction = (
return {
appState: nextAppState,
elements: nextElements,
storeAction: StoreAction.UPDATE,
captureUpdate: CaptureUpdateAction.NEVER,
};
}
return { storeAction: StoreAction.NONE };
return { captureUpdate: CaptureUpdateAction.EVENTUALLY };
};
type ActionCreator = (history: History, store: Store) => Action;
@@ -2,7 +2,7 @@ import { DEFAULT_CATEGORIES } from "../components/CommandPalette/CommandPalette"
import { LinearElementEditor } from "../element/linearElementEditor";
import { isElbowArrow, isLinearElement } from "../element/typeChecks";
import type { ExcalidrawLinearElement } from "../element/types";
import { StoreAction } from "../store";
import { CaptureUpdateAction } from "../store";
import { register } from "./register";
import { ToolButton } from "../components/ToolButton";
import { t } from "../i18n";
@@ -51,7 +51,7 @@ export const actionToggleLinearEditor = register({
...appState,
editingLinearElement,
},
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
},
PanelComponent: ({ appState, updateData, app }) => {
+2 -2
View File
@@ -5,7 +5,7 @@ import { isEmbeddableElement } from "../element/typeChecks";
import { t } from "../i18n";
import { KEYS } from "../keys";
import { getSelectedElements } from "../scene";
import { StoreAction } from "../store";
import { CaptureUpdateAction } from "../store";
import { getShortcutKey } from "../utils";
import { register } from "./register";
@@ -25,7 +25,7 @@ export const actionLink = register({
showHyperlinkPopup: "editor",
openMenu: null,
},
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
},
trackEvent: { category: "hyperlink", action: "click" },
+4 -4
View File
@@ -4,7 +4,7 @@ import { t } from "../i18n";
import { showSelectedShapeActions, getNonDeletedElements } from "../element";
import { register } from "./register";
import { KEYS } from "../keys";
import { StoreAction } from "../store";
import { CaptureUpdateAction } from "../store";
export const actionToggleCanvasMenu = register({
name: "toggleCanvasMenu",
@@ -15,7 +15,7 @@ export const actionToggleCanvasMenu = register({
...appState,
openMenu: appState.openMenu === "canvas" ? null : "canvas",
},
storeAction: StoreAction.NONE,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
}),
PanelComponent: ({ appState, updateData }) => (
<ToolButton
@@ -37,7 +37,7 @@ export const actionToggleEditMenu = register({
...appState,
openMenu: appState.openMenu === "shape" ? null : "shape",
},
storeAction: StoreAction.NONE,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
}),
PanelComponent: ({ elements, appState, updateData }) => (
<ToolButton
@@ -74,7 +74,7 @@ export const actionShortcuts = register({
name: "help",
},
},
storeAction: StoreAction.NONE,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
};
},
keyTest: (event) => event.key === KEYS.QUESTION_MARK,
@@ -7,7 +7,7 @@ import {
microphoneMutedIcon,
} from "../components/icons";
import { t } from "../i18n";
import { StoreAction } from "../store";
import { CaptureUpdateAction } from "../store";
import type { Collaborator } from "../types";
import { register } from "./register";
import clsx from "clsx";
@@ -28,7 +28,7 @@ export const actionGoToCollaborator = register({
...appState,
userToFollow: null,
},
storeAction: StoreAction.NONE,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
};
}
@@ -42,7 +42,7 @@ export const actionGoToCollaborator = register({
// Close mobile menu
openMenu: appState.openMenu === "canvas" ? null : appState.openMenu,
},
storeAction: StoreAction.NONE,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
};
},
PanelComponent: ({ updateData, data, appState }) => {
@@ -1,6 +1,6 @@
import { useEffect, useMemo, useRef, useState } from "react";
import type { AppClassProperties, AppState, Primitive } from "../types";
import type { StoreActionType } from "../store";
import type { CaptureUpdateActionType } from "../store";
import {
DEFAULT_ELEMENT_BACKGROUND_COLOR_PALETTE,
DEFAULT_ELEMENT_BACKGROUND_PICKS,
@@ -109,7 +109,7 @@ import {
tupleToCoors,
} from "../utils";
import { register } from "./register";
import { StoreAction } from "../store";
import { CaptureUpdateAction } from "../store";
import { Fonts, getLineHeight } from "../fonts";
import {
bindLinearElement,
@@ -119,8 +119,8 @@ import {
updateBoundElements,
} from "../element/binding";
import { LinearElementEditor } from "../element/linearElementEditor";
import type { LocalPoint } from "../../math";
import { pointFrom } from "../../math";
import type { LocalPoint } from "@excalidraw/math";
import { pointFrom } from "@excalidraw/math";
import { Range } from "../components/Range";
const FONT_SIZE_RELATIVE_INCREASE_STEP = 0.1;
@@ -271,7 +271,7 @@ const changeFontSize = (
? [...newFontSizes][0]
: fallbackValue ?? appState.currentItemFontSize,
},
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
};
@@ -301,9 +301,9 @@ export const actionChangeStrokeColor = register({
...appState,
...value,
},
storeAction: !!value.currentItemStrokeColor
? StoreAction.CAPTURE
: StoreAction.NONE,
captureUpdate: !!value.currentItemStrokeColor
? CaptureUpdateAction.IMMEDIATELY
: CaptureUpdateAction.EVENTUALLY,
};
},
PanelComponent: ({ elements, appState, updateData, appProps }) => (
@@ -347,9 +347,9 @@ export const actionChangeBackgroundColor = register({
...appState,
...value,
},
storeAction: !!value.currentItemBackgroundColor
? StoreAction.CAPTURE
: StoreAction.NONE,
captureUpdate: !!value.currentItemBackgroundColor
? CaptureUpdateAction.IMMEDIATELY
: CaptureUpdateAction.EVENTUALLY,
};
},
PanelComponent: ({ elements, appState, updateData, appProps }) => (
@@ -393,7 +393,7 @@ export const actionChangeFillStyle = register({
}),
),
appState: { ...appState, currentItemFillStyle: value },
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
},
PanelComponent: ({ elements, appState, updateData }) => {
@@ -466,7 +466,7 @@ export const actionChangeStrokeWidth = register({
}),
),
appState: { ...appState, currentItemStrokeWidth: value },
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
},
PanelComponent: ({ elements, appState, updateData }) => (
@@ -521,7 +521,7 @@ export const actionChangeSloppiness = register({
}),
),
appState: { ...appState, currentItemRoughness: value },
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
},
PanelComponent: ({ elements, appState, updateData }) => (
@@ -572,7 +572,7 @@ export const actionChangeStrokeStyle = register({
}),
),
appState: { ...appState, currentItemStrokeStyle: value },
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
},
PanelComponent: ({ elements, appState, updateData }) => (
@@ -627,7 +627,7 @@ export const actionChangeOpacity = register({
true,
),
appState: { ...appState, currentItemOpacity: value },
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
},
PanelComponent: ({ elements, appState, updateData }) => (
@@ -802,22 +802,23 @@ export const actionChangeFontFamily = register({
...appState,
...nextAppState,
},
storeAction: StoreAction.UPDATE,
captureUpdate: CaptureUpdateAction.NEVER,
};
}
const { currentItemFontFamily, currentHoveredFontFamily } = value;
let nexStoreAction: StoreActionType = StoreAction.NONE;
let nextCaptureUpdateAction: CaptureUpdateActionType =
CaptureUpdateAction.EVENTUALLY;
let nextFontFamily: FontFamilyValues | undefined;
let skipOnHoverRender = false;
if (currentItemFontFamily) {
nextFontFamily = currentItemFontFamily;
nexStoreAction = StoreAction.CAPTURE;
nextCaptureUpdateAction = CaptureUpdateAction.IMMEDIATELY;
} else if (currentHoveredFontFamily) {
nextFontFamily = currentHoveredFontFamily;
nexStoreAction = StoreAction.NONE;
nextCaptureUpdateAction = CaptureUpdateAction.EVENTUALLY;
const selectedTextElements = getSelectedElements(elements, appState, {
includeBoundTextElement: true,
@@ -850,7 +851,7 @@ export const actionChangeFontFamily = register({
...appState,
...nextAppState,
},
storeAction: nexStoreAction,
captureUpdate: nextCaptureUpdateAction,
};
if (nextFontFamily && !skipOnHoverRender) {
@@ -1175,7 +1176,7 @@ export const actionChangeTextAlign = register({
...appState,
currentItemTextAlign: value,
},
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
},
PanelComponent: ({ elements, appState, updateData, app }) => {
@@ -1265,7 +1266,7 @@ export const actionChangeVerticalAlign = register({
appState: {
...appState,
},
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
},
PanelComponent: ({ elements, appState, updateData, app }) => {
@@ -1350,7 +1351,7 @@ export const actionChangeRoundness = register({
...appState,
currentItemRoundness: value,
},
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
},
PanelComponent: ({ elements, appState, updateData }) => {
@@ -1509,7 +1510,7 @@ export const actionChangeArrowhead = register({
? "currentItemStartArrowhead"
: "currentItemEndArrowhead"]: value.type,
},
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
},
PanelComponent: ({ elements, appState, updateData }) => {
@@ -1721,7 +1722,7 @@ export const actionChangeArrowType = register({
return {
elements: newElements,
appState: newState,
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
},
PanelComponent: ({ elements, appState, updateData }) => {
@@ -6,7 +6,7 @@ import type { ExcalidrawElement } from "../element/types";
import { isLinearElement } from "../element/typeChecks";
import { LinearElementEditor } from "../element/linearElementEditor";
import { selectAllIcon } from "../components/icons";
import { StoreAction } from "../store";
import { CaptureUpdateAction } from "../store";
export const actionSelectAll = register({
name: "selectAll",
@@ -50,7 +50,7 @@ export const actionSelectAll = register({
? new LinearElementEditor(elements[0])
: null,
},
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
},
keyTest: (event) => event[KEYS.CTRL_OR_CMD] && event.key === KEYS.A,
+4 -4
View File
@@ -23,7 +23,7 @@ import {
import { getSelectedElements } from "../scene";
import type { ExcalidrawTextElement } from "../element/types";
import { paintIcon } from "../components/icons";
import { StoreAction } from "../store";
import { CaptureUpdateAction } from "../store";
import { getLineHeight } from "../fonts";
// `copiedStyles` is exported only for tests.
@@ -53,7 +53,7 @@ export const actionCopyStyles = register({
...appState,
toast: { message: t("toast.copyStyles") },
},
storeAction: StoreAction.NONE,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
};
},
keyTest: (event) =>
@@ -70,7 +70,7 @@ export const actionPasteStyles = register({
const pastedElement = elementsCopied[0];
const boundTextElement = elementsCopied[1];
if (!isExcalidrawElement(pastedElement)) {
return { elements, storeAction: StoreAction.NONE };
return { elements, captureUpdate: CaptureUpdateAction.EVENTUALLY };
}
const selectedElements = getSelectedElements(elements, appState, {
@@ -159,7 +159,7 @@ export const actionPasteStyles = register({
}
return element;
}),
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
},
keyTest: (event) =>
@@ -2,7 +2,7 @@ import { isTextElement } from "../element";
import { newElementWith } from "../element/mutateElement";
import { measureText } from "../element/textMeasurements";
import { getSelectedElements } from "../scene";
import { StoreAction } from "../store";
import { CaptureUpdateAction } from "../store";
import type { AppClassProperties } from "../types";
import { getFontString } from "../utils";
import { register } from "./register";
@@ -42,7 +42,7 @@ export const actionTextAutoResize = register({
}
return element;
}),
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
},
});
@@ -2,7 +2,7 @@ import { CODES, KEYS } from "../keys";
import { register } from "./register";
import type { AppState } from "../types";
import { gridIcon } from "../components/icons";
import { StoreAction } from "../store";
import { CaptureUpdateAction } from "../store";
export const actionToggleGridMode = register({
name: "gridMode",
@@ -21,7 +21,7 @@ export const actionToggleGridMode = register({
gridModeEnabled: !this.checked!(appState),
objectsSnapModeEnabled: false,
},
storeAction: StoreAction.NONE,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
};
},
checked: (appState: AppState) => appState.gridModeEnabled,
@@ -1,6 +1,6 @@
import { magnetIcon } from "../components/icons";
import { CODES, KEYS } from "../keys";
import { StoreAction } from "../store";
import { CaptureUpdateAction } from "../store";
import { register } from "./register";
export const actionToggleObjectsSnapMode = register({
@@ -19,7 +19,7 @@ export const actionToggleObjectsSnapMode = register({
objectsSnapModeEnabled: !this.checked!(appState),
gridModeEnabled: false,
},
storeAction: StoreAction.NONE,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
};
},
checked: (appState) => appState.objectsSnapModeEnabled,
@@ -2,7 +2,7 @@ import { KEYS } from "../keys";
import { register } from "./register";
import type { AppState } from "../types";
import { searchIcon } from "../components/icons";
import { StoreAction } from "../store";
import { CaptureUpdateAction } from "../store";
import { CANVAS_SEARCH_TAB, CLASSES, DEFAULT_SIDEBAR } from "../constants";
export const actionToggleSearchMenu = register({
@@ -29,7 +29,7 @@ export const actionToggleSearchMenu = register({
if (searchInput?.matches(":focus")) {
return {
appState: { ...appState, openSidebar: null },
storeAction: StoreAction.NONE,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
};
}
@@ -44,7 +44,7 @@ export const actionToggleSearchMenu = register({
openSidebar: { name: DEFAULT_SIDEBAR.name, tab: CANVAS_SEARCH_TAB },
openDialog: null,
},
storeAction: StoreAction.NONE,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
};
},
checked: (appState: AppState) => appState.gridModeEnabled,
@@ -1,7 +1,7 @@
import { register } from "./register";
import { CODES, KEYS } from "../keys";
import { abacusIcon } from "../components/icons";
import { StoreAction } from "../store";
import { CaptureUpdateAction } from "../store";
export const actionToggleStats = register({
name: "stats",
@@ -17,7 +17,7 @@ export const actionToggleStats = register({
...appState,
stats: { ...appState.stats, open: !this.checked!(appState) },
},
storeAction: StoreAction.NONE,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
};
},
checked: (appState) => appState.stats.open,
@@ -1,6 +1,6 @@
import { eyeIcon } from "../components/icons";
import { CODES, KEYS } from "../keys";
import { StoreAction } from "../store";
import { CaptureUpdateAction } from "../store";
import { register } from "./register";
export const actionToggleViewMode = register({
@@ -19,7 +19,7 @@ export const actionToggleViewMode = register({
...appState,
viewModeEnabled: !this.checked!(appState),
},
storeAction: StoreAction.NONE,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
};
},
checked: (appState) => appState.viewModeEnabled,
@@ -1,6 +1,6 @@
import { coffeeIcon } from "../components/icons";
import { CODES, KEYS } from "../keys";
import { StoreAction } from "../store";
import { CaptureUpdateAction } from "../store";
import { register } from "./register";
export const actionToggleZenMode = register({
@@ -19,7 +19,7 @@ export const actionToggleZenMode = register({
...appState,
zenModeEnabled: !this.checked!(appState),
},
storeAction: StoreAction.NONE,
captureUpdate: CaptureUpdateAction.EVENTUALLY,
};
},
checked: (appState) => appState.zenModeEnabled,
+5 -5
View File
@@ -15,7 +15,7 @@ import {
SendToBackIcon,
} from "../components/icons";
import { isDarwin } from "../constants";
import { StoreAction } from "../store";
import { CaptureUpdateAction } from "../store";
export const actionSendBackward = register({
name: "sendBackward",
@@ -27,7 +27,7 @@ export const actionSendBackward = register({
return {
elements: moveOneLeft(elements, appState),
appState,
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
},
keyPriority: 40,
@@ -57,7 +57,7 @@ export const actionBringForward = register({
return {
elements: moveOneRight(elements, appState),
appState,
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
},
keyPriority: 40,
@@ -87,7 +87,7 @@ export const actionSendToBack = register({
return {
elements: moveAllLeft(elements, appState),
appState,
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
},
keyTest: (event) =>
@@ -125,7 +125,7 @@ export const actionBringToFront = register({
return {
elements: moveAllRight(elements, appState),
appState,
storeAction: StoreAction.CAPTURE,
captureUpdate: CaptureUpdateAction.IMMEDIATELY,
};
},
keyTest: (event) =>
+2 -2
View File
@@ -10,7 +10,7 @@ import type {
BinaryFiles,
UIAppState,
} from "../types";
import type { StoreActionType } from "../store";
import type { CaptureUpdateActionType } from "../store";
export type ActionSource =
| "ui"
@@ -25,7 +25,7 @@ export type ActionResult =
elements?: readonly ExcalidrawElement[] | null;
appState?: Partial<AppState> | null;
files?: BinaryFiles | null;
storeAction: StoreActionType;
captureUpdate: CaptureUpdateActionType;
replaceFiles?: boolean;
}
| false;