import type { Action, ActionResult } from "./types"; import { UndoIcon, RedoIcon } from "../components/icons"; import { ToolButton } from "../components/ToolButton"; import { t } from "../i18n"; import type { History } from "../history"; import { HistoryChangedEvent } from "../history"; import type { AppClassProperties, AppState } from "../types"; import { KEYS, matchKey } from "../keys"; import { arrayToMap } from "../utils"; import { isWindows } from "../constants"; import type { SceneElementsMap } from "../element/types"; import type { Store } from "../store"; import { StoreAction } from "../store"; import { useEmitter } from "../hooks/useEmitter"; const executeHistoryAction = ( app: AppClassProperties, appState: Readonly, updater: () => [SceneElementsMap, AppState] | void, ): ActionResult => { if ( !appState.multiElement && !appState.resizingElement && !appState.editingTextElement && !appState.newElement && !appState.selectedElementsAreBeingDragged && !appState.selectionElement && !app.flowChartCreator.isCreatingChart ) { const result = updater(); if (!result) { return { storeAction: StoreAction.NONE }; } const [nextElementsMap, nextAppState] = result; const nextElements = Array.from(nextElementsMap.values()); return { appState: nextAppState, elements: nextElements, storeAction: StoreAction.UPDATE, }; } return { storeAction: StoreAction.NONE }; }; type ActionCreator = (history: History, store: Store) => Action; export const createUndoAction: ActionCreator = (history, store) => ({ name: "undo", label: "buttons.undo", icon: UndoIcon, trackEvent: { category: "history" }, viewMode: false, perform: (elements, appState, value, app) => executeHistoryAction(app, appState, () => history.undo( arrayToMap(elements) as SceneElementsMap, // TODO: #7348 refactor action manager to already include `SceneElementsMap` appState, store.snapshot, ), ), keyTest: (event) => event[KEYS.CTRL_OR_CMD] && matchKey(event, KEYS.Z) && !event.shiftKey, PanelComponent: ({ updateData, data }) => { const { isUndoStackEmpty } = useEmitter( history.onHistoryChangedEmitter, new HistoryChangedEvent( history.isUndoStackEmpty, history.isRedoStackEmpty, ), ); return ( ); }, }); export const createRedoAction: ActionCreator = (history, store) => ({ name: "redo", label: "buttons.redo", icon: RedoIcon, trackEvent: { category: "history" }, viewMode: false, perform: (elements, appState, _, app) => executeHistoryAction(app, appState, () => history.redo( arrayToMap(elements) as SceneElementsMap, // TODO: #7348 refactor action manager to already include `SceneElementsMap` appState, store.snapshot, ), ), keyTest: (event) => (event[KEYS.CTRL_OR_CMD] && event.shiftKey && matchKey(event, KEYS.Z)) || (isWindows && event.ctrlKey && !event.shiftKey && matchKey(event, KEYS.Y)), PanelComponent: ({ updateData, data }) => { const { isRedoStackEmpty } = useEmitter( history.onHistoryChangedEmitter, new HistoryChangedEvent( history.isUndoStackEmpty, history.isRedoStackEmpty, ), ); return ( ); }, });