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,63 @@
# stream-mixer
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
`<StreamMixer>` renders one strip per remote peer, each with a volume range slider, a
mute toggle, a solo toggle, and a read-only FX-slot-count indicator. The component is
the visible counterpart to `useStreamMixer()` — both surfaces are required by
Requirement 6 ("Per-peer stream mixer") and the component's solo button proves the
DAW-semantics test case from the spec.
Markup is intentionally minimal and unstyled — every interactive control carries an
`aria-label` derived from the peer id so screen readers announce the right peer, and
the toggles use `aria-pressed` for accessibility. Consumers who want richer chrome pass
a `renderStrip` render-prop and own the layout entirely.
## Features
- Default markup with `range` slider, `aria-pressed` mute/solo toggles, FX-slot count.
- `renderStrip` render-prop for custom layouts (e.g. shadcn cards, drag handles).
- All mutations route through `useStreamMixer()` — DAW solo semantics inherited
unchanged.
- Group `role="group"` with consumer-supplied `aria-label` for screen readers.
- Throws `REACT_AUDIO_STREAM.NO_PROVIDER` outside a `<StreamProvider>`.
## Usage: Basic
```tsx
<StreamMixer label="Live room mix" />
```
## Usage: Advanced
```tsx
<StreamMixer
label="Studio mix"
renderStrip={(peer, { setVolume, setMute, setSolo }) => (
<PeerStrip
peer={peer}
onVolume={setVolume}
onMute={() => setMute(!peer.muted)}
onSolo={() => setSolo(!peer.soloed)}
/>
)}
/>
```
## API Reference
- `StreamMixerProps` — `{ label?: string; renderStrip?: (peer, controls) => ReactNode }`
- `StreamMixer(props): ReactNode`
## Implementation Notes
The `aria-pressed` attribute is set on both the mute and solo buttons because they are
two-state toggles — this matches WAI-ARIA's authoring practice for toggle buttons and
allows assistive tech to announce the current state without parsing the button label.
The range slider's `value` is bound to the live `peer.volume` so it stays in sync with
ducking caused by other peers' solo state (per Requirement 6: when any peer is soloed,
non-soloed peers' track volumes go to 0, and the slider reflects that).