# `parameter-keyboard` Internal helper consumed by `` and `` to translate a `KeyboardEvent` into a clamped next parameter value. The helper is a pure function — no React, no DOM — so it is fully unit-testable without rendering a tree. ## Purpose The `` accessibility requirement mandates an identical keyboard contract on every parameter control: arrow keys for fine / coarse adjustments, `PageUp`/`PageDown` for ×10 coarse, `Home`/`End` for range endpoints, `Enter` for type-edit, plus `Shift` ×10 and `Alt` ÷10 modifiers. Reimplementing this contract in two component files would double the surface area subject to drift. The shared helper guarantees both primitives interpret the keymap identically. ## Features - 1 % step base ×1, ×10, ×100 binding factors (from `PARAMETER_KEY_BINDINGS`). - `Shift` multiplier ×10, `Alt` multiplier ÷10. - Clamping to `[min, max]` on every increment, decrement, and `Home`/`End` jump. - Returns the matching `KeyBinding` so the caller can detect the special `Enter` action and open a type-edit affordance. ## Usage: Basic ```ts import { resolveParameterKeyboardChange } from "./parameter-keyboard.js"; const result = resolveParameterKeyboardChange( { key: "ArrowRight", shiftKey: false, altKey: false }, 0, -24, 24 ); // result.handled === true; result.next === 0.48 (1 % of 48) ``` ## Usage: Advanced ```ts // Compose with the React keyboard handler in : function onKeyDown(event: React.KeyboardEvent) { const out = resolveParameterKeyboardChange(event, value, min, max); if (!out.handled) return; event.preventDefault(); if (out.binding?.action === "enter-value") { setEditing(true); return; } onChange(out.next); } ``` ## API Reference - `resolveParameterKeyboardChange(event, current, min, max) → ParameterKeyboardResult` - `event` — `{ key, shiftKey, altKey }`; matches the shape of `KeyboardEvent`. - `current` — current numeric value. - `min` / `max` — declared parameter range. - `ParameterKeyboardResult` — `{ handled, next, binding }`. ## Implementation Notes - The function iterates `PARAMETER_KEY_BINDINGS` in declaration order. Adding new bindings is purely declarative — the helper picks them up for free. - `Home`/`End` deliberately ignore the modifier multipliers; they are endpoint jumps, not stepped moves. - The function never throws; an unrecognised key returns `{ handled: false, next: current, binding: undefined }` so the caller can fall through to other listeners.