first commit

This commit is contained in:
2026-05-29 08:20:56 +01:00
commit 949299f58d
6368 changed files with 527176 additions and 0 deletions

View File

@@ -0,0 +1,56 @@
# `compound` handler
## Purpose
The `compound` handler is the binding-registry slot responsible for
fanning a single control's value out to multiple leaf bindings — for
example, a knob that simultaneously drives a plugin parameter, a MIDI CC,
and a DMX channel. Unlike the leaf handlers, the compound handler always
has a working default because compounding is a pure structural operation
that doesn't depend on any external integration.
The default iterates `binding.bindings` in registration order and calls
`registry.dispatchLeaf(leaf, value)` for each — every leaf is sent the
same value, so the per-leaf range/scale logic stays in the leaf handlers.
The schema rejects nested compounds at parse time, so the iteration is
guaranteed to bottom out after one step.
## Features
- Default implementation needs no consumer wiring.
- Stable iteration order (registration order) for deterministic test
assertions.
- Takes the owning `BindingRegistry` as a parameter so callers can
customise the fan-out target (e.g. dispatch through a wrapping spy
registry).
## Usage: Basic
```ts
import { BindingRegistry } from "@suaveplan/react-control-surface/runtime/binding-registry";
// No compound override needed; the default fans out automatically.
const registry = new BindingRegistry({ pluginParam: handler });
```
## Usage: Advanced
```ts
import { defaultCompoundHandler } from "@suaveplan/react-control-surface/runtime/binding-registry";
// Manually fan out, perhaps after a custom pre-flight check.
defaultCompoundHandler(compoundBinding, 0.42, registry);
```
## API Reference
- `defaultCompoundHandler(binding: CompoundBinding, value: number, registry: BindingRegistry): void`
— iterates `binding.bindings` and dispatches each leaf through `registry.dispatchLeaf`.
## Implementation Notes
The schema's nested-compound rejection is enforced at parse time, but the
default handler defends in depth by routing through `dispatchLeaf`, which
accepts only the `LeafBinding` union. A nested compound would fail the
TypeScript narrowing at the boundary even if a malicious caller bypassed
the schema validator.