2.7 KiB
Actions System
Actions are the trigger layer for user-initiated operations. They connect keyboard shortcuts, UI buttons, and context menus to editor functionality.
Adding a New Action
1. Define the action — src/lib/actions/definitions.ts
Add an entry to the ACTIONS object:
"my-action": {
description: "What it does",
category: "editing", // playback | navigation | editing | selection | history | timeline | controls
defaultShortcuts: ["ctrl+m"], // optional
args: { someValue: "number" }, // optional, only if it takes args
},
If your shortcut uses a special key (not a letter/digit), check getPressedKey in src/stores/keybindings-store.ts and add a case if it's missing:
if (key === "escape") return "escape";
If your action has a defaultShortcuts, also add a keybindings migration so existing users get it (keybindings are persisted in localStorage — new defaults only apply to fresh installs):
- Create
src/stores/keybindings/migrations/vN-to-vN+1.ts:
export function vNToVN1({ state }: { state: unknown }): unknown {
const s = state as { keybindings: Record<string, string>; isCustomized: boolean };
const keybindings = { ...s.keybindings };
if (!keybindings["my-key"]) {
keybindings["my-key"] = "my-action";
}
return { ...s, keybindings };
}
- Register it in
src/stores/keybindings/migrations/index.tsand bumpCURRENT_VERSION.
2. Register the handler — src/hooks/actions/use-editor-actions.ts
useActionHandler(
"my-action",
() => {
editor.timeline.doSomething();
},
undefined, // isActive: MutableRefObject<boolean> | boolean | undefined
);
3. Register arg types (if needed) — src/lib/actions/types.ts
Only required if your action accepts arguments:
export type TActionArgsMap = {
// ...existing actions...
"my-action": { someValue: number } | undefined; // | undefined = optional args
};
Invoking Actions
Use invokeAction for any user-triggered operation (buttons, context menus, etc.):
import { invokeAction } from "@/lib/actions";
invokeAction("my-action");
invokeAction("seek-forward", { seconds: 5 });
Avoid calling editor.xxx() directly from UI components — that bypasses the action layer (toasts, validation feedback, keybinding support).
The isActive parameter
The third argument to useActionHandler controls when the handler is active:
undefined— always activetrue/false— statically enabled/disabledMutableRefObject<boolean>— reactive, toggled at runtime (e.g. only active when a panel is focused)