@opentui/keymap 0.2.1 → 0.2.3

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 (86) hide show
  1. package/README.md +64 -30
  2. package/chunks/index-frk6sdcd.js +409 -0
  3. package/chunks/index-frk6sdcd.js.map +14 -0
  4. package/package.json +43 -23
  5. package/src/addons/index.js +1130 -0
  6. package/src/addons/index.js.map +25 -0
  7. package/src/addons/opentui/edit-buffer-bindings.d.ts +6 -2
  8. package/src/addons/opentui/index.d.ts +2 -2
  9. package/src/addons/opentui/index.js +467 -0
  10. package/src/addons/opentui/index.js.map +12 -0
  11. package/src/addons/universal/binding-overrides.d.ts +6 -0
  12. package/src/addons/universal/dead-bindings.d.ts +1 -1
  13. package/src/addons/universal/default-parser.d.ts +2 -2
  14. package/src/addons/universal/ex-commands.d.ts +11 -8
  15. package/src/addons/universal/index.d.ts +3 -1
  16. package/src/addons/universal/leader.d.ts +1 -1
  17. package/src/addons/universal/metadata.d.ts +2 -2
  18. package/src/addons/universal/mod-bindings.d.ts +6 -0
  19. package/src/addons/universal/unresolved-commands.d.ts +1 -1
  20. package/src/extras/binding-sections.d.ts +18 -0
  21. package/src/extras/command-bindings.d.ts +19 -0
  22. package/src/extras/formatting.d.ts +27 -0
  23. package/src/extras/graph.d.ts +9 -0
  24. package/src/extras/graph.js +373 -0
  25. package/src/extras/graph.js.map +11 -0
  26. package/src/extras/index.d.ts +6 -0
  27. package/src/extras/index.js +239 -0
  28. package/src/extras/index.js.map +12 -0
  29. package/src/extras/lib/graph-snapshot.d.ts +14 -0
  30. package/src/extras/lib/graph-types.d.ts +83 -0
  31. package/src/html.d.ts +3 -3
  32. package/src/html.js +297 -0
  33. package/src/html.js.map +10 -0
  34. package/src/index.d.ts +3 -1
  35. package/src/index.js +4492 -0
  36. package/src/index.js.map +34 -0
  37. package/src/keymap.d.ts +23 -35
  38. package/src/lib/emitter.d.ts +1 -2
  39. package/src/lib/registry.d.ts +2 -2
  40. package/src/lib/runtime-utils.d.ts +34 -0
  41. package/src/opentui.d.ts +1 -3
  42. package/src/opentui.js +133 -0
  43. package/src/opentui.js.map +10 -0
  44. package/src/react/index.d.ts +5 -19
  45. package/{react → src/react}/index.js +3 -0
  46. package/src/react/index.js.map +10 -0
  47. package/src/runtime-modules.d.ts +20 -0
  48. package/src/runtime-modules.js +28 -0
  49. package/src/runtime-modules.js.map +10 -0
  50. package/src/services/activation.d.ts +7 -33
  51. package/src/services/active-key-cache.d.ts +29 -0
  52. package/src/services/command-catalog.d.ts +28 -45
  53. package/src/services/command-executor.d.ts +7 -13
  54. package/src/services/compiler.d.ts +6 -12
  55. package/src/services/conditions.d.ts +4 -16
  56. package/src/services/dispatch-decisions.d.ts +21 -0
  57. package/src/services/dispatch-patterns.d.ts +5 -0
  58. package/src/services/dispatch.d.ts +6 -42
  59. package/src/services/environment.d.ts +6 -21
  60. package/src/services/extension-context.d.ts +16 -0
  61. package/src/services/layer-diagnostics.d.ts +10 -0
  62. package/src/services/layers.d.ts +15 -23
  63. package/src/services/notify.d.ts +6 -8
  64. package/src/services/pending-sequence.d.ts +4 -0
  65. package/src/services/primitives/active-layers.d.ts +2 -3
  66. package/src/services/primitives/bindings.d.ts +4 -0
  67. package/src/services/primitives/command-normalization.d.ts +3 -0
  68. package/src/services/primitives/field-invariants.d.ts +16 -1
  69. package/src/services/primitives/pending-captures.d.ts +5 -0
  70. package/src/services/runtime-view.d.ts +5 -0
  71. package/src/services/runtime.d.ts +2 -7
  72. package/src/services/sequence-index.d.ts +24 -0
  73. package/src/services/state.d.ts +46 -91
  74. package/src/solid/index.d.ts +5 -19
  75. package/{solid → src/solid}/index.js +3 -0
  76. package/src/solid/index.js.map +10 -0
  77. package/src/testing/index.d.ts +90 -0
  78. package/src/testing/index.js +276 -0
  79. package/src/testing/index.js.map +10 -0
  80. package/src/types.d.ts +194 -126
  81. package/addons/index.js +0 -5240
  82. package/addons/opentui/index.js +0 -5632
  83. package/html.js +0 -5042
  84. package/index.js +0 -4411
  85. package/opentui.js +0 -4887
  86. package/src/services/primitives/binding-inputs.d.ts +0 -4
package/src/types.d.ts CHANGED
@@ -10,7 +10,16 @@ export interface KeymapEvent {
10
10
  stopPropagation(): void;
11
11
  readonly propagationStopped: boolean;
12
12
  }
13
+ export type HostPlatform = "macos" | "windows" | "linux" | "unknown";
14
+ export type HostModifier = "ctrl" | "shift" | "meta" | "super" | "hyper";
15
+ export type HostCapability = "supported" | "unsupported" | "unknown";
16
+ export interface HostMetadata {
17
+ platform: HostPlatform;
18
+ primaryModifier: "ctrl" | "super" | "unknown";
19
+ modifiers: Record<HostModifier, HostCapability>;
20
+ }
13
21
  export interface KeymapHost<TTarget extends object, TEvent extends KeymapEvent = KeymapEvent> {
22
+ readonly metadata: HostMetadata;
14
23
  readonly rootTarget: TTarget;
15
24
  readonly isDestroyed: boolean;
16
25
  getFocusedTarget(): TTarget | null;
@@ -88,9 +97,12 @@ export interface KeySequencePart {
88
97
  display: string;
89
98
  match: KeyMatch;
90
99
  tokenName?: string;
100
+ patternName?: string;
101
+ payloadKey?: string;
91
102
  }
92
103
  export interface StringifyOptions {
93
104
  preferDisplay?: boolean;
105
+ separator?: string;
94
106
  }
95
107
  export type KeyStringifyInput = KeyStrokeInput | NormalizedKeyStroke | KeySequencePart | {
96
108
  stroke: NormalizedKeyStroke;
@@ -98,55 +110,65 @@ export type KeyStringifyInput = KeyStrokeInput | NormalizedKeyStroke | KeySequen
98
110
  };
99
111
  export type KeyLike = string | KeyStrokeInput;
100
112
  /**
101
- * Read-only view of a registered command. `fields` is raw registration
102
- * metadata; `attrs` is compiled command-field metadata.
113
+ * Public command shape used for layer registration, command queries, command
114
+ * contexts, and command resolver results. Custom command fields are top-level
115
+ * properties so registration stays as simple as `{ name, run, desc }`.
103
116
  */
104
- export interface CommandRecord {
117
+ export interface Command<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent, TPayload = unknown> {
105
118
  name: string;
106
- fields: Readonly<Record<string, unknown>>;
107
- attrs?: Readonly<Attributes>;
119
+ run(ctx: CommandContext<TTarget, TEvent, TPayload>): CommandResult<TTarget, TEvent>;
120
+ [key: string]: unknown;
108
121
  }
109
- export type CommandQueryValue = unknown | readonly unknown[] | ((value: unknown, command: CommandRecord) => boolean);
110
- export type CommandFilter = Readonly<Record<string, CommandQueryValue>> | ((command: CommandRecord) => boolean);
111
- export interface CommandQuery<TTarget extends object = object> {
122
+ export type CommandQueryValue<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> = unknown | readonly unknown[] | ((value: unknown, command: Command<TTarget, TEvent>) => boolean);
123
+ export type CommandFilter<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> = Readonly<Record<string, CommandQueryValue<TTarget, TEvent>>> | ((command: Command<TTarget, TEvent>) => boolean);
124
+ export interface CommandQuery<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> {
112
125
  visibility?: "reachable" | "active" | "registered";
113
126
  focused?: TTarget | null;
114
127
  namespace?: string | readonly string[];
115
128
  search?: string;
116
129
  searchIn?: readonly string[];
117
- filter?: CommandFilter;
130
+ filter?: CommandFilter<TTarget, TEvent>;
131
+ limit?: number;
132
+ }
133
+ export interface CommandBindingsQuery<TTarget extends object = object> {
134
+ visibility?: "reachable" | "active" | "registered";
135
+ focused?: TTarget | null;
136
+ commands: readonly string[];
118
137
  }
119
138
  export interface RunCommandOptions<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> {
120
139
  event?: TEvent;
121
140
  focused?: TTarget | null;
122
141
  target?: TTarget | null;
123
142
  includeCommand?: boolean;
143
+ payload?: unknown;
124
144
  }
125
- export type RunCommandResult = {
145
+ export type RunCommandResult<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> = {
126
146
  ok: true;
127
- command?: CommandRecord;
147
+ command?: Command<TTarget, TEvent>;
128
148
  } | {
129
149
  ok: false;
130
150
  reason: "not-found";
131
151
  } | {
132
152
  ok: false;
133
153
  reason: "inactive" | "disabled" | "invalid-args" | "rejected" | "error";
134
- command?: CommandRecord;
154
+ command?: Command<TTarget, TEvent>;
135
155
  };
136
- export interface CommandContext<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> {
156
+ export interface CommandContext<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent, TPayload = unknown> {
137
157
  keymap: Keymap<TTarget, TEvent>;
138
158
  event: TEvent;
139
159
  focused: TTarget | null;
140
160
  target: TTarget | null;
141
161
  data: Readonly<EventData>;
142
- command?: CommandRecord;
162
+ command?: Command<TTarget, TEvent, TPayload>;
163
+ input: string;
164
+ payload: TPayload;
143
165
  }
144
- export type CommandResult = boolean | void | Promise<boolean | void>;
166
+ export type CommandResult<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> = boolean | void | RunCommandResult<TTarget, TEvent> | Promise<boolean | void | RunCommandResult<TTarget, TEvent>>;
145
167
  export type CommandResolutionStatus = "resolved" | "unresolved" | "error";
146
- export type CommandHandler<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> = (ctx: CommandContext<TTarget, TEvent>) => CommandResult;
168
+ export type CommandHandler<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent, TPayload = unknown> = (ctx: CommandContext<TTarget, TEvent, TPayload>) => CommandResult<TTarget, TEvent>;
147
169
  export type BindingCommand<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> = string | CommandHandler<TTarget, TEvent>;
148
170
  export type BindingEvent = "press" | "release";
149
- export interface BindingInput<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> {
171
+ export interface Binding<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> {
150
172
  key: KeyLike;
151
173
  cmd?: BindingCommand<TTarget, TEvent>;
152
174
  event?: BindingEvent;
@@ -167,13 +189,13 @@ export interface BindingInput<TTarget extends object = object, TEvent extends Ke
167
189
  fallthrough?: boolean;
168
190
  [key: string]: unknown;
169
191
  }
170
- export type BindingShorthand<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> = Record<string, BindingCommand<TTarget, TEvent>>;
171
- export type Bindings<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> = BindingInput<TTarget, TEvent>[] | BindingShorthand<TTarget, TEvent>;
192
+ export type Bindings<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> = readonly Binding<TTarget, TEvent>[];
172
193
  export type TargetMode = "focus" | "focus-within";
173
- export interface LayerFields<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> {
194
+ export interface Layer<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> {
195
+ target?: TTarget;
174
196
  priority?: number;
175
197
  bindings?: Bindings<TTarget, TEvent>;
176
- commands?: readonly CommandDefinition<TTarget, TEvent>[];
198
+ commands?: readonly Command<TTarget, TEvent, any>[];
177
199
  targetMode?: TargetMode;
178
200
  /**
179
201
  * Extra layer fields feed layer-field compilers and binding compilation via
@@ -182,55 +204,45 @@ export interface LayerFields<TTarget extends object = object, TEvent extends Key
182
204
  */
183
205
  [key: string]: unknown;
184
206
  }
185
- export interface Layer<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> extends LayerFields<TTarget, TEvent> {
186
- target?: TTarget;
187
- }
188
- export interface GlobalLayer<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> extends LayerFields<TTarget, TEvent> {
189
- target?: undefined;
190
- }
191
- export interface FocusWithinLayer<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> extends LayerFields<TTarget, TEvent> {
192
- target: TTarget;
193
- targetMode?: TargetMode;
194
- }
195
- export interface FocusLayer<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> extends LayerFields<TTarget, TEvent> {
196
- target: TTarget;
197
- targetMode?: TargetMode;
198
- }
199
- export type TargetLayer<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> = FocusWithinLayer<TTarget, TEvent> | FocusLayer<TTarget, TEvent>;
200
207
  export interface ParsedCommand {
201
208
  input: string;
202
209
  name: string;
203
210
  args: string[];
204
211
  }
205
- export interface CommandResolverContext {
206
- getCommandAttrs(name: string): Readonly<Attributes> | undefined;
207
- getCommandRecord(name: string): CommandRecord | undefined;
212
+ export interface CommandResolverContext<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> {
213
+ readonly input: string;
214
+ readonly payload: unknown;
215
+ setInput(input: string): void;
216
+ setPayload(payload: unknown): void;
217
+ getCommand(name: string): Command<TTarget, TEvent> | undefined;
208
218
  }
209
- /**
210
- * Resolver output. `run` executes the command, `attrs` / `record` expose
211
- * metadata, and `rejectedResult` overrides the default rejected result.
212
- */
213
- export interface ResolvedBindingCommand<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> {
214
- run: CommandHandler<TTarget, TEvent>;
215
- attrs?: Readonly<Attributes>;
216
- record?: CommandRecord;
217
- rejectedResult?: Extract<RunCommandResult, {
218
- ok: false;
219
- }>;
219
+ export type CommandResolver<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> = (command: string, ctx: CommandResolverContext<TTarget, TEvent>) => Command<TTarget, TEvent> | undefined;
220
+ export interface KeyToken {
221
+ name: string;
222
+ key: KeyLike;
220
223
  }
221
- export type CommandResolver<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> = (command: string, ctx: CommandResolverContext) => ResolvedBindingCommand<TTarget, TEvent> | undefined;
222
- /**
223
- * Layer command registration input. Extra fields stay on `fields` and can be
224
- * compiled into `attrs` by command-field addons.
225
- */
226
- export interface CommandDefinition<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> {
224
+ export interface SequencePatternMatch {
225
+ value?: unknown;
226
+ display?: string;
227
+ }
228
+ export interface SequencePattern<TEvent extends KeymapEvent = KeymapEvent> {
227
229
  name: string;
228
- run: CommandHandler<TTarget, TEvent>;
229
- [key: string]: unknown;
230
+ display?: string;
231
+ payloadKey?: string;
232
+ min?: number;
233
+ max?: number;
234
+ match(event: TEvent): SequencePatternMatch | undefined;
235
+ finalize?(values: readonly unknown[]): unknown;
230
236
  }
231
- export interface KeyToken {
237
+ export interface ResolvedSequencePattern<TEvent extends KeymapEvent = KeymapEvent> {
232
238
  name: string;
233
- key: KeyLike;
239
+ display?: string;
240
+ payloadKey: string;
241
+ match: KeyMatch;
242
+ min: number;
243
+ max: number;
244
+ matcher(event: TEvent): SequencePatternMatch | undefined;
245
+ finalize?: (values: readonly unknown[]) => unknown;
234
246
  }
235
247
  export interface ActiveBinding<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> {
236
248
  sequence: KeySequencePart[];
@@ -241,12 +253,48 @@ export interface ActiveBinding<TTarget extends object = object, TEvent extends K
241
253
  preventDefault: boolean;
242
254
  fallthrough: boolean;
243
255
  }
256
+ export interface DispatchLayer<TTarget extends object = object> {
257
+ order: number;
258
+ priority: number;
259
+ target?: TTarget;
260
+ targetMode?: TargetMode;
261
+ }
262
+ export interface DispatchBinding<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> extends ActiveBinding<TTarget, TEvent> {
263
+ sourceLayerOrder: number;
264
+ bindingIndex: number;
265
+ }
266
+ export type DispatchPhase = "sequence-start" | "sequence-advance" | "sequence-clear" | "binding-execute" | "binding-reject";
267
+ export interface DispatchEvent<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> {
268
+ phase: DispatchPhase;
269
+ event: BindingEvent;
270
+ focused: TTarget | null;
271
+ layer?: DispatchLayer<TTarget>;
272
+ binding?: DispatchBinding<TTarget, TEvent>;
273
+ sequence: readonly KeySequencePart[];
274
+ command?: BindingCommand<TTarget, TEvent>;
275
+ }
276
+ export type KeyAfterReason = "intercept-consumed" | "binding-handled" | "binding-rejected" | "no-match" | "sequence-pending" | "sequence-miss" | "sequence-cleared";
277
+ export interface KeyAfterInputContext<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> {
278
+ event: TEvent;
279
+ eventType: BindingEvent;
280
+ focused: TTarget | null;
281
+ handled: boolean;
282
+ reason: KeyAfterReason;
283
+ sequence: readonly KeySequencePart[];
284
+ pendingSequence: readonly KeySequencePart[];
285
+ setData: (name: string, value: unknown) => void;
286
+ getData: (name: string) => unknown;
287
+ consume: (options?: {
288
+ preventDefault?: boolean;
289
+ stopPropagation?: boolean;
290
+ }) => void;
291
+ }
244
292
  /**
245
293
  * Command metadata together with the bindings that invoke it in a given query
246
294
  * projection.
247
295
  */
248
296
  export interface CommandEntry<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> {
249
- command: CommandRecord;
297
+ command: Command<TTarget, TEvent>;
250
298
  bindings: readonly ActiveBinding<TTarget, TEvent>[];
251
299
  }
252
300
  export interface ActiveKeyOptions {
@@ -276,21 +324,20 @@ export interface BindingFieldContext {
276
324
  require(name: string, value: unknown): void;
277
325
  attr(name: string, value: unknown): void;
278
326
  /**
279
- * Registers a runtime matcher. Raw callbacks re-run on every read;
280
- * reactive matchers stay cached until they notify.
327
+ * Registers a runtime matcher. Matchers are evaluated when the owning
328
+ * record is queried or dispatched; reactive matchers also notify state
329
+ * subscribers when their external source changes.
281
330
  */
282
331
  activeWhen(matcher: (() => boolean) | ReactiveMatcher): void;
283
332
  }
284
333
  export type BindingFieldCompiler = (value: unknown, ctx: BindingFieldContext) => void;
285
334
  export interface LayerFieldContext {
286
335
  require(name: string, value: unknown): void;
336
+ attr(name: string, value: unknown): void;
287
337
  /**
288
- * Layer fields only influence activation and binding compilation. They do
289
- * not expose `attr(...)` because the current model has no layer-level attrs
290
- * surface on `ActiveKey`, `ActiveBinding`, or `CommandRecord`.
291
- *
292
- * Registers a runtime matcher. Raw callbacks re-run on every read;
293
- * reactive matchers stay cached until they notify.
338
+ * Registers a runtime matcher. Matchers are evaluated when the owning
339
+ * record is queried or dispatched; reactive matchers also notify state
340
+ * subscribers when their external source changes.
294
341
  */
295
342
  activeWhen(matcher: (() => boolean) | ReactiveMatcher): void;
296
343
  }
@@ -298,7 +345,7 @@ export type LayerFieldCompiler = (value: unknown, ctx: LayerFieldContext) => voi
298
345
  export interface LayerAnalysisContext<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> {
299
346
  target?: TTarget;
300
347
  order: number;
301
- bindingInputs: readonly BindingInput<TTarget, TEvent>[];
348
+ sourceBindings: readonly Binding<TTarget, TEvent>[];
302
349
  bindings: readonly LayerBindingAnalysis<TTarget, TEvent>[];
303
350
  hasTokenBindings: boolean;
304
351
  checkCommandResolution(command: string): CommandResolutionStatus;
@@ -313,10 +360,10 @@ export interface LayerBindingAnalysis<TTarget extends object = object, TEvent ex
313
360
  event: BindingEvent;
314
361
  preventDefault: boolean;
315
362
  fallthrough: boolean;
316
- sourceBinding: ParsedBindingInput<TTarget, TEvent>;
363
+ parsedBinding: ParsedBinding<TTarget, TEvent>;
317
364
  sourceTarget?: TTarget;
318
365
  sourceLayerOrder: number;
319
- sourceBindingIndex: number;
366
+ bindingIndex: number;
320
367
  hasCommandAtSequence: boolean;
321
368
  hasContinuations: boolean;
322
369
  }
@@ -326,6 +373,7 @@ export interface BindingParserContext {
326
373
  index: number;
327
374
  layer: Readonly<Record<string, unknown>>;
328
375
  tokens: ReadonlyMap<string, ResolvedKeyToken>;
376
+ patterns: ReadonlyMap<string, ResolvedSequencePattern>;
329
377
  normalizeTokenName(token: string): string;
330
378
  createMatch(id: string): KeyMatch;
331
379
  parseObjectKey(key: KeyStrokeInput, options?: {
@@ -336,8 +384,13 @@ export interface BindingParserContext {
336
384
  }
337
385
  export interface BindingExpanderContext {
338
386
  input: string;
387
+ displays?: readonly string[];
339
388
  layer: Readonly<Record<string, unknown>>;
340
389
  }
390
+ export interface BindingExpansion {
391
+ key: string;
392
+ displays?: readonly string[];
393
+ }
341
394
  export interface BindingParserResult {
342
395
  parts: KeySequencePart[];
343
396
  nextIndex: number;
@@ -345,8 +398,8 @@ export interface BindingParserResult {
345
398
  unknownTokens?: readonly string[];
346
399
  }
347
400
  export type BindingParser = (ctx: BindingParserContext) => BindingParserResult | undefined;
348
- export type BindingExpander = (ctx: BindingExpanderContext) => readonly string[] | undefined;
349
- export interface ParsedBindingInput<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> {
401
+ export type BindingExpander = (ctx: BindingExpanderContext) => readonly BindingExpansion[] | undefined;
402
+ export interface ParsedBinding<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> {
350
403
  key: KeyLike;
351
404
  sequence: KeySequencePart[];
352
405
  cmd?: BindingCommand<TTarget, TEvent>;
@@ -358,16 +411,34 @@ export interface ParsedBindingInput<TTarget extends object = object, TEvent exte
358
411
  export interface BindingTransformerContext<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> {
359
412
  layer: Readonly<Record<string, unknown>>;
360
413
  parseKey(key: KeyLike): KeySequencePart;
361
- add(binding: ParsedBindingInput<TTarget, TEvent>): void;
414
+ add(binding: ParsedBinding<TTarget, TEvent>): void;
362
415
  skipOriginal(): void;
363
416
  }
364
- export type BindingTransformer<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> = (binding: ParsedBindingInput<TTarget, TEvent>, ctx: BindingTransformerContext<TTarget, TEvent>) => void;
417
+ export type BindingTransformer<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> = (binding: ParsedBinding<TTarget, TEvent>, ctx: BindingTransformerContext<TTarget, TEvent>) => void;
418
+ export type BindingsValidationResult = {
419
+ ok: true;
420
+ } | {
421
+ ok: false;
422
+ reason: string;
423
+ };
424
+ export interface LayerBindingsTransformerContext<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> {
425
+ layer: Readonly<Layer<TTarget, TEvent>>;
426
+ validateBindings(bindings: unknown): BindingsValidationResult;
427
+ }
428
+ export type LayerBindingsTransformer<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> = (bindings: readonly Binding<TTarget, TEvent>[], ctx: LayerBindingsTransformerContext<TTarget, TEvent>) => readonly Binding<TTarget, TEvent>[] | void;
429
+ export interface CommandTransformerContext<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> {
430
+ layer: Readonly<Layer<TTarget, TEvent>>;
431
+ add(command: Command<TTarget, TEvent>): void;
432
+ skipOriginal(): void;
433
+ }
434
+ export type CommandTransformer<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> = (command: Command<TTarget, TEvent>, ctx: CommandTransformerContext<TTarget, TEvent>) => void;
365
435
  export interface CommandFieldContext {
366
436
  require(name: string, value: unknown): void;
367
437
  attr(name: string, value: unknown): void;
368
438
  /**
369
- * Registers a runtime matcher. Raw callbacks re-run on every read;
370
- * reactive matchers stay cached until they notify.
439
+ * Registers a runtime matcher. Matchers are evaluated when the owning
440
+ * record is queried or dispatched; reactive matchers also notify state
441
+ * subscribers when their external source changes.
371
442
  */
372
443
  activeWhen(matcher: (() => boolean) | ReactiveMatcher): void;
373
444
  }
@@ -396,6 +467,8 @@ export type Hooks<TTarget extends object = object, TEvent extends KeymapEvent =
396
467
  * current sequence.
397
468
  */
398
469
  pendingSequence: readonly KeySequencePart[];
470
+ /** Dispatch trace events for sequence continuation and binding execution. */
471
+ dispatch: DispatchEvent<TTarget, TEvent>;
399
472
  };
400
473
  export type HookName = keyof Hooks;
401
474
  export type Listener<TValue> = [TValue] extends [void] ? () => void : (value: TValue) => void;
@@ -415,8 +488,9 @@ export type Events<TTarget extends object = object, TEvent extends KeymapEvent =
415
488
  error: ErrorEvent;
416
489
  };
417
490
  export type EventName = keyof Events;
418
- export type Intercepts<TEvent extends KeymapEvent = KeymapEvent> = {
491
+ export type Intercepts<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> = {
419
492
  key: KeyInputContext<TEvent>;
493
+ "key:after": KeyAfterInputContext<TTarget, TEvent>;
420
494
  raw: RawInputContext;
421
495
  };
422
496
  export type InterceptName = keyof Intercepts;
@@ -431,11 +505,6 @@ export type { Keymap };
431
505
  export interface RuntimeMatcher {
432
506
  source: string;
433
507
  match: () => boolean;
434
- /**
435
- * False for raw callbacks with no subscription or data dependency, so the
436
- * owner must re-evaluate on every read.
437
- */
438
- cacheable: boolean;
439
508
  /**
440
509
  * Present for reactive matchers; wired during registration and torn down via
441
510
  * `dispose`.
@@ -446,27 +515,22 @@ export interface RuntimeMatcher {
446
515
  export interface RuntimeMatchable {
447
516
  requires: readonly [name: string, value: unknown][];
448
517
  matchers: readonly RuntimeMatcher[];
449
- /** Data keys referenced via `require(...)`; used for `setData` invalidation. */
450
- conditionKeys: readonly string[];
451
- /** True when any matcher is a raw callback and therefore cannot be cached. */
452
- hasUnkeyedMatchers: boolean;
453
- matchCacheDirty?: boolean;
454
- matchCache?: boolean;
455
- }
456
- export interface CompiledBinding<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> extends ActiveBinding<TTarget, TEvent>, RuntimeMatchable {
518
+ }
519
+ export interface BindingState<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> extends ActiveBinding<TTarget, TEvent>, RuntimeMatchable {
520
+ binding: Binding<TTarget, TEvent>;
457
521
  run?: CommandHandler<TTarget, TEvent>;
458
- sourceBinding: ParsedBindingInput<TTarget, TEvent>;
522
+ parsedBinding: ParsedBinding<TTarget, TEvent>;
459
523
  sourceTarget?: TTarget;
460
524
  sourceLayerOrder: number;
461
- sourceBindingIndex: number;
525
+ bindingIndex: number;
462
526
  }
463
527
  export interface ActiveKeySelection<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> {
464
528
  display: string;
465
529
  tokenName?: string;
466
530
  continues: boolean;
467
- firstBinding?: CompiledBinding<TTarget, TEvent>;
468
- commandBinding?: CompiledBinding<TTarget, TEvent>;
469
- bindings?: readonly CompiledBinding<TTarget, TEvent>[];
531
+ firstBinding?: BindingState<TTarget, TEvent>;
532
+ commandBinding?: BindingState<TTarget, TEvent>;
533
+ bindings?: readonly BindingState<TTarget, TEvent>[];
470
534
  stop: boolean;
471
535
  }
472
536
  export interface ActiveKeyState<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> {
@@ -474,20 +538,17 @@ export interface ActiveKeyState<TTarget extends object = object, TEvent extends
474
538
  display: string;
475
539
  tokenName?: string;
476
540
  continues: boolean;
477
- firstBinding?: CompiledBinding<TTarget, TEvent>;
478
- commandBinding?: CompiledBinding<TTarget, TEvent>;
479
- bindings?: CompiledBinding<TTarget, TEvent>[];
480
- }
481
- export interface RegisteredCommand<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> extends CommandRecord, RuntimeMatchable {
482
- run: (ctx: CommandContext<TTarget, TEvent>) => CommandResult;
483
- runner?: CommandHandler<TTarget, TEvent>;
484
- resolved?: ResolvedBindingCommand<TTarget, TEvent>;
485
- resolvedWithRecord?: ResolvedBindingCommand<TTarget, TEvent>;
486
- record?: CommandRecord;
487
- }
488
- export interface CompiledBindingsResult<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> {
489
- root: SequenceNode<TTarget, TEvent>;
490
- bindings: readonly CompiledBinding<TTarget, TEvent>[];
541
+ firstBinding?: BindingState<TTarget, TEvent>;
542
+ commandBinding?: BindingState<TTarget, TEvent>;
543
+ bindings?: BindingState<TTarget, TEvent>[];
544
+ }
545
+ export interface CommandState<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> extends RuntimeMatchable {
546
+ command: Command<TTarget, TEvent, any>;
547
+ fields: Readonly<Record<string, unknown>>;
548
+ attrs?: Readonly<Attributes>;
549
+ }
550
+ export interface BindingCompilationResult<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> {
551
+ bindings: readonly BindingState<TTarget, TEvent>[];
491
552
  hasTokenBindings: boolean;
492
553
  }
493
554
  export interface SequenceNode<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> {
@@ -495,9 +556,11 @@ export interface SequenceNode<TTarget extends object = object, TEvent extends Ke
495
556
  depth: number;
496
557
  stroke: NormalizedKeyStroke | null;
497
558
  match: KeyMatch | null;
559
+ pattern?: ResolvedSequencePattern<TEvent>;
498
560
  children: Map<KeyMatch, SequenceNode<TTarget, TEvent>>;
499
- bindings: CompiledBinding<TTarget, TEvent>[];
500
- reachableBindings: CompiledBinding<TTarget, TEvent>[];
561
+ patternChildren: SequenceNode<TTarget, TEvent>[];
562
+ bindings: BindingState<TTarget, TEvent>[];
563
+ reachableBindings: BindingState<TTarget, TEvent>[];
501
564
  }
502
565
  export interface RegisteredLayer<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> {
503
566
  order: number;
@@ -506,24 +569,29 @@ export interface RegisteredLayer<TTarget extends object = object, TEvent extends
506
569
  priority: number;
507
570
  requires: readonly [name: string, value: unknown][];
508
571
  matchers: readonly RuntimeMatcher[];
509
- conditionKeys: readonly string[];
510
- hasUnkeyedMatchers: boolean;
511
- matchCacheDirty?: boolean;
512
- matchCache?: boolean;
513
- compileFields?: Readonly<Record<string, unknown>>;
514
- commands: readonly RegisteredCommand<TTarget, TEvent>[];
515
- commandLookup?: ReadonlyMap<string, RegisteredCommand<TTarget, TEvent>>;
516
- bindingInputs: readonly BindingInput<TTarget, TEvent>[];
517
- compiledBindings: readonly CompiledBinding<TTarget, TEvent>[];
518
- hasUnkeyedCommands: boolean;
519
- hasUnkeyedBindings: boolean;
520
- hasTokenBindings: boolean;
572
+ fields?: Readonly<Record<string, unknown>>;
573
+ attrs?: Readonly<Attributes>;
574
+ commands: readonly CommandState<TTarget, TEvent>[];
575
+ sourceBindings: readonly Binding<TTarget, TEvent>[];
576
+ bindings: readonly BindingState<TTarget, TEvent>[];
521
577
  root: SequenceNode<TTarget, TEvent>;
578
+ hasTokenBindings: boolean;
579
+ activeKeyCacheBlocked: boolean;
580
+ activeCommandViewCacheBlocked: boolean;
522
581
  offTargetDestroy?: () => void;
523
582
  }
524
583
  export interface PendingSequenceCapture<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> {
525
584
  layer: RegisteredLayer<TTarget, TEvent>;
526
- node: SequenceNode<TTarget, TEvent>;
585
+ binding: BindingState<TTarget, TEvent>;
586
+ index: number;
587
+ parts: readonly KeySequencePart[];
588
+ patterns?: readonly PendingSequencePatternCapture[];
589
+ }
590
+ export interface PendingSequencePatternCapture {
591
+ name: string;
592
+ payloadKey: string;
593
+ values: readonly unknown[];
594
+ parts: readonly KeySequencePart[];
527
595
  }
528
596
  export interface PendingSequenceState<TTarget extends object = object, TEvent extends KeymapEvent = KeymapEvent> {
529
597
  captures: readonly PendingSequenceCapture<TTarget, TEvent>[];