-
Notifications
You must be signed in to change notification settings - Fork 12
Expand file tree
/
Copy pathKnobBase.tsx
More file actions
98 lines (94 loc) · 2.57 KB
/
Copy pathKnobBase.tsx
File metadata and controls
98 lines (94 loc) · 2.57 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
import clsx from 'clsx';
import {useId, useState} from 'react';
import {
KnobHeadless,
KnobHeadlessLabel,
KnobHeadlessOutput,
useKnobKeyboardControls,
} from 'react-knob-headless';
import {mapFrom01Linear, mapTo01Linear} from '@dsp-ts/math';
import {KnobBaseThumb} from './KnobBaseThumb';
type KnobHeadlessProps = React.ComponentProps<typeof KnobHeadless>;
type KnobBaseThumbProps = React.ComponentProps<typeof KnobBaseThumb>;
type KnobBaseProps = Pick<
KnobHeadlessProps,
| 'valueMin'
| 'valueMax'
| 'valueRawRoundFn'
| 'valueRawDisplayFn'
| 'axis'
| 'mapTo01'
| 'mapFrom01'
| 'disabled'
> &
Pick<KnobBaseThumbProps, 'theme'> & {
readonly label: string;
readonly valueDefault: number;
readonly stepFn: (valueRaw: number) => number;
readonly stepLargerFn: (valueRaw: number) => number;
};
export function KnobBase({
theme,
label,
valueDefault,
valueMin,
valueMax,
valueRawRoundFn,
valueRawDisplayFn,
axis,
disabled,
stepFn,
stepLargerFn,
mapTo01 = mapTo01Linear,
mapFrom01 = mapFrom01Linear,
}: KnobBaseProps) {
const knobId = useId();
const labelId = useId();
const [valueRaw, setValueRaw] = useState<number>(valueDefault);
const value01 = mapTo01(valueRaw, valueMin, valueMax);
const step = stepFn(valueRaw);
const stepLarger = stepLargerFn(valueRaw);
const dragSensitivity = 0.006;
const keyboardControlHandlers = useKnobKeyboardControls({
valueRaw,
valueMin,
valueMax,
step,
stepLarger,
disabled,
onValueRawChange: setValueRaw,
});
return (
<div
className={clsx(
'w-16 flex flex-col gap-0.5 justify-center items-center text-xs select-none',
!disabled &&
'outline-none focus-within:outline-1 focus-within:outline-offset-4 focus-within:outline-stone-300',
)}
>
<KnobHeadlessLabel id={labelId}>{label}</KnobHeadlessLabel>
<KnobHeadless
id={knobId}
aria-labelledby={labelId}
className='relative w-16 h-16 outline-none'
valueMin={valueMin}
valueMax={valueMax}
valueRaw={valueRaw}
valueRawRoundFn={valueRawRoundFn}
valueRawDisplayFn={valueRawDisplayFn}
dragSensitivity={dragSensitivity}
axis={axis}
disabled={disabled}
mapTo01={mapTo01}
mapFrom01={mapFrom01}
onValueRawChange={setValueRaw}
{...keyboardControlHandlers}
>
<KnobBaseThumb theme={theme} value01={value01} />
</KnobHeadless>
<KnobHeadlessOutput htmlFor={knobId}>
{valueRawDisplayFn(valueRaw)}
</KnobHeadlessOutput>
</div>
);
}