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,81 @@
# `hooks/use-midi-devices`
<!-- begin:auto-docs -->
_(no submodules)_
<!-- end:auto-docs -->
## Purpose
`useMidiDevices()` returns the live `{ inputs, outputs }` device-list
view, re-rendering whenever the provider's `stateVersion` advances —
i.e. whenever a Web MIDI `statechange` event fires (device plugged
in, unplugged, or its state otherwise changed). It is a thin wrapper
over `useMidi()` for components that only need the device lists and
want a narrower call site. Use this hook in device-picker UIs.
## Features
- `inputs` and `outputs` are `readonly WebMIDIInput[]` /
`readonly WebMIDIOutput[]` materialised on every state change.
- Stable array identity between state changes — safe to pass to
`key` in renders without forcing unnecessary remounts.
- No subscription bookkeeping — the underlying provider already owns
the single `onstatechange` listener.
## Usage: Basic
```tsx
import { useMidiDevices } from "@suaveplan/react-midi";
function DeviceCount() {
const { inputs, outputs } = useMidiDevices();
return (
<p>
{inputs.length} inputs, {outputs.length} outputs
</p>
);
}
```
## Usage: Advanced
```tsx
function PortPicker({ value, onChange }: {
value: string | null;
onChange: (id: string | null) => void;
}) {
const { inputs } = useMidiDevices();
return (
<select
value={value ?? ""}
onChange={(e) => onChange(e.target.value || null)}
>
<option value="">(none)</option>
{inputs.map((i) => (
<option key={i.id} value={i.id}>
{i.name}
</option>
))}
</select>
);
}
```
## API Reference
- `useMidiDevices(): { inputs, outputs }`
## Implementation Notes
This hook deliberately avoids duplicating the `useMidi` snapshot —
it simply destructures and re-projects. Callers that also need the
`status` or `error` should reach for `useMidi` instead.
Because the underlying `useMidi` re-materialises its `inputs` and
`outputs` arrays only when the provider's `stateVersion` advances,
the values returned here are referentially stable between
`statechange` events. That means downstream effects keyed on
`inputs` or `outputs` do not fire on every render — only when the
device list actually changes — which matters for a device-picker UI
that triggers expensive operations (e.g. preset reloads) on the
selected device.