Tier 2: drag feel, wheel overhaul, refs/meta/forms, Meter, gradients
- rotaryMode: 'absolute' | 'relative' (angle deltas, no grab jump) |
'pickup' (MIDI-style: engages when the pointer sweeps past the value)
- dragAcceleration: velocity gain for relative drags (Shift bypasses);
hideCursorOnDrag hides the cursor mid-gesture
- Wheel: trackpad delta accumulation (flicks can't rocket the value,
one notch per wheel click), wheelStep override, wheelRequiresFocus
opt-out of the hover scroll-trap
- onChange/onChangeStart/onChangeEnd now receive { source: 'drag' |
'wheel' | 'keyboard' | 'reset' | 'api' }
- Every component forwards a ref to its root; name prop renders a
hidden form input; SVG primitives carry data-part attributes
- Arc gradient: position-anchored color stops rendered as sliced arcs
(mixColors/sampleGradient exported, unit-tested)
- New read-only Meter: LED level meter with peak hold, zones, readout
- Fader capColor/capLength for custom handle styling
- Docs: Meter/gradient/drag-feel gallery cards, white-cap fader demo,
API rows, README
This commit is contained in:
parent
804a85cca6
commit
0aee48b749
27 changed files with 756 additions and 134 deletions
|
|
@ -10,6 +10,7 @@ import {
|
|||
LEDFader,
|
||||
LEDKnob,
|
||||
MetalKnob,
|
||||
Meter,
|
||||
NeonKnob,
|
||||
Pointer,
|
||||
RubberKnob,
|
||||
|
|
@ -57,6 +58,32 @@ const useGeneratedStrip = (frames = 31, fs = 120): string | null => {
|
|||
return src;
|
||||
};
|
||||
|
||||
const MeterDemo: React.FC = () => {
|
||||
const [levels, setLevels] = React.useState<[number, number]>([-18, -20]);
|
||||
React.useEffect(() => {
|
||||
let t = 0;
|
||||
const id = setInterval(() => {
|
||||
t += 0.09;
|
||||
setLevels([
|
||||
-13 + Math.sin(t) * 6 + Math.random() * 7,
|
||||
-14 + Math.sin(t * 1.3 + 1) * 6 + Math.random() * 7,
|
||||
]);
|
||||
}, 90);
|
||||
return () => clearInterval(id);
|
||||
}, []);
|
||||
const zones = [
|
||||
{ upTo: 0.72, color: '#3df2ad' },
|
||||
{ upTo: 0.9, color: '#ffd23e' },
|
||||
{ upTo: 1, color: '#ff4d6b' },
|
||||
];
|
||||
return (
|
||||
<div style={{ display: 'flex', gap: 12 }}>
|
||||
<Meter value={levels[0]} min={-60} max={6} length={132} zones={zones} peakColor="#fff" label="L" aria-label="Left level" />
|
||||
<Meter value={levels[1]} min={-60} max={6} length={132} zones={zones} peakColor="#fff" label="R" aria-label="Right level" />
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const ImageKnobDemo: React.FC = () => {
|
||||
const src = useGeneratedStrip();
|
||||
if (!src) return null;
|
||||
|
|
@ -136,8 +163,9 @@ export const Gallery: React.FC = () => (
|
|||
<SteppedKnob size={92} min={-24} max={24} steps={9} color="#4cc2ff" defaultValue={0} label="Semi" aria-label="Semitones demo" />
|
||||
</Card>
|
||||
|
||||
<Card title="Fader" desc="Absolute-position linear control, both orientations." tag="<Fader />">
|
||||
<Card title="Fader" desc="Absolute-position linear control, both orientations, custom caps." tag="<Fader />">
|
||||
<Fader length={130} defaultValue={-6} min={-60} max={12} step={0.5} unit=" dB" label="Main" aria-label="Fader demo" />
|
||||
<Fader length={130} defaultValue={20} step={1} capColor="#e8e8ec" capLength={26} color="#3df2ad" label="Aux" aria-label="White cap fader demo" />
|
||||
<Fader orientation="horizontal" length={150} defaultValue={35} step={1} color="#e44cff" label="X-Fade" aria-label="Crossfade demo" />
|
||||
</Card>
|
||||
|
||||
|
|
@ -269,6 +297,49 @@ export const Gallery: React.FC = () => (
|
|||
</div>
|
||||
</Card>
|
||||
|
||||
<Card title="Meter" desc="Read-only LED metering with peak hold — the display sibling of LEDFader." tag="<Meter peakHold />">
|
||||
<MeterDemo />
|
||||
</Card>
|
||||
|
||||
<Card title="Gradient arc" desc="Position-anchored gradient — the red zone stays at the top of travel." tag="<Arc gradient={...} />">
|
||||
<Knob size={96} min={-60} max={6} step={0.5} defaultValue={-8} aria-label="Gradient arc demo">
|
||||
<Arc
|
||||
thickness={7}
|
||||
trackColor="rgba(255,255,255,0.08)"
|
||||
gradient={[
|
||||
{ at: 0, color: '#3df2ad' },
|
||||
{ at: 0.72, color: '#3df2ad' },
|
||||
{ at: 0.9, color: '#ffd23e' },
|
||||
{ at: 1, color: '#ff4d6b' },
|
||||
]}
|
||||
/>
|
||||
<Pointer type="line" radius={33} length={12} width={3} color="#e8eaf0" />
|
||||
<KnobValue unit=" dB" color="#e8eaf0" fontSize={14} />
|
||||
</Knob>
|
||||
</Card>
|
||||
|
||||
<Card title="Drag feel options" desc="Pickup mode never jumps on grab; acceleration makes fast vertical drags cover more range." tag="rotaryMode · dragAcceleration">
|
||||
<FlatKnob
|
||||
size={88}
|
||||
defaultValue={70}
|
||||
rotaryMode="pickup"
|
||||
color="#ffd23e"
|
||||
label="Pickup"
|
||||
aria-label="Pickup mode demo"
|
||||
/>
|
||||
<RubberKnob
|
||||
size={88}
|
||||
defaultValue={40}
|
||||
interaction="vertical"
|
||||
dragAcceleration={2}
|
||||
hideCursorOnDrag
|
||||
showValue
|
||||
color="#4cc2ff"
|
||||
label="Accel"
|
||||
aria-label="Acceleration demo"
|
||||
/>
|
||||
</Card>
|
||||
|
||||
<Card title="Compose your own" desc="Primitives + headless core = any design you want." tag="<Knob> + primitives">
|
||||
<Knob size={96} defaultValue={42} aria-label="Composed demo">
|
||||
<Ticks count={28} radius={47} length={5} width={1.5} color="rgba(255,255,255,0.12)" activeColor="#ffd23e" />
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue