3.7 KiB
a11y/keyboard-bindings
(no submodules)
Purpose
Pure-value table mapping keyboard keys to parameter-control actions
(fine-decrement, coarse-increment, page-decrement, min,
max, enter-value). Phase-2 components — knobs, sliders, the
parameter inspector — consume this table directly so the keymap is
declared in exactly one place and easy to audit for accessibility
compliance.
The module is React-free; it exports a frozen array, two factor
constants (KEY_MODIFIER_FACTOR_SHIFT = 10, KEY_MODIFIER_FACTOR_ALT
= 0.1), and a helper matchKeyBinding(event) that resolves a
KeyboardEvent-shaped value into { binding, compositeFactor } or
undefined for a no-match.
Features
PARAMETER_KEY_BINDINGS— frozenReadonlyArray<KeyBinding>.KEY_MODIFIER_FACTOR_SHIFT,KEY_MODIFIER_FACTOR_ALT— composable multipliers.matchKeyBinding(event)— pure function, no DOM imports.- Standard a11y keymap (arrows, page-up/down, home, end, enter).
Usage: Basic
import { matchKeyBinding } from "@suaveplan/react-audio/a11y";
function onKey(event: KeyboardEvent) {
const match = matchKeyBinding(event);
if (match === undefined) return;
console.log(match.binding.action, match.compositeFactor);
}
Usage: Advanced
import {
matchKeyBinding,
PARAMETER_KEY_BINDINGS,
} from "@suaveplan/react-audio/a11y";
function Knob({
value,
min,
max,
step,
onChange,
}: {
value: number;
min: number;
max: number;
step: number;
onChange: (next: number) => void;
}) {
return (
<div
role="slider"
aria-valuemin={min}
aria-valuemax={max}
aria-valuenow={value}
tabIndex={0}
onKeyDown={(event) => {
const match = matchKeyBinding(event);
if (match === undefined) return;
event.preventDefault();
const delta = step * match.compositeFactor;
switch (match.binding.action) {
case "fine-decrement":
case "coarse-decrement":
case "page-decrement":
onChange(Math.max(min, value - delta));
return;
case "fine-increment":
case "coarse-increment":
case "page-increment":
onChange(Math.min(max, value + delta));
return;
case "min":
onChange(min);
return;
case "max":
onChange(max);
return;
default:
return;
}
}}
>
{value}
</div>
);
}
API Reference
KeyBinding—{ key, action, factor, modifiers? }.PARAMETER_KEY_BINDINGS: ReadonlyArray<KeyBinding>.KEY_MODIFIER_FACTOR_SHIFT: 10.KEY_MODIFIER_FACTOR_ALT: 0.1.matchKeyBinding(event): { binding, compositeFactor } | undefined.
Implementation Notes
The keymap conventions (← fine, ↓ coarse, Shift ×10, Alt
×0.1) match the design.md accessibility section so the upstream
behaviour carries forward. The matchKeyBinding helper takes an
event-shaped object rather than a KeyboardEvent so it is callable
from test harnesses with plain object literals — and zero DOM types
are imported into this file. The factor multiplication
order is binding.factor * shift * alt; with both modifiers pressed
the net effect is factor × 10 × 0.1 = factor, which is the
intended "shift cancels alt" semantics.