Initial Commit

This commit is contained in:
2026-05-27 23:47:53 +01:00
parent fbc70f96e6
commit 9b28db724f
18103 changed files with 1600554 additions and 0 deletions

View File

@@ -0,0 +1,93 @@
# slider-helpers (module-private)
## Purpose
Shared pure functions for both `<SliderV>` and `<SliderH>` so that
value resolution, detent snapping, and keyboard stepping are identical
across the two orientations. The helpers live under `slider-v/` for a
stable physical home, and `<SliderH>` reaches across with a single
relative import. They are not re-exported from the package barrel —
consumers of the package only see `<SliderV>` and `<SliderH>`.
## Features
- `clamp` / `quantize` — primitive numeric helpers.
- `applyDetents` — within-threshold snap to the nearest detent `at`.
- `resolveSliderValue` — full pipeline: clamp → step quantize →
detent snap.
- `fractionForValue` — normalize value to 0..1 for thumb-position math.
- `keyboardStep` — returns the next value for arrow / Home / End /
PageUp / PageDown keys, orientation-aware, Shift-fine-mode aware.
Returns `null` for unrecognised keys.
## Usage: Basic
```ts
import {
resolveSliderValue,
fractionForValue,
} from "./slider-helpers.js";
const next = resolveSliderValue({
raw: 0.42,
min: 0,
max: 1,
step: 0.05,
});
const pct = fractionForValue(next, 0, 1); // 0.4
```
## Usage: Advanced
Keyboard-driven step with custom fine factor and detents:
```ts
import {
keyboardStep,
resolveSliderValue,
} from "./slider-helpers.js";
const proposed = keyboardStep({
key: event.key,
value: current,
min: -60,
max: 12,
step: 0.5,
fineFactor: 0.1,
shiftKey: event.shiftKey,
orientation: "vertical",
});
if (proposed !== null) {
const snapped = resolveSliderValue({
raw: proposed,
min: -60,
max: 12,
step: 0.5,
detents: [{ at: 0, label: "0 dB" }],
snapThreshold: 0.5,
});
onChange(snapped);
}
```
## API Reference
| Function | Signature |
| -------------------- | ------------------------------------------------------------------------------ |
| `clamp` | `(value, min, max) => number` |
| `quantize` | `(value, step, min) => number` |
| `applyDetents` | `(value, detents, threshold) => number` |
| `resolveSliderValue` | `({ raw, min, max, step, detents?, snapThreshold? }) => number` |
| `fractionForValue` | `(value, min, max) => number` (always clamped to 0..1) |
| `keyboardStep` | `(args) => number \| null`; returns `null` for unrecognised keys. |
## Implementation Notes
`applyDetents` greedily picks the closest detent within `threshold`
distance; `threshold` defaults to 2% of the span when not supplied.
`quantize` short-circuits when `step <= 0` so consumers can opt out
of stepping with `step: 0`. `keyboardStep` derives a perceptible
per-key delta of `max(step, span / 100)` so wide ranges still respond
to a single arrow key even when `step` is tiny. The orientation flip
between vertical / horizontal is encoded purely in the key mapping;
all downstream math is direction-agnostic.