123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134 |
- import React from "react";
- import {
- Action,
- ActionsManagerInterface,
- UpdaterFn,
- ActionFilterFn,
- ActionName,
- } from "./types";
- import { ExcalidrawElement } from "../element/types";
- import { AppState } from "../types";
- import { t } from "../i18n";
- import { globalSceneState } from "../scene";
- export class ActionManager implements ActionsManagerInterface {
- actions = {} as ActionsManagerInterface["actions"];
- updater: UpdaterFn;
- getAppState: () => AppState;
- getElementsIncludingDeleted: () => readonly ExcalidrawElement[];
- constructor(
- updater: UpdaterFn,
- getAppState: () => AppState,
- getElementsIncludingDeleted: () => ReturnType<
- typeof globalSceneState["getElementsIncludingDeleted"]
- >,
- ) {
- this.updater = updater;
- this.getAppState = getAppState;
- this.getElementsIncludingDeleted = getElementsIncludingDeleted;
- }
- registerAction(action: Action) {
- this.actions[action.name] = action;
- }
- registerAll(actions: readonly Action[]) {
- actions.forEach((action) => this.registerAction(action));
- }
- handleKeyDown(event: KeyboardEvent) {
- const data = Object.values(this.actions)
- .sort((a, b) => (b.keyPriority || 0) - (a.keyPriority || 0))
- .filter(
- (action) =>
- action.keyTest &&
- action.keyTest(
- event,
- this.getAppState(),
- this.getElementsIncludingDeleted(),
- ),
- );
- if (data.length === 0) {
- return false;
- }
- event.preventDefault();
- this.updater(
- data[0].perform(
- this.getElementsIncludingDeleted(),
- this.getAppState(),
- null,
- ),
- );
- return true;
- }
- executeAction(action: Action) {
- this.updater(
- action.perform(
- this.getElementsIncludingDeleted(),
- this.getAppState(),
- null,
- ),
- );
- }
- getContextMenuItems(actionFilter: ActionFilterFn = (action) => action) {
- return Object.values(this.actions)
- .filter(actionFilter)
- .filter((action) => "contextItemLabel" in action)
- .sort(
- (a, b) =>
- (a.contextMenuOrder !== undefined ? a.contextMenuOrder : 999) -
- (b.contextMenuOrder !== undefined ? b.contextMenuOrder : 999),
- )
- .map((action) => ({
- label: action.contextItemLabel ? t(action.contextItemLabel) : "",
- action: () => {
- this.updater(
- action.perform(
- this.getElementsIncludingDeleted(),
- this.getAppState(),
- null,
- ),
- );
- },
- }));
- }
- // Id is an attribute that we can use to pass in data like keys.
- // This is needed for dynamically generated action components
- // like the user list. We can use this key to extract more
- // data from app state. This is an alternative to generic prop hell!
- renderAction = (name: ActionName, id?: string) => {
- if (this.actions[name] && "PanelComponent" in this.actions[name]) {
- const action = this.actions[name];
- const PanelComponent = action.PanelComponent!;
- const updateData = (formState?: any) => {
- this.updater(
- action.perform(
- this.getElementsIncludingDeleted(),
- this.getAppState(),
- formState,
- ),
- );
- };
- return (
- <PanelComponent
- elements={this.getElementsIncludingDeleted()}
- appState={this.getAppState()}
- updateData={updateData}
- id={id}
- />
- );
- }
- return null;
- };
- }
|