@tremolo-ui/react 0.0.9 → 0.0.10
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/index.js +432 -269
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/types/components/AnimationCanvas/index.d.ts +9 -4
- package/dist/cjs/types/components/AnimationCanvas/index.d.ts.map +1 -1
- package/dist/cjs/types/components/AnimationKnob/index.d.ts +2 -0
- package/dist/cjs/types/components/AnimationKnob/index.d.ts.map +1 -1
- package/dist/cjs/types/components/DragObserver/index.d.ts +3 -1
- package/dist/cjs/types/components/DragObserver/index.d.ts.map +1 -1
- package/dist/cjs/types/components/Knob/index.d.ts +2 -0
- package/dist/cjs/types/components/Knob/index.d.ts.map +1 -1
- package/dist/cjs/types/components/NumberInput/DecrementStepper.d.ts +7 -0
- package/dist/cjs/types/components/NumberInput/DecrementStepper.d.ts.map +1 -0
- package/dist/cjs/types/components/NumberInput/IncrementStepper.d.ts +7 -0
- package/dist/cjs/types/components/NumberInput/IncrementStepper.d.ts.map +1 -0
- package/dist/cjs/types/components/NumberInput/Stepper.d.ts +8 -0
- package/dist/cjs/types/components/NumberInput/Stepper.d.ts.map +1 -0
- package/dist/cjs/types/components/NumberInput/context.d.ts +27 -0
- package/dist/cjs/types/components/NumberInput/context.d.ts.map +1 -0
- package/dist/cjs/types/components/NumberInput/index.d.ts +31 -16
- package/dist/cjs/types/components/NumberInput/index.d.ts.map +1 -1
- package/dist/cjs/types/components/Piano/BlackKey.d.ts +1 -0
- package/dist/cjs/types/components/Piano/BlackKey.d.ts.map +1 -1
- package/dist/cjs/types/components/Piano/KeyLabel.d.ts +2 -0
- package/dist/cjs/types/components/Piano/KeyLabel.d.ts.map +1 -1
- package/dist/cjs/types/components/Piano/WhiteKey.d.ts +2 -0
- package/dist/cjs/types/components/Piano/WhiteKey.d.ts.map +1 -1
- package/dist/cjs/types/components/Piano/index.d.ts +6 -4
- package/dist/cjs/types/components/Piano/index.d.ts.map +1 -1
- package/dist/cjs/types/components/Piano/key.d.ts +8 -2
- package/dist/cjs/types/components/Piano/key.d.ts.map +1 -1
- package/dist/cjs/types/components/Piano/keyboardShortcuts.d.ts +2 -0
- package/dist/cjs/types/components/Piano/keyboardShortcuts.d.ts.map +1 -1
- package/dist/cjs/types/components/Slider/Scale.d.ts +2 -0
- package/dist/cjs/types/components/Slider/Scale.d.ts.map +1 -1
- package/dist/cjs/types/components/Slider/ScaleOption.d.ts +2 -0
- package/dist/cjs/types/components/Slider/ScaleOption.d.ts.map +1 -1
- package/dist/cjs/types/components/Slider/Thumb.d.ts +4 -0
- package/dist/cjs/types/components/Slider/Thumb.d.ts.map +1 -1
- package/dist/cjs/types/components/Slider/Track.d.ts +6 -1
- package/dist/cjs/types/components/Slider/Track.d.ts.map +1 -1
- package/dist/cjs/types/components/Slider/context.d.ts +15 -12
- package/dist/cjs/types/components/Slider/context.d.ts.map +1 -1
- package/dist/cjs/types/components/Slider/index.d.ts +8 -5
- package/dist/cjs/types/components/Slider/index.d.ts.map +1 -1
- package/dist/cjs/types/components/WheelObserver/index.d.ts +1 -0
- package/dist/cjs/types/components/WheelObserver/index.d.ts.map +1 -1
- package/dist/cjs/types/components/XYPad/Area.d.ts +2 -0
- package/dist/cjs/types/components/XYPad/Area.d.ts.map +1 -1
- package/dist/cjs/types/components/XYPad/Thumb.d.ts +3 -0
- package/dist/cjs/types/components/XYPad/Thumb.d.ts.map +1 -1
- package/dist/cjs/types/components/XYPad/index.d.ts +4 -0
- package/dist/cjs/types/components/XYPad/index.d.ts.map +1 -1
- package/dist/cjs/types/hooks/useAnimationFrame.d.ts +3 -0
- package/dist/cjs/types/hooks/useAnimationFrame.d.ts.map +1 -0
- package/dist/cjs/types/hooks/useDrag.d.ts +15 -0
- package/dist/cjs/types/hooks/useDrag.d.ts.map +1 -0
- package/dist/cjs/types/hooks/useRefCallbackEvent.d.ts +1 -4
- package/dist/cjs/types/hooks/useRefCallbackEvent.d.ts.map +1 -1
- package/dist/esm/index.js +430 -260
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/types/components/AnimationCanvas/index.d.ts +9 -4
- package/dist/esm/types/components/AnimationCanvas/index.d.ts.map +1 -1
- package/dist/esm/types/components/AnimationKnob/index.d.ts +2 -0
- package/dist/esm/types/components/AnimationKnob/index.d.ts.map +1 -1
- package/dist/esm/types/components/DragObserver/index.d.ts +3 -1
- package/dist/esm/types/components/DragObserver/index.d.ts.map +1 -1
- package/dist/esm/types/components/Knob/index.d.ts +2 -0
- package/dist/esm/types/components/Knob/index.d.ts.map +1 -1
- package/dist/esm/types/components/NumberInput/DecrementStepper.d.ts +7 -0
- package/dist/esm/types/components/NumberInput/DecrementStepper.d.ts.map +1 -0
- package/dist/esm/types/components/NumberInput/IncrementStepper.d.ts +7 -0
- package/dist/esm/types/components/NumberInput/IncrementStepper.d.ts.map +1 -0
- package/dist/esm/types/components/NumberInput/Stepper.d.ts +8 -0
- package/dist/esm/types/components/NumberInput/Stepper.d.ts.map +1 -0
- package/dist/esm/types/components/NumberInput/context.d.ts +27 -0
- package/dist/esm/types/components/NumberInput/context.d.ts.map +1 -0
- package/dist/esm/types/components/NumberInput/index.d.ts +31 -16
- package/dist/esm/types/components/NumberInput/index.d.ts.map +1 -1
- package/dist/esm/types/components/Piano/BlackKey.d.ts +1 -0
- package/dist/esm/types/components/Piano/BlackKey.d.ts.map +1 -1
- package/dist/esm/types/components/Piano/KeyLabel.d.ts +2 -0
- package/dist/esm/types/components/Piano/KeyLabel.d.ts.map +1 -1
- package/dist/esm/types/components/Piano/WhiteKey.d.ts +2 -0
- package/dist/esm/types/components/Piano/WhiteKey.d.ts.map +1 -1
- package/dist/esm/types/components/Piano/index.d.ts +6 -4
- package/dist/esm/types/components/Piano/index.d.ts.map +1 -1
- package/dist/esm/types/components/Piano/key.d.ts +8 -2
- package/dist/esm/types/components/Piano/key.d.ts.map +1 -1
- package/dist/esm/types/components/Piano/keyboardShortcuts.d.ts +2 -0
- package/dist/esm/types/components/Piano/keyboardShortcuts.d.ts.map +1 -1
- package/dist/esm/types/components/Slider/Scale.d.ts +2 -0
- package/dist/esm/types/components/Slider/Scale.d.ts.map +1 -1
- package/dist/esm/types/components/Slider/ScaleOption.d.ts +2 -0
- package/dist/esm/types/components/Slider/ScaleOption.d.ts.map +1 -1
- package/dist/esm/types/components/Slider/Thumb.d.ts +4 -0
- package/dist/esm/types/components/Slider/Thumb.d.ts.map +1 -1
- package/dist/esm/types/components/Slider/Track.d.ts +6 -1
- package/dist/esm/types/components/Slider/Track.d.ts.map +1 -1
- package/dist/esm/types/components/Slider/context.d.ts +15 -12
- package/dist/esm/types/components/Slider/context.d.ts.map +1 -1
- package/dist/esm/types/components/Slider/index.d.ts +8 -5
- package/dist/esm/types/components/Slider/index.d.ts.map +1 -1
- package/dist/esm/types/components/WheelObserver/index.d.ts +1 -0
- package/dist/esm/types/components/WheelObserver/index.d.ts.map +1 -1
- package/dist/esm/types/components/XYPad/Area.d.ts +2 -0
- package/dist/esm/types/components/XYPad/Area.d.ts.map +1 -1
- package/dist/esm/types/components/XYPad/Thumb.d.ts +3 -0
- package/dist/esm/types/components/XYPad/Thumb.d.ts.map +1 -1
- package/dist/esm/types/components/XYPad/index.d.ts +4 -0
- package/dist/esm/types/components/XYPad/index.d.ts.map +1 -1
- package/dist/esm/types/hooks/useAnimationFrame.d.ts +3 -0
- package/dist/esm/types/hooks/useAnimationFrame.d.ts.map +1 -0
- package/dist/esm/types/hooks/useDrag.d.ts +15 -0
- package/dist/esm/types/hooks/useDrag.d.ts.map +1 -0
- package/dist/esm/types/hooks/useRefCallbackEvent.d.ts +1 -4
- package/dist/esm/types/hooks/useRefCallbackEvent.d.ts.map +1 -1
- package/dist/styles/index.css +110 -14
- package/package.json +5 -2
- package/src/components/AnimationCanvas/index.tsx +13 -4
- package/src/components/AnimationKnob/index.tsx +24 -42
- package/src/components/DragObserver/index.tsx +14 -52
- package/src/components/Knob/index.tsx +23 -40
- package/src/components/NumberInput/DecrementStepper.tsx +52 -0
- package/src/components/NumberInput/IncrementStepper.tsx +52 -0
- package/src/components/NumberInput/Stepper.tsx +25 -0
- package/src/components/NumberInput/context.tsx +150 -0
- package/src/components/NumberInput/index.css +102 -14
- package/src/components/NumberInput/index.tsx +164 -55
- package/src/components/Piano/BlackKey.tsx +13 -10
- package/src/components/Piano/KeyLabel.tsx +2 -0
- package/src/components/Piano/WhiteKey.tsx +14 -10
- package/src/components/Piano/index.tsx +13 -11
- package/src/components/Piano/key.ts +8 -2
- package/src/components/Piano/keyboardShortcuts.ts +2 -0
- package/src/components/Slider/Scale.tsx +8 -6
- package/src/components/Slider/ScaleOption.tsx +8 -6
- package/src/components/Slider/Thumb.tsx +7 -3
- package/src/components/Slider/Track.tsx +27 -15
- package/src/components/Slider/context.tsx +65 -51
- package/src/components/Slider/index.css +8 -0
- package/src/components/Slider/index.tsx +19 -10
- package/src/components/WheelObserver/index.tsx +1 -0
- package/src/components/XYPad/Area.tsx +2 -0
- package/src/components/XYPad/Thumb.tsx +3 -0
- package/src/components/XYPad/index.tsx +6 -2
- package/src/hooks/useAnimationFrame.ts +18 -0
- package/src/hooks/useDrag.ts +92 -0
- package/src/hooks/useRefCallbackEvent.ts +4 -7
|
@@ -12,6 +12,7 @@ import { defaultWhiteKeyWidth } from './WhiteKey'
|
|
|
12
12
|
|
|
13
13
|
type Props = KeyProps & Omit<ComponentPropsWithoutRef<'div'>, keyof KeyProps>
|
|
14
14
|
|
|
15
|
+
/** @category Piano */
|
|
15
16
|
export const BlackKey = forwardRef<KeyMethods, Props>(
|
|
16
17
|
(
|
|
17
18
|
{
|
|
@@ -27,8 +28,8 @@ export const BlackKey = forwardRef<KeyMethods, Props>(
|
|
|
27
28
|
__index,
|
|
28
29
|
__fill,
|
|
29
30
|
__width,
|
|
30
|
-
|
|
31
|
-
|
|
31
|
+
__onPlayNote,
|
|
32
|
+
__onStopNote,
|
|
32
33
|
__label,
|
|
33
34
|
...props
|
|
34
35
|
}: Props,
|
|
@@ -41,17 +42,17 @@ export const BlackKey = forwardRef<KeyMethods, Props>(
|
|
|
41
42
|
play() {
|
|
42
43
|
if (__disabled) return
|
|
43
44
|
setPlayed(true)
|
|
44
|
-
if (
|
|
45
|
+
if (__onPlayNote) __onPlayNote(__note!)
|
|
45
46
|
},
|
|
46
47
|
stop() {
|
|
47
48
|
setPlayed(false)
|
|
48
|
-
if (
|
|
49
|
+
if (__onStopNote) __onStopNote(__note!)
|
|
49
50
|
},
|
|
50
51
|
played() {
|
|
51
52
|
return played
|
|
52
53
|
},
|
|
53
54
|
}
|
|
54
|
-
}, [__disabled, __note,
|
|
55
|
+
}, [__disabled, __note, __onPlayNote, __onStopNote, played])
|
|
55
56
|
|
|
56
57
|
let keyLabelProps: KeyLabelProps = {}
|
|
57
58
|
if (children != undefined) {
|
|
@@ -82,24 +83,26 @@ export const BlackKey = forwardRef<KeyMethods, Props>(
|
|
|
82
83
|
onPointerDown={() => {
|
|
83
84
|
if (__disabled) return
|
|
84
85
|
setPlayed(true)
|
|
85
|
-
if (
|
|
86
|
+
if (__onPlayNote) __onPlayNote(__note!)
|
|
86
87
|
}}
|
|
87
88
|
onPointerEnter={() => {
|
|
88
89
|
if (__disabled) return
|
|
89
90
|
if (__glissando) {
|
|
90
91
|
setPlayed(true)
|
|
91
|
-
if (
|
|
92
|
+
if (__onPlayNote) __onPlayNote(__note!)
|
|
92
93
|
}
|
|
93
94
|
}}
|
|
94
95
|
onPointerUp={() => {
|
|
95
96
|
if (__disabled) return
|
|
96
97
|
setPlayed(false)
|
|
97
|
-
if (
|
|
98
|
+
if (__onStopNote) __onStopNote(__note!)
|
|
98
99
|
}}
|
|
99
100
|
onPointerLeave={() => {
|
|
100
101
|
if (__disabled) return
|
|
101
|
-
|
|
102
|
-
|
|
102
|
+
if (__glissando) {
|
|
103
|
+
setPlayed(false)
|
|
104
|
+
if (__onStopNote) __onStopNote(__note!)
|
|
105
|
+
}
|
|
103
106
|
}}
|
|
104
107
|
{...props}
|
|
105
108
|
>
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import clsx from 'clsx'
|
|
2
2
|
import { ComponentPropsWithoutRef, CSSProperties, ReactNode } from 'react'
|
|
3
3
|
|
|
4
|
+
/** @category Piano */
|
|
4
5
|
export interface KeyLabelProps {
|
|
5
6
|
/**
|
|
6
7
|
* override Piano.label
|
|
@@ -18,6 +19,7 @@ export interface KeyLabelProps {
|
|
|
18
19
|
__label?: (note: number, index: number) => ReactNode
|
|
19
20
|
}
|
|
20
21
|
|
|
22
|
+
/** @category Piano */
|
|
21
23
|
export function KeyLabel({
|
|
22
24
|
label,
|
|
23
25
|
className,
|
|
@@ -11,8 +11,10 @@ import { KeyLabel, KeyLabelProps } from './KeyLabel'
|
|
|
11
11
|
|
|
12
12
|
type Props = KeyProps & Omit<ComponentPropsWithoutRef<'div'>, keyof KeyProps>
|
|
13
13
|
|
|
14
|
+
/** @category Piano */
|
|
14
15
|
export const defaultWhiteKeyWidth = 40
|
|
15
16
|
|
|
17
|
+
/** @category Piano */
|
|
16
18
|
export const WhiteKey = forwardRef<KeyMethods, Props>(
|
|
17
19
|
(
|
|
18
20
|
{
|
|
@@ -28,8 +30,8 @@ export const WhiteKey = forwardRef<KeyMethods, Props>(
|
|
|
28
30
|
__index,
|
|
29
31
|
__fill,
|
|
30
32
|
__width,
|
|
31
|
-
|
|
32
|
-
|
|
33
|
+
__onPlayNote,
|
|
34
|
+
__onStopNote,
|
|
33
35
|
__label,
|
|
34
36
|
...props
|
|
35
37
|
}: Props,
|
|
@@ -42,17 +44,17 @@ export const WhiteKey = forwardRef<KeyMethods, Props>(
|
|
|
42
44
|
play() {
|
|
43
45
|
if (__disabled) return
|
|
44
46
|
setPlayed(true)
|
|
45
|
-
if (
|
|
47
|
+
if (__onPlayNote) __onPlayNote(__note!)
|
|
46
48
|
},
|
|
47
49
|
stop() {
|
|
48
50
|
setPlayed(false)
|
|
49
|
-
if (
|
|
51
|
+
if (__onStopNote) __onStopNote(__note!)
|
|
50
52
|
},
|
|
51
53
|
played() {
|
|
52
54
|
return played
|
|
53
55
|
},
|
|
54
56
|
}
|
|
55
|
-
}, [__disabled, __note,
|
|
57
|
+
}, [__disabled, __note, __onPlayNote, __onStopNote, played])
|
|
56
58
|
|
|
57
59
|
let keyLabelProps: KeyLabelProps = {}
|
|
58
60
|
if (children != undefined) {
|
|
@@ -83,24 +85,26 @@ export const WhiteKey = forwardRef<KeyMethods, Props>(
|
|
|
83
85
|
onPointerDown={() => {
|
|
84
86
|
if (__disabled) return
|
|
85
87
|
setPlayed(true)
|
|
86
|
-
if (
|
|
88
|
+
if (__onPlayNote) __onPlayNote(__note!)
|
|
87
89
|
}}
|
|
88
90
|
onPointerEnter={() => {
|
|
89
91
|
if (__disabled) return
|
|
90
92
|
if (__glissando) {
|
|
91
93
|
setPlayed(true)
|
|
92
|
-
if (
|
|
94
|
+
if (__onPlayNote) __onPlayNote(__note!)
|
|
93
95
|
}
|
|
94
96
|
}}
|
|
95
97
|
onPointerUp={() => {
|
|
96
98
|
if (__disabled) return
|
|
97
99
|
setPlayed(false)
|
|
98
|
-
if (
|
|
100
|
+
if (__onStopNote) __onStopNote(__note!)
|
|
99
101
|
}}
|
|
100
102
|
onPointerLeave={() => {
|
|
101
103
|
if (__disabled) return
|
|
102
|
-
|
|
103
|
-
|
|
104
|
+
if (__glissando) {
|
|
105
|
+
setPlayed(false)
|
|
106
|
+
if (__onStopNote) __onStopNote(__note!)
|
|
107
|
+
}
|
|
104
108
|
}}
|
|
105
109
|
{...props}
|
|
106
110
|
>
|
|
@@ -33,6 +33,7 @@ import { defaultWhiteKeyWidth, WhiteKey } from './WhiteKey'
|
|
|
33
33
|
* - add scale highlight
|
|
34
34
|
*/
|
|
35
35
|
|
|
36
|
+
/** @category Piano */
|
|
36
37
|
export interface PianoProps {
|
|
37
38
|
// required
|
|
38
39
|
noteRange: { first: number; last: number }
|
|
@@ -47,8 +48,8 @@ export interface PianoProps {
|
|
|
47
48
|
|
|
48
49
|
style?: CSSProperties
|
|
49
50
|
|
|
50
|
-
|
|
51
|
-
|
|
51
|
+
onPlayNote?: (noteNumber: number) => void
|
|
52
|
+
onStopNote?: (noteNumber: number) => void
|
|
52
53
|
|
|
53
54
|
label?: (note: number, index: number) => ReactNode
|
|
54
55
|
|
|
@@ -58,6 +59,7 @@ export interface PianoProps {
|
|
|
58
59
|
children?: ReactElement | ReactElement[]
|
|
59
60
|
}
|
|
60
61
|
|
|
62
|
+
/** @category Piano */
|
|
61
63
|
export function Piano({
|
|
62
64
|
noteRange,
|
|
63
65
|
glissando = true,
|
|
@@ -67,8 +69,8 @@ export function Piano({
|
|
|
67
69
|
height = fill ? '100%' : 160,
|
|
68
70
|
style,
|
|
69
71
|
className,
|
|
70
|
-
|
|
71
|
-
|
|
72
|
+
onPlayNote,
|
|
73
|
+
onStopNote,
|
|
72
74
|
label,
|
|
73
75
|
children,
|
|
74
76
|
...props
|
|
@@ -153,7 +155,7 @@ export function Piano({
|
|
|
153
155
|
}
|
|
154
156
|
}, [fill, whiteKeyProps?.width, whiteNoteCount])
|
|
155
157
|
|
|
156
|
-
useEventListener(window, 'keydown', (e) => {
|
|
158
|
+
useEventListener(globalThis.window, 'keydown', (e) => {
|
|
157
159
|
if (e.repeat) return
|
|
158
160
|
if (!keyboardShortcuts) return
|
|
159
161
|
const index = keyboardShortcuts.keys.indexOf(e.key)
|
|
@@ -164,7 +166,7 @@ export function Piano({
|
|
|
164
166
|
}
|
|
165
167
|
})
|
|
166
168
|
|
|
167
|
-
useEventListener(window, 'keyup', (e) => {
|
|
169
|
+
useEventListener(globalThis.window, 'keyup', (e) => {
|
|
168
170
|
if (e.repeat) return
|
|
169
171
|
if (!keyboardShortcuts) return
|
|
170
172
|
const index = keyboardShortcuts.keys.indexOf(e.key)
|
|
@@ -204,8 +206,8 @@ export function Piano({
|
|
|
204
206
|
__index={index}
|
|
205
207
|
__fill={fill}
|
|
206
208
|
__width={whiteNoteWidth}
|
|
207
|
-
|
|
208
|
-
|
|
209
|
+
__onPlayNote={onPlayNote}
|
|
210
|
+
__onStopNote={onStopNote}
|
|
209
211
|
__label={label}
|
|
210
212
|
{...whiteKeyProps}
|
|
211
213
|
/>
|
|
@@ -220,8 +222,8 @@ export function Piano({
|
|
|
220
222
|
__index={index}
|
|
221
223
|
__fill={fill}
|
|
222
224
|
__width={whiteNoteWidth * 0.65}
|
|
223
|
-
|
|
224
|
-
|
|
225
|
+
__onPlayNote={onPlayNote}
|
|
226
|
+
__onStopNote={onStopNote}
|
|
225
227
|
__label={label}
|
|
226
228
|
{...blackKeyProps}
|
|
227
229
|
/>
|
|
@@ -236,4 +238,4 @@ export * from './keyboardShortcuts'
|
|
|
236
238
|
|
|
237
239
|
export { WhiteKey } from './WhiteKey'
|
|
238
240
|
export { BlackKey } from './BlackKey'
|
|
239
|
-
export { KeyLabel } from './KeyLabel'
|
|
241
|
+
export { KeyLabel, type KeyLabelProps } from './KeyLabel'
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { CSSProperties, ReactElement, ReactNode } from 'react'
|
|
2
2
|
|
|
3
|
+
/**
|
|
4
|
+
* @category Piano
|
|
5
|
+
*/
|
|
3
6
|
export interface KeyProps {
|
|
4
7
|
width?: number
|
|
5
8
|
height?: number | `${number}%`
|
|
@@ -26,13 +29,16 @@ export interface KeyProps {
|
|
|
26
29
|
/** @internal */
|
|
27
30
|
__width?: number
|
|
28
31
|
/** @internal */
|
|
29
|
-
|
|
32
|
+
__onPlayNote?: (noteNumber: number) => void
|
|
30
33
|
/** @internal */
|
|
31
|
-
|
|
34
|
+
__onStopNote?: (noteNumber: number) => void
|
|
32
35
|
/** @internal */
|
|
33
36
|
__label?: (note: number, index: number) => ReactNode
|
|
34
37
|
}
|
|
35
38
|
|
|
39
|
+
/**
|
|
40
|
+
* @category Piano
|
|
41
|
+
*/
|
|
36
42
|
export interface KeyMethods {
|
|
37
43
|
play: () => void
|
|
38
44
|
stop: () => void
|
|
@@ -4,9 +4,10 @@ import { ComponentPropsWithoutRef, ReactNode } from 'react'
|
|
|
4
4
|
import { xor } from '@tremolo-ui/functions'
|
|
5
5
|
import { generateOptionsList, ScaleOptions } from '@tremolo-ui/functions/Slider'
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { useSliderContext } from './context'
|
|
8
8
|
import { ScaleOption } from './ScaleOption'
|
|
9
9
|
|
|
10
|
+
/** @category Slider */
|
|
10
11
|
export interface ScaleProps {
|
|
11
12
|
gap?: number | string
|
|
12
13
|
options?: ScaleOptions
|
|
@@ -16,6 +17,7 @@ export interface ScaleProps {
|
|
|
16
17
|
type Props = ScaleProps &
|
|
17
18
|
Omit<ComponentPropsWithoutRef<'div'>, keyof ScaleProps>
|
|
18
19
|
|
|
20
|
+
/** @category Slider */
|
|
19
21
|
export function Scale({
|
|
20
22
|
gap = 6,
|
|
21
23
|
options,
|
|
@@ -24,11 +26,11 @@ export function Scale({
|
|
|
24
26
|
style,
|
|
25
27
|
...props
|
|
26
28
|
}: Props) {
|
|
27
|
-
const min =
|
|
28
|
-
const max =
|
|
29
|
-
const step =
|
|
30
|
-
const vertical =
|
|
31
|
-
const reverse =
|
|
29
|
+
const min = useSliderContext((s) => s.min)
|
|
30
|
+
const max = useSliderContext((s) => s.max)
|
|
31
|
+
const step = useSliderContext((s) => s.step)
|
|
32
|
+
const vertical = useSliderContext((s) => s.vertical)
|
|
33
|
+
const reverse = useSliderContext((s) => s.reverse)
|
|
32
34
|
|
|
33
35
|
const optionsList = options
|
|
34
36
|
? generateOptionsList(options, min, max, step)
|
|
@@ -4,8 +4,9 @@ import { ComponentPropsWithoutRef, CSSProperties, useCallback } from 'react'
|
|
|
4
4
|
import { toFixed, xor, normalizeValue } from '@tremolo-ui/functions'
|
|
5
5
|
import { ScaleType } from '@tremolo-ui/functions/Slider'
|
|
6
6
|
|
|
7
|
-
import {
|
|
7
|
+
import { useSliderContext } from './context'
|
|
8
8
|
|
|
9
|
+
/** @category Slider */
|
|
9
10
|
export interface ScaleOptionProps {
|
|
10
11
|
// required
|
|
11
12
|
value: number
|
|
@@ -31,6 +32,7 @@ export interface ScaleOptionProps {
|
|
|
31
32
|
}
|
|
32
33
|
}
|
|
33
34
|
|
|
35
|
+
/** @category Slider */
|
|
34
36
|
export function ScaleOption({
|
|
35
37
|
value,
|
|
36
38
|
type = 'mark-number',
|
|
@@ -46,11 +48,11 @@ export function ScaleOption({
|
|
|
46
48
|
...props
|
|
47
49
|
}: ScaleOptionProps &
|
|
48
50
|
Omit<ComponentPropsWithoutRef<'div'>, keyof ScaleOptionProps>) {
|
|
49
|
-
const min =
|
|
50
|
-
const max =
|
|
51
|
-
const skew =
|
|
52
|
-
const vertical =
|
|
53
|
-
const reverse =
|
|
51
|
+
const min = useSliderContext((s) => s.min)
|
|
52
|
+
const max = useSliderContext((s) => s.max)
|
|
53
|
+
const skew = useSliderContext((s) => s.skew)
|
|
54
|
+
const vertical = useSliderContext((s) => s.vertical)
|
|
55
|
+
const reverse = useSliderContext((s) => s.reverse)
|
|
54
56
|
|
|
55
57
|
const calcPercent = useCallback(
|
|
56
58
|
(rawValue: number) => {
|
|
@@ -7,8 +7,9 @@ import {
|
|
|
7
7
|
useRef,
|
|
8
8
|
} from 'react'
|
|
9
9
|
|
|
10
|
-
import {
|
|
10
|
+
import { useSliderContext } from './context'
|
|
11
11
|
|
|
12
|
+
/** @category Slider */
|
|
12
13
|
export interface SliderThumbProps {
|
|
13
14
|
size?: number | string
|
|
14
15
|
width?: number | string
|
|
@@ -22,13 +23,16 @@ export interface SliderThumbProps {
|
|
|
22
23
|
__percent?: number
|
|
23
24
|
}
|
|
24
25
|
|
|
26
|
+
/** @category Slider */
|
|
25
27
|
export interface SliderThumbMethods {
|
|
26
28
|
focus: () => void
|
|
27
29
|
blur: () => void
|
|
28
30
|
}
|
|
29
31
|
|
|
32
|
+
/** @category Slider */
|
|
30
33
|
export const defaultThumbSize = 22
|
|
31
34
|
|
|
35
|
+
/** @category Slider */
|
|
32
36
|
export const SliderThumb = forwardRef<SliderThumbMethods, SliderThumbProps>(
|
|
33
37
|
(
|
|
34
38
|
{
|
|
@@ -43,8 +47,8 @@ export const SliderThumb = forwardRef<SliderThumbMethods, SliderThumbProps>(
|
|
|
43
47
|
ref,
|
|
44
48
|
) => {
|
|
45
49
|
const wrapperRef = useRef<HTMLDivElement>(null)
|
|
46
|
-
const vertical =
|
|
47
|
-
const disabled =
|
|
50
|
+
const vertical = useSliderContext((s) => s.vertical)
|
|
51
|
+
const disabled = useSliderContext((s) => s.disabled)
|
|
48
52
|
|
|
49
53
|
useImperativeHandle(ref, () => {
|
|
50
54
|
return {
|
|
@@ -3,11 +3,14 @@ import { CSSProperties, ReactElement } from 'react'
|
|
|
3
3
|
|
|
4
4
|
import { styleHelper, xor } from '@tremolo-ui/functions'
|
|
5
5
|
|
|
6
|
-
import {
|
|
6
|
+
import { useSliderContext } from './context'
|
|
7
7
|
|
|
8
|
+
/** @category Slider */
|
|
8
9
|
export const defaultLength = 140
|
|
10
|
+
/** @category Slider */
|
|
9
11
|
export const defaultThickness = 10
|
|
10
12
|
|
|
13
|
+
/** @category Slider */
|
|
11
14
|
export interface SliderTrackProps {
|
|
12
15
|
length?: number | string
|
|
13
16
|
thickness?: number | string
|
|
@@ -15,6 +18,8 @@ export interface SliderTrackProps {
|
|
|
15
18
|
active?: string
|
|
16
19
|
inactive?: string
|
|
17
20
|
|
|
21
|
+
defaultStyle?: boolean
|
|
22
|
+
|
|
18
23
|
className?: string
|
|
19
24
|
style?: CSSProperties
|
|
20
25
|
children?: ReactElement
|
|
@@ -25,6 +30,7 @@ export interface SliderTrackProps {
|
|
|
25
30
|
__percent?: number
|
|
26
31
|
}
|
|
27
32
|
|
|
33
|
+
/** @category Slider */
|
|
28
34
|
export function SliderTrack({
|
|
29
35
|
length = defaultLength,
|
|
30
36
|
thickness = defaultThickness,
|
|
@@ -33,12 +39,13 @@ export function SliderTrack({
|
|
|
33
39
|
children,
|
|
34
40
|
className,
|
|
35
41
|
style,
|
|
42
|
+
defaultStyle = true,
|
|
36
43
|
__thumb,
|
|
37
|
-
__percent,
|
|
44
|
+
__percent = 0,
|
|
38
45
|
}: SliderTrackProps) {
|
|
39
|
-
const vertical =
|
|
40
|
-
const reverse =
|
|
41
|
-
const disabled =
|
|
46
|
+
const vertical = useSliderContext((s) => s.vertical)
|
|
47
|
+
const reverse = useSliderContext((s) => s.reverse)
|
|
48
|
+
const disabled = useSliderContext((s) => s.disabled)
|
|
42
49
|
|
|
43
50
|
const direction = vertical ? 'bottom' : 'right'
|
|
44
51
|
const colors = {
|
|
@@ -50,16 +57,21 @@ export function SliderTrack({
|
|
|
50
57
|
<div
|
|
51
58
|
className={clsx('tremolo-slider-track', className)}
|
|
52
59
|
aria-disabled={disabled}
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
?
|
|
57
|
-
:
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
60
|
+
data-vertical={vertical}
|
|
61
|
+
style={
|
|
62
|
+
!defaultStyle
|
|
63
|
+
? style
|
|
64
|
+
: {
|
|
65
|
+
...colors,
|
|
66
|
+
background: xor(vertical, reverse)
|
|
67
|
+
? `linear-gradient(to ${direction}, var(--inactive, #eee) ${__percent}%, var(--active, #7998ec) ${__percent}%)`
|
|
68
|
+
: `linear-gradient(to ${direction}, var(--active, #7998ec) ${__percent}%, var(--inactive, #eee) ${__percent}%)`,
|
|
69
|
+
borderRadius: styleHelper(thickness!, '/', 2),
|
|
70
|
+
width: !vertical ? length : thickness,
|
|
71
|
+
height: vertical ? length : thickness,
|
|
72
|
+
...style,
|
|
73
|
+
}
|
|
74
|
+
}
|
|
63
75
|
>
|
|
64
76
|
{children}
|
|
65
77
|
{__thumb}
|
|
@@ -1,14 +1,7 @@
|
|
|
1
|
-
import { createContext,
|
|
1
|
+
import { createContext, useContext, useEffect, useRef } from 'react'
|
|
2
|
+
import { createStore, useStore } from 'zustand'
|
|
2
3
|
|
|
3
|
-
|
|
4
|
-
const maxContext = createContext(0)
|
|
5
|
-
const stepContext = createContext(0)
|
|
6
|
-
const skewContext = createContext(0)
|
|
7
|
-
const verticalContext = createContext(false)
|
|
8
|
-
const reverseContext = createContext(false)
|
|
9
|
-
const disabledContext = createContext(false)
|
|
10
|
-
|
|
11
|
-
interface Props {
|
|
4
|
+
type State = {
|
|
12
5
|
min: number
|
|
13
6
|
max: number
|
|
14
7
|
step: number
|
|
@@ -16,51 +9,72 @@ interface Props {
|
|
|
16
9
|
vertical: boolean
|
|
17
10
|
reverse: boolean
|
|
18
11
|
disabled: boolean
|
|
19
|
-
children: ReactNode
|
|
20
12
|
}
|
|
21
13
|
|
|
22
|
-
|
|
23
|
-
min:
|
|
24
|
-
max:
|
|
25
|
-
step:
|
|
26
|
-
skew:
|
|
27
|
-
vertical:
|
|
28
|
-
reverse:
|
|
29
|
-
disabled:
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
const
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
14
|
+
type Action = {
|
|
15
|
+
updateMin: (min: State['min']) => void
|
|
16
|
+
updateMax: (max: State['max']) => void
|
|
17
|
+
updateStep: (step: State['step']) => void
|
|
18
|
+
updateSkew: (skew: State['skew']) => void
|
|
19
|
+
updateVertical: (vertical: State['vertical']) => void
|
|
20
|
+
updateReverse: (reverse: State['reverse']) => void
|
|
21
|
+
updateDisabled: (disabled: State['disabled']) => void
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
type SliderStore = ReturnType<typeof createSliderStore>
|
|
25
|
+
|
|
26
|
+
const createSliderStore = (initProps?: Partial<State>) => {
|
|
27
|
+
const DEFAULT_PROPS: State = {
|
|
28
|
+
min: 0,
|
|
29
|
+
max: 0,
|
|
30
|
+
step: 0,
|
|
31
|
+
skew: 0,
|
|
32
|
+
vertical: false,
|
|
33
|
+
reverse: false,
|
|
34
|
+
disabled: false,
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
return createStore<State & Action>()((set) => ({
|
|
38
|
+
...DEFAULT_PROPS,
|
|
39
|
+
...initProps,
|
|
40
|
+
updateMin: (min) => set(() => ({ min: min })),
|
|
41
|
+
updateMax: (max) => set(() => ({ max: max })),
|
|
42
|
+
updateStep: (step) => set(() => ({ step: step })),
|
|
43
|
+
updateSkew: (skew) => set(() => ({ skew: skew })),
|
|
44
|
+
updateVertical: (vertical) => set(() => ({ vertical: vertical })),
|
|
45
|
+
updateReverse: (reverse) => set(() => ({ reverse: reverse })),
|
|
46
|
+
updateDisabled: (disabled) => set(() => ({ disabled: disabled })),
|
|
47
|
+
}))
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const SliderContext = createContext<SliderStore | null>(null)
|
|
51
|
+
|
|
52
|
+
type SliderProviderProps = React.PropsWithChildren<Partial<State>>
|
|
53
|
+
|
|
54
|
+
export function SliderProvider({ children, ...props }: SliderProviderProps) {
|
|
55
|
+
const storeRef = useRef<SliderStore>()
|
|
56
|
+
if (!storeRef.current) {
|
|
57
|
+
storeRef.current = createSliderStore(props)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
useEffect(() => {
|
|
61
|
+
if (storeRef.current) {
|
|
62
|
+
storeRef.current.setState(props)
|
|
63
|
+
} else {
|
|
64
|
+
storeRef.current = createSliderStore(props)
|
|
65
|
+
}
|
|
66
|
+
}, [props])
|
|
39
67
|
|
|
40
68
|
return (
|
|
41
|
-
<
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
<skewContext.Provider value={skew}>
|
|
45
|
-
<verticalContext.Provider value={vertical}>
|
|
46
|
-
<reverseContext.Provider value={reverse}>
|
|
47
|
-
<disabledContext.Provider value={disabled}>
|
|
48
|
-
{children}
|
|
49
|
-
</disabledContext.Provider>
|
|
50
|
-
</reverseContext.Provider>
|
|
51
|
-
</verticalContext.Provider>
|
|
52
|
-
</skewContext.Provider>
|
|
53
|
-
</stepContext.Provider>
|
|
54
|
-
</maxContext.Provider>
|
|
55
|
-
</minContext.Provider>
|
|
69
|
+
<SliderContext.Provider value={storeRef.current}>
|
|
70
|
+
{children}
|
|
71
|
+
</SliderContext.Provider>
|
|
56
72
|
)
|
|
57
73
|
}
|
|
58
74
|
|
|
59
|
-
|
|
60
|
-
export
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
export const useReverse = () => useContext(reverseContext)
|
|
66
|
-
export const useDisabled = () => useContext(disabledContext)
|
|
75
|
+
/** @category Slider */
|
|
76
|
+
export function useSliderContext<T>(selector: (state: State & Action) => T): T {
|
|
77
|
+
const store = useContext(SliderContext)
|
|
78
|
+
if (!store) throw new Error('Missing SliderContext.Provider in the tree')
|
|
79
|
+
return useStore(store, selector)
|
|
80
|
+
}
|