2.6 KiB
2.6 KiB
parameter-keyboard
Internal helper consumed by <PluginParameterKnob> and
<PluginParameterSlider> 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 <PluginSlot> 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). Shiftmultiplier ×10,Altmultiplier ÷10.- Clamping to
[min, max]on every increment, decrement, andHome/Endjump. - Returns the matching
KeyBindingso the caller can detect the specialEnteraction and open a type-edit affordance.
Usage: Basic
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
// Compose with the React keyboard handler in <PluginParameterKnob>:
function onKeyDown(event: React.KeyboardEvent<HTMLDivElement>) {
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) → ParameterKeyboardResultevent—{ key, shiftKey, altKey }; matches the shape ofKeyboardEvent.current— current numeric value.min/max— declared parameter range.
ParameterKeyboardResult—{ handled, next, binding }.
Implementation Notes
- The function iterates
PARAMETER_KEY_BINDINGSin declaration order. Adding new bindings is purely declarative — the helper picks them up for free. Home/Enddeliberately 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.