mirror of
https://github.com/excalidraw/excalidraw.git
synced 2025-05-03 10:00:07 -04:00
Simplify custom Actions: universal Action predicates instead of
action-specific guards.
This commit is contained in:
parent
512e506798
commit
c8d4e8c421
9 changed files with 105 additions and 193 deletions
|
@ -1,18 +1,19 @@
|
|||
import { ExcalidrawElement } from "../element/types";
|
||||
import { getShortcutKey } from "../utils";
|
||||
import { API } from "./helpers/api";
|
||||
import { render } from "./test-utils";
|
||||
import ExcalidrawApp from "../excalidraw-app";
|
||||
import {
|
||||
CustomShortcutName,
|
||||
getShortcutFromShortcutName,
|
||||
registerCustomShortcuts,
|
||||
} from "../actions/shortcuts";
|
||||
import { Action, ActionName, DisableFn, EnableFn } from "../actions/types";
|
||||
import { Action, ActionPredicateFn, ActionResult } from "../actions/types";
|
||||
import {
|
||||
getActionDisablers,
|
||||
getActionEnablers,
|
||||
registerDisableFn,
|
||||
registerEnableFn,
|
||||
} from "../actions/guards";
|
||||
actionChangeFontFamily,
|
||||
actionChangeFontSize,
|
||||
} from "../actions/actionProperties";
|
||||
import { isTextElement } from "../element";
|
||||
|
||||
const { h } = window;
|
||||
|
||||
|
@ -25,61 +26,60 @@ describe("regression tests", () => {
|
|||
expect(getShortcutFromShortcutName("test")).toBe("Ctrl+1");
|
||||
});
|
||||
|
||||
it("should follow action guards", () => {
|
||||
it("should apply universal action predicates", async () => {
|
||||
await render(<ExcalidrawApp />);
|
||||
// Create the test elements
|
||||
const text1 = API.createElement({ type: "rectangle", id: "A", y: 0 });
|
||||
const text2 = API.createElement({ type: "rectangle", id: "B", y: 30 });
|
||||
const text3 = API.createElement({ type: "rectangle", id: "C", y: 60 });
|
||||
const el12: ExcalidrawElement[] = [text1, text2];
|
||||
const el13: ExcalidrawElement[] = [text1, text3];
|
||||
const el23: ExcalidrawElement[] = [text2, text3];
|
||||
const el123: ExcalidrawElement[] = [text1, text2, text3];
|
||||
const el1 = API.createElement({ type: "rectangle", id: "A", y: 0 });
|
||||
const el2 = API.createElement({ type: "rectangle", id: "B", y: 30 });
|
||||
const el3 = API.createElement({ type: "text", id: "C", y: 60 });
|
||||
const el12: ExcalidrawElement[] = [el1, el2];
|
||||
const el13: ExcalidrawElement[] = [el1, el3];
|
||||
const el23: ExcalidrawElement[] = [el2, el3];
|
||||
const el123: ExcalidrawElement[] = [el1, el2, el3];
|
||||
// Set up the custom Action enablers
|
||||
const enableName = "custom" as Action["name"];
|
||||
const enabler: EnableFn = function (elements) {
|
||||
if (elements.some((el) => el.y === 30)) {
|
||||
const enableAction: Action = {
|
||||
name: enableName,
|
||||
perform: (): ActionResult => {
|
||||
return {} as ActionResult;
|
||||
},
|
||||
trackEvent: false,
|
||||
};
|
||||
const enabler: ActionPredicateFn = function (action, elements) {
|
||||
if (action.name !== enableName || elements.some((el) => el.y === 30)) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
};
|
||||
registerEnableFn(enableName, enabler);
|
||||
// Set up the standard Action disablers
|
||||
const disableName1 = "changeFontFamily" as ActionName;
|
||||
const disableName2 = "changeFontSize" as ActionName;
|
||||
const disabler: DisableFn = function (elements) {
|
||||
if (elements.some((el) => el.y === 0)) {
|
||||
return true;
|
||||
const disabled1 = actionChangeFontFamily;
|
||||
const disabled2 = actionChangeFontSize;
|
||||
const disabler: ActionPredicateFn = function (action, elements) {
|
||||
if (
|
||||
action.name === disabled2.name &&
|
||||
elements.some((el) => el.y === 0 || isTextElement(el))
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
return true;
|
||||
};
|
||||
registerDisableFn(disableName1, disabler);
|
||||
// Test the custom Action enablers
|
||||
const enablers = getActionEnablers();
|
||||
const isCustomEnabled = function (
|
||||
elements: ExcalidrawElement[],
|
||||
name: string,
|
||||
) {
|
||||
return (
|
||||
name in enablers &&
|
||||
enablers[name].some((enabler) => enabler(elements, h.state, name))
|
||||
);
|
||||
};
|
||||
expect(isCustomEnabled(el12, enableName)).toBe(true);
|
||||
expect(isCustomEnabled(el13, enableName)).toBe(false);
|
||||
expect(isCustomEnabled(el23, enableName)).toBe(true);
|
||||
const am = h.app.actionManager;
|
||||
am.registerActionPredicate(enabler);
|
||||
expect(am.isActionEnabled(enableAction, { elements: el12 })).toBe(true);
|
||||
expect(am.isActionEnabled(enableAction, { elements: el13 })).toBe(false);
|
||||
expect(am.isActionEnabled(enableAction, { elements: el23 })).toBe(true);
|
||||
expect(am.isActionEnabled(disabled1, { elements: el12 })).toBe(true);
|
||||
expect(am.isActionEnabled(disabled1, { elements: el13 })).toBe(true);
|
||||
expect(am.isActionEnabled(disabled1, { elements: el23 })).toBe(true);
|
||||
// Test the standard Action disablers
|
||||
const disablers = getActionDisablers();
|
||||
const isStandardDisabled = function (
|
||||
elements: ExcalidrawElement[],
|
||||
name: ActionName,
|
||||
) {
|
||||
return (
|
||||
name in disablers &&
|
||||
disablers[name].some((disabler) => disabler(elements, h.state, name))
|
||||
);
|
||||
};
|
||||
expect(isStandardDisabled(el12, disableName1)).toBe(true);
|
||||
expect(isStandardDisabled(el23, disableName1)).toBe(false);
|
||||
expect(isStandardDisabled(el123, disableName2)).toBe(false);
|
||||
am.registerActionPredicate(disabler);
|
||||
expect(am.isActionEnabled(disabled1, { elements: el123 })).toBe(true);
|
||||
expect(am.isActionEnabled(disabled2, { elements: [el1] })).toBe(false);
|
||||
expect(am.isActionEnabled(disabled2, { elements: [el2] })).toBe(true);
|
||||
expect(am.isActionEnabled(disabled2, { elements: [el3] })).toBe(false);
|
||||
expect(am.isActionEnabled(disabled2, { elements: el12 })).toBe(false);
|
||||
expect(am.isActionEnabled(disabled2, { elements: el23 })).toBe(false);
|
||||
expect(am.isActionEnabled(disabled2, { elements: el13 })).toBe(false);
|
||||
});
|
||||
});
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue