import { Action, ActionResult } from "./types"; import React from "react"; import { undo, redo } from "../components/icons"; import { ToolButton } from "../components/ToolButton"; import { t } from "../i18n"; import { SceneHistory, HistoryEntry } from "../history"; import { ExcalidrawElement } from "../element/types"; import { AppState } from "../types"; import { KEYS } from "../keys"; import { getElementMap } from "../element"; import { newElementWith } from "../element/mutateElement"; import { fixBindingsAfterDeletion } from "../element/binding"; const writeData = ( prevElements: readonly ExcalidrawElement[], appState: AppState, updater: () => HistoryEntry | null, ): ActionResult => { const commitToHistory = false; if ( !appState.multiElement && !appState.resizingElement && !appState.editingElement && !appState.draggingElement ) { const data = updater(); if (data === null) { return { commitToHistory }; } const prevElementMap = getElementMap(prevElements); const nextElements = data.elements; const nextElementMap = getElementMap(nextElements); const deletedElements = prevElements.filter( (prevElement) => !nextElementMap.hasOwnProperty(prevElement.id), ); const elements = nextElements .map((nextElement) => newElementWith( prevElementMap[nextElement.id] || nextElement, nextElement, ), ) .concat( deletedElements.map((prevElement) => newElementWith(prevElement, { isDeleted: true }), ), ); fixBindingsAfterDeletion(elements, deletedElements); return { elements, appState: { ...appState, ...data.appState }, commitToHistory, syncHistory: true, }; } return { commitToHistory }; }; const testUndo = (shift: boolean) => (event: KeyboardEvent) => event[KEYS.CTRL_OR_CMD] && /z/i.test(event.key) && event.shiftKey === shift; type ActionCreator = (history: SceneHistory) => Action; export const createUndoAction: ActionCreator = (history) => ({ name: "undo", perform: (elements, appState) => writeData(elements, appState, () => history.undoOnce()), keyTest: testUndo(false), PanelComponent: ({ updateData }) => ( ), commitToHistory: () => false, }); export const createRedoAction: ActionCreator = (history) => ({ name: "redo", perform: (elements, appState) => writeData(elements, appState, () => history.redoOnce()), keyTest: testUndo(true), PanelComponent: ({ updateData }) => ( ), commitToHistory: () => false, });