From 00691631d876006c5dcc23b9f07290ddc7811a04 Mon Sep 17 00:00:00 2001 From: "Daniel J. Geiger" <1852529+DanielJGeiger@users.noreply.github.com> Date: Sat, 18 Nov 2023 10:56:17 -0600 Subject: [PATCH] fix: Narrow the type of `Action.name` while still allowing custom names --- src/actions/manager.tsx | 7 ++++--- src/actions/types.ts | 3 ++- src/components/Subtypes.tsx | 4 ++-- src/element/subtypes/index.ts | 18 ++++++++++++++---- .../subtypes/mathjax/implementation.tsx | 8 ++++---- src/tests/customActions.test.tsx | 2 +- src/tests/subtypes.test.tsx | 2 +- 7 files changed, 28 insertions(+), 16 deletions(-) diff --git a/src/actions/manager.tsx b/src/actions/manager.tsx index e8cb8d488..d935579a2 100644 --- a/src/actions/manager.tsx +++ b/src/actions/manager.tsx @@ -2,6 +2,7 @@ import React from "react"; import { Action, UpdaterFn, + ActionName, ActionResult, PanelComponentProps, ActionSource, @@ -40,7 +41,7 @@ const trackAction = ( }; export class ActionManager { - actions = {} as Record; + actions = {} as Record; actionPredicates = [] as ActionPredicateFn[]; updater: (actionResult: ActionResult | Promise) => void; @@ -92,7 +93,7 @@ export class ActionManager { const actions: Action[] = []; for (const key in this.actions) { - const action = this.actions[key]; + const action = this.actions[key as ActionName]; if (filter(action, elements, appState, data)) { actions.push(action); } @@ -167,7 +168,7 @@ export class ActionManager { /** * @param data additional data sent to the PanelComponent */ - renderAction = (name: Action["name"], data?: PanelComponentProps["data"]) => { + renderAction = (name: ActionName, data?: PanelComponentProps["data"]) => { const canvasActions = this.app.props.UIOptions.canvasActions; if ( diff --git a/src/actions/types.ts b/src/actions/types.ts index 4edae51bc..b939467cd 100644 --- a/src/actions/types.ts +++ b/src/actions/types.ts @@ -45,6 +45,7 @@ export type UpdaterFn = (res: ActionResult) => void; export type ActionFilterFn = (action: Action) => void; export type ActionName = + | `custom.${string}` | "copy" | "cut" | "paste" @@ -145,7 +146,7 @@ export type PanelComponentProps = { }; export interface Action { - name: string; + name: ActionName; PanelComponent?: React.FC; perform: ActionFn; keyPriority?: number; diff --git a/src/components/Subtypes.tsx b/src/components/Subtypes.tsx index 7fc1540a9..2df6955b0 100644 --- a/src/components/Subtypes.tsx +++ b/src/components/Subtypes.tsx @@ -28,7 +28,7 @@ export const SubtypeButton = ( const keyTest: Action["keyTest"] = key !== undefined ? (event) => event.code === `Key${key}` : undefined; const subtypeAction: Action = { - name: subtype, + name: `custom.${subtype}`, trackEvent: false, predicate: (...rest) => rest[4]?.subtype === subtype, perform: (elements, appState) => { @@ -147,7 +147,7 @@ export const SubtypeToggles = () => { <> {getSubtypeNames().map((subtype) => am.renderAction( - subtype, + `custom.${subtype}`, hasAlwaysEnabledActions(subtype) ? { onContextMenu } : {}, ), )} diff --git a/src/element/subtypes/index.ts b/src/element/subtypes/index.ts index f2d8339a6..552cdcd0c 100644 --- a/src/element/subtypes/index.ts +++ b/src/element/subtypes/index.ts @@ -28,7 +28,7 @@ let parentTypeMap: readonly { }[] = []; let subtypeActionMap: readonly { subtype: Subtype; - actions: readonly SubtypeActionName[]; + actions: readonly ActionName[]; }[] = []; let disabledActionMap: readonly { subtype: Subtype; @@ -91,7 +91,7 @@ const isDisabledActionName = (s: any): s is DisabledActionName => // by `subtype` (if `isAdded` is false)? const isForSubtype = ( subtype: ExcalidrawElement["subtype"], - actionName: ActionName | SubtypeActionName, + actionName: ActionName, isAdded: boolean, ) => { const actions = isAdded ? subtypeActionMap : disabledActionMap; @@ -371,7 +371,12 @@ export const prepareSubtype = ( if (record.actionNames) { subtypeActionMap = [ ...subtypeActionMap, - { subtype, actions: record.actionNames }, + { + subtype, + actions: record.actionNames.map( + (actionName) => `custom.${actionName}` as ActionName, + ), + }, ]; } if (record.disabledNames) { @@ -383,7 +388,12 @@ export const prepareSubtype = ( if (record.alwaysEnabledNames) { alwaysEnabledMap = [ ...alwaysEnabledMap, - { subtype, actions: record.alwaysEnabledNames }, + { + subtype, + actions: record.alwaysEnabledNames.map( + (actionName) => `custom.${actionName}` as ActionName, + ), + }, ]; } if (record.shortcutMap) { diff --git a/src/element/subtypes/mathjax/implementation.tsx b/src/element/subtypes/mathjax/implementation.tsx index 052bd5064..c1b35bfbe 100644 --- a/src/element/subtypes/mathjax/implementation.tsx +++ b/src/element/subtypes/mathjax/implementation.tsx @@ -1395,7 +1395,7 @@ const enableActionChangeMathProps = ( const createMathActions = () => { const mathActions: Action[] = []; const actionUseTexTrue: Action = { - name: "useTexTrue", + name: "custom.useTexTrue", perform: (elements, appState) => { const mathOnly = getMathProps.getMathOnly(appState); const customData = appState.customData ?? {}; @@ -1414,7 +1414,7 @@ const createMathActions = () => { trackEvent: false, }; const actionUseTexFalse: Action = { - name: "useTexFalse", + name: "custom.useTexFalse", perform: (elements, appState) => { const mathOnly = getMathProps.getMathOnly(appState); const customData = appState.customData ?? {}; @@ -1433,7 +1433,7 @@ const createMathActions = () => { trackEvent: false, }; const actionResetUseTex: Action = { - name: "resetUseTex", + name: "custom.resetUseTex", perform: (elements, appState) => { const useTex = getMathProps.getUseTex(appState); const modElements = changeProperty( @@ -1481,7 +1481,7 @@ const createMathActions = () => { trackEvent: false, }; const actionChangeMathOnly: Action = { - name: "changeMathOnly", + name: "custom.changeMathOnly", perform: (elements, appState, mathOnly: boolean | null) => { if (mathOnly === null) { mathOnly = getFormValue( diff --git a/src/tests/customActions.test.tsx b/src/tests/customActions.test.tsx index 655c5ed0f..f8a18fc61 100644 --- a/src/tests/customActions.test.tsx +++ b/src/tests/customActions.test.tsx @@ -37,7 +37,7 @@ describe("regression tests", () => { const el23: ExcalidrawElement[] = [el2, el3]; const el123: ExcalidrawElement[] = [el1, el2, el3]; // Set up the custom Action enablers - const enableName = "custom" as Action["name"]; + const enableName = "custom.enable"; const enableAction: Action = { name: enableName, perform: (): ActionResult => { diff --git a/src/tests/subtypes.test.tsx b/src/tests/subtypes.test.tsx index d667d5082..34fd3400a 100644 --- a/src/tests/subtypes.test.tsx +++ b/src/tests/subtypes.test.tsx @@ -81,7 +81,7 @@ const test1: SubtypeRecord = { }; const testAction: Action = { - name: TEST_ACTION, + name: `custom.${TEST_ACTION}`, trackEvent: false, perform: (elements, appState) => { return {