@tooee/commands 0.1.16 → 0.1.18

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/context.d.ts CHANGED
@@ -1,11 +1,12 @@
1
1
  import { type ReactNode } from "react";
2
- import type { Command, CommandContext, CommandRegistry } from "./types.js";
2
+ import type { Command, CommandContext, CommandGroup, CommandRegistry, CommandSequenceState, RegisteredCommandGroup } from "./types.js";
3
3
  import type { Mode } from "./mode.js";
4
4
  type ContextGetter = () => Partial<CommandContext>;
5
5
  interface CommandContextValue {
6
6
  registry: CommandRegistry;
7
7
  leaderKey?: string;
8
8
  contextSources: Map<string, ContextGetter>;
9
+ groups: Map<string, RegisteredCommandGroup>;
9
10
  }
10
11
  declare const CommandContext: import("react").Context<CommandContextValue | null>;
11
12
  export interface CommandProviderProps {
@@ -13,13 +14,16 @@ export interface CommandProviderProps {
13
14
  leader?: string;
14
15
  keymap?: Record<string, string>;
15
16
  initialMode?: Mode;
17
+ sequenceTimeoutMs?: number;
16
18
  }
17
- export declare function CommandProvider({ children, leader, keymap, initialMode }: CommandProviderProps): ReactNode;
19
+ export declare function CommandProvider({ children, leader, keymap, initialMode, sequenceTimeoutMs, }: CommandProviderProps): ReactNode;
18
20
  export declare function useCommandContext(): {
19
21
  commands: Command[];
20
22
  invoke: (id: string) => void;
21
23
  };
22
24
  export declare function useCommandRegistry(): CommandContextValue;
25
+ export declare function useCommandSequenceState(): CommandSequenceState | null;
26
+ export declare function useCommandGroup(group: CommandGroup): void;
23
27
  export declare function useProvideCommandContext(getter: () => Partial<CommandContext>): void;
24
28
  export {};
25
29
  //# sourceMappingURL=context.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.tsx"],"names":[],"mappings":"AAAA,OAAO,EAOL,KAAK,SAAS,EACf,MAAM,OAAO,CAAA;AAEd,OAAO,KAAK,EAAE,OAAO,EAAE,cAAc,EAAE,eAAe,EAAgB,MAAM,YAAY,CAAA;AACxF,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAQrC,KAAK,aAAa,GAAG,MAAM,OAAO,CAAC,cAAc,CAAC,CAAA;AAElD,UAAU,mBAAmB;IAC3B,QAAQ,EAAE,eAAe,CAAA;IACzB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAA;CAC3C;AAED,QAAA,MAAM,cAAc,qDAAkD,CAAA;AAEtE,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,SAAS,CAAA;IACnB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC/B,WAAW,CAAC,EAAE,IAAI,CAAA;CACnB;AAED,wBAAgB,eAAe,CAAC,EAAE,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,WAAW,EAAE,EAAE,oBAAoB,aAQ9F;AAuID,wBAAgB,iBAAiB,IAAI;IAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;IAAC,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,CAazF;AAED,wBAAgB,kBAAkB,IAAI,mBAAmB,CAMxD;AAID,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,OAAO,CAAC,cAAc,CAAC,GAAG,IAAI,CAuBpF"}
1
+ {"version":3,"file":"context.d.ts","sourceRoot":"","sources":["../src/context.tsx"],"names":[],"mappings":"AAAA,OAAO,EAQL,KAAK,SAAS,EACf,MAAM,OAAO,CAAA;AAEd,OAAO,KAAK,EACV,OAAO,EACP,cAAc,EACd,YAAY,EACZ,eAAe,EACf,oBAAoB,EAGpB,sBAAsB,EACvB,MAAM,YAAY,CAAA;AACnB,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAQrC,KAAK,aAAa,GAAG,MAAM,OAAO,CAAC,cAAc,CAAC,CAAA;AAElD,UAAU,mBAAmB;IAC3B,QAAQ,EAAE,eAAe,CAAA;IACzB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,cAAc,EAAE,GAAG,CAAC,MAAM,EAAE,aAAa,CAAC,CAAA;IAC1C,MAAM,EAAE,GAAG,CAAC,MAAM,EAAE,sBAAsB,CAAC,CAAA;CAC5C;AAED,QAAA,MAAM,cAAc,qDAAkD,CAAA;AAGtE,MAAM,WAAW,oBAAoB;IACnC,QAAQ,EAAE,SAAS,CAAA;IACnB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAA;IAC/B,WAAW,CAAC,EAAE,IAAI,CAAA;IAClB,iBAAiB,CAAC,EAAE,MAAM,CAAA;CAC3B;AAED,wBAAgB,eAAe,CAAC,EAC9B,QAAQ,EACR,MAAM,EACN,MAAM,EACN,WAAW,EACX,iBAAiB,GAClB,EAAE,oBAAoB,aAQtB;AAqLD,wBAAgB,iBAAiB,IAAI;IAAE,QAAQ,EAAE,OAAO,EAAE,CAAC;IAAC,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;CAAE,CAazF;AAED,wBAAgB,kBAAkB,IAAI,mBAAmB,CAMxD;AAED,wBAAgB,uBAAuB,IAAI,oBAAoB,GAAG,IAAI,CAErE;AAED,wBAAgB,eAAe,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,CA8BzD;AAkBD,wBAAgB,wBAAwB,CAAC,MAAM,EAAE,MAAM,OAAO,CAAC,cAAc,CAAC,GAAG,IAAI,CAuBpF"}
package/dist/context.js CHANGED
@@ -1,5 +1,5 @@
1
1
  import { jsx as _jsx } from "@opentui/react/jsx-runtime";
2
- import { createContext, useContext, useRef, useCallback, useEffect, useMemo, } from "react";
2
+ import { createContext, useContext, useRef, useCallback, useEffect, useMemo, useState, } from "react";
3
3
  import { useKeyboard } from "@opentui/react";
4
4
  import { ModeProvider, useMode, useSetMode } from "./mode.js";
5
5
  import { parseHotkey } from "./parse.js";
@@ -7,16 +7,21 @@ import { matchStep } from "./match.js";
7
7
  import { SequenceTracker } from "./sequence.js";
8
8
  const DEFAULT_MODES = ["cursor"];
9
9
  const CommandContext = createContext(null);
10
- export function CommandProvider({ children, leader, keymap, initialMode }) {
11
- return (_jsx(ModeProvider, { initialMode: initialMode, children: _jsx(CommandDispatcher, { leader: leader, keymap: keymap, children: children }) }));
10
+ const CommandSequenceContext = createContext(null);
11
+ export function CommandProvider({ children, leader, keymap, initialMode, sequenceTimeoutMs, }) {
12
+ return (_jsx(ModeProvider, { initialMode: initialMode, children: _jsx(CommandDispatcher, { leader: leader, keymap: keymap, sequenceTimeoutMs: sequenceTimeoutMs, children: children }) }));
12
13
  }
13
- function CommandDispatcher({ children, leader, keymap, }) {
14
+ function CommandDispatcher({ children, leader, keymap, sequenceTimeoutMs, }) {
14
15
  const registryRef = useRef(null);
15
16
  const contextSourcesRef = useRef(new Map());
17
+ const groupsRef = useRef(new Map());
16
18
  const mode = useMode();
17
19
  const modeRef = useRef(mode);
18
20
  modeRef.current = mode;
19
21
  const setMode = useSetMode();
22
+ const [sequenceState, setSequenceState] = useState(null);
23
+ const clearSequenceStateRef = useRef(() => setSequenceState(null));
24
+ clearSequenceStateRef.current = () => setSequenceState(null);
20
25
  const buildCtx = useCallback(() => {
21
26
  const ctx = {
22
27
  mode: modeRef.current,
@@ -51,7 +56,10 @@ function CommandDispatcher({ children, leader, keymap, }) {
51
56
  },
52
57
  };
53
58
  }
54
- const trackerRef = useRef(new SequenceTracker());
59
+ const trackerRef = useRef(new SequenceTracker({
60
+ timeout: sequenceTimeoutMs,
61
+ onReset: () => clearSequenceStateRef.current(),
62
+ }));
55
63
  const parseCacheRef = useRef(new Map());
56
64
  const getParsedHotkey = useCallback((hotkey) => {
57
65
  const cache = parseCacheRef.current;
@@ -73,8 +81,7 @@ function CommandDispatcher({ children, leader, keymap, }) {
73
81
  const ctx = buildCtx();
74
82
  // Collect eligible commands with their parsed hotkeys
75
83
  const singleStepCandidates = [];
76
- const multiStepHotkeys = [];
77
- const multiStepCommands = [];
84
+ const multiStepCandidates = [];
78
85
  for (const command of registry.commands.values()) {
79
86
  const commandModes = command.modes ?? DEFAULT_MODES;
80
87
  if (!commandModes.includes(currentMode))
@@ -89,34 +96,61 @@ function CommandDispatcher({ children, leader, keymap, }) {
89
96
  singleStepCandidates.push({ command, parsed });
90
97
  }
91
98
  else {
92
- multiStepHotkeys.push(parsed);
93
- multiStepCommands.push(command);
99
+ multiStepCandidates.push({ command, hotkey, parsed });
94
100
  }
95
101
  }
96
102
  // Check multi-step sequences first (they consume buffer state)
97
- if (multiStepHotkeys.length > 0) {
98
- const idx = trackerRef.current.feed(event, multiStepHotkeys);
99
- if (idx >= 0) {
103
+ if (multiStepCandidates.length > 0) {
104
+ const multiStepHotkeys = multiStepCandidates.map((candidate) => candidate.parsed);
105
+ const result = trackerRef.current.feedWithState(event, multiStepHotkeys);
106
+ if (result.matchedIndex >= 0) {
100
107
  event.preventDefault();
101
- multiStepCommands[idx].handler(ctx);
108
+ setSequenceState(null);
109
+ multiStepCandidates[result.matchedIndex].command.handler(ctx);
102
110
  return;
103
111
  }
112
+ if (result.pending) {
113
+ const firstCandidate = multiStepCandidates[result.pending.indexes[0]];
114
+ setSequenceState({
115
+ prefix: firstCandidate.parsed.steps.slice(0, result.pending.prefixLength),
116
+ candidates: result.pending.indexes
117
+ .map((idx) => multiStepCandidates[idx])
118
+ .filter(({ command }) => !command.hidden)
119
+ .map(({ command, hotkey, parsed }) => ({
120
+ command,
121
+ hotkey,
122
+ steps: parsed.steps,
123
+ remainingSteps: parsed.steps.slice(result.pending.prefixLength),
124
+ nextStep: parsed.steps[result.pending.prefixLength],
125
+ group: groupsRef.current.get(stepsKey(parsed.steps.slice(0, result.pending.prefixLength + 1))),
126
+ })),
127
+ });
128
+ event.preventDefault();
129
+ return;
130
+ }
131
+ setSequenceState(null);
104
132
  }
105
133
  // Check single-step matches
106
134
  for (const { command, parsed } of singleStepCandidates) {
107
135
  if (matchStep(event, parsed.steps[0])) {
108
136
  event.preventDefault();
137
+ setSequenceState(null);
109
138
  command.handler(ctx);
110
139
  return;
111
140
  }
112
141
  }
113
142
  });
143
+ useEffect(() => {
144
+ trackerRef.current.reset();
145
+ setSequenceState(null);
146
+ }, [mode]);
114
147
  const ctxValue = useMemo(() => ({
115
148
  registry: registryRef.current,
116
149
  leaderKey: leader,
117
150
  contextSources: contextSourcesRef.current,
151
+ groups: groupsRef.current,
118
152
  }), [leader]);
119
- return _jsx(CommandContext.Provider, { value: ctxValue, children: children });
153
+ return (_jsx(CommandContext.Provider, { value: ctxValue, children: _jsx(CommandSequenceContext, { value: sequenceState, children: children }) }));
120
154
  }
121
155
  export function useCommandContext() {
122
156
  const ctx = useContext(CommandContext);
@@ -138,6 +172,54 @@ export function useCommandRegistry() {
138
172
  }
139
173
  return ctx;
140
174
  }
175
+ export function useCommandSequenceState() {
176
+ return useContext(CommandSequenceContext);
177
+ }
178
+ export function useCommandGroup(group) {
179
+ const ctx = useContext(CommandContext);
180
+ if (!ctx) {
181
+ throw new Error("useCommandGroup must be used within a CommandProvider");
182
+ }
183
+ const groupRef = useRef(group);
184
+ groupRef.current = group;
185
+ const { groups, leaderKey } = ctx;
186
+ useEffect(() => {
187
+ const parsed = parseHotkey(groupRef.current.prefix, leaderKey);
188
+ const registered = {
189
+ ...groupRef.current,
190
+ prefixKey: stepsKey(parsed.steps),
191
+ };
192
+ groups.set(registered.prefixKey, registered);
193
+ return () => {
194
+ groups.delete(registered.prefixKey);
195
+ };
196
+ }, [
197
+ group.id,
198
+ group.prefix,
199
+ group.title,
200
+ group.description,
201
+ group.icon,
202
+ group.order,
203
+ groups,
204
+ leaderKey,
205
+ ]);
206
+ }
207
+ function stepsKey(steps) {
208
+ return steps.map(formatStepKey).join(" ");
209
+ }
210
+ function formatStepKey(step) {
211
+ const modifiers = [];
212
+ if (step.ctrl)
213
+ modifiers.push("ctrl");
214
+ if (step.meta)
215
+ modifiers.push("meta");
216
+ if (step.option)
217
+ modifiers.push("option");
218
+ if (step.shift)
219
+ modifiers.push("shift");
220
+ modifiers.push(step.key);
221
+ return modifiers.join("+");
222
+ }
141
223
  let nextContextSourceId = 0;
142
224
  export function useProvideCommandContext(getter) {
143
225
  const ctx = useContext(CommandContext);
@@ -1 +1 @@
1
- {"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.tsx"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.tsx"],"names":[],"mappings":"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"}
package/dist/index.d.ts CHANGED
@@ -1,12 +1,12 @@
1
- export type { Command, CommandContext, CommandContextBase, CommandHandler, CommandWhen, ParsedHotkey, ParsedStep, } from "./types.js";
1
+ export type { Command, CommandContext, CommandContextBase, CommandGroup, CommandHandler, CommandSequenceCandidate, CommandSequenceState, CommandWhen, ParsedHotkey, ParsedStep, RegisteredCommandGroup, } from "./types.js";
2
2
  export type { Mode } from "./mode.js";
3
3
  export { ModeProvider, useMode, useSetMode } from "./mode.js";
4
4
  export type { ModeProviderProps } from "./mode.js";
5
5
  export { parseHotkey } from "./parse.js";
6
6
  export { matchStep } from "./match.js";
7
- export { SequenceTracker } from "./sequence.js";
8
- export type { SequenceTrackerOptions } from "./sequence.js";
9
- export { CommandProvider, useCommandContext, useProvideCommandContext } from "./context.js";
7
+ export { DEFAULT_SEQUENCE_TIMEOUT_MS, SequenceTracker } from "./sequence.js";
8
+ export type { SequenceFeedResult, SequencePendingMatch, SequenceTrackerOptions, } from "./sequence.js";
9
+ export { CommandProvider, useCommandContext, useCommandGroup, useCommandRegistry, useCommandSequenceState, useProvideCommandContext, } from "./context.js";
10
10
  export type { CommandProviderProps } from "./context.js";
11
11
  export { useCommand } from "./use-command.js";
12
12
  export type { UseCommandOptions } from "./use-command.js";
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,OAAO,EACP,cAAc,EACd,kBAAkB,EAClB,cAAc,EACd,WAAW,EACX,YAAY,EACZ,UAAU,GACX,MAAM,YAAY,CAAA;AACnB,YAAY,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AACrC,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAC7D,YAAY,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AACtC,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAC/C,YAAY,EAAE,sBAAsB,EAAE,MAAM,eAAe,CAAA;AAC3D,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAA;AAC3F,YAAY,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAA;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,YAAY,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,YAAY,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,OAAO,EACP,cAAc,EACd,kBAAkB,EAClB,YAAY,EACZ,cAAc,EACd,wBAAwB,EACxB,oBAAoB,EACpB,WAAW,EACX,YAAY,EACZ,UAAU,EACV,sBAAsB,GACvB,MAAM,YAAY,CAAA;AACnB,YAAY,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AACrC,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAC7D,YAAY,EAAE,iBAAiB,EAAE,MAAM,WAAW,CAAA;AAClD,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AACtC,OAAO,EAAE,2BAA2B,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAC5E,YAAY,EACV,kBAAkB,EAClB,oBAAoB,EACpB,sBAAsB,GACvB,MAAM,eAAe,CAAA;AACtB,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,eAAe,EACf,kBAAkB,EAClB,uBAAuB,EACvB,wBAAwB,GACzB,MAAM,cAAc,CAAA;AACrB,YAAY,EAAE,oBAAoB,EAAE,MAAM,cAAc,CAAA;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,YAAY,EAAE,iBAAiB,EAAE,MAAM,kBAAkB,CAAA;AACzD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,YAAY,EAAE,gBAAgB,EAAE,MAAM,kBAAkB,CAAA"}
package/dist/index.js CHANGED
@@ -1,8 +1,8 @@
1
1
  export { ModeProvider, useMode, useSetMode } from "./mode.js";
2
2
  export { parseHotkey } from "./parse.js";
3
3
  export { matchStep } from "./match.js";
4
- export { SequenceTracker } from "./sequence.js";
5
- export { CommandProvider, useCommandContext, useProvideCommandContext } from "./context.js";
4
+ export { DEFAULT_SEQUENCE_TIMEOUT_MS, SequenceTracker } from "./sequence.js";
5
+ export { CommandProvider, useCommandContext, useCommandGroup, useCommandRegistry, useCommandSequenceState, useProvideCommandContext, } from "./context.js";
6
6
  export { useCommand } from "./use-command.js";
7
7
  export { useActions } from "./use-actions.js";
8
8
  //# sourceMappingURL=index.js.map
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAUA,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAE7D,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AACtC,OAAO,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAE/C,OAAO,EAAE,eAAe,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,MAAM,cAAc,CAAA;AAE3F,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAE7C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAcA,OAAO,EAAE,YAAY,EAAE,OAAO,EAAE,UAAU,EAAE,MAAM,WAAW,CAAA;AAE7D,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AACxC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AACtC,OAAO,EAAE,2BAA2B,EAAE,eAAe,EAAE,MAAM,eAAe,CAAA;AAM5E,OAAO,EACL,eAAe,EACf,iBAAiB,EACjB,eAAe,EACf,kBAAkB,EAClB,uBAAuB,EACvB,wBAAwB,GACzB,MAAM,cAAc,CAAA;AAErB,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAE7C,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA"}
@@ -1,19 +1,36 @@
1
1
  import type { KeyEvent } from "@opentui/core";
2
2
  import type { ParsedHotkey } from "./types.js";
3
+ export declare const DEFAULT_SEQUENCE_TIMEOUT_MS = 1500;
3
4
  export interface SequenceTrackerOptions {
4
5
  timeout?: number;
6
+ onReset?: () => void;
7
+ }
8
+ export interface SequencePendingMatch {
9
+ prefixLength: number;
10
+ indexes: number[];
11
+ }
12
+ export interface SequenceFeedResult {
13
+ matchedIndex: number;
14
+ pending: SequencePendingMatch | null;
5
15
  }
6
16
  export declare class SequenceTracker {
7
17
  private buffer;
8
18
  private timer;
9
19
  private timeout;
20
+ private onReset?;
10
21
  constructor(options?: SequenceTrackerOptions);
11
22
  /**
12
23
  * Feed a key event and check against registered hotkeys.
13
- * Returns the index of the matched hotkey, or -1 if no match.
24
+ * Returns the index of the matched hotkey, or -1 if no full match.
14
25
  */
15
26
  feed(event: KeyEvent, hotkeys: ParsedHotkey[]): number;
27
+ /**
28
+ * Feed a key event and return both full-match and pending-prefix state.
29
+ */
30
+ feedWithState(event: KeyEvent, hotkeys: ParsedHotkey[]): SequenceFeedResult;
31
+ getPendingMatch(hotkeys: ParsedHotkey[]): SequencePendingMatch | null;
16
32
  private matchesBuffer;
33
+ private findPendingMatch;
17
34
  reset(): void;
18
35
  private resetTimer;
19
36
  private clearTimer;
@@ -1 +1 @@
1
- {"version":3,"file":"sequence.d.ts","sourceRoot":"","sources":["../src/sequence.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAC7C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAG9C,MAAM,WAAW,sBAAsB;IACrC,OAAO,CAAC,EAAE,MAAM,CAAA;CACjB;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,KAAK,CAA6C;IAC1D,OAAO,CAAC,OAAO,CAAQ;gBAEX,OAAO,CAAC,EAAE,sBAAsB;IAI5C;;;OAGG;IACH,IAAI,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,MAAM;IAqBtD,OAAO,CAAC,aAAa;IAWrB,KAAK,IAAI,IAAI;IAKb,OAAO,CAAC,UAAU;IAKlB,OAAO,CAAC,UAAU;CAMnB"}
1
+ {"version":3,"file":"sequence.d.ts","sourceRoot":"","sources":["../src/sequence.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAA;AAC7C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAA;AAG9C,eAAO,MAAM,2BAA2B,OAAO,CAAA;AAE/C,MAAM,WAAW,sBAAsB;IACrC,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,OAAO,CAAC,EAAE,MAAM,IAAI,CAAA;CACrB;AAED,MAAM,WAAW,oBAAoB;IACnC,YAAY,EAAE,MAAM,CAAA;IACpB,OAAO,EAAE,MAAM,EAAE,CAAA;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,MAAM,CAAA;IACpB,OAAO,EAAE,oBAAoB,GAAG,IAAI,CAAA;CACrC;AAED,qBAAa,eAAe;IAC1B,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,KAAK,CAA6C;IAC1D,OAAO,CAAC,OAAO,CAAQ;IACvB,OAAO,CAAC,OAAO,CAAC,CAAY;gBAEhB,OAAO,CAAC,EAAE,sBAAsB;IAK5C;;;OAGG;IACH,IAAI,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,MAAM;IAItD;;OAEG;IACH,aAAa,CAAC,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAE,YAAY,EAAE,GAAG,kBAAkB;IAuB3E,eAAe,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,oBAAoB,GAAG,IAAI;IAIrE,OAAO,CAAC,aAAa;IAWrB,OAAO,CAAC,gBAAgB;IA+BxB,KAAK,IAAI,IAAI;IAOb,OAAO,CAAC,UAAU;IAKlB,OAAO,CAAC,UAAU;CAMnB"}
package/dist/sequence.js CHANGED
@@ -1,31 +1,45 @@
1
1
  import { matchStep } from "./match.js";
2
+ export const DEFAULT_SEQUENCE_TIMEOUT_MS = 1500;
2
3
  export class SequenceTracker {
3
4
  buffer = [];
4
5
  timer = null;
5
6
  timeout;
7
+ onReset;
6
8
  constructor(options) {
7
- this.timeout = options?.timeout ?? 500;
9
+ this.timeout = options?.timeout ?? DEFAULT_SEQUENCE_TIMEOUT_MS;
10
+ this.onReset = options?.onReset;
8
11
  }
9
12
  /**
10
13
  * Feed a key event and check against registered hotkeys.
11
- * Returns the index of the matched hotkey, or -1 if no match.
14
+ * Returns the index of the matched hotkey, or -1 if no full match.
12
15
  */
13
16
  feed(event, hotkeys) {
17
+ return this.feedWithState(event, hotkeys).matchedIndex;
18
+ }
19
+ /**
20
+ * Feed a key event and return both full-match and pending-prefix state.
21
+ */
22
+ feedWithState(event, hotkeys) {
14
23
  this.buffer.push(event);
15
24
  this.resetTimer();
16
25
  for (let i = 0; i < hotkeys.length; i++) {
17
26
  const hotkey = hotkeys[i];
18
27
  if (this.matchesBuffer(hotkey)) {
19
28
  this.reset();
20
- return i;
29
+ return { matchedIndex: i, pending: null };
21
30
  }
22
31
  }
23
32
  // Prune buffer if no hotkey could possibly match
24
- const maxLen = Math.max(...hotkeys.map((h) => h.steps.length));
25
- if (this.buffer.length > maxLen) {
26
- this.buffer.shift();
33
+ const maxLen = Math.max(0, ...hotkeys.map((h) => h.steps.length));
34
+ if (maxLen > 0) {
35
+ while (this.buffer.length > maxLen) {
36
+ this.buffer.shift();
37
+ }
27
38
  }
28
- return -1;
39
+ return { matchedIndex: -1, pending: this.findPendingMatch(hotkeys) };
40
+ }
41
+ getPendingMatch(hotkeys) {
42
+ return this.findPendingMatch(hotkeys);
29
43
  }
30
44
  matchesBuffer(hotkey) {
31
45
  const { steps } = hotkey;
@@ -38,9 +52,36 @@ export class SequenceTracker {
38
52
  }
39
53
  return true;
40
54
  }
55
+ findPendingMatch(hotkeys) {
56
+ const maxPrefixLength = Math.min(this.buffer.length, Math.max(0, ...hotkeys.map((h) => h.steps.length - 1)));
57
+ for (let prefixLength = maxPrefixLength; prefixLength > 0; prefixLength--) {
58
+ const start = this.buffer.length - prefixLength;
59
+ const indexes = [];
60
+ for (let hotkeyIndex = 0; hotkeyIndex < hotkeys.length; hotkeyIndex++) {
61
+ const hotkey = hotkeys[hotkeyIndex];
62
+ if (hotkey.steps.length <= prefixLength)
63
+ continue;
64
+ let matches = true;
65
+ for (let i = 0; i < prefixLength; i++) {
66
+ if (!matchStep(this.buffer[start + i], hotkey.steps[i])) {
67
+ matches = false;
68
+ break;
69
+ }
70
+ }
71
+ if (matches)
72
+ indexes.push(hotkeyIndex);
73
+ }
74
+ if (indexes.length > 0)
75
+ return { prefixLength, indexes };
76
+ }
77
+ return null;
78
+ }
41
79
  reset() {
80
+ const hadBuffer = this.buffer.length > 0;
42
81
  this.buffer = [];
43
82
  this.clearTimer();
83
+ if (hadBuffer)
84
+ this.onReset?.();
44
85
  }
45
86
  resetTimer() {
46
87
  this.clearTimer();
@@ -1 +1 @@
1
- {"version":3,"file":"sequence.js","sourceRoot":"","sources":["../src/sequence.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAA;AAMtC,MAAM,OAAO,eAAe;IAClB,MAAM,GAAe,EAAE,CAAA;IACvB,KAAK,GAAyC,IAAI,CAAA;IAClD,OAAO,CAAQ;IAEvB,YAAY,OAAgC;QAC1C,IAAI,CAAC,OAAO,GAAG,OAAO,EAAE,OAAO,IAAI,GAAG,CAAA;IACxC,CAAC;IAED;;;OAGG;IACH,IAAI,CAAC,KAAe,EAAE,OAAuB;QAC3C,IAAI,CAAC,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;QACvB,IAAI,CAAC,UAAU,EAAE,CAAA;QAEjB,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACxC,MAAM,MAAM,GAAG,OAAO,CAAC,CAAC,CAAE,CAAA;YAC1B,IAAI,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,EAAE,CAAC;gBAC/B,IAAI,CAAC,KAAK,EAAE,CAAA;gBACZ,OAAO,CAAC,CAAA;YACV,CAAC;QACH,CAAC;QAED,iDAAiD;QACjD,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAA;QAC9D,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,MAAM,EAAE,CAAC;YAChC,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAA;QACrB,CAAC;QAED,OAAO,CAAC,CAAC,CAAA;IACX,CAAC;IAEO,aAAa,CAAC,MAAoB;QACxC,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,CAAA;QACxB,IAAI,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM;YAAE,OAAO,KAAK,CAAA;QAEnD,MAAM,KAAK,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,GAAG,KAAK,CAAC,MAAM,CAAA;QAC/C,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,KAAK,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YACtC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,MAAM,CAAC,KAAK,GAAG,CAAC,CAAE,EAAE,KAAK,CAAC,CAAC,CAAE,CAAC;gBAAE,OAAO,KAAK,CAAA;QAClE,CAAC;QACD,OAAO,IAAI,CAAA;IACb,CAAC;IAED,KAAK;QACH,IAAI,CAAC,MAAM,GAAG,EAAE,CAAA;QAChB,IAAI,CAAC,UAAU,EAAE,CAAA;IACnB,CAAC;IAEO,UAAU;QAChB,IAAI,CAAC,UAAU,EAAE,CAAA;QACjB,IAAI,CAAC,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,EAAE,IAAI,CAAC,OAAO,CAAC,CAAA;IAC3D,CAAC;IAEO,UAAU;QAChB,IAAI,IAAI,CAAC,KAAK,KAAK,IAAI,EAAE,CAAC;YACxB,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;YACxB,IAAI,CAAC,KAAK,GAAG,IAAI,CAAA;QACnB,CAAC;IACH,CAAC;CACF"}
1
+ {"version":3,"file":"sequence.js","sourceRoot":"","sources":["../src/sequence.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -40,4 +40,27 @@ export interface CommandRegistry {
40
40
  register: (command: Command) => () => void;
41
41
  invoke: (id: string) => void;
42
42
  }
43
+ export interface CommandGroup {
44
+ id: string;
45
+ title: string;
46
+ prefix: string;
47
+ description?: string;
48
+ icon?: string;
49
+ order?: number;
50
+ }
51
+ export interface RegisteredCommandGroup extends CommandGroup {
52
+ prefixKey: string;
53
+ }
54
+ export interface CommandSequenceCandidate {
55
+ command: Command;
56
+ hotkey: string;
57
+ steps: ParsedStep[];
58
+ remainingSteps: ParsedStep[];
59
+ nextStep: ParsedStep;
60
+ group?: CommandGroup;
61
+ }
62
+ export interface CommandSequenceState {
63
+ prefix: ParsedStep[];
64
+ candidates: CommandSequenceCandidate[];
65
+ }
43
66
  //# sourceMappingURL=types.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAErC,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,IAAI,CAAA;IACV,OAAO,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAA;IAC7B,QAAQ,EAAE;QAAE,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;QAAC,IAAI,EAAE,MAAM,OAAO,EAAE,CAAA;KAAE,CAAA;IACjE,IAAI,EAAE,MAAM,IAAI,CAAA;CACjB;AAED,MAAM,WAAW,cAAe,SAAQ,kBAAkB;IACxD,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CACnB;AAED,MAAM,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE,cAAc,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;AAC1E,MAAM,MAAM,WAAW,GAAG,CAAC,GAAG,EAAE,cAAc,KAAK,OAAO,CAAA;AAE1D,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,cAAc,CAAA;IACvB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,KAAK,CAAC,EAAE,IAAI,EAAE,CAAA;IACd,IAAI,CAAC,EAAE,WAAW,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,UAAU,EAAE,CAAA;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,OAAO,CAAA;IACb,IAAI,EAAE,OAAO,CAAA;IACb,KAAK,EAAE,OAAO,CAAA;IACd,MAAM,EAAE,OAAO,CAAA;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC9B,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,IAAI,CAAA;IAC1C,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;CAC7B"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAErC,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,IAAI,CAAA;IACV,OAAO,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,IAAI,CAAA;IAC7B,QAAQ,EAAE;QAAE,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAC;QAAC,IAAI,EAAE,MAAM,OAAO,EAAE,CAAA;KAAE,CAAA;IACjE,IAAI,EAAE,MAAM,IAAI,CAAA;CACjB;AAED,MAAM,WAAW,cAAe,SAAQ,kBAAkB;IACxD,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAA;CACnB;AAED,MAAM,MAAM,cAAc,GAAG,CAAC,GAAG,EAAE,cAAc,KAAK,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAAA;AAC1E,MAAM,MAAM,WAAW,GAAG,CAAC,GAAG,EAAE,cAAc,KAAK,OAAO,CAAA;AAE1D,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,cAAc,CAAA;IACvB,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,KAAK,CAAC,EAAE,IAAI,EAAE,CAAA;IACd,IAAI,CAAC,EAAE,WAAW,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED,MAAM,WAAW,YAAY;IAC3B,KAAK,EAAE,UAAU,EAAE,CAAA;CACpB;AAED,MAAM,WAAW,UAAU;IACzB,GAAG,EAAE,MAAM,CAAA;IACX,IAAI,EAAE,OAAO,CAAA;IACb,IAAI,EAAE,OAAO,CAAA;IACb,KAAK,EAAE,OAAO,CAAA;IACd,MAAM,EAAE,OAAO,CAAA;CAChB;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAC9B,QAAQ,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,MAAM,IAAI,CAAA;IAC1C,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,KAAK,IAAI,CAAA;CAC7B;AAED,MAAM,WAAW,YAAY;IAC3B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,MAAM,CAAA;IACd,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,KAAK,CAAC,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,sBAAuB,SAAQ,YAAY;IAC1D,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,wBAAwB;IACvC,OAAO,EAAE,OAAO,CAAA;IAChB,MAAM,EAAE,MAAM,CAAA;IACd,KAAK,EAAE,UAAU,EAAE,CAAA;IACnB,cAAc,EAAE,UAAU,EAAE,CAAA;IAC5B,QAAQ,EAAE,UAAU,CAAA;IACpB,KAAK,CAAC,EAAE,YAAY,CAAA;CACrB;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,UAAU,EAAE,CAAA;IACpB,UAAU,EAAE,wBAAwB,EAAE,CAAA;CACvC"}
@@ -7,6 +7,10 @@ export interface ActionDefinition {
7
7
  modes?: Mode[];
8
8
  handler: CommandHandler;
9
9
  when?: CommandWhen;
10
+ category?: string;
11
+ group?: string;
12
+ icon?: string;
13
+ hidden?: boolean;
10
14
  }
11
15
  export declare function useActions(actions: ActionDefinition[] | undefined): void;
12
16
  //# sourceMappingURL=use-actions.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"use-actions.d.ts","sourceRoot":"","sources":["../src/use-actions.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAW,cAAc,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AACtE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAErC,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,IAAI,EAAE,CAAA;IACd,OAAO,EAAE,cAAc,CAAA;IACvB,IAAI,CAAC,EAAE,WAAW,CAAA;CACnB;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,gBAAgB,EAAE,GAAG,SAAS,GAAG,IAAI,CAgCxE"}
1
+ {"version":3,"file":"use-actions.d.ts","sourceRoot":"","sources":["../src/use-actions.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAW,cAAc,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AACtE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAErC,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,IAAI,EAAE,CAAA;IACd,OAAO,EAAE,cAAc,CAAA;IACvB,IAAI,CAAC,EAAE,WAAW,CAAA;IAClB,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,gBAAgB,EAAE,GAAG,SAAS,GAAG,IAAI,CA0CxE"}
@@ -4,7 +4,9 @@ export function useActions(actions) {
4
4
  const { registry } = useCommandRegistry();
5
5
  const actionsRef = useRef(actions);
6
6
  actionsRef.current = actions;
7
- const key = useMemo(() => actions?.map((a) => `${a.id}:${a.hotkey ?? ""}`).join(",") ?? "", [actions]);
7
+ const key = useMemo(() => actions
8
+ ?.map((a) => `${a.id}:${a.title}:${a.hotkey ?? ""}:${a.category ?? ""}:${a.group ?? ""}:${a.icon ?? ""}:${a.hidden ?? false}`)
9
+ .join(",") ?? "", [actions]);
8
10
  useEffect(() => {
9
11
  const current = actionsRef.current;
10
12
  if (!current || current.length === 0)
@@ -17,6 +19,10 @@ export function useActions(actions) {
17
19
  modes: action.modes,
18
20
  handler: (ctx) => actionsRef.current?.[i]?.handler(ctx),
19
21
  when: action.when ? (ctx) => actionsRef.current?.[i]?.when?.(ctx) ?? false : undefined,
22
+ category: action.category,
23
+ group: action.group,
24
+ icon: action.icon,
25
+ hidden: action.hidden,
20
26
  };
21
27
  return registry.register(command);
22
28
  });
@@ -1 +1 @@
1
- {"version":3,"file":"use-actions.js","sourceRoot":"","sources":["../src/use-actions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AAajD,MAAM,UAAU,UAAU,CAAC,OAAuC;IAChE,MAAM,EAAE,QAAQ,EAAE,GAAG,kBAAkB,EAAE,CAAA;IACzC,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,CAAA;IAClC,UAAU,CAAC,OAAO,GAAG,OAAO,CAAA;IAE5B,MAAM,GAAG,GAAG,OAAO,CACjB,GAAG,EAAE,CAAC,OAAO,EAAE,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,MAAM,IAAI,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,EACtE,CAAC,OAAO,CAAC,CACV,CAAA;IAED,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAA;QAClC,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,OAAM;QAE5C,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;YAC5C,MAAM,OAAO,GAAY;gBACvB,EAAE,EAAE,MAAM,CAAC,EAAE;gBACb,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,aAAa,EAAE,MAAM,CAAC,MAAM;gBAC5B,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC;gBACvD,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,SAAS;aACvF,CAAA;YACD,OAAO,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAA;QACnC,CAAC,CAAC,CAAA;QAEF,OAAO,GAAG,EAAE;YACV,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;gBACrC,UAAU,EAAE,CAAA;YACd,CAAC;QACH,CAAC,CAAA;IACH,CAAC,EAAE,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAA;AACrB,CAAC"}
1
+ {"version":3,"file":"use-actions.js","sourceRoot":"","sources":["../src/use-actions.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,OAAO,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;AAClD,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AAiBjD,MAAM,UAAU,UAAU,CAAC,OAAuC;IAChE,MAAM,EAAE,QAAQ,EAAE,GAAG,kBAAkB,EAAE,CAAA;IACzC,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,CAAA;IAClC,UAAU,CAAC,OAAO,GAAG,OAAO,CAAA;IAE5B,MAAM,GAAG,GAAG,OAAO,CACjB,GAAG,EAAE,CACH,OAAO;QACL,EAAE,GAAG,CACH,CAAC,CAAC,EAAE,EAAE,CACJ,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC,KAAK,IAAI,CAAC,CAAC,MAAM,IAAI,EAAE,IAAI,CAAC,CAAC,QAAQ,IAAI,EAAE,IAAI,CAAC,CAAC,KAAK,IAAI,EAAE,IAAI,CAAC,CAAC,IAAI,IAAI,EAAE,IAAI,CAAC,CAAC,MAAM,IAAI,KAAK,EAAE,CACnH;SACA,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,EACpB,CAAC,OAAO,CAAC,CACV,CAAA;IAED,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,OAAO,GAAG,UAAU,CAAC,OAAO,CAAA;QAClC,IAAI,CAAC,OAAO,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;YAAE,OAAM;QAE5C,MAAM,WAAW,GAAG,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE;YAC5C,MAAM,OAAO,GAAY;gBACvB,EAAE,EAAE,MAAM,CAAC,EAAE;gBACb,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,aAAa,EAAE,MAAM,CAAC,MAAM;gBAC5B,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC;gBACvD,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,GAAG,CAAC,IAAI,KAAK,CAAC,CAAC,CAAC,SAAS;gBACtF,QAAQ,EAAE,MAAM,CAAC,QAAQ;gBACzB,KAAK,EAAE,MAAM,CAAC,KAAK;gBACnB,IAAI,EAAE,MAAM,CAAC,IAAI;gBACjB,MAAM,EAAE,MAAM,CAAC,MAAM;aACtB,CAAA;YACD,OAAO,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAA;QACnC,CAAC,CAAC,CAAA;QAEF,OAAO,GAAG,EAAE;YACV,KAAK,MAAM,UAAU,IAAI,WAAW,EAAE,CAAC;gBACrC,UAAU,EAAE,CAAA;YACd,CAAC;QACH,CAAC,CAAA;IACH,CAAC,EAAE,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAA;AACrB,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tooee/commands",
3
- "version": "0.1.16",
3
+ "version": "0.1.18",
4
4
  "description": "Vim-inspired modal command system for Tooee",
5
5
  "keywords": [
6
6
  "cli",
package/src/context.tsx CHANGED
@@ -5,10 +5,20 @@ import {
5
5
  useCallback,
6
6
  useEffect,
7
7
  useMemo,
8
+ useState,
8
9
  type ReactNode,
9
10
  } from "react"
10
11
  import { useKeyboard } from "@opentui/react"
11
- import type { Command, CommandContext, CommandRegistry, ParsedHotkey } from "./types.js"
12
+ import type {
13
+ Command,
14
+ CommandContext,
15
+ CommandGroup,
16
+ CommandRegistry,
17
+ CommandSequenceState,
18
+ ParsedHotkey,
19
+ ParsedStep,
20
+ RegisteredCommandGroup,
21
+ } from "./types.js"
12
22
  import type { Mode } from "./mode.js"
13
23
  import { ModeProvider, useMode, useSetMode } from "./mode.js"
14
24
  import { parseHotkey } from "./parse.js"
@@ -23,21 +33,30 @@ interface CommandContextValue {
23
33
  registry: CommandRegistry
24
34
  leaderKey?: string
25
35
  contextSources: Map<string, ContextGetter>
36
+ groups: Map<string, RegisteredCommandGroup>
26
37
  }
27
38
 
28
39
  const CommandContext = createContext<CommandContextValue | null>(null)
40
+ const CommandSequenceContext = createContext<CommandSequenceState | null>(null)
29
41
 
30
42
  export interface CommandProviderProps {
31
43
  children: ReactNode
32
44
  leader?: string
33
45
  keymap?: Record<string, string>
34
46
  initialMode?: Mode
47
+ sequenceTimeoutMs?: number
35
48
  }
36
49
 
37
- export function CommandProvider({ children, leader, keymap, initialMode }: CommandProviderProps) {
50
+ export function CommandProvider({
51
+ children,
52
+ leader,
53
+ keymap,
54
+ initialMode,
55
+ sequenceTimeoutMs,
56
+ }: CommandProviderProps) {
38
57
  return (
39
58
  <ModeProvider initialMode={initialMode}>
40
- <CommandDispatcher leader={leader} keymap={keymap}>
59
+ <CommandDispatcher leader={leader} keymap={keymap} sequenceTimeoutMs={sequenceTimeoutMs}>
41
60
  {children}
42
61
  </CommandDispatcher>
43
62
  </ModeProvider>
@@ -48,17 +67,23 @@ function CommandDispatcher({
48
67
  children,
49
68
  leader,
50
69
  keymap,
70
+ sequenceTimeoutMs,
51
71
  }: {
52
72
  children: ReactNode
53
73
  leader?: string
54
74
  keymap?: Record<string, string>
75
+ sequenceTimeoutMs?: number
55
76
  }) {
56
77
  const registryRef = useRef<CommandRegistry | null>(null)
57
78
  const contextSourcesRef = useRef(new Map<string, ContextGetter>())
79
+ const groupsRef = useRef(new Map<string, RegisteredCommandGroup>())
58
80
  const mode = useMode()
59
81
  const modeRef = useRef(mode)
60
82
  modeRef.current = mode
61
83
  const setMode = useSetMode()
84
+ const [sequenceState, setSequenceState] = useState<CommandSequenceState | null>(null)
85
+ const clearSequenceStateRef = useRef(() => setSequenceState(null))
86
+ clearSequenceStateRef.current = () => setSequenceState(null)
62
87
 
63
88
  const buildCtx = useCallback((): CommandContext => {
64
89
  const ctx: Record<string, any> = {
@@ -96,7 +121,12 @@ function CommandDispatcher({
96
121
  }
97
122
  }
98
123
 
99
- const trackerRef = useRef(new SequenceTracker())
124
+ const trackerRef = useRef(
125
+ new SequenceTracker({
126
+ timeout: sequenceTimeoutMs,
127
+ onReset: () => clearSequenceStateRef.current(),
128
+ }),
129
+ )
100
130
  const parseCacheRef = useRef(new Map<string, ParsedHotkey>())
101
131
 
102
132
  const getParsedHotkey = useCallback(
@@ -124,8 +154,7 @@ function CommandDispatcher({
124
154
 
125
155
  // Collect eligible commands with their parsed hotkeys
126
156
  const singleStepCandidates: { command: Command; parsed: ParsedHotkey }[] = []
127
- const multiStepHotkeys: ParsedHotkey[] = []
128
- const multiStepCommands: Command[] = []
157
+ const multiStepCandidates: { command: Command; hotkey: string; parsed: ParsedHotkey }[] = []
129
158
 
130
159
  for (const command of registry.commands.values()) {
131
160
  const commandModes = command.modes ?? DEFAULT_MODES
@@ -140,41 +169,77 @@ function CommandDispatcher({
140
169
  if (parsed.steps.length === 1) {
141
170
  singleStepCandidates.push({ command, parsed })
142
171
  } else {
143
- multiStepHotkeys.push(parsed)
144
- multiStepCommands.push(command)
172
+ multiStepCandidates.push({ command, hotkey, parsed })
145
173
  }
146
174
  }
147
175
 
148
176
  // Check multi-step sequences first (they consume buffer state)
149
- if (multiStepHotkeys.length > 0) {
150
- const idx = trackerRef.current.feed(event, multiStepHotkeys)
151
- if (idx >= 0) {
177
+ if (multiStepCandidates.length > 0) {
178
+ const multiStepHotkeys = multiStepCandidates.map((candidate) => candidate.parsed)
179
+ const result = trackerRef.current.feedWithState(event, multiStepHotkeys)
180
+ if (result.matchedIndex >= 0) {
181
+ event.preventDefault()
182
+ setSequenceState(null)
183
+ multiStepCandidates[result.matchedIndex]!.command.handler(ctx)
184
+ return
185
+ }
186
+
187
+ if (result.pending) {
188
+ const firstCandidate = multiStepCandidates[result.pending.indexes[0]!]!
189
+ setSequenceState({
190
+ prefix: firstCandidate.parsed.steps.slice(0, result.pending.prefixLength),
191
+ candidates: result.pending.indexes
192
+ .map((idx) => multiStepCandidates[idx]!)
193
+ .filter(({ command }) => !command.hidden)
194
+ .map(({ command, hotkey, parsed }) => ({
195
+ command,
196
+ hotkey,
197
+ steps: parsed.steps,
198
+ remainingSteps: parsed.steps.slice(result.pending!.prefixLength),
199
+ nextStep: parsed.steps[result.pending!.prefixLength]!,
200
+ group: groupsRef.current.get(
201
+ stepsKey(parsed.steps.slice(0, result.pending!.prefixLength + 1)),
202
+ ),
203
+ })),
204
+ })
152
205
  event.preventDefault()
153
- multiStepCommands[idx]!.handler(ctx)
154
206
  return
155
207
  }
208
+
209
+ setSequenceState(null)
156
210
  }
157
211
 
158
212
  // Check single-step matches
159
213
  for (const { command, parsed } of singleStepCandidates) {
160
214
  if (matchStep(event, parsed.steps[0]!)) {
161
215
  event.preventDefault()
216
+ setSequenceState(null)
162
217
  command.handler(ctx)
163
218
  return
164
219
  }
165
220
  }
166
221
  })
167
222
 
223
+ useEffect(() => {
224
+ trackerRef.current.reset()
225
+ setSequenceState(null)
226
+ }, [mode])
227
+
168
228
  const ctxValue = useMemo(
169
229
  () => ({
170
230
  registry: registryRef.current!,
171
231
  leaderKey: leader,
172
232
  contextSources: contextSourcesRef.current,
233
+ groups: groupsRef.current,
173
234
  }),
174
235
  [leader],
175
236
  )
176
237
 
177
- return <CommandContext.Provider value={ctxValue}>{children}</CommandContext.Provider>
238
+ return (
239
+ <CommandContext.Provider value={ctxValue}>
240
+ <CommandSequenceContext value={sequenceState}>{children}</CommandSequenceContext>
241
+ </CommandContext.Provider>
242
+ )
178
243
  }
179
244
 
180
245
  export function useCommandContext(): { commands: Command[]; invoke: (id: string) => void } {
@@ -200,6 +265,56 @@ export function useCommandRegistry(): CommandContextValue {
200
265
  return ctx
201
266
  }
202
267
 
268
+ export function useCommandSequenceState(): CommandSequenceState | null {
269
+ return useContext(CommandSequenceContext)
270
+ }
271
+
272
+ export function useCommandGroup(group: CommandGroup): void {
273
+ const ctx = useContext(CommandContext)
274
+ if (!ctx) {
275
+ throw new Error("useCommandGroup must be used within a CommandProvider")
276
+ }
277
+
278
+ const groupRef = useRef(group)
279
+ groupRef.current = group
280
+ const { groups, leaderKey } = ctx
281
+
282
+ useEffect(() => {
283
+ const parsed = parseHotkey(groupRef.current.prefix, leaderKey)
284
+ const registered: RegisteredCommandGroup = {
285
+ ...groupRef.current,
286
+ prefixKey: stepsKey(parsed.steps),
287
+ }
288
+ groups.set(registered.prefixKey, registered)
289
+ return () => {
290
+ groups.delete(registered.prefixKey)
291
+ }
292
+ }, [
293
+ group.id,
294
+ group.prefix,
295
+ group.title,
296
+ group.description,
297
+ group.icon,
298
+ group.order,
299
+ groups,
300
+ leaderKey,
301
+ ])
302
+ }
303
+
304
+ function stepsKey(steps: ParsedStep[]): string {
305
+ return steps.map(formatStepKey).join(" ")
306
+ }
307
+
308
+ function formatStepKey(step: ParsedStep): string {
309
+ const modifiers = []
310
+ if (step.ctrl) modifiers.push("ctrl")
311
+ if (step.meta) modifiers.push("meta")
312
+ if (step.option) modifiers.push("option")
313
+ if (step.shift) modifiers.push("shift")
314
+ modifiers.push(step.key)
315
+ return modifiers.join("+")
316
+ }
317
+
203
318
  let nextContextSourceId = 0
204
319
 
205
320
  export function useProvideCommandContext(getter: () => Partial<CommandContext>): void {
package/src/index.ts CHANGED
@@ -2,19 +2,34 @@ export type {
2
2
  Command,
3
3
  CommandContext,
4
4
  CommandContextBase,
5
+ CommandGroup,
5
6
  CommandHandler,
7
+ CommandSequenceCandidate,
8
+ CommandSequenceState,
6
9
  CommandWhen,
7
10
  ParsedHotkey,
8
11
  ParsedStep,
12
+ RegisteredCommandGroup,
9
13
  } from "./types.js"
10
14
  export type { Mode } from "./mode.js"
11
15
  export { ModeProvider, useMode, useSetMode } from "./mode.js"
12
16
  export type { ModeProviderProps } from "./mode.js"
13
17
  export { parseHotkey } from "./parse.js"
14
18
  export { matchStep } from "./match.js"
15
- export { SequenceTracker } from "./sequence.js"
16
- export type { SequenceTrackerOptions } from "./sequence.js"
17
- export { CommandProvider, useCommandContext, useProvideCommandContext } from "./context.js"
19
+ export { DEFAULT_SEQUENCE_TIMEOUT_MS, SequenceTracker } from "./sequence.js"
20
+ export type {
21
+ SequenceFeedResult,
22
+ SequencePendingMatch,
23
+ SequenceTrackerOptions,
24
+ } from "./sequence.js"
25
+ export {
26
+ CommandProvider,
27
+ useCommandContext,
28
+ useCommandGroup,
29
+ useCommandRegistry,
30
+ useCommandSequenceState,
31
+ useProvideCommandContext,
32
+ } from "./context.js"
18
33
  export type { CommandProviderProps } from "./context.js"
19
34
  export { useCommand } from "./use-command.js"
20
35
  export type { UseCommandOptions } from "./use-command.js"
package/src/sequence.ts CHANGED
@@ -2,24 +2,46 @@ import type { KeyEvent } from "@opentui/core"
2
2
  import type { ParsedHotkey } from "./types.js"
3
3
  import { matchStep } from "./match.js"
4
4
 
5
+ export const DEFAULT_SEQUENCE_TIMEOUT_MS = 1500
6
+
5
7
  export interface SequenceTrackerOptions {
6
- timeout?: number // ms, default 500
8
+ timeout?: number // ms, default DEFAULT_SEQUENCE_TIMEOUT_MS
9
+ onReset?: () => void
10
+ }
11
+
12
+ export interface SequencePendingMatch {
13
+ prefixLength: number
14
+ indexes: number[]
15
+ }
16
+
17
+ export interface SequenceFeedResult {
18
+ matchedIndex: number
19
+ pending: SequencePendingMatch | null
7
20
  }
8
21
 
9
22
  export class SequenceTracker {
10
23
  private buffer: KeyEvent[] = []
11
24
  private timer: ReturnType<typeof setTimeout> | null = null
12
25
  private timeout: number
26
+ private onReset?: () => void
13
27
 
14
28
  constructor(options?: SequenceTrackerOptions) {
15
- this.timeout = options?.timeout ?? 500
29
+ this.timeout = options?.timeout ?? DEFAULT_SEQUENCE_TIMEOUT_MS
30
+ this.onReset = options?.onReset
16
31
  }
17
32
 
18
33
  /**
19
34
  * Feed a key event and check against registered hotkeys.
20
- * Returns the index of the matched hotkey, or -1 if no match.
35
+ * Returns the index of the matched hotkey, or -1 if no full match.
21
36
  */
22
37
  feed(event: KeyEvent, hotkeys: ParsedHotkey[]): number {
38
+ return this.feedWithState(event, hotkeys).matchedIndex
39
+ }
40
+
41
+ /**
42
+ * Feed a key event and return both full-match and pending-prefix state.
43
+ */
44
+ feedWithState(event: KeyEvent, hotkeys: ParsedHotkey[]): SequenceFeedResult {
23
45
  this.buffer.push(event)
24
46
  this.resetTimer()
25
47
 
@@ -27,17 +49,23 @@ export class SequenceTracker {
27
49
  const hotkey = hotkeys[i]!
28
50
  if (this.matchesBuffer(hotkey)) {
29
51
  this.reset()
30
- return i
52
+ return { matchedIndex: i, pending: null }
31
53
  }
32
54
  }
33
55
 
34
56
  // Prune buffer if no hotkey could possibly match
35
- const maxLen = Math.max(...hotkeys.map((h) => h.steps.length))
36
- if (this.buffer.length > maxLen) {
37
- this.buffer.shift()
57
+ const maxLen = Math.max(0, ...hotkeys.map((h) => h.steps.length))
58
+ if (maxLen > 0) {
59
+ while (this.buffer.length > maxLen) {
60
+ this.buffer.shift()
61
+ }
38
62
  }
39
63
 
40
- return -1
64
+ return { matchedIndex: -1, pending: this.findPendingMatch(hotkeys) }
65
+ }
66
+
67
+ getPendingMatch(hotkeys: ParsedHotkey[]): SequencePendingMatch | null {
68
+ return this.findPendingMatch(hotkeys)
41
69
  }
42
70
 
43
71
  private matchesBuffer(hotkey: ParsedHotkey): boolean {
@@ -51,9 +79,42 @@ export class SequenceTracker {
51
79
  return true
52
80
  }
53
81
 
82
+ private findPendingMatch(hotkeys: ParsedHotkey[]): SequencePendingMatch | null {
83
+ const maxPrefixLength = Math.min(
84
+ this.buffer.length,
85
+ Math.max(0, ...hotkeys.map((h) => h.steps.length - 1)),
86
+ )
87
+
88
+ for (let prefixLength = maxPrefixLength; prefixLength > 0; prefixLength--) {
89
+ const start = this.buffer.length - prefixLength
90
+ const indexes: number[] = []
91
+
92
+ for (let hotkeyIndex = 0; hotkeyIndex < hotkeys.length; hotkeyIndex++) {
93
+ const hotkey = hotkeys[hotkeyIndex]!
94
+ if (hotkey.steps.length <= prefixLength) continue
95
+
96
+ let matches = true
97
+ for (let i = 0; i < prefixLength; i++) {
98
+ if (!matchStep(this.buffer[start + i]!, hotkey.steps[i]!)) {
99
+ matches = false
100
+ break
101
+ }
102
+ }
103
+
104
+ if (matches) indexes.push(hotkeyIndex)
105
+ }
106
+
107
+ if (indexes.length > 0) return { prefixLength, indexes }
108
+ }
109
+
110
+ return null
111
+ }
112
+
54
113
  reset(): void {
114
+ const hadBuffer = this.buffer.length > 0
55
115
  this.buffer = []
56
116
  this.clearTimer()
117
+ if (hadBuffer) this.onReset?.()
57
118
  }
58
119
 
59
120
  private resetTimer(): void {
package/src/types.ts CHANGED
@@ -44,3 +44,30 @@ export interface CommandRegistry {
44
44
  register: (command: Command) => () => void
45
45
  invoke: (id: string) => void
46
46
  }
47
+
48
+ export interface CommandGroup {
49
+ id: string
50
+ title: string
51
+ prefix: string
52
+ description?: string
53
+ icon?: string
54
+ order?: number
55
+ }
56
+
57
+ export interface RegisteredCommandGroup extends CommandGroup {
58
+ prefixKey: string
59
+ }
60
+
61
+ export interface CommandSequenceCandidate {
62
+ command: Command
63
+ hotkey: string
64
+ steps: ParsedStep[]
65
+ remainingSteps: ParsedStep[]
66
+ nextStep: ParsedStep
67
+ group?: CommandGroup
68
+ }
69
+
70
+ export interface CommandSequenceState {
71
+ prefix: ParsedStep[]
72
+ candidates: CommandSequenceCandidate[]
73
+ }
@@ -10,6 +10,10 @@ export interface ActionDefinition {
10
10
  modes?: Mode[]
11
11
  handler: CommandHandler
12
12
  when?: CommandWhen
13
+ category?: string
14
+ group?: string
15
+ icon?: string
16
+ hidden?: boolean
13
17
  }
14
18
 
15
19
  export function useActions(actions: ActionDefinition[] | undefined): void {
@@ -18,7 +22,13 @@ export function useActions(actions: ActionDefinition[] | undefined): void {
18
22
  actionsRef.current = actions
19
23
 
20
24
  const key = useMemo(
21
- () => actions?.map((a) => `${a.id}:${a.hotkey ?? ""}`).join(",") ?? "",
25
+ () =>
26
+ actions
27
+ ?.map(
28
+ (a) =>
29
+ `${a.id}:${a.title}:${a.hotkey ?? ""}:${a.category ?? ""}:${a.group ?? ""}:${a.icon ?? ""}:${a.hidden ?? false}`,
30
+ )
31
+ .join(",") ?? "",
22
32
  [actions],
23
33
  )
24
34
 
@@ -34,6 +44,10 @@ export function useActions(actions: ActionDefinition[] | undefined): void {
34
44
  modes: action.modes,
35
45
  handler: (ctx) => actionsRef.current?.[i]?.handler(ctx),
36
46
  when: action.when ? (ctx) => actionsRef.current?.[i]?.when?.(ctx) ?? false : undefined,
47
+ category: action.category,
48
+ group: action.group,
49
+ icon: action.icon,
50
+ hidden: action.hidden,
37
51
  }
38
52
  return registry.register(command)
39
53
  })