@tooee/commands 0.1.19 → 0.1.21

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.
Files changed (46) hide show
  1. package/README.md +33 -0
  2. package/dist/command-store.d.ts +147 -0
  3. package/dist/command-store.d.ts.map +1 -0
  4. package/dist/command-store.js +367 -0
  5. package/dist/command-store.js.map +1 -0
  6. package/dist/context.d.ts +52 -3
  7. package/dist/context.d.ts.map +1 -1
  8. package/dist/context.js +244 -153
  9. package/dist/context.js.map +1 -1
  10. package/dist/index.d.ts +5 -3
  11. package/dist/index.d.ts.map +1 -1
  12. package/dist/index.js +2 -1
  13. package/dist/index.js.map +1 -1
  14. package/dist/match.d.ts.map +1 -1
  15. package/dist/match.js +2 -0
  16. package/dist/match.js.map +1 -1
  17. package/dist/mode.d.ts +7 -1
  18. package/dist/mode.d.ts.map +1 -1
  19. package/dist/mode.js +12 -3
  20. package/dist/mode.js.map +1 -1
  21. package/dist/parse.d.ts.map +1 -1
  22. package/dist/parse.js +17 -5
  23. package/dist/parse.js.map +1 -1
  24. package/dist/sequence.d.ts +17 -2
  25. package/dist/sequence.d.ts.map +1 -1
  26. package/dist/sequence.js +66 -45
  27. package/dist/sequence.js.map +1 -1
  28. package/dist/types.d.ts +51 -1
  29. package/dist/types.d.ts.map +1 -1
  30. package/dist/use-actions.d.ts.map +1 -1
  31. package/dist/use-actions.js +6 -3
  32. package/dist/use-actions.js.map +1 -1
  33. package/dist/use-command.d.ts.map +1 -1
  34. package/dist/use-command.js +12 -4
  35. package/dist/use-command.js.map +1 -1
  36. package/package.json +5 -1
  37. package/src/command-store.ts +554 -0
  38. package/src/context.tsx +353 -165
  39. package/src/index.ts +27 -1
  40. package/src/match.ts +1 -0
  41. package/src/mode.tsx +31 -3
  42. package/src/parse.ts +20 -5
  43. package/src/sequence.ts +80 -52
  44. package/src/types.ts +56 -3
  45. package/src/use-actions.ts +5 -3
  46. package/src/use-command.ts +13 -4
package/dist/mode.js CHANGED
@@ -1,9 +1,18 @@
1
1
  import { jsx as _jsx } from "@opentui/react/jsx-runtime";
2
- import { createContext, useContext, useState, useCallback, useMemo } from "react";
2
+ import { createContext, useContext, useState, useCallback, useMemo, useRef, } from "react";
3
3
  const ModeContext = createContext(null);
4
- export function ModeProvider({ children, initialMode = "cursor" }) {
4
+ export function ModeProvider({ children, initialMode = "cursor", onModeChange, }) {
5
5
  const [mode, setModeState] = useState(initialMode);
6
- const setMode = useCallback((m) => setModeState(m), []);
6
+ const modeRef = useRef(mode);
7
+ const onModeChangeRef = useRef(onModeChange);
8
+ onModeChangeRef.current = onModeChange;
9
+ const setMode = useCallback((m) => {
10
+ if (m !== modeRef.current) {
11
+ modeRef.current = m;
12
+ onModeChangeRef.current?.(m);
13
+ }
14
+ setModeState(m);
15
+ }, []);
7
16
  const value = useMemo(() => ({ mode, setMode }), [mode, setMode]);
8
17
  return _jsx(ModeContext.Provider, { value: value, children: children });
9
18
  }
package/dist/mode.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"mode.js","sourceRoot":"","sources":["../src/mode.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,QAAQ,EAAE,WAAW,EAAE,OAAO,EAAkB,MAAM,OAAO,CAAA;AASjG,MAAM,WAAW,GAAG,aAAa,CAA0B,IAAI,CAAC,CAAA;AAOhE,MAAM,UAAU,YAAY,CAAC,EAAE,QAAQ,EAAE,WAAW,GAAG,QAAQ,EAAqB;IAClF,MAAM,CAAC,IAAI,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAO,WAAW,CAAC,CAAA;IACxD,MAAM,OAAO,GAAG,WAAW,CAAC,CAAC,CAAO,EAAE,EAAE,CAAC,YAAY,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAA;IAE7D,MAAM,KAAK,GAAG,OAAO,CAAmB,GAAG,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAA;IAEnF,OAAO,KAAC,WAAW,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,YAAG,QAAQ,GAAwB,CAAA;AAC9E,CAAC;AAED,MAAM,UAAU,OAAO;IACrB,MAAM,GAAG,GAAG,UAAU,CAAC,WAAW,CAAC,CAAA;IACnC,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAA;IAC/D,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,CAAA;AACjB,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,MAAM,GAAG,GAAG,UAAU,CAAC,WAAW,CAAC,CAAA;IACnC,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAA;IAClE,CAAC;IACD,OAAO,GAAG,CAAC,OAAO,CAAA;AACpB,CAAC"}
1
+ {"version":3,"file":"mode.js","sourceRoot":"","sources":["../src/mode.tsx"],"names":[],"mappings":";AAAA,OAAO,EACL,aAAa,EACb,UAAU,EACV,QAAQ,EACR,WAAW,EACX,OAAO,EACP,MAAM,GAEP,MAAM,OAAO,CAAA;AASd,MAAM,WAAW,GAAG,aAAa,CAA0B,IAAI,CAAC,CAAA;AAahE,MAAM,UAAU,YAAY,CAAC,EAC3B,QAAQ,EACR,WAAW,GAAG,QAAQ,EACtB,YAAY,GACM;IAClB,MAAM,CAAC,IAAI,EAAE,YAAY,CAAC,GAAG,QAAQ,CAAO,WAAW,CAAC,CAAA;IACxD,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,CAAA;IAC5B,MAAM,eAAe,GAAG,MAAM,CAAC,YAAY,CAAC,CAAA;IAC5C,eAAe,CAAC,OAAO,GAAG,YAAY,CAAA;IAEtC,MAAM,OAAO,GAAG,WAAW,CAAC,CAAC,CAAO,EAAE,EAAE;QACtC,IAAI,CAAC,KAAK,OAAO,CAAC,OAAO,EAAE,CAAC;YAC1B,OAAO,CAAC,OAAO,GAAG,CAAC,CAAA;YACnB,eAAe,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAA;QAC9B,CAAC;QACD,YAAY,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC,EAAE,EAAE,CAAC,CAAA;IAEN,MAAM,KAAK,GAAG,OAAO,CAAmB,GAAG,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,OAAO,EAAE,CAAC,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC,CAAA;IAEnF,OAAO,KAAC,WAAW,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,YAAG,QAAQ,GAAwB,CAAA;AAC9E,CAAC;AAED,MAAM,UAAU,OAAO;IACrB,MAAM,GAAG,GAAG,UAAU,CAAC,WAAW,CAAC,CAAA;IACnC,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAA;IAC/D,CAAC;IACD,OAAO,GAAG,CAAC,IAAI,CAAA;AACjB,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,MAAM,GAAG,GAAG,UAAU,CAAC,WAAW,CAAC,CAAA;IACnC,IAAI,CAAC,GAAG,EAAE,CAAC;QACT,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAA;IAClE,CAAC;IACD,OAAO,GAAG,CAAC,OAAO,CAAA;AACpB,CAAC"}
@@ -1 +1 @@
1
- {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAc,MAAM,YAAY,CAAA;AA6C1D;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,YAAY,CAiB5E"}
1
+ {"version":3,"file":"parse.d.ts","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAc,MAAM,YAAY,CAAA;AAsD1D;;;;;;;GAOG;AACH,wBAAgB,WAAW,CAAC,MAAM,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,YAAY,CAuB5E"}
package/dist/parse.js CHANGED
@@ -11,6 +11,13 @@ function normalizeKey(key) {
11
11
  const lower = key.toLowerCase();
12
12
  return KEY_ALIASES[lower] ?? lower;
13
13
  }
14
+ const warned = new Set();
15
+ function warnOnce(message) {
16
+ if (warned.has(message))
17
+ return;
18
+ warned.add(message);
19
+ console.warn(message);
20
+ }
14
21
  function parseStep(step) {
15
22
  const parts = step.toLowerCase().split("+");
16
23
  let key = "";
@@ -18,6 +25,7 @@ function parseStep(step) {
18
25
  let meta = false;
19
26
  let shift = false;
20
27
  let option = false;
28
+ let superKey = false;
21
29
  for (const part of parts) {
22
30
  const trimmed = part.trim();
23
31
  if (trimmed === "ctrl" || trimmed === "control") {
@@ -33,13 +41,13 @@ function parseStep(step) {
33
41
  option = true;
34
42
  }
35
43
  else if (trimmed === "super") {
36
- // super modifier — not tracked in ParsedStep currently
44
+ superKey = true;
37
45
  }
38
46
  else {
39
47
  key = normalizeKey(trimmed);
40
48
  }
41
49
  }
42
- return { key, ctrl, meta, shift, option };
50
+ return { key, ctrl, meta, shift, option, super: superKey };
43
51
  }
44
52
  /**
45
53
  * Parse a hotkey string into a ParsedHotkey.
@@ -54,9 +62,13 @@ export function parseHotkey(hotkey, leaderKey) {
54
62
  // Handle leader prefix
55
63
  const leaderMatch = trimmed.match(/^<leader>(.+)$/);
56
64
  if (leaderMatch) {
57
- const leaderStep = leaderKey
58
- ? parseStep(leaderKey)
59
- : { key: "x", ctrl: true, meta: false, shift: false, option: false };
65
+ if (!leaderKey) {
66
+ // No leader configured: the hotkey must not spring to life on some
67
+ // invented default. Zero steps = unmatchable; the dispatcher skips it.
68
+ warnOnce(`[tooee/commands] Hotkey "${trimmed}" uses <leader> but no leader key is configured; the hotkey is disabled.`);
69
+ return { steps: [] };
70
+ }
71
+ const leaderStep = parseStep(leaderKey);
60
72
  const followStep = parseStep(leaderMatch[1]);
61
73
  return { steps: [leaderStep, followStep] };
62
74
  }
package/dist/parse.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"parse.js","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"AAEA,MAAM,WAAW,GAA2B;IAC1C,GAAG,EAAE,QAAQ;IACb,KAAK,EAAE,QAAQ;IACf,EAAE,EAAE,QAAQ;IACZ,GAAG,EAAE,QAAQ;IACb,GAAG,EAAE,KAAK;IACV,SAAS,EAAE,WAAW;IACtB,IAAI,EAAE,GAAG;CACV,CAAA;AAED,SAAS,YAAY,CAAC,GAAW;IAC/B,MAAM,KAAK,GAAG,GAAG,CAAC,WAAW,EAAE,CAAA;IAC/B,OAAO,WAAW,CAAC,KAAK,CAAC,IAAI,KAAK,CAAA;AACpC,CAAC;AAED,SAAS,SAAS,CAAC,IAAY;IAC7B,MAAM,KAAK,GAAG,IAAI,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAA;IAC3C,IAAI,GAAG,GAAG,EAAE,CAAA;IACZ,IAAI,IAAI,GAAG,KAAK,CAAA;IAChB,IAAI,IAAI,GAAG,KAAK,CAAA;IAChB,IAAI,KAAK,GAAG,KAAK,CAAA;IACjB,IAAI,MAAM,GAAG,KAAK,CAAA;IAElB,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAA;QAC3B,IAAI,OAAO,KAAK,MAAM,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;YAChD,IAAI,GAAG,IAAI,CAAA;QACb,CAAC;aAAM,IAAI,OAAO,KAAK,MAAM,IAAI,OAAO,KAAK,KAAK,EAAE,CAAC;YACnD,IAAI,GAAG,IAAI,CAAA;QACb,CAAC;aAAM,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;YAC/B,KAAK,GAAG,IAAI,CAAA;QACd,CAAC;aAAM,IAAI,OAAO,KAAK,QAAQ,EAAE,CAAC;YAChC,MAAM,GAAG,IAAI,CAAA;QACf,CAAC;aAAM,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;YAC/B,uDAAuD;QACzD,CAAC;aAAM,CAAC;YACN,GAAG,GAAG,YAAY,CAAC,OAAO,CAAC,CAAA;QAC7B,CAAC;IACH,CAAC;IAED,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,MAAM,EAAE,CAAA;AAC3C,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CAAC,MAAc,EAAE,SAAkB;IAC5D,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,EAAE,CAAA;IAE7B,uBAAuB;IACvB,MAAM,WAAW,GAAG,OAAO,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAA;IACnD,IAAI,WAAW,EAAE,CAAC;QAChB,MAAM,UAAU,GAAG,SAAS;YAC1B,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC;YACtB,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,CAAA;QACtE,MAAM,UAAU,GAAG,SAAS,CAAC,WAAW,CAAC,CAAC,CAAE,CAAC,CAAA;QAC7C,OAAO,EAAE,KAAK,EAAE,CAAC,UAAU,EAAE,UAAU,CAAC,EAAE,CAAA;IAC5C,CAAC;IAED,6BAA6B;IAC7B,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,KAAK,CAAC,CAAA;IAClC,MAAM,KAAK,GAAG,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;IAClC,OAAO,EAAE,KAAK,EAAE,CAAA;AAClB,CAAC"}
1
+ {"version":3,"file":"parse.js","sourceRoot":"","sources":["../src/parse.ts"],"names":[],"mappings":"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"}
@@ -13,6 +13,23 @@ export interface SequenceFeedResult {
13
13
  matchedIndex: number;
14
14
  pending: SequencePendingMatch | null;
15
15
  }
16
+ /**
17
+ * True when the tail of `buffer` fully matches every step of `hotkey`.
18
+ * Zero-step hotkeys (e.g. a disabled leaderless `<leader>` binding) never
19
+ * match anything.
20
+ */
21
+ export declare function matchesBuffer(buffer: readonly KeyEvent[], hotkey: ParsedHotkey): boolean;
22
+ /**
23
+ * Find the longest buffer tail that is a proper prefix of at least one hotkey.
24
+ * Returns the prefix length and the indexes of the hotkeys it could still
25
+ * complete, or null when nothing is pending.
26
+ */
27
+ export declare function findPendingMatch(buffer: readonly KeyEvent[], hotkeys: readonly ParsedHotkey[]): SequencePendingMatch | null;
28
+ /**
29
+ * Drop buffer entries older than the longest hotkey could ever consume.
30
+ * Returns the same array when nothing needs pruning.
31
+ */
32
+ export declare function pruneBuffer(buffer: readonly KeyEvent[], hotkeys: readonly ParsedHotkey[]): readonly KeyEvent[];
16
33
  export declare class SequenceTracker {
17
34
  private buffer;
18
35
  private timer;
@@ -29,8 +46,6 @@ export declare class SequenceTracker {
29
46
  */
30
47
  feedWithState(event: KeyEvent, hotkeys: ParsedHotkey[]): SequenceFeedResult;
31
48
  getPendingMatch(hotkeys: ParsedHotkey[]): SequencePendingMatch | null;
32
- private matchesBuffer;
33
- private findPendingMatch;
34
49
  reset(): void;
35
50
  private resetTimer;
36
51
  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,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"}
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;AAOD;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,SAAS,QAAQ,EAAE,EAAE,MAAM,EAAE,YAAY,GAAG,OAAO,CAUxF;AAED;;;;GAIG;AACH,wBAAgB,gBAAgB,CAC9B,MAAM,EAAE,SAAS,QAAQ,EAAE,EAC3B,OAAO,EAAE,SAAS,YAAY,EAAE,GAC/B,oBAAoB,GAAG,IAAI,CA6B7B;AAED;;;GAGG;AACH,wBAAgB,WAAW,CACzB,MAAM,EAAE,SAAS,QAAQ,EAAE,EAC3B,OAAO,EAAE,SAAS,YAAY,EAAE,GAC/B,SAAS,QAAQ,EAAE,CAMrB;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;IAiB3E,eAAe,CAAC,OAAO,EAAE,YAAY,EAAE,GAAG,oBAAoB,GAAG,IAAI;IAIrE,KAAK,IAAI,IAAI;IAOb,OAAO,CAAC,UAAU;IAKlB,OAAO,CAAC,UAAU;CAMnB"}
package/dist/sequence.js CHANGED
@@ -1,5 +1,67 @@
1
1
  import { matchStep } from "./match.js";
2
2
  export const DEFAULT_SEQUENCE_TIMEOUT_MS = 1500;
3
+ // --- Pure matching helpers ---------------------------------------------------
4
+ // These are the sequence-matching primitives, extracted so a store (or any
5
+ // non-React dispatcher) can run them against its own buffer without
6
+ // instantiating SequenceTracker. SequenceTracker delegates to them.
7
+ /**
8
+ * True when the tail of `buffer` fully matches every step of `hotkey`.
9
+ * Zero-step hotkeys (e.g. a disabled leaderless `<leader>` binding) never
10
+ * match anything.
11
+ */
12
+ export function matchesBuffer(buffer, hotkey) {
13
+ const { steps } = hotkey;
14
+ if (steps.length === 0)
15
+ return false;
16
+ if (buffer.length < steps.length)
17
+ return false;
18
+ const start = buffer.length - steps.length;
19
+ for (let i = 0; i < steps.length; i++) {
20
+ if (!matchStep(buffer[start + i], steps[i]))
21
+ return false;
22
+ }
23
+ return true;
24
+ }
25
+ /**
26
+ * Find the longest buffer tail that is a proper prefix of at least one hotkey.
27
+ * Returns the prefix length and the indexes of the hotkeys it could still
28
+ * complete, or null when nothing is pending.
29
+ */
30
+ export function findPendingMatch(buffer, hotkeys) {
31
+ const maxPrefixLength = Math.min(buffer.length, Math.max(0, ...hotkeys.map((h) => h.steps.length - 1)));
32
+ for (let prefixLength = maxPrefixLength; prefixLength > 0; prefixLength--) {
33
+ const start = buffer.length - prefixLength;
34
+ const indexes = [];
35
+ for (let hotkeyIndex = 0; hotkeyIndex < hotkeys.length; hotkeyIndex++) {
36
+ const hotkey = hotkeys[hotkeyIndex];
37
+ if (hotkey.steps.length <= prefixLength)
38
+ continue;
39
+ let matches = true;
40
+ for (let i = 0; i < prefixLength; i++) {
41
+ if (!matchStep(buffer[start + i], hotkey.steps[i])) {
42
+ matches = false;
43
+ break;
44
+ }
45
+ }
46
+ if (matches)
47
+ indexes.push(hotkeyIndex);
48
+ }
49
+ if (indexes.length > 0)
50
+ return { prefixLength, indexes };
51
+ }
52
+ return null;
53
+ }
54
+ /**
55
+ * Drop buffer entries older than the longest hotkey could ever consume.
56
+ * Returns the same array when nothing needs pruning.
57
+ */
58
+ export function pruneBuffer(buffer, hotkeys) {
59
+ const maxLen = Math.max(0, ...hotkeys.map((h) => h.steps.length));
60
+ if (maxLen > 0 && buffer.length > maxLen) {
61
+ return buffer.slice(buffer.length - maxLen);
62
+ }
63
+ return buffer;
64
+ }
3
65
  export class SequenceTracker {
4
66
  buffer = [];
5
67
  timer = null;
@@ -23,58 +85,17 @@ export class SequenceTracker {
23
85
  this.buffer.push(event);
24
86
  this.resetTimer();
25
87
  for (let i = 0; i < hotkeys.length; i++) {
26
- const hotkey = hotkeys[i];
27
- if (this.matchesBuffer(hotkey)) {
88
+ if (matchesBuffer(this.buffer, hotkeys[i])) {
28
89
  this.reset();
29
90
  return { matchedIndex: i, pending: null };
30
91
  }
31
92
  }
32
93
  // Prune buffer if no hotkey could possibly match
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
- }
38
- }
39
- return { matchedIndex: -1, pending: this.findPendingMatch(hotkeys) };
94
+ this.buffer = [...pruneBuffer(this.buffer, hotkeys)];
95
+ return { matchedIndex: -1, pending: findPendingMatch(this.buffer, hotkeys) };
40
96
  }
41
97
  getPendingMatch(hotkeys) {
42
- return this.findPendingMatch(hotkeys);
43
- }
44
- matchesBuffer(hotkey) {
45
- const { steps } = hotkey;
46
- if (this.buffer.length < steps.length)
47
- return false;
48
- const start = this.buffer.length - steps.length;
49
- for (let i = 0; i < steps.length; i++) {
50
- if (!matchStep(this.buffer[start + i], steps[i]))
51
- return false;
52
- }
53
- return true;
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;
98
+ return findPendingMatch(this.buffer, hotkeys);
78
99
  }
79
100
  reset() {
80
101
  const hadBuffer = this.buffer.length > 0;
@@ -1 +1 @@
1
- {"version":3,"file":"sequence.js","sourceRoot":"","sources":["../src/sequence.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"sequence.js","sourceRoot":"","sources":["../src/sequence.ts"],"names":[],"mappings":"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"}
package/dist/types.d.ts CHANGED
@@ -8,8 +8,20 @@ export interface CommandContextBase {
8
8
  };
9
9
  exit: () => void;
10
10
  }
11
+ /**
12
+ * The context handed to command handlers. Domain packages contribute typed
13
+ * fields via module augmentation (the mechanism the shell already uses for
14
+ * `overlay` and `toast`):
15
+ *
16
+ * ```ts
17
+ * declare module "@tooee/commands" {
18
+ * interface CommandContext {
19
+ * myDomain: MyDomainContext
20
+ * }
21
+ * }
22
+ * ```
23
+ */
11
24
  export interface CommandContext extends CommandContextBase {
12
- [key: string]: any;
13
25
  }
14
26
  export type CommandHandler = (ctx: CommandContext) => void | Promise<void>;
15
27
  export type CommandWhen = (ctx: CommandContext) => boolean;
@@ -34,12 +46,50 @@ export interface ParsedStep {
34
46
  meta: boolean;
35
47
  shift: boolean;
36
48
  option: boolean;
49
+ /** Super/Windows/Cmd-as-super modifier. Optional for back-compat. */
50
+ super?: boolean;
37
51
  }
38
52
  export interface CommandRegistry {
39
53
  commands: Map<string, Command>;
40
54
  register: (command: Command) => () => void;
41
55
  invoke: (id: string) => void;
42
56
  }
57
+ /**
58
+ * Interaction role of a command surface.
59
+ * - `modal`: owns keyboard input while topmost and suspends every lower surface
60
+ * (including the root app) — even for keys it does not handle.
61
+ * - `passive`: never becomes the keyboard owner; purely visual.
62
+ */
63
+ export type CommandSurfaceRole = "modal" | "passive";
64
+ /**
65
+ * A command surface is an interaction surface that can own keyboard input.
66
+ * The root app is the implicit base surface; modal overlays push surfaces on
67
+ * top of it. Each surface carries its own command registry and local mode so
68
+ * the same command definitions can be rooted in a standalone app or pushed by
69
+ * an overlay without leaking mode/command state into the parent.
70
+ */
71
+ export interface CommandSurfaceEntry {
72
+ id: string;
73
+ role: CommandSurfaceRole;
74
+ /** Nesting depth (root children are depth 0; the first overlay surface is 1). */
75
+ depth: number;
76
+ /** Monotonic registration order, used to break depth ties. */
77
+ order: number;
78
+ registry: CommandRegistry;
79
+ /** Reads this surface's current local mode. */
80
+ getMode: () => Mode;
81
+ /** Builds the command context handed to this surface's command handlers. */
82
+ buildCtx: () => CommandContext;
83
+ }
84
+ export interface ActiveCommandSurface {
85
+ id: string;
86
+ role: CommandSurfaceRole;
87
+ /**
88
+ * Commands registered on this surface (reactive). Enables surface-aware
89
+ * which-key/help/palette consumers.
90
+ */
91
+ commands: readonly Command[];
92
+ }
43
93
  export interface CommandGroup {
44
94
  id: string;
45
95
  title: string;
@@ -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;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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"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"}
@@ -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;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"}
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,CA4CxE"}
@@ -1,11 +1,14 @@
1
1
  import { useEffect, useMemo, useRef } from "react";
2
- import { useCommandRegistry } from "./context.js";
2
+ import { useSurfaceRegistry } from "./context.js";
3
3
  export function useActions(actions) {
4
- const { registry } = useCommandRegistry();
4
+ const registry = useSurfaceRegistry();
5
5
  const actionsRef = useRef(actions);
6
6
  actionsRef.current = actions;
7
7
  const key = useMemo(() => actions
8
- ?.map((a) => `${a.id}:${a.title}:${a.hotkey ?? ""}:${a.category ?? ""}:${a.group ?? ""}:${a.icon ?? ""}:${a.hidden ?? false}`)
8
+ ?.map((a) =>
9
+ // modes and when-presence are frozen into the registration, so
10
+ // they must participate in the re-registration key.
11
+ `${a.id}:${a.title}:${a.hotkey ?? ""}:${a.category ?? ""}:${a.group ?? ""}:${a.icon ?? ""}:${a.hidden ?? false}:${a.modes?.join("|") ?? ""}:${a.when ? 1 : 0}`)
9
12
  .join(",") ?? "", [actions]);
10
13
  useEffect(() => {
11
14
  const current = actionsRef.current;
@@ -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;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"}
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,QAAQ,GAAG,kBAAkB,EAAE,CAAA;IACrC,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;IACJ,+DAA+D;IAC/D,oDAAoD;IACpD,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,IAAI,CAAC,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,CACjK;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"}
@@ -1 +1 @@
1
- {"version":3,"file":"use-command.d.ts","sourceRoot":"","sources":["../src/use-command.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAW,cAAc,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AACtE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAGrC,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,cAAc,CAAA;IACvB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,IAAI,EAAE,CAAA;IACd,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,WAAW,CAAA;IAClB,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,IAAI,CA8B3D"}
1
+ {"version":3,"file":"use-command.d.ts","sourceRoot":"","sources":["../src/use-command.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAW,cAAc,EAAE,WAAW,EAAE,MAAM,YAAY,CAAA;AACtE,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,WAAW,CAAA;AAGrC,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAA;IACV,KAAK,EAAE,MAAM,CAAA;IACb,OAAO,EAAE,cAAc,CAAA;IACvB,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,KAAK,CAAC,EAAE,IAAI,EAAE,CAAA;IACd,QAAQ,CAAC,EAAE,MAAM,CAAA;IACjB,KAAK,CAAC,EAAE,MAAM,CAAA;IACd,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,WAAW,CAAA;IAClB,MAAM,CAAC,EAAE,OAAO,CAAA;CACjB;AAED,wBAAgB,UAAU,CAAC,OAAO,EAAE,iBAAiB,GAAG,IAAI,CAuC3D"}
@@ -1,16 +1,24 @@
1
1
  import { useEffect, useRef } from "react";
2
- import { useCommandRegistry } from "./context.js";
2
+ import { useSurfaceRegistry } from "./context.js";
3
3
  export function useCommand(options) {
4
- const { registry } = useCommandRegistry();
4
+ const registry = useSurfaceRegistry();
5
5
  const optionsRef = useRef(options);
6
6
  optionsRef.current = options;
7
+ // Key on the modes CONTENT, not the array identity: callers pass inline
8
+ // array literals, and with a subscribable registry an identity-keyed effect
9
+ // would re-register on every render — re-notifying the subscriber that
10
+ // caused the render (an infinite update loop for components that both
11
+ // register and observe commands, e.g. the command palette provider).
12
+ const modesKey = options.modes?.join("|") ?? "";
7
13
  useEffect(() => {
8
14
  const command = {
9
15
  id: options.id,
10
16
  title: options.title,
11
17
  handler: (...args) => optionsRef.current.handler(...args),
12
18
  defaultHotkey: options.hotkey,
13
- modes: options.modes,
19
+ // Read through the ref: the effect is keyed on modesKey (content), and
20
+ // the ref holds the same-render options when the effect runs.
21
+ modes: optionsRef.current.modes,
14
22
  category: options.category,
15
23
  group: options.group,
16
24
  icon: options.icon,
@@ -22,7 +30,7 @@ export function useCommand(options) {
22
30
  options.id,
23
31
  options.title,
24
32
  options.hotkey,
25
- options.modes,
33
+ modesKey,
26
34
  options.category,
27
35
  options.group,
28
36
  options.icon,
@@ -1 +1 @@
1
- {"version":3,"file":"use-command.js","sourceRoot":"","sources":["../src/use-command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;AAGzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AAejD,MAAM,UAAU,UAAU,CAAC,OAA0B;IACnD,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,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,OAAO,GAAY;YACvB,EAAE,EAAE,OAAO,CAAC,EAAE;YACd,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,OAAO,EAAE,CAAC,GAAG,IAAoC,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;YACzF,aAAa,EAAE,OAAO,CAAC,MAAM;YAC7B,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,IAAI,EAAE,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,IAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS;YAClF,MAAM,EAAE,OAAO,CAAC,MAAM;SACvB,CAAA;QACD,OAAO,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAA;IACnC,CAAC,EAAE;QACD,OAAO,CAAC,EAAE;QACV,OAAO,CAAC,KAAK;QACb,OAAO,CAAC,MAAM;QACd,OAAO,CAAC,KAAK;QACb,OAAO,CAAC,QAAQ;QAChB,OAAO,CAAC,KAAK;QACb,OAAO,CAAC,IAAI;QACZ,OAAO,CAAC,MAAM;QACd,QAAQ;KACT,CAAC,CAAA;AACJ,CAAC"}
1
+ {"version":3,"file":"use-command.js","sourceRoot":"","sources":["../src/use-command.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,EAAE,MAAM,OAAO,CAAA;AAGzC,OAAO,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAA;AAejD,MAAM,UAAU,UAAU,CAAC,OAA0B;IACnD,MAAM,QAAQ,GAAG,kBAAkB,EAAE,CAAA;IACrC,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,CAAA;IAClC,UAAU,CAAC,OAAO,GAAG,OAAO,CAAA;IAE5B,wEAAwE;IACxE,4EAA4E;IAC5E,uEAAuE;IACvE,sEAAsE;IACtE,qEAAqE;IACrE,MAAM,QAAQ,GAAG,OAAO,CAAC,KAAK,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAA;IAE/C,SAAS,CAAC,GAAG,EAAE;QACb,MAAM,OAAO,GAAY;YACvB,EAAE,EAAE,OAAO,CAAC,EAAE;YACd,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,OAAO,EAAE,CAAC,GAAG,IAAoC,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC;YACzF,aAAa,EAAE,OAAO,CAAC,MAAM;YAC7B,uEAAuE;YACvE,8DAA8D;YAC9D,KAAK,EAAE,UAAU,CAAC,OAAO,CAAC,KAAK;YAC/B,QAAQ,EAAE,OAAO,CAAC,QAAQ;YAC1B,KAAK,EAAE,OAAO,CAAC,KAAK;YACpB,IAAI,EAAE,OAAO,CAAC,IAAI;YAClB,IAAI,EAAE,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,UAAU,CAAC,OAAO,CAAC,IAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS;YAClF,MAAM,EAAE,OAAO,CAAC,MAAM;SACvB,CAAA;QACD,OAAO,QAAQ,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAA;IACnC,CAAC,EAAE;QACD,OAAO,CAAC,EAAE;QACV,OAAO,CAAC,KAAK;QACb,OAAO,CAAC,MAAM;QACd,QAAQ;QACR,OAAO,CAAC,QAAQ;QAChB,OAAO,CAAC,KAAK;QACb,OAAO,CAAC,IAAI;QACZ,OAAO,CAAC,MAAM;QACd,QAAQ;KACT,CAAC,CAAA;AACJ,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tooee/commands",
3
- "version": "0.1.19",
3
+ "version": "0.1.21",
4
4
  "description": "Vim-inspired modal command system for Tooee",
5
5
  "keywords": [
6
6
  "cli",
@@ -35,6 +35,10 @@
35
35
  "scripts": {
36
36
  "typecheck": "tsc --noEmit"
37
37
  },
38
+ "dependencies": {
39
+ "@xstate/store": "^4",
40
+ "@xstate/store-react": "^2"
41
+ },
38
42
  "devDependencies": {
39
43
  "@opentui/core": "^0.2.15",
40
44
  "@opentui/react": "^0.2.15",