feat(renderer): command store (action registry for menu/shortcut/toolbar)

- useCommandStore: register/unregister/registerMany/dispatch/get
- keyed by id (e.g. 'file.open', 'view.toggleSidebar')
- TDD: 10 unit tests covering register, dispatch, unregister, batch
- foundation for Phase 6 native menu + toolbar wiring
This commit is contained in:
Amit Haridas
2026-06-05 15:49:45 +05:30
parent d865b181e9
commit c93747c476
2 changed files with 115 additions and 0 deletions
+35
View File
@@ -0,0 +1,35 @@
import { create } from 'zustand';
export type CommandId = string;
export type CommandHandler = (args?: unknown) => void | Promise<void>;
interface CommandState {
handlers: Record<string, CommandHandler>;
register: (id: CommandId, handler: CommandHandler) => void;
registerMany: (handlers: Record<string, CommandHandler>) => void;
unregister: (id: CommandId) => void;
dispatch: (id: CommandId, args?: unknown) => void;
get: (id: CommandId) => CommandHandler | undefined;
}
export const useCommandStore = create<CommandState>((set, get) => ({
handlers: {},
register: (id, handler) =>
set((s) => ({ handlers: { ...s.handlers, [id]: handler } })),
registerMany: (handlers) =>
set((s) => ({ handlers: { ...s.handlers, ...handlers } })),
unregister: (id) =>
set((s) => {
const next = { ...s.handlers };
delete next[id];
return { handlers: next };
}),
dispatch: (id, args) => {
const handler = get().handlers[id];
if (handler) {
void handler(args);
}
},
get: (id) => get().handlers[id],
}));