mirror of
https://github.com/amitwh/markdown-converter.git
synced 2026-08-02 18:10:18 +05:30
feat(renderer): command store persists userBindings (Phase 6)
- add userBindings map (commandId -> combo string) - setUserBinding / clearUserBinding / getUserBinding actions - persist middleware with partialize: handlers are runtime-only, userBindings are serialized - TDD: 7 persistence tests + existing 10 command-store tests still pass - 162/162 total tests pass
This commit is contained in:
@@ -1,35 +1,66 @@
|
||||
import { create } from 'zustand';
|
||||
import { persist } from 'zustand/middleware';
|
||||
|
||||
export type CommandId = string;
|
||||
|
||||
export type CommandHandler = (args?: unknown) => void | Promise<void>;
|
||||
|
||||
/**
|
||||
* User-customizable key binding for a command.
|
||||
* Format: same as useShortcut combo ('mod+s', 'mod+shift+s', etc.)
|
||||
* Undefined means "use the default binding" (if any).
|
||||
*/
|
||||
export type UserBindings = Record<string, string>;
|
||||
|
||||
interface CommandState {
|
||||
handlers: Record<string, CommandHandler>;
|
||||
userBindings: UserBindings;
|
||||
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;
|
||||
setUserBinding: (id: CommandId, combo: string) => void;
|
||||
clearUserBinding: (id: CommandId) => void;
|
||||
getUserBinding: (id: CommandId) => string | 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 };
|
||||
export const useCommandStore = create<CommandState>()(
|
||||
persist(
|
||||
(set, get) => ({
|
||||
handlers: {},
|
||||
userBindings: {},
|
||||
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],
|
||||
setUserBinding: (id, combo) =>
|
||||
set((s) => ({ userBindings: { ...s.userBindings, [id]: combo } })),
|
||||
clearUserBinding: (id) =>
|
||||
set((s) => {
|
||||
const next = { ...s.userBindings };
|
||||
delete next[id];
|
||||
return { userBindings: next };
|
||||
}),
|
||||
getUserBinding: (id) => get().userBindings[id],
|
||||
}),
|
||||
dispatch: (id, args) => {
|
||||
const handler = get().handlers[id];
|
||||
if (handler) {
|
||||
void handler(args);
|
||||
{
|
||||
name: 'mc-command-store',
|
||||
// Only persist user-customizable bindings; handlers are runtime-only.
|
||||
partialize: (state) => ({ userBindings: state.userBindings }),
|
||||
}
|
||||
},
|
||||
get: (id) => get().handlers[id],
|
||||
}));
|
||||
)
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user