parent
ca5f37850e
commit
82ce068972
@ -14,7 +14,10 @@ import { newElementWith } from "../element/mutateElement";
|
|||||||
export const actionChangeViewBackgroundColor = register({
|
export const actionChangeViewBackgroundColor = register({
|
||||||
name: "changeViewBackgroundColor",
|
name: "changeViewBackgroundColor",
|
||||||
perform: (_, appState, value) => {
|
perform: (_, appState, value) => {
|
||||||
return { appState: { ...appState, viewBackgroundColor: value } };
|
return {
|
||||||
|
appState: { ...appState, viewBackgroundColor: value },
|
||||||
|
commitToHistory: true,
|
||||||
|
};
|
||||||
},
|
},
|
||||||
PanelComponent: ({ appState, updateData }) => {
|
PanelComponent: ({ appState, updateData }) => {
|
||||||
return (
|
return (
|
||||||
@ -28,18 +31,17 @@ export const actionChangeViewBackgroundColor = register({
|
|||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
commitToHistory: () => true,
|
|
||||||
});
|
});
|
||||||
|
|
||||||
export const actionClearCanvas = register({
|
export const actionClearCanvas = register({
|
||||||
name: "clearCanvas",
|
name: "clearCanvas",
|
||||||
commitToHistory: () => true,
|
|
||||||
perform: elements => {
|
perform: elements => {
|
||||||
return {
|
return {
|
||||||
elements: elements.map(element =>
|
elements: elements.map(element =>
|
||||||
newElementWith(element, { isDeleted: true }),
|
newElementWith(element, { isDeleted: true }),
|
||||||
),
|
),
|
||||||
appState: getDefaultAppState(),
|
appState: getDefaultAppState(),
|
||||||
|
commitToHistory: true,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
PanelComponent: ({ updateData }) => (
|
PanelComponent: ({ updateData }) => (
|
||||||
@ -81,6 +83,7 @@ export const actionZoomIn = register({
|
|||||||
...appState,
|
...appState,
|
||||||
zoom: getNormalizedZoom(appState.zoom + ZOOM_STEP),
|
zoom: getNormalizedZoom(appState.zoom + ZOOM_STEP),
|
||||||
},
|
},
|
||||||
|
commitToHistory: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
PanelComponent: ({ updateData }) => (
|
PanelComponent: ({ updateData }) => (
|
||||||
@ -107,6 +110,7 @@ export const actionZoomOut = register({
|
|||||||
...appState,
|
...appState,
|
||||||
zoom: getNormalizedZoom(appState.zoom - ZOOM_STEP),
|
zoom: getNormalizedZoom(appState.zoom - ZOOM_STEP),
|
||||||
},
|
},
|
||||||
|
commitToHistory: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
PanelComponent: ({ updateData }) => (
|
PanelComponent: ({ updateData }) => (
|
||||||
@ -133,6 +137,7 @@ export const actionResetZoom = register({
|
|||||||
...appState,
|
...appState,
|
||||||
zoom: 1,
|
zoom: 1,
|
||||||
},
|
},
|
||||||
|
commitToHistory: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
PanelComponent: ({ updateData }) => (
|
PanelComponent: ({ updateData }) => (
|
||||||
|
@ -20,12 +20,11 @@ export const actionDeleteSelected = register({
|
|||||||
elementType: "selection",
|
elementType: "selection",
|
||||||
multiElement: null,
|
multiElement: null,
|
||||||
},
|
},
|
||||||
|
commitToHistory: isSomeElementSelected(elements, appState),
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
contextItemLabel: "labels.delete",
|
contextItemLabel: "labels.delete",
|
||||||
contextMenuOrder: 3,
|
contextMenuOrder: 3,
|
||||||
commitToHistory: (appState, elements) =>
|
|
||||||
isSomeElementSelected(elements, appState),
|
|
||||||
keyTest: event => event.key === KEYS.BACKSPACE || event.key === KEYS.DELETE,
|
keyTest: event => event.key === KEYS.BACKSPACE || event.key === KEYS.DELETE,
|
||||||
PanelComponent: ({ elements, appState, updateData }) => (
|
PanelComponent: ({ elements, appState, updateData }) => (
|
||||||
<ToolButton
|
<ToolButton
|
||||||
|
@ -23,6 +23,7 @@ export const actionDuplicateSelection = register({
|
|||||||
},
|
},
|
||||||
[],
|
[],
|
||||||
),
|
),
|
||||||
|
commitToHistory: true,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
contextItemLabel: "labels.duplicateSelection",
|
contextItemLabel: "labels.duplicateSelection",
|
||||||
|
@ -10,7 +10,7 @@ import { register } from "./register";
|
|||||||
export const actionChangeProjectName = register({
|
export const actionChangeProjectName = register({
|
||||||
name: "changeProjectName",
|
name: "changeProjectName",
|
||||||
perform: (_elements, appState, value) => {
|
perform: (_elements, appState, value) => {
|
||||||
return { appState: { ...appState, name: value } };
|
return { appState: { ...appState, name: value }, commitToHistory: false };
|
||||||
},
|
},
|
||||||
PanelComponent: ({ appState, updateData }) => (
|
PanelComponent: ({ appState, updateData }) => (
|
||||||
<ProjectName
|
<ProjectName
|
||||||
@ -24,7 +24,10 @@ export const actionChangeProjectName = register({
|
|||||||
export const actionChangeExportBackground = register({
|
export const actionChangeExportBackground = register({
|
||||||
name: "changeExportBackground",
|
name: "changeExportBackground",
|
||||||
perform: (_elements, appState, value) => {
|
perform: (_elements, appState, value) => {
|
||||||
return { appState: { ...appState, exportBackground: value } };
|
return {
|
||||||
|
appState: { ...appState, exportBackground: value },
|
||||||
|
commitToHistory: false,
|
||||||
|
};
|
||||||
},
|
},
|
||||||
PanelComponent: ({ appState, updateData }) => (
|
PanelComponent: ({ appState, updateData }) => (
|
||||||
<label>
|
<label>
|
||||||
@ -42,7 +45,7 @@ export const actionSaveScene = register({
|
|||||||
name: "saveScene",
|
name: "saveScene",
|
||||||
perform: (elements, appState, value) => {
|
perform: (elements, appState, value) => {
|
||||||
saveAsJSON(elements, appState).catch(error => console.error(error));
|
saveAsJSON(elements, appState).catch(error => console.error(error));
|
||||||
return {};
|
return { commitToHistory: false };
|
||||||
},
|
},
|
||||||
PanelComponent: ({ updateData }) => (
|
PanelComponent: ({ updateData }) => (
|
||||||
<ToolButton
|
<ToolButton
|
||||||
@ -63,7 +66,11 @@ export const actionLoadScene = register({
|
|||||||
appState,
|
appState,
|
||||||
{ elements: loadedElements, appState: loadedAppState },
|
{ elements: loadedElements, appState: loadedAppState },
|
||||||
) => {
|
) => {
|
||||||
return { elements: loadedElements, appState: loadedAppState };
|
return {
|
||||||
|
elements: loadedElements,
|
||||||
|
appState: loadedAppState,
|
||||||
|
commitToHistory: false,
|
||||||
|
};
|
||||||
},
|
},
|
||||||
PanelComponent: ({ updateData }) => (
|
PanelComponent: ({ updateData }) => (
|
||||||
<ToolButton
|
<ToolButton
|
||||||
|
@ -52,6 +52,7 @@ export const actionFinalize = register({
|
|||||||
editingElement: null,
|
editingElement: null,
|
||||||
selectedElementIds: {},
|
selectedElementIds: {},
|
||||||
},
|
},
|
||||||
|
commitToHistory: false,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
keyTest: (event, appState) =>
|
keyTest: (event, appState) =>
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Action } from "./types";
|
import { Action, ActionResult } from "./types";
|
||||||
import React from "react";
|
import React from "react";
|
||||||
import { undo, redo } from "../components/icons";
|
import { undo, redo } from "../components/icons";
|
||||||
import { ToolButton } from "../components/ToolButton";
|
import { ToolButton } from "../components/ToolButton";
|
||||||
@ -13,8 +13,12 @@ import { newElementWith } from "../element/mutateElement";
|
|||||||
const writeData = (
|
const writeData = (
|
||||||
prevElements: readonly ExcalidrawElement[],
|
prevElements: readonly ExcalidrawElement[],
|
||||||
appState: AppState,
|
appState: AppState,
|
||||||
updater: () => { elements: ExcalidrawElement[]; appState: AppState } | null,
|
updater: () => {
|
||||||
) => {
|
elements: ExcalidrawElement[];
|
||||||
|
appState: AppState;
|
||||||
|
} | null,
|
||||||
|
): ActionResult => {
|
||||||
|
const commitToHistory = false;
|
||||||
if (
|
if (
|
||||||
!appState.multiElement &&
|
!appState.multiElement &&
|
||||||
!appState.resizingElement &&
|
!appState.resizingElement &&
|
||||||
@ -23,7 +27,7 @@ const writeData = (
|
|||||||
) {
|
) {
|
||||||
const data = updater();
|
const data = updater();
|
||||||
if (data === null) {
|
if (data === null) {
|
||||||
return {};
|
return { commitToHistory };
|
||||||
}
|
}
|
||||||
|
|
||||||
const prevElementMap = getElementMap(prevElements);
|
const prevElementMap = getElementMap(prevElements);
|
||||||
@ -47,9 +51,10 @@ const writeData = (
|
|||||||
),
|
),
|
||||||
),
|
),
|
||||||
appState: { ...appState, ...data.appState },
|
appState: { ...appState, ...data.appState },
|
||||||
|
commitToHistory,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
return {};
|
return { commitToHistory };
|
||||||
};
|
};
|
||||||
|
|
||||||
const testUndo = (shift: boolean) => (event: KeyboardEvent) =>
|
const testUndo = (shift: boolean) => (event: KeyboardEvent) =>
|
||||||
|
@ -12,6 +12,7 @@ export const actionToggleCanvasMenu = register({
|
|||||||
...appState,
|
...appState,
|
||||||
openMenu: appState.openMenu === "canvas" ? null : "canvas",
|
openMenu: appState.openMenu === "canvas" ? null : "canvas",
|
||||||
},
|
},
|
||||||
|
commitToHistory: false,
|
||||||
}),
|
}),
|
||||||
PanelComponent: ({ appState, updateData }) => (
|
PanelComponent: ({ appState, updateData }) => (
|
||||||
<ToolButton
|
<ToolButton
|
||||||
@ -31,6 +32,7 @@ export const actionToggleEditMenu = register({
|
|||||||
...appState,
|
...appState,
|
||||||
openMenu: appState.openMenu === "shape" ? null : "shape",
|
openMenu: appState.openMenu === "shape" ? null : "shape",
|
||||||
},
|
},
|
||||||
|
commitToHistory: false,
|
||||||
}),
|
}),
|
||||||
PanelComponent: ({ elements, appState, updateData }) => (
|
PanelComponent: ({ elements, appState, updateData }) => (
|
||||||
<ToolButton
|
<ToolButton
|
||||||
|
@ -52,9 +52,9 @@ export const actionChangeStrokeColor = register({
|
|||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
appState: { ...appState, currentItemStrokeColor: value },
|
appState: { ...appState, currentItemStrokeColor: value },
|
||||||
|
commitToHistory: true,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
commitToHistory: () => true,
|
|
||||||
PanelComponent: ({ elements, appState, updateData }) => (
|
PanelComponent: ({ elements, appState, updateData }) => (
|
||||||
<>
|
<>
|
||||||
<h3 aria-hidden="true">{t("labels.stroke")}</h3>
|
<h3 aria-hidden="true">{t("labels.stroke")}</h3>
|
||||||
@ -83,9 +83,9 @@ export const actionChangeBackgroundColor = register({
|
|||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
appState: { ...appState, currentItemBackgroundColor: value },
|
appState: { ...appState, currentItemBackgroundColor: value },
|
||||||
|
commitToHistory: true,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
commitToHistory: () => true,
|
|
||||||
PanelComponent: ({ elements, appState, updateData }) => (
|
PanelComponent: ({ elements, appState, updateData }) => (
|
||||||
<>
|
<>
|
||||||
<h3 aria-hidden="true">{t("labels.background")}</h3>
|
<h3 aria-hidden="true">{t("labels.background")}</h3>
|
||||||
@ -114,9 +114,9 @@ export const actionChangeFillStyle = register({
|
|||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
appState: { ...appState, currentItemFillStyle: value },
|
appState: { ...appState, currentItemFillStyle: value },
|
||||||
|
commitToHistory: true,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
commitToHistory: () => true,
|
|
||||||
PanelComponent: ({ elements, appState, updateData }) => (
|
PanelComponent: ({ elements, appState, updateData }) => (
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>{t("labels.fill")}</legend>
|
<legend>{t("labels.fill")}</legend>
|
||||||
@ -151,9 +151,9 @@ export const actionChangeStrokeWidth = register({
|
|||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
appState: { ...appState, currentItemStrokeWidth: value },
|
appState: { ...appState, currentItemStrokeWidth: value },
|
||||||
|
commitToHistory: true,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
commitToHistory: () => true,
|
|
||||||
PanelComponent: ({ elements, appState, updateData }) => (
|
PanelComponent: ({ elements, appState, updateData }) => (
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>{t("labels.strokeWidth")}</legend>
|
<legend>{t("labels.strokeWidth")}</legend>
|
||||||
@ -186,9 +186,9 @@ export const actionChangeSloppiness = register({
|
|||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
appState: { ...appState, currentItemRoughness: value },
|
appState: { ...appState, currentItemRoughness: value },
|
||||||
|
commitToHistory: true,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
commitToHistory: () => true,
|
|
||||||
PanelComponent: ({ elements, appState, updateData }) => (
|
PanelComponent: ({ elements, appState, updateData }) => (
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>{t("labels.sloppiness")}</legend>
|
<legend>{t("labels.sloppiness")}</legend>
|
||||||
@ -221,9 +221,9 @@ export const actionChangeOpacity = register({
|
|||||||
}),
|
}),
|
||||||
),
|
),
|
||||||
appState: { ...appState, currentItemOpacity: value },
|
appState: { ...appState, currentItemOpacity: value },
|
||||||
|
commitToHistory: true,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
commitToHistory: () => true,
|
|
||||||
PanelComponent: ({ elements, appState, updateData }) => (
|
PanelComponent: ({ elements, appState, updateData }) => (
|
||||||
<label className="control-label">
|
<label className="control-label">
|
||||||
{t("labels.opacity")}
|
{t("labels.opacity")}
|
||||||
@ -281,9 +281,9 @@ export const actionChangeFontSize = register({
|
|||||||
appState.currentItemFont.split("px ")[1]
|
appState.currentItemFont.split("px ")[1]
|
||||||
}`,
|
}`,
|
||||||
},
|
},
|
||||||
|
commitToHistory: true,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
commitToHistory: () => true,
|
|
||||||
PanelComponent: ({ elements, appState, updateData }) => (
|
PanelComponent: ({ elements, appState, updateData }) => (
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>{t("labels.fontSize")}</legend>
|
<legend>{t("labels.fontSize")}</legend>
|
||||||
@ -328,9 +328,9 @@ export const actionChangeFontFamily = register({
|
|||||||
appState.currentItemFont.split("px ")[0]
|
appState.currentItemFont.split("px ")[0]
|
||||||
}px ${value}`,
|
}px ${value}`,
|
||||||
},
|
},
|
||||||
|
commitToHistory: true,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
commitToHistory: () => true,
|
|
||||||
PanelComponent: ({ elements, appState, updateData }) => (
|
PanelComponent: ({ elements, appState, updateData }) => (
|
||||||
<fieldset>
|
<fieldset>
|
||||||
<legend>{t("labels.fontFamily")}</legend>
|
<legend>{t("labels.fontFamily")}</legend>
|
||||||
|
@ -12,6 +12,7 @@ export const actionSelectAll = register({
|
|||||||
return map;
|
return map;
|
||||||
}, {} as any),
|
}, {} as any),
|
||||||
},
|
},
|
||||||
|
commitToHistory: true,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
contextItemLabel: "labels.selectAll",
|
contextItemLabel: "labels.selectAll",
|
||||||
|
@ -17,7 +17,9 @@ export const actionCopyStyles = register({
|
|||||||
if (element) {
|
if (element) {
|
||||||
copiedStyles = JSON.stringify(element);
|
copiedStyles = JSON.stringify(element);
|
||||||
}
|
}
|
||||||
return {};
|
return {
|
||||||
|
commitToHistory: false,
|
||||||
|
};
|
||||||
},
|
},
|
||||||
contextItemLabel: "labels.copyStyles",
|
contextItemLabel: "labels.copyStyles",
|
||||||
keyTest: event =>
|
keyTest: event =>
|
||||||
@ -30,7 +32,7 @@ export const actionPasteStyles = register({
|
|||||||
perform: (elements, appState) => {
|
perform: (elements, appState) => {
|
||||||
const pastedElement = JSON.parse(copiedStyles);
|
const pastedElement = JSON.parse(copiedStyles);
|
||||||
if (!isExcalidrawElement(pastedElement)) {
|
if (!isExcalidrawElement(pastedElement)) {
|
||||||
return { elements };
|
return { elements, commitToHistory: false };
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
elements: elements.map(element => {
|
elements: elements.map(element => {
|
||||||
@ -53,9 +55,9 @@ export const actionPasteStyles = register({
|
|||||||
}
|
}
|
||||||
return element;
|
return element;
|
||||||
}),
|
}),
|
||||||
|
commitToHistory: true,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
commitToHistory: () => true,
|
|
||||||
contextItemLabel: "labels.pasteStyles",
|
contextItemLabel: "labels.pasteStyles",
|
||||||
keyTest: event =>
|
keyTest: event =>
|
||||||
event[KEYS.CTRL_OR_CMD] && event.shiftKey && event.key === "V",
|
event[KEYS.CTRL_OR_CMD] && event.shiftKey && event.key === "V",
|
||||||
|
@ -26,11 +26,11 @@ export const actionSendBackward = register({
|
|||||||
getSelectedIndices(elements, appState),
|
getSelectedIndices(elements, appState),
|
||||||
),
|
),
|
||||||
appState,
|
appState,
|
||||||
|
commitToHistory: true,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
contextItemLabel: "labels.sendBackward",
|
contextItemLabel: "labels.sendBackward",
|
||||||
keyPriority: 40,
|
keyPriority: 40,
|
||||||
commitToHistory: () => true,
|
|
||||||
keyTest: event =>
|
keyTest: event =>
|
||||||
event[KEYS.CTRL_OR_CMD] && !event.shiftKey && event.code === "BracketLeft",
|
event[KEYS.CTRL_OR_CMD] && !event.shiftKey && event.code === "BracketLeft",
|
||||||
PanelComponent: ({ updateData }) => (
|
PanelComponent: ({ updateData }) => (
|
||||||
@ -54,11 +54,11 @@ export const actionBringForward = register({
|
|||||||
getSelectedIndices(elements, appState),
|
getSelectedIndices(elements, appState),
|
||||||
),
|
),
|
||||||
appState,
|
appState,
|
||||||
|
commitToHistory: true,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
contextItemLabel: "labels.bringForward",
|
contextItemLabel: "labels.bringForward",
|
||||||
keyPriority: 40,
|
keyPriority: 40,
|
||||||
commitToHistory: () => true,
|
|
||||||
keyTest: event =>
|
keyTest: event =>
|
||||||
event[KEYS.CTRL_OR_CMD] && !event.shiftKey && event.code === "BracketRight",
|
event[KEYS.CTRL_OR_CMD] && !event.shiftKey && event.code === "BracketRight",
|
||||||
PanelComponent: ({ updateData }) => (
|
PanelComponent: ({ updateData }) => (
|
||||||
@ -82,10 +82,10 @@ export const actionSendToBack = register({
|
|||||||
getSelectedIndices(elements, appState),
|
getSelectedIndices(elements, appState),
|
||||||
),
|
),
|
||||||
appState,
|
appState,
|
||||||
|
commitToHistory: true,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
contextItemLabel: "labels.sendToBack",
|
contextItemLabel: "labels.sendToBack",
|
||||||
commitToHistory: () => true,
|
|
||||||
keyTest: event => {
|
keyTest: event => {
|
||||||
return isDarwin
|
return isDarwin
|
||||||
? event[KEYS.CTRL_OR_CMD] && event.altKey && event.code === "BracketLeft"
|
? event[KEYS.CTRL_OR_CMD] && event.altKey && event.code === "BracketLeft"
|
||||||
@ -118,9 +118,9 @@ export const actionBringToFront = register({
|
|||||||
getSelectedIndices(elements, appState),
|
getSelectedIndices(elements, appState),
|
||||||
),
|
),
|
||||||
appState,
|
appState,
|
||||||
|
commitToHistory: true,
|
||||||
};
|
};
|
||||||
},
|
},
|
||||||
commitToHistory: () => true,
|
|
||||||
contextItemLabel: "labels.bringToFront",
|
contextItemLabel: "labels.bringToFront",
|
||||||
keyTest: event => {
|
keyTest: event => {
|
||||||
return isDarwin
|
return isDarwin
|
||||||
|
@ -50,24 +50,12 @@ export class ActionManager implements ActionsManagerInterface {
|
|||||||
}
|
}
|
||||||
|
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const commitToHistory =
|
this.updater(data[0].perform(this.getElements(), this.getAppState(), null));
|
||||||
data[0].commitToHistory &&
|
|
||||||
data[0].commitToHistory(this.getAppState(), this.getElements());
|
|
||||||
this.updater(
|
|
||||||
data[0].perform(this.getElements(), this.getAppState(), null),
|
|
||||||
commitToHistory,
|
|
||||||
);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
executeAction(action: Action) {
|
executeAction(action: Action) {
|
||||||
const commitToHistory =
|
this.updater(action.perform(this.getElements(), this.getAppState(), null));
|
||||||
action.commitToHistory &&
|
|
||||||
action.commitToHistory(this.getAppState(), this.getElements());
|
|
||||||
this.updater(
|
|
||||||
action.perform(this.getElements(), this.getAppState(), null),
|
|
||||||
commitToHistory,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
getContextMenuItems(actionFilter: ActionFilterFn = action => action) {
|
getContextMenuItems(actionFilter: ActionFilterFn = action => action) {
|
||||||
@ -82,12 +70,8 @@ export class ActionManager implements ActionsManagerInterface {
|
|||||||
.map(action => ({
|
.map(action => ({
|
||||||
label: action.contextItemLabel ? t(action.contextItemLabel) : "",
|
label: action.contextItemLabel ? t(action.contextItemLabel) : "",
|
||||||
action: () => {
|
action: () => {
|
||||||
const commitToHistory =
|
|
||||||
action.commitToHistory &&
|
|
||||||
action.commitToHistory(this.getAppState(), this.getElements());
|
|
||||||
this.updater(
|
this.updater(
|
||||||
action.perform(this.getElements(), this.getAppState(), null),
|
action.perform(this.getElements(), this.getAppState(), null),
|
||||||
commitToHistory,
|
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
}));
|
}));
|
||||||
@ -98,12 +82,8 @@ export class ActionManager implements ActionsManagerInterface {
|
|||||||
const action = this.actions[name];
|
const action = this.actions[name];
|
||||||
const PanelComponent = action.PanelComponent!;
|
const PanelComponent = action.PanelComponent!;
|
||||||
const updateData = (formState?: any) => {
|
const updateData = (formState?: any) => {
|
||||||
const commitToHistory =
|
|
||||||
action.commitToHistory &&
|
|
||||||
action.commitToHistory(this.getAppState(), this.getElements());
|
|
||||||
this.updater(
|
this.updater(
|
||||||
action.perform(this.getElements(), this.getAppState(), formState),
|
action.perform(this.getElements(), this.getAppState(), formState),
|
||||||
commitToHistory,
|
|
||||||
);
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -5,6 +5,7 @@ import { AppState } from "../types";
|
|||||||
export type ActionResult = {
|
export type ActionResult = {
|
||||||
elements?: readonly ExcalidrawElement[] | null;
|
elements?: readonly ExcalidrawElement[] | null;
|
||||||
appState?: AppState | null;
|
appState?: AppState | null;
|
||||||
|
commitToHistory: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
type ActionFn = (
|
type ActionFn = (
|
||||||
@ -32,10 +33,6 @@ export interface Action {
|
|||||||
) => boolean;
|
) => boolean;
|
||||||
contextItemLabel?: string;
|
contextItemLabel?: string;
|
||||||
contextMenuOrder?: number;
|
contextMenuOrder?: number;
|
||||||
commitToHistory?: (
|
|
||||||
appState: AppState,
|
|
||||||
elements: readonly ExcalidrawElement[],
|
|
||||||
) => boolean;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ActionsManagerInterface {
|
export interface ActionsManagerInterface {
|
||||||
|
@ -105,11 +105,14 @@ import { isLinearElement } from "../element/typeChecks";
|
|||||||
import { rescalePoints } from "../points";
|
import { rescalePoints } from "../points";
|
||||||
import { actionFinalize } from "../actions";
|
import { actionFinalize } from "../actions";
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @param func handler taking at most single parameter (event).
|
||||||
|
*/
|
||||||
function withBatchedUpdates<
|
function withBatchedUpdates<
|
||||||
TFunction extends ((event: any) => void) | (() => void)
|
TFunction extends ((event: any) => void) | (() => void)
|
||||||
>(func: TFunction) {
|
>(func: Parameters<TFunction>["length"] extends 0 | 1 ? TFunction : never) {
|
||||||
return (event => {
|
return (event => {
|
||||||
unstable_batchedUpdates(func, event);
|
unstable_batchedUpdates(func as TFunction, event);
|
||||||
}) as TFunction;
|
}) as TFunction;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -164,20 +167,19 @@ export class App extends React.Component<any, AppState> {
|
|||||||
this.actionManager.registerAction(createRedoAction(history));
|
this.actionManager.registerAction(createRedoAction(history));
|
||||||
}
|
}
|
||||||
|
|
||||||
private syncActionResult = withBatchedUpdates(
|
private syncActionResult = withBatchedUpdates((res: ActionResult) => {
|
||||||
(res: ActionResult, commitToHistory: boolean = true) => {
|
|
||||||
if (this.unmounted) {
|
if (this.unmounted) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
if (res.elements) {
|
if (res.elements) {
|
||||||
globalSceneState.replaceAllElements(res.elements);
|
globalSceneState.replaceAllElements(res.elements);
|
||||||
if (commitToHistory) {
|
if (res.commitToHistory) {
|
||||||
history.resumeRecording();
|
history.resumeRecording();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (res.appState) {
|
if (res.appState) {
|
||||||
if (commitToHistory) {
|
if (res.commitToHistory) {
|
||||||
history.resumeRecording();
|
history.resumeRecording();
|
||||||
}
|
}
|
||||||
this.setState(state => ({
|
this.setState(state => ({
|
||||||
@ -186,8 +188,7 @@ export class App extends React.Component<any, AppState> {
|
|||||||
collaborators: state.collaborators,
|
collaborators: state.collaborators,
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
},
|
});
|
||||||
);
|
|
||||||
|
|
||||||
private onCut = withBatchedUpdates((event: ClipboardEvent) => {
|
private onCut = withBatchedUpdates((event: ClipboardEvent) => {
|
||||||
if (isWritableElement(event.target)) {
|
if (isWritableElement(event.target)) {
|
||||||
@ -917,7 +918,11 @@ export class App extends React.Component<any, AppState> {
|
|||||||
) {
|
) {
|
||||||
loadFromBlob(file)
|
loadFromBlob(file)
|
||||||
.then(({ elements, appState }) =>
|
.then(({ elements, appState }) =>
|
||||||
this.syncActionResult({ elements, appState }),
|
this.syncActionResult({
|
||||||
|
elements,
|
||||||
|
appState,
|
||||||
|
commitToHistory: false,
|
||||||
|
}),
|
||||||
)
|
)
|
||||||
.catch(error => console.error(error));
|
.catch(error => console.error(error));
|
||||||
}
|
}
|
||||||
|
@ -357,5 +357,6 @@ export async function loadScene(id: string | null, privateKey?: string) {
|
|||||||
return {
|
return {
|
||||||
elements: data.elements,
|
elements: data.elements,
|
||||||
appState: data.appState && { ...data.appState },
|
appState: data.appState && { ...data.appState },
|
||||||
|
commitToHistory: false,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@ -83,7 +83,7 @@ export class SceneHistory {
|
|||||||
}
|
}
|
||||||
|
|
||||||
undoOnce(): Result | null {
|
undoOnce(): Result | null {
|
||||||
if (this.stateHistory.length === 0) {
|
if (this.stateHistory.length === 1) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user