@opentui/keymap 0.0.0-20260423-618ea9b1 → 0.1.106

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/package.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "main": "index.js",
5
5
  "types": "src/index.d.ts",
6
6
  "type": "module",
7
- "version": "0.0.0-20260423-618ea9b1",
7
+ "version": "0.1.106",
8
8
  "description": "Standalone keymap package for OpenTUI",
9
9
  "license": "MIT",
10
10
  "repository": {
@@ -50,7 +50,7 @@
50
50
  }
51
51
  },
52
52
  "dependencies": {
53
- "@opentui/core": "0.0.0-20260423-618ea9b1"
53
+ "@opentui/core": "0.1.106"
54
54
  },
55
55
  "devDependencies": {
56
56
  "@opentui/react": "workspace:*",
@@ -63,8 +63,8 @@
63
63
  "typescript": "^5"
64
64
  },
65
65
  "peerDependencies": {
66
- "@opentui/react": "0.0.0-20260423-618ea9b1",
67
- "@opentui/solid": "0.0.0-20260423-618ea9b1",
66
+ "@opentui/react": "0.1.106",
67
+ "@opentui/solid": "0.1.106",
68
68
  "react": ">=19.0.0",
69
69
  "solid-js": "1.9.12"
70
70
  },
package/react/index.js CHANGED
@@ -57,46 +57,45 @@ function useBindings(createLayer, deps = []) {
57
57
  const layerRef = useRef(layer);
58
58
  const disposeRef = useRef(undefined);
59
59
  const registeredLayerRef = useRef(undefined);
60
- const registeredScopeRef = useRef(undefined);
60
+ const registeredTargetModeRef = useRef(undefined);
61
61
  const registeredTargetRef = useRef(undefined);
62
62
  layerRef.current = layer;
63
63
  const unregister = useCallback(() => {
64
64
  disposeRef.current?.();
65
65
  disposeRef.current = undefined;
66
66
  registeredLayerRef.current = undefined;
67
- registeredScopeRef.current = undefined;
67
+ registeredTargetModeRef.current = undefined;
68
68
  registeredTargetRef.current = undefined;
69
69
  }, []);
70
70
  useEffect(() => {
71
71
  const currentLayer = layerRef.current;
72
72
  const hasExplicitTarget = currentLayer.targetRef !== undefined;
73
73
  const explicitTarget = resolveBindingsTarget(currentLayer.targetRef);
74
- const resolvedScope = currentLayer.scope ?? (hasExplicitTarget ? "focus-within" : "global");
75
- const nextTarget = resolvedScope === "global" ? undefined : explicitTarget;
76
- if (!hasExplicitTarget && resolvedScope !== "global") {
74
+ const nextTargetMode = currentLayer.targetMode ?? (hasExplicitTarget ? "focus-within" : undefined);
75
+ const nextTarget = nextTargetMode ? explicitTarget : undefined;
76
+ if (!hasExplicitTarget && nextTargetMode) {
77
77
  throw new Error("useBindings local bindings need a targetRef");
78
78
  }
79
- if (registeredLayerRef.current === currentLayer && registeredScopeRef.current === resolvedScope && registeredTargetRef.current === nextTarget) {
79
+ if (registeredLayerRef.current === currentLayer && registeredTargetModeRef.current === nextTargetMode && registeredTargetRef.current === nextTarget) {
80
80
  return;
81
81
  }
82
82
  unregister();
83
- if (!nextTarget && resolvedScope !== "global") {
83
+ if (!nextTarget && nextTargetMode) {
84
84
  registeredLayerRef.current = currentLayer;
85
- registeredScopeRef.current = resolvedScope;
85
+ registeredTargetModeRef.current = nextTargetMode;
86
86
  registeredTargetRef.current = undefined;
87
87
  return;
88
88
  }
89
- const { scope: _scope, targetRef: _targetRef, ...baseLayer } = currentLayer;
90
- disposeRef.current = keymap.registerLayer(resolvedScope === "global" ? {
91
- ...baseLayer,
92
- scope: "global"
89
+ const { targetRef: _targetRef, targetMode: _targetMode, ...baseLayer } = currentLayer;
90
+ disposeRef.current = keymap.registerLayer(!nextTargetMode ? {
91
+ ...baseLayer
93
92
  } : {
94
93
  ...baseLayer,
95
- scope: resolvedScope,
96
- target: nextTarget
94
+ target: nextTarget,
95
+ targetMode: nextTargetMode
97
96
  });
98
97
  registeredLayerRef.current = currentLayer;
99
- registeredScopeRef.current = resolvedScope;
98
+ registeredTargetModeRef.current = nextTargetMode;
100
99
  registeredTargetRef.current = nextTarget;
101
100
  });
102
101
  useEffect(() => {
package/solid/index.js CHANGED
@@ -68,12 +68,11 @@ function useBindings(createLayer) {
68
68
  const layer = createLayer();
69
69
  const hasExplicitTarget = layer.target !== undefined;
70
70
  const explicitTarget = resolveBindingsTarget(layer.target);
71
- const resolvedScope = layer.scope ?? (hasExplicitTarget ? "focus-within" : "global");
72
- const { scope: _scope, target: _target, ...baseLayer } = layer;
73
- if (resolvedScope === "global") {
71
+ const nextTargetMode = layer.targetMode ?? (hasExplicitTarget ? "focus-within" : undefined);
72
+ const { target: _target, targetMode: _targetMode, ...baseLayer } = layer;
73
+ if (!nextTargetMode) {
74
74
  const dispose2 = keymap.registerLayer({
75
- ...baseLayer,
76
- scope: "global"
75
+ ...baseLayer
77
76
  });
78
77
  onCleanup(() => {
79
78
  dispose2();
@@ -88,8 +87,8 @@ function useBindings(createLayer) {
88
87
  }
89
88
  const dispose = keymap.registerLayer({
90
89
  ...baseLayer,
91
- scope: resolvedScope,
92
- target: explicitTarget
90
+ target: explicitTarget,
91
+ targetMode: nextTargetMode
93
92
  });
94
93
  onCleanup(() => {
95
94
  dispose();
@@ -6,8 +6,10 @@ export interface EditBufferCommandOptions {
6
6
  commandNames?: Partial<Record<EditBufferCommandName, string>>;
7
7
  descriptions?: Partial<Record<EditBufferCommandName, string>>;
8
8
  }
9
- export type ManagedTextareaLayer = Omit<Layer<Renderable, KeyEvent>, "bindings"> & {
9
+ export type ManagedTextareaLayer = Omit<Layer<Renderable, KeyEvent>, "bindings" | "target" | "targetMode"> & {
10
10
  bindings?: Bindings<Renderable, KeyEvent>;
11
+ target?: never;
12
+ targetMode?: never;
11
13
  };
12
14
  /**
13
15
  * Returns the default textarea bindings with any overrides prepended so they
@@ -30,7 +32,7 @@ export declare function registerTextareaMappingSuspension(keymap: Keymap<Rendera
30
32
  */
31
33
  export declare function registerEditBufferCommands(keymap: Keymap<Renderable, KeyEvent>, renderer: CliRenderer, options?: EditBufferCommandOptions): () => void;
32
34
  /**
33
- * High-level textarea integration: registers the edit-buffer commands,
35
+ * High-level global textarea integration: registers the edit-buffer commands,
34
36
  * suspends the textarea's built-in key handling while focused, and installs
35
37
  * the layer with default bindings plus overrides. Safe to combine with the
36
38
  * lower-level helpers because they are reference-counted.
@@ -5,12 +5,7 @@ import type { Keymap, KeymapEvent, ReactiveMatcher } from "../../index.js";
5
5
  */
6
6
  export type Enabled = boolean | (() => boolean) | ReactiveMatcher;
7
7
  /**
8
- * Adds an `enabled` layer field for boolean, callback, or reactive matcher
9
- * gating.
8
+ * Adds `enabled` layer and command fields for boolean, callback, or reactive
9
+ * matcher gating.
10
10
  */
11
- export declare function registerEnabledField<TTarget extends object, TEvent extends KeymapEvent>(keymap: Keymap<TTarget, TEvent>): () => void;
12
- /**
13
- * Adds an `enabled` command field for boolean, callback, or reactive matcher
14
- * gating.
15
- */
16
- export declare function registerEnabledCommandField<TTarget extends object, TEvent extends KeymapEvent>(keymap: Keymap<TTarget, TEvent>): () => void;
11
+ export declare function registerEnabledFields<TTarget extends object, TEvent extends KeymapEvent>(keymap: Keymap<TTarget, TEvent>): () => void;
@@ -4,12 +4,12 @@ export { registerBackspacePopsPendingSequence } from "./backspace-pops-pending-s
4
4
  export { registerCommaBindings } from "./comma-bindings.js";
5
5
  export { registerDeadBindingWarnings } from "./dead-bindings.js";
6
6
  export { registerEscapeClearsPendingSequence } from "./escape-clears-pending-sequence.js";
7
- export { registerEnabledField } from "./enabled.js";
8
- export { registerEnabledCommandField } from "./enabled.js";
7
+ export { registerEnabledFields } from "./enabled.js";
9
8
  export { registerEmacsBindings } from "./emacs-bindings.js";
10
9
  export { registerExCommands } from "./ex-commands.js";
11
10
  export { registerLeader } from "./leader.js";
12
11
  export { registerMetadataFields } from "./metadata.js";
12
+ export { registerNeovimDisambiguation } from "./neovim-disambiguation.js";
13
13
  export { registerTimedLeader } from "./timed-leader.js";
14
14
  export { registerUnresolvedCommandWarnings } from "./unresolved-commands.js";
15
15
  export type { Aliases } from "./aliases.js";
@@ -18,4 +18,5 @@ export type { EscapeClearsPendingSequenceOptions } from "./escape-clears-pending
18
18
  export type { Enabled } from "./enabled.js";
19
19
  export type { ExCommand } from "./ex-commands.js";
20
20
  export type { LeaderOptions } from "./leader.js";
21
+ export type { NeovimDisambiguationOptions } from "./neovim-disambiguation.js";
21
22
  export type { TimedLeaderOptions } from "./timed-leader.js";
@@ -2,5 +2,8 @@ import type { Keymap, KeymapEvent } from "../../index.js";
2
2
  /**
3
3
  * Maps `desc`, `group`, `title`, and `category` fields into binding and
4
4
  * command attrs.
5
+ *
6
+ * Layer fields intentionally do not compile into attrs in the current model,
7
+ * so this addon only registers binding and command field compilers.
5
8
  */
6
9
  export declare function registerMetadataFields<TTarget extends object, TEvent extends KeymapEvent>(keymap: Keymap<TTarget, TEvent>): () => void;
@@ -0,0 +1,10 @@
1
+ import type { Keymap, KeymapEvent } from "../../index.js";
2
+ export interface NeovimDisambiguationOptions {
3
+ timeoutMs?: number;
4
+ }
5
+ /**
6
+ * Defers ambiguous exact-vs-prefix bindings and runs the exact binding if no
7
+ * continuation arrives before the timeout, matching Neovim-style timeout-based
8
+ * disambiguation.
9
+ */
10
+ export declare function registerNeovimDisambiguation<TTarget extends object, TEvent extends KeymapEvent>(keymap: Keymap<TTarget, TEvent>, options?: NeovimDisambiguationOptions): () => void;
package/src/index.d.ts CHANGED
@@ -1,3 +1,3 @@
1
1
  export { Keymap } from "./keymap.js";
2
2
  export { stringifyKeySequence, stringifyKeyStroke } from "./services/keys.js";
3
- export type { KeyLike, KeyMatch, ActiveBinding, KeyStringifyInput, StringifyOptions, Attributes, BindingCommand, BindingParser, BindingParserContext, BindingParserResult, BindingExpander, BindingExpanderContext, BindingEvent, BindingFieldCompiler, BindingFieldContext, BindingInput, BindingTransformer, BindingTransformerContext, ParsedBindingInput, BindingShorthand, Bindings, ActiveKey, ActiveKeyOptions, KeymapActiveKey, KeymapBindingInput, KeymapCommandEntry, KeymapCommandDefinition, KeymapCommandRecord, Listener, ErrorEvent, CommandDefinition, CommandEntry, CommandFilter, CommandQuery, CommandQueryValue, CommandRecord, RunCommandOptions, RunCommandResult, CommandHandler, CommandFieldCompiler, CommandFieldContext, CommandContext, CommandResolver, CommandResolverContext, CommandResult, EventData, KeyInputContext, KeymapEvent, KeymapHost, FocusLayer, FocusWithinLayer, GlobalLayer, LayerAnalysisContext, LayerBindingAnalysis, LayerAnalyzer, LayerFieldCompiler, LayerFieldContext, LayerFields, Layer, EventName, Events, InterceptName, Intercepts, KeyInterceptOptions, ParsedCommand, RawInterceptOptions, RawInputContext, ReactiveMatcher, WarningEvent, ResolvedBindingCommand, Scope, EventMatchResolverContext, EventMatchResolver, TargetLayer, KeyToken, ResolvedKeyToken, KeySequencePart, NormalizedKeyStroke, KeyStrokeInput, } from "./types.js";
3
+ export type { KeyLike, KeyMatch, ActiveBinding, KeyStringifyInput, StringifyOptions, Attributes, BindingCommand, BindingParser, BindingParserContext, BindingParserResult, BindingExpander, BindingExpanderContext, BindingEvent, BindingFieldCompiler, BindingFieldContext, BindingInput, BindingTransformer, BindingTransformerContext, ParsedBindingInput, BindingShorthand, Bindings, ActiveKey, ActiveKeyOptions, Listener, ErrorEvent, CommandDefinition, CommandEntry, CommandFilter, CommandQuery, CommandQueryValue, CommandRecord, RunCommandOptions, RunCommandResult, CommandHandler, CommandFieldCompiler, CommandFieldContext, CommandContext, CommandResolver, CommandResolverContext, CommandResult, EventData, KeyInputContext, KeymapEvent, KeymapHost, FocusLayer, FocusWithinLayer, GlobalLayer, LayerAnalysisContext, LayerBindingAnalysis, LayerAnalyzer, LayerFieldCompiler, LayerFieldContext, LayerFields, Layer, EventName, Events, InterceptName, Intercepts, KeyInterceptOptions, ParsedCommand, RawInterceptOptions, RawInputContext, ReactiveMatcher, WarningEvent, ResolvedBindingCommand, TargetMode, EventMatchResolverContext, EventMatchResolver, KeyDisambiguationContext, KeyDisambiguationDecision, KeyDeferredDisambiguationContext, KeyDeferredDisambiguationDecision, KeyDeferredDisambiguationHandler, KeyDisambiguationResolver, TargetLayer, KeyToken, ResolvedKeyToken, KeySequencePart, NormalizedKeyStroke, KeyStrokeInput, } from "./types.js";
package/src/keymap.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import type { ActiveKey, ActiveKeyOptions, BindingInput, BindingExpander, BindingParser, BindingFieldCompiler, Bindings, BindingTransformer, Events, CommandFieldCompiler, CommandEntry, CommandQuery, CommandRecord, KeymapEvent, KeymapHost, LayerAnalyzer, Listener, RunCommandOptions, RunCommandResult, CommandResolver, KeyInterceptOptions, KeyInputContext, Layer, LayerFieldCompiler, RawInterceptOptions, RawInputContext, EventMatchResolver, KeyStringifyInput, KeyToken, KeyLike, KeySequencePart } from "./types.js";
1
+ import type { ActiveKey, ActiveKeyOptions, BindingInput, BindingExpander, BindingParser, BindingFieldCompiler, Bindings, BindingTransformer, Events, CommandFieldCompiler, CommandEntry, CommandQuery, CommandRecord, KeymapEvent, KeymapHost, LayerAnalyzer, Listener, RunCommandOptions, RunCommandResult, CommandResolver, KeyInterceptOptions, KeyInputContext, Layer, LayerFieldCompiler, KeyDisambiguationResolver, RawInterceptOptions, RawInputContext, EventMatchResolver, KeyStringifyInput, KeyToken, KeyLike, KeySequencePart } from "./types.js";
2
2
  export declare class Keymap<TTarget extends object, TEvent extends KeymapEvent = KeymapEvent> {
3
3
  private readonly host;
4
4
  private readonly state;
@@ -37,6 +37,7 @@ export declare class Keymap<TTarget extends object, TEvent extends KeymapEvent =
37
37
  normalizeBindings(bindings: Bindings<TTarget, TEvent>): BindingInput<TTarget, TEvent>[];
38
38
  acquireResource(key: symbol, setup: () => () => void): () => void;
39
39
  runCommand(cmd: string, options?: RunCommandOptions<TTarget, TEvent>): RunCommandResult;
40
+ dispatchCommand(cmd: string, options?: RunCommandOptions<TTarget, TEvent>): RunCommandResult;
40
41
  on(name: "state", fn: Listener<Events<TTarget, TEvent>["state"]>): () => void;
41
42
  on(name: "pendingSequence", fn: Listener<Events<TTarget, TEvent>["pendingSequence"]>): () => void;
42
43
  on(name: "warning", fn: Listener<Events<TTarget, TEvent>["warning"]>): () => void;
@@ -66,6 +67,9 @@ export declare class Keymap<TTarget extends object, TEvent extends KeymapEvent =
66
67
  prependEventMatchResolver(resolver: EventMatchResolver<TEvent>): () => void;
67
68
  appendEventMatchResolver(resolver: EventMatchResolver<TEvent>): () => void;
68
69
  clearEventMatchResolvers(): void;
70
+ prependDisambiguationResolver(resolver: KeyDisambiguationResolver<TTarget, TEvent>): () => void;
71
+ appendDisambiguationResolver(resolver: KeyDisambiguationResolver<TTarget, TEvent>): () => void;
72
+ clearDisambiguationResolvers(): void;
69
73
  private handleFocusedTargetChange;
70
74
  private warnUnknownField;
71
75
  private warnUnknownToken;
@@ -12,19 +12,17 @@ export interface UseBindingsTargetRef<TRenderable extends Renderable = Renderabl
12
12
  }
13
13
  type UseBindingsLayerBase = LayerFields<Renderable, KeyEvent>;
14
14
  export interface UseGlobalBindingsLayer extends UseBindingsLayerBase {
15
- scope?: "global";
16
15
  targetRef?: undefined;
17
16
  }
18
17
  export interface UseFocusBindingsLayer<TRenderable extends Renderable = Renderable> extends UseBindingsLayerBase {
19
- scope: "focus";
18
+ targetMode: "focus";
20
19
  targetRef: UseBindingsTargetRef<TRenderable>;
21
20
  }
22
21
  export interface UseFocusWithinBindingsLayer<TRenderable extends Renderable = Renderable> extends UseBindingsLayerBase {
23
- scope: "focus-within";
22
+ targetMode?: "focus-within";
24
23
  targetRef: UseBindingsTargetRef<TRenderable>;
25
24
  }
26
25
  export interface UseInferredFocusWithinBindingsLayer<TRenderable extends Renderable = Renderable> extends UseBindingsLayerBase {
27
- scope?: undefined;
28
26
  targetRef: UseBindingsTargetRef<TRenderable>;
29
27
  }
30
28
  export type UseTargetBindingsLayer<TRenderable extends Renderable = Renderable> = UseFocusBindingsLayer<TRenderable> | UseFocusWithinBindingsLayer<TRenderable> | UseInferredFocusWithinBindingsLayer<TRenderable>;
@@ -1,9 +1,12 @@
1
1
  import type { Emitter } from "../lib/emitter.js";
2
- import type { ActiveKey, ActiveKeyOptions, Hooks, KeymapEvent, KeymapHost, KeySequencePart, PendingSequenceState, RegisteredLayer, SequenceNode } from "../types.js";
2
+ import type { ActiveBinding, ActiveKey, ActiveKeyOptions, CompiledBinding, Hooks, KeymapEvent, KeymapHost, PendingSequenceCapture, KeySequencePart, PendingSequenceState, RegisteredLayer, SequenceNode } from "../types.js";
3
3
  import type { CommandCatalogService } from "./command-catalog.js";
4
4
  import type { ConditionService } from "./conditions.js";
5
5
  import type { NotificationService } from "./notify.js";
6
- import type { State } from "./state.js";
6
+ import type { ActiveCommandView, State } from "./state.js";
7
+ interface ActivationOptions<TTarget extends object, TEvent extends KeymapEvent> {
8
+ onPendingSequenceChanged?: (previous: PendingSequenceState<TTarget, TEvent> | null, next: PendingSequenceState<TTarget, TEvent> | null) => void;
9
+ }
7
10
  export declare class ActivationService<TTarget extends object, TEvent extends KeymapEvent> {
8
11
  private readonly state;
9
12
  private readonly host;
@@ -11,26 +14,32 @@ export declare class ActivationService<TTarget extends object, TEvent extends Ke
11
14
  private readonly notify;
12
15
  private readonly conditions;
13
16
  private readonly catalog;
14
- constructor(state: State<TTarget, TEvent>, host: KeymapHost<TTarget, TEvent>, hooks: Emitter<Hooks<TTarget, TEvent>>, notify: NotificationService<TTarget, TEvent>, conditions: ConditionService<TTarget, TEvent>, catalog: CommandCatalogService<TTarget, TEvent>);
17
+ private readonly options;
18
+ constructor(state: State<TTarget, TEvent>, host: KeymapHost<TTarget, TEvent>, hooks: Emitter<Hooks<TTarget, TEvent>>, notify: NotificationService<TTarget, TEvent>, conditions: ConditionService<TTarget, TEvent>, catalog: CommandCatalogService<TTarget, TEvent>, options?: ActivationOptions<TTarget, TEvent>);
15
19
  getFocusedTarget(): TTarget | null;
16
20
  getFocusedTargetIfAvailable(): TTarget | null;
17
21
  setPendingSequence(next: PendingSequenceState<TTarget, TEvent> | null): void;
18
22
  ensureValidPendingSequence(): PendingSequenceState<TTarget, TEvent> | undefined;
23
+ revalidatePendingSequenceIfNeeded(): void;
24
+ hasPendingSequenceState(): boolean;
19
25
  getPendingSequence(): readonly KeySequencePart[];
20
26
  popPendingSequence(): boolean;
21
27
  getActiveKeys(options?: ActiveKeyOptions): readonly ActiveKey<TTarget, TEvent>[];
28
+ getActiveKeysForCaptures(captures: readonly PendingSequenceCapture<TTarget, TEvent>[], options?: ActiveKeyOptions): readonly ActiveKey<TTarget, TEvent>[];
22
29
  nodeHasReachableBindings(node: SequenceNode<TTarget, TEvent>, focused: TTarget | null): boolean;
23
30
  getActiveLayers(focused: TTarget | null): RegisteredLayer<TTarget, TEvent>[];
31
+ refreshActiveLayers(focused?: TTarget | null): void;
32
+ invalidateActiveLayers(): void;
24
33
  isLayerActiveForFocused(layer: RegisteredLayer<TTarget, TEvent>, focused: TTarget | null): boolean;
25
34
  layerCanCacheActiveKeys(layer: RegisteredLayer<TTarget, TEvent>): boolean;
26
35
  activeLayersCanCacheActiveKeys(activeLayers: readonly RegisteredLayer<TTarget, TEvent>[]): boolean;
27
36
  private collectNodesFromNode;
28
- private collectSequencePartsFromPending;
29
- private getMatchingBindings;
37
+ collectSequencePartsFromPending(pending: PendingSequenceState<TTarget, TEvent>): KeySequencePart[];
38
+ collectMatchingBindings(bindings: readonly CompiledBinding<TTarget, TEvent>[], focused: TTarget | null, activeView: ActiveCommandView<TTarget, TEvent>): CompiledBinding<TTarget, TEvent>[];
30
39
  private hasMatchingBindings;
31
40
  private getNodePresentation;
32
41
  private toActiveBinding;
33
- private collectActiveBindings;
42
+ collectActiveBindings(bindings: readonly CompiledBinding<TTarget, TEvent>[], focused: TTarget | null, activeView: ActiveCommandView<TTarget, TEvent>): ActiveBinding<TTarget, TEvent>[];
34
43
  private collectActiveKeysAtRoot;
35
44
  private collectActiveKeysFromPending;
36
45
  private selectActiveKey;
@@ -43,3 +52,4 @@ export declare class ActivationService<TTarget extends object, TEvent extends Ke
43
52
  private invalidateCaches;
44
53
  private notifyPendingSequenceChange;
45
54
  }
55
+ export {};
@@ -1,7 +1,7 @@
1
1
  import type { Attributes, BindingCommand, CommandEntry, CommandDefinition, CommandResolutionStatus, CommandQuery, CommandRecord, CommandResolver, CompiledBinding, KeymapEvent, KeymapHost, RegisteredCommand, ResolvedBindingCommand } from "../types.js";
2
2
  import type { ConditionService } from "./conditions.js";
3
3
  import type { NotificationService } from "./notify.js";
4
- import type { ActiveCommandView, ResolvedCommandEntry, State } from "./state.js";
4
+ import type { ActiveCommandView, RegisteredCommandView, ResolvedCommandEntry, State } from "./state.js";
5
5
  interface CommandCatalogOptions {
6
6
  onCommandResolversChanged(): void;
7
7
  }
@@ -24,14 +24,26 @@ export declare class CommandCatalogService<TTarget extends object, TEvent extend
24
24
  entries?: readonly ResolvedCommandEntry<TTarget, TEvent>[];
25
25
  hadError: boolean;
26
26
  };
27
+ getRegisteredResolvedEntries(command: string, includeRecord: boolean): readonly ResolvedCommandEntry<TTarget, TEvent>[] | undefined;
28
+ getRegisteredResolverFallback(command: string, includeRecord: boolean): {
29
+ resolved?: ResolvedBindingCommand<TTarget, TEvent>;
30
+ hadError: boolean;
31
+ };
27
32
  getCommandAttrs(command: string, focused: TTarget | null): Readonly<Attributes> | undefined;
28
33
  getTopCommandRecord(command: string, focused: TTarget | null): CommandRecord | undefined;
34
+ getTopRegisteredCommandRecord(command: string): CommandRecord | undefined;
35
+ getDispatchUnavailableCommandState(command: string, focused: TTarget | null, includeRecord: boolean): {
36
+ reason: "inactive" | "disabled";
37
+ command?: CommandRecord;
38
+ } | undefined;
29
39
  getActiveCommandView(focused: TTarget | null): ActiveCommandView<TTarget, TEvent>;
40
+ getRegisteredCommandView(): RegisteredCommandView<TTarget, TEvent>;
30
41
  isBindingVisible(binding: CompiledBinding<TTarget, TEvent>, focused: TTarget | null, activeView: ActiveCommandView<TTarget, TEvent>): boolean;
31
42
  getBindingCommandAttrs(binding: CompiledBinding<TTarget, TEvent>, focused: TTarget | null, activeView: ActiveCommandView<TTarget, TEvent>): Readonly<Attributes> | undefined;
32
43
  getCommandResolutionStatus(command: string, layerCommands?: ReadonlyMap<string, RegisteredCommand<TTarget, TEvent>>): CommandResolutionStatus;
33
44
  private mutateCommandResolvers;
34
45
  private getTopResolvedCommand;
46
+ private getTopRegisteredCommand;
35
47
  private getFallbackResolvedCommand;
36
48
  private getResolvedCommandChainFromView;
37
49
  private getRegisteredLayerCommandEntries;
@@ -16,6 +16,7 @@ export declare class CommandExecutorService<TTarget extends object, TEvent exten
16
16
  private readonly options;
17
17
  constructor(notify: NotificationService<TTarget, TEvent>, runtime: RuntimeService<TTarget, TEvent>, activation: ActivationService<TTarget, TEvent>, catalog: CommandCatalogService<TTarget, TEvent>, options: CommandExecutorOptions<TTarget, TEvent>);
18
18
  runCommand(cmd: string, options?: RunCommandOptions<TTarget, TEvent>): RunCommandResult;
19
+ dispatchCommand(cmd: string, options?: RunCommandOptions<TTarget, TEvent>): RunCommandResult;
19
20
  runBinding(bindingLayer: RegisteredLayer<TTarget, TEvent>, binding: CompiledBinding<TTarget, TEvent>, event: TEvent, focused: TTarget | null): boolean;
20
21
  private executeResolvedCommand;
21
22
  }
@@ -1,7 +1,7 @@
1
1
  import type { ConditionService } from "./conditions.js";
2
2
  import type { State } from "./state.js";
3
3
  import type { NotificationService } from "./notify.js";
4
- import type { BindingInput, Scope, CompiledBindingsResult, KeyLike, KeymapEvent, KeySequencePart, ResolvedKeyToken } from "../types.js";
4
+ import type { BindingInput, CompiledBindingsResult, KeyLike, KeymapEvent, KeySequencePart, ResolvedKeyToken } from "../types.js";
5
5
  export interface CompilerOptions {
6
6
  warnUnknownField: (kind: "binding" | "layer", fieldName: string) => void;
7
7
  warnUnknownToken: (token: string, sequence: string) => void;
@@ -13,7 +13,7 @@ export declare class CompilerService<TTarget extends object, TEvent extends Keym
13
13
  private readonly options;
14
14
  constructor(state: State<TTarget, TEvent>, notify: NotificationService<TTarget, TEvent>, conditions: ConditionService<TTarget, TEvent>, options: CompilerOptions);
15
15
  parseTokenKey(key: KeyLike): KeySequencePart;
16
- compileBindings(bindings: readonly BindingInput<TTarget, TEvent>[], tokens: ReadonlyMap<string, ResolvedKeyToken>, sourceScope: Scope, sourceTarget: TTarget | undefined, sourceLayerOrder: number, compileFields?: Readonly<Record<string, unknown>>): CompiledBindingsResult<TTarget, TEvent>;
16
+ compileBindings(bindings: readonly BindingInput<TTarget, TEvent>[], tokens: ReadonlyMap<string, ResolvedKeyToken>, sourceTarget: TTarget | undefined, sourceLayerOrder: number, compileFields?: Readonly<Record<string, unknown>>): CompiledBindingsResult<TTarget, TEvent>;
17
17
  private parseObjectKeyPart;
18
18
  private normalizeBindingEvent;
19
19
  private applyBindingTransformers;
@@ -7,8 +7,8 @@ export declare class ConditionService<TTarget extends object, TEvent extends Key
7
7
  constructor(state: State<TTarget, TEvent>, notify: NotificationService<TTarget, TEvent>);
8
8
  buildRuntimeMatcher(matcher: (() => boolean) | ReactiveMatcher, source: string): RuntimeMatcher;
9
9
  hasNoConditions(target: RuntimeMatchable): boolean;
10
- registerRuntimeMatchable(target: RuntimeMatchable): void;
11
- unregisterRuntimeMatchable(target: RuntimeMatchable): void;
10
+ indexRuntimeMatchable(target: RuntimeMatchable): void;
11
+ unindexRuntimeMatchable(target: RuntimeMatchable): void;
12
12
  invalidateRuntimeConditionKey(name: string): void;
13
13
  matchesConditions(target: RuntimeMatchable): boolean;
14
14
  layerMatchesRuntimeState(layer: RegisteredLayer<TTarget, TEvent>): boolean;
@@ -1,11 +1,13 @@
1
1
  import type { CompilerService } from "./compiler.js";
2
2
  import type { ActivationService } from "./activation.js";
3
3
  import type { CommandExecutorService } from "./command-executor.js";
4
+ import type { CommandCatalogService } from "./command-catalog.js";
4
5
  import type { ConditionService } from "./conditions.js";
6
+ import type { LayerService } from "./layers.js";
5
7
  import type { NotificationService } from "./notify.js";
6
8
  import type { RuntimeService } from "./runtime.js";
7
9
  import type { State } from "./state.js";
8
- import type { EventMatchResolver, KeyInterceptOptions, KeyInputContext, KeymapEvent, RawInterceptOptions, RawInputContext } from "../types.js";
10
+ import { type EventMatchResolver, type KeyDisambiguationResolver, type KeyInterceptOptions, type KeyInputContext, type KeymapEvent, type PendingSequenceState, type RawInterceptOptions, type RawInputContext } from "../types.js";
9
11
  export declare class DispatchService<TTarget extends object, TEvent extends KeymapEvent> {
10
12
  private readonly state;
11
13
  private readonly notify;
@@ -14,20 +16,45 @@ export declare class DispatchService<TTarget extends object, TEvent extends Keym
14
16
  private readonly conditions;
15
17
  private readonly executor;
16
18
  private readonly compiler;
19
+ private readonly catalog;
20
+ private readonly layers;
17
21
  private readonly eventMatchResolverContext;
18
- constructor(state: State<TTarget, TEvent>, notify: NotificationService<TTarget, TEvent>, runtime: RuntimeService<TTarget, TEvent>, activation: ActivationService<TTarget, TEvent>, conditions: ConditionService<TTarget, TEvent>, executor: CommandExecutorService<TTarget, TEvent>, compiler: CompilerService<TTarget, TEvent>);
22
+ private pendingDisambiguation;
23
+ private nextPendingDisambiguationId;
24
+ constructor(state: State<TTarget, TEvent>, notify: NotificationService<TTarget, TEvent>, runtime: RuntimeService<TTarget, TEvent>, activation: ActivationService<TTarget, TEvent>, conditions: ConditionService<TTarget, TEvent>, executor: CommandExecutorService<TTarget, TEvent>, compiler: CompilerService<TTarget, TEvent>, catalog: CommandCatalogService<TTarget, TEvent>, layers: LayerService<TTarget, TEvent>);
19
25
  intercept(name: "key", fn: (ctx: KeyInputContext<TEvent>) => void, options?: KeyInterceptOptions): () => void;
20
26
  intercept(name: "raw", fn: (ctx: RawInputContext) => void, options?: RawInterceptOptions): () => void;
21
27
  prependEventMatchResolver(resolver: EventMatchResolver<TEvent>): () => void;
22
28
  appendEventMatchResolver(resolver: EventMatchResolver<TEvent>): () => void;
23
29
  clearEventMatchResolvers(): void;
30
+ prependDisambiguationResolver(resolver: KeyDisambiguationResolver<TTarget, TEvent>): () => void;
31
+ appendDisambiguationResolver(resolver: KeyDisambiguationResolver<TTarget, TEvent>): () => void;
32
+ clearDisambiguationResolvers(): void;
33
+ handlePendingSequenceChange(_previous: PendingSequenceState<TTarget, TEvent> | null, _next: PendingSequenceState<TTarget, TEvent> | null): void;
24
34
  handleRawSequence(sequence: string): boolean;
25
35
  handleKeyEvent(event: TEvent, release: boolean): void;
36
+ private mutateDisambiguationResolvers;
26
37
  private dispatchReleaseLayers;
27
38
  private dispatchLayers;
28
39
  private dispatchPendingSequence;
40
+ private dispatchPendingCapturesFromIndex;
29
41
  private dispatchFromRoot;
42
+ private dispatchFromRootAtIndex;
43
+ private tryResolveRootAmbiguity;
44
+ private tryResolvePendingAmbiguity;
45
+ private tryResolveAmbiguity;
46
+ private applySyncDecision;
47
+ private resolveDisambiguation;
48
+ private scheduleDeferredDisambiguation;
49
+ private executeDeferredDisambiguation;
50
+ private applyDeferredDisambiguationResult;
51
+ private finishPendingDisambiguation;
52
+ private cancelPendingDisambiguation;
53
+ private isPendingDisambiguationCurrent;
54
+ private sleepWithSignal;
55
+ private warnUnresolvedAmbiguity;
30
56
  private collectPendingCapturesFromRoot;
57
+ private collectPendingCapturesFromAdvanced;
31
58
  private resolveEventMatchKeys;
32
59
  private runReleaseBindings;
33
60
  private getReachableChild;
@@ -20,15 +20,22 @@ export declare class LayerService<TTarget extends object, TEvent extends KeymapE
20
20
  constructor(state: State<TTarget, TEvent>, notify: NotificationService<TTarget, TEvent>, conditions: ConditionService<TTarget, TEvent>, activation: ActivationService<TTarget, TEvent>, options: LayersOptions<TTarget, TEvent>);
21
21
  registerLayer(layer: Layer<TTarget, TEvent>): () => void;
22
22
  applyTokenState(nextTokens: Map<string, ResolvedKeyToken>): void;
23
+ recompileBindings(): void;
23
24
  prependLayerAnalyzer(analyzer: LayerAnalyzer<TTarget, TEvent>): () => void;
24
25
  appendLayerAnalyzer(analyzer: LayerAnalyzer<TTarget, TEvent>): () => void;
25
26
  clearLayerAnalyzers(): void;
26
- private normalizeScope;
27
+ cleanup(): void;
28
+ private normalizeTargetMode;
27
29
  private runLayerAnalyzers;
28
30
  private compileLayerRuntimeState;
29
- private getOrCreateTargetBucket;
31
+ private compileLayerBindings;
32
+ private applyCompiledBindings;
30
33
  private indexLayer;
31
34
  private removeLayerFromIndex;
32
35
  private unregisterLayer;
36
+ private connectRuntimeMatchable;
37
+ private disconnectRuntimeMatchable;
38
+ private attachReactiveMatchers;
39
+ private detachReactiveMatchers;
33
40
  }
34
41
  export {};
@@ -2,6 +2,7 @@ import type { Events, HookName, Hooks, KeymapEvent } from "../types.js";
2
2
  import type { State } from "./state.js";
3
3
  import { Emitter } from "../lib/emitter.js";
4
4
  type DiagnosticEvents<TTarget extends object, TEvent extends KeymapEvent> = Pick<Events<TTarget, TEvent>, "warning" | "error">;
5
+ export declare const MAX_STATE_CHANGE_FLUSH_ITERATIONS = 1000;
5
6
  export declare class NotificationService<TTarget extends object, TEvent extends KeymapEvent> {
6
7
  private readonly state;
7
8
  private readonly events;
@@ -1,5 +1,8 @@
1
- import type { KeymapEvent, KeymapHost, RegisteredLayer, RegisteredLayerBucket } from "../../types.js";
1
+ import type { KeymapEvent, KeymapHost, RegisteredLayer } from "../../types.js";
2
+ import type { LayersState } from "../state.js";
2
3
  export declare function getFocusedTargetIfAvailable<TTarget extends object, TEvent extends KeymapEvent>(host: KeymapHost<TTarget, TEvent>): TTarget | null;
3
4
  export declare function forEachActivationTarget<TTarget extends object, TEvent extends KeymapEvent>(host: KeymapHost<TTarget, TEvent>, focused: TTarget | null, visit: (target: TTarget, isFocusedTarget: boolean) => boolean | void): void;
4
- export declare function getActiveLayersForFocused<TTarget extends object, TEvent extends KeymapEvent>(targetLayers: WeakMap<TTarget, RegisteredLayerBucket<TTarget, TEvent>>, host: KeymapHost<TTarget, TEvent>, focused: TTarget | null): RegisteredLayer<TTarget, TEvent>[];
5
- export declare function isLayerActiveForFocused<TTarget extends object, TEvent extends KeymapEvent>(host: KeymapHost<TTarget, TEvent>, layer: RegisteredLayer<TTarget, TEvent>, focused: TTarget | null): boolean;
5
+ export declare function getActivationPath<TTarget extends object, TEvent extends KeymapEvent>(host: KeymapHost<TTarget, TEvent>, focused: TTarget | null): Set<TTarget>;
6
+ export declare function getActiveLayersForFocused<TTarget extends object, TEvent extends KeymapEvent>(state: LayersState<TTarget, TEvent>, host: KeymapHost<TTarget, TEvent>, focused: TTarget | null): readonly RegisteredLayer<TTarget, TEvent>[];
7
+ export declare function invalidateCachedActiveLayers<TTarget extends object, TEvent extends KeymapEvent>(state: LayersState<TTarget, TEvent>): void;
8
+ export declare function isLayerActiveForFocused<TTarget extends object, TEvent extends KeymapEvent>(host: KeymapHost<TTarget, TEvent>, layer: RegisteredLayer<TTarget, TEvent>, focused: TTarget | null, activationPath?: ReadonlySet<TTarget>): boolean;
@@ -1,4 +1,4 @@
1
- import type { ActiveKey, BindingExpander, BindingFieldCompiler, BindingParser, BindingTransformer, CommandFieldCompiler, CommandResolver, EventData, EventMatchResolver, KeyInputContext, KeySequencePart, KeymapEvent, LayerAnalyzer, LayerFieldCompiler, PendingSequenceState, RawInputContext, RegisteredCommand, RegisteredLayer, RegisteredLayerBucket, ResolvedBindingCommand, RuntimeMatchable } from "../types.js";
1
+ import type { ActiveKey, BindingExpander, BindingFieldCompiler, BindingParser, BindingTransformer, CommandFieldCompiler, CommandResolver, EventData, KeyDisambiguationResolver, EventMatchResolver, KeyInputContext, KeySequencePart, KeymapEvent, LayerAnalyzer, LayerFieldCompiler, PendingSequenceState, RawInputContext, RegisteredCommand, RegisteredLayer, ResolvedBindingCommand, RuntimeMatchable } from "../types.js";
2
2
  import { OrderedRegistry, PriorityRegistry } from "../lib/registry.js";
3
3
  export interface CoreState {
4
4
  order: number;
@@ -12,8 +12,9 @@ export interface EnvironmentState<TTarget extends object, TEvent extends KeymapE
12
12
  bindingFields: Map<string, BindingFieldCompiler>;
13
13
  commandFields: Map<string, CommandFieldCompiler>;
14
14
  }
15
- export interface DispatchState<TEvent extends KeymapEvent> {
15
+ export interface DispatchState<TTarget extends object, TEvent extends KeymapEvent> {
16
16
  eventMatchResolvers: OrderedRegistry<EventMatchResolver<TEvent>>;
17
+ disambiguationResolvers: OrderedRegistry<KeyDisambiguationResolver<TTarget, TEvent>>;
17
18
  keyHooks: PriorityRegistry<(ctx: KeyInputContext<TEvent>) => void, {
18
19
  priority: number;
19
20
  release: boolean;
@@ -24,7 +25,11 @@ export interface DispatchState<TEvent extends KeymapEvent> {
24
25
  }
25
26
  export interface LayersState<TTarget extends object, TEvent extends KeymapEvent> {
26
27
  layers: Set<RegisteredLayer<TTarget, TEvent>>;
27
- targetLayers: WeakMap<TTarget, RegisteredLayerBucket<TTarget, TEvent>>;
28
+ sortedLayers: RegisteredLayer<TTarget, TEvent>[];
29
+ activeLayersVersion: number;
30
+ activeLayersCacheVersion: number;
31
+ activeLayersCacheFocused: TTarget | null | undefined;
32
+ activeLayersCache: readonly RegisteredLayer<TTarget, TEvent>[];
28
33
  layersWithConditions: number;
29
34
  layersWithCommands: number;
30
35
  layerAnalyzers: OrderedRegistry<LayerAnalyzer<TTarget, TEvent>>;
@@ -37,12 +42,7 @@ export interface ResolvedCommandEntry<TTarget extends object, TEvent extends Key
37
42
  target?: TTarget;
38
43
  resolved: ResolvedBindingCommand<TTarget, TEvent>;
39
44
  }
40
- export interface ActiveCommandView<TTarget extends object, TEvent extends KeymapEvent> {
41
- cacheable: boolean;
42
- entries: readonly LayerCommandEntry<TTarget, TEvent>[];
43
- reachable: readonly LayerCommandEntry<TTarget, TEvent>[];
44
- reachableByName: ReadonlyMap<string, LayerCommandEntry<TTarget, TEvent>>;
45
- chainsByName: ReadonlyMap<string, readonly LayerCommandEntry<TTarget, TEvent>[]>;
45
+ export interface CommandChainCacheState<TTarget extends object, TEvent extends KeymapEvent> {
46
46
  resolvedWithoutRecordChains: Map<string, readonly ResolvedCommandEntry<TTarget, TEvent>[]>;
47
47
  resolvedWithRecordChains: Map<string, readonly ResolvedCommandEntry<TTarget, TEvent>[]>;
48
48
  fallbackWithoutRecord: Map<string, ResolvedBindingCommand<TTarget, TEvent> | null>;
@@ -50,12 +50,25 @@ export interface ActiveCommandView<TTarget extends object, TEvent extends Keymap
50
50
  fallbackWithoutRecordErrors: Set<string>;
51
51
  fallbackWithRecordErrors: Set<string>;
52
52
  }
53
+ export interface ActiveCommandView<TTarget extends object, TEvent extends KeymapEvent> extends CommandChainCacheState<TTarget, TEvent> {
54
+ cacheable: boolean;
55
+ entries: readonly LayerCommandEntry<TTarget, TEvent>[];
56
+ reachable: readonly LayerCommandEntry<TTarget, TEvent>[];
57
+ reachableByName: ReadonlyMap<string, LayerCommandEntry<TTarget, TEvent>>;
58
+ chainsByName: ReadonlyMap<string, readonly LayerCommandEntry<TTarget, TEvent>[]>;
59
+ }
60
+ export interface RegisteredCommandView<TTarget extends object, TEvent extends KeymapEvent> extends CommandChainCacheState<TTarget, TEvent> {
61
+ entries: readonly LayerCommandEntry<TTarget, TEvent>[];
62
+ chainsByName: ReadonlyMap<string, readonly LayerCommandEntry<TTarget, TEvent>[]>;
63
+ }
53
64
  export interface CommandsState<TTarget extends object, TEvent extends KeymapEvent> {
54
65
  commandMetadataVersion: number;
55
66
  registeredNames: Map<string, number>;
56
67
  commandResolvers: OrderedRegistry<CommandResolver<TTarget, TEvent>>;
57
68
  activeCommandViewVersion: number;
58
69
  activeCommandView?: ActiveCommandView<TTarget, TEvent>;
70
+ registeredCommandViewVersion: number;
71
+ registeredCommandView?: RegisteredCommandView<TTarget, TEvent>;
59
72
  registeredCommandEntriesCacheVersion: number;
60
73
  registeredCommandEntriesCache: readonly LayerCommandEntry<TTarget, TEvent>[];
61
74
  }
@@ -91,7 +104,7 @@ export interface NotifyState {
91
104
  export interface State<TTarget extends object, TEvent extends KeymapEvent> {
92
105
  core: CoreState;
93
106
  environment: EnvironmentState<TTarget, TEvent>;
94
- dispatch: DispatchState<TEvent>;
107
+ dispatch: DispatchState<TTarget, TEvent>;
95
108
  layers: LayersState<TTarget, TEvent>;
96
109
  commands: CommandsState<TTarget, TEvent>;
97
110
  projection: ProjectionState<TTarget, TEvent>;
@@ -10,19 +10,17 @@ export declare function KeymapProvider(props: KeymapProviderProps): JSX.Element;
10
10
  export type UseBindingsTarget<TRenderable extends Renderable = Renderable> = () => TRenderable | null | undefined;
11
11
  type UseBindingsLayerBase = LayerFields<Renderable, KeyEvent>;
12
12
  export interface UseGlobalBindingsLayer extends UseBindingsLayerBase {
13
- scope?: "global";
14
13
  target?: undefined;
15
14
  }
16
15
  export interface UseFocusBindingsLayer<TRenderable extends Renderable = Renderable> extends UseBindingsLayerBase {
17
- scope: "focus";
16
+ targetMode: "focus";
18
17
  target: UseBindingsTarget<TRenderable>;
19
18
  }
20
19
  export interface UseFocusWithinBindingsLayer<TRenderable extends Renderable = Renderable> extends UseBindingsLayerBase {
21
- scope: "focus-within";
20
+ targetMode?: "focus-within";
22
21
  target: UseBindingsTarget<TRenderable>;
23
22
  }
24
23
  export interface UseInferredFocusWithinBindingsLayer<TRenderable extends Renderable = Renderable> extends UseBindingsLayerBase {
25
- scope?: undefined;
26
24
  target: UseBindingsTarget<TRenderable>;
27
25
  }
28
26
  export type UseTargetBindingsLayer<TRenderable extends Renderable = Renderable> = UseFocusBindingsLayer<TRenderable> | UseFocusWithinBindingsLayer<TRenderable> | UseInferredFocusWithinBindingsLayer<TRenderable>;