Переглянути джерело

fix: Narrow the type of `Action.name` while still allowing custom names

Daniel J. Geiger 1 рік тому
батько
коміт
00691631d8

+ 4 - 3
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<Action["name"], Action>;
+  actions = {} as Record<ActionName, Action>;
   actionPredicates = [] as ActionPredicateFn[];
 
   updater: (actionResult: ActionResult | Promise<ActionResult>) => 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 (

+ 2 - 1
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<PanelComponentProps>;
   perform: ActionFn;
   keyPriority?: number;

+ 2 - 2
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 } : {},
         ),
       )}

+ 14 - 4
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) {

+ 4 - 4
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(

+ 1 - 1
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 => {

+ 1 - 1
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 {