first commit
This commit is contained in:
@@ -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.
|
||||
Reference in New Issue
Block a user