2023-01-27 13:23:40 -06:00

188 lines
4.2 KiB
TypeScript

import React from "react";
import { ExcalidrawElement } from "../element/types";
import {
AppClassProperties,
AppState,
ExcalidrawProps,
BinaryFiles,
} from "../types";
export type ActionSource = "ui" | "keyboard" | "contextMenu" | "api";
/** if false, the action should be prevented */
export type ActionResult =
| {
elements?: readonly ExcalidrawElement[] | null;
appState?: MarkOptional<
AppState,
"offsetTop" | "offsetLeft" | "width" | "height"
> | null;
files?: BinaryFiles | null;
commitToHistory: boolean;
syncHistory?: boolean;
replaceFiles?: boolean;
}
| false;
type ActionFn = (
elements: readonly ExcalidrawElement[],
appState: Readonly<AppState>,
formData: any,
app: AppClassProperties,
) => ActionResult | Promise<ActionResult>;
// Return `true` *unless* `Action` should be disabled
// given `elements`, `appState`, and optionally `data`.
export type ActionPredicateFn = (
action: Action,
elements: readonly ExcalidrawElement[],
appState: AppState,
data?: Record<string, any>,
) => boolean;
export type UpdaterFn = (res: ActionResult) => void;
export type ActionFilterFn = (action: Action) => void;
const actionNames = [
"copy",
"cut",
"paste",
"copyAsPng",
"copyAsSvg",
"copyText",
"sendBackward",
"bringForward",
"sendToBack",
"bringToFront",
"copyStyles",
"selectAll",
"pasteStyles",
"gridMode",
"zenMode",
"stats",
"changeStrokeColor",
"changeBackgroundColor",
"changeFillStyle",
"changeStrokeWidth",
"changeStrokeShape",
"changeSloppiness",
"changeStrokeStyle",
"changeArrowhead",
"changeOpacity",
"changeFontSize",
"toggleCanvasMenu",
"toggleEditMenu",
"undo",
"redo",
"finalize",
"changeProjectName",
"changeExportBackground",
"changeExportEmbedScene",
"changeExportScale",
"saveToActiveFile",
"saveFileToDisk",
"loadScene",
"duplicateSelection",
"deleteSelectedElements",
"changeViewBackgroundColor",
"clearCanvas",
"zoomIn",
"zoomOut",
"resetZoom",
"zoomToFit",
"zoomToSelection",
"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",
"toggleLock",
"toggleLinearEditor",
"toggleEraserTool",
"toggleHandTool",
] as const;
// So we can have the `isActionName` type guard
export type ActionName = typeof actionNames[number];
export const isActionName = (n: any): n is ActionName =>
actionNames.includes(n);
export type PanelComponentProps = {
elements: readonly ExcalidrawElement[];
appState: AppState;
updateData: (formData?: any) => void;
appProps: ExcalidrawProps;
data?: Record<string, any>;
};
export interface Action {
name: string;
PanelComponent?: React.FC<PanelComponentProps>;
perform: ActionFn;
keyPriority?: number;
keyTest?: (
event: React.KeyboardEvent | KeyboardEvent,
appState: AppState,
elements: readonly ExcalidrawElement[],
) => boolean;
contextItemLabel?:
| string
| ((
elements: readonly ExcalidrawElement[],
appState: Readonly<AppState>,
) => string);
predicate?: (
elements: readonly ExcalidrawElement[],
appState: AppState,
appProps: ExcalidrawProps,
app: AppClassProperties,
data?: Record<string, any>,
) => boolean;
checked?: (appState: Readonly<AppState>) => boolean;
trackEvent:
| false
| {
category:
| "toolbar"
| "element"
| "canvas"
| "export"
| "history"
| "menu"
| "collab"
| "hyperlink";
action?: string;
predicate?: (
appState: Readonly<AppState>,
elements: readonly ExcalidrawElement[],
value: any,
) => boolean;
};
/** if set to `true`, allow action to be performed in viewMode.
* Defaults to `false` */
viewMode?: boolean;
}