@tremolo-ui/react 0.0.11 → 0.0.12
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 +428 -196
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/types/components/AnimationCanvas/index.d.ts +2 -2
- package/dist/cjs/types/components/AnimationCanvas/index.d.ts.map +1 -1
- package/dist/cjs/types/components/AnimationKnob/index.d.ts +10 -3
- package/dist/cjs/types/components/AnimationKnob/index.d.ts.map +1 -1
- package/dist/cjs/types/components/Knob/index.d.ts +13 -3
- package/dist/cjs/types/components/Knob/index.d.ts.map +1 -1
- package/dist/cjs/types/components/NumberInput/DecrementStepper.d.ts +2 -0
- package/dist/cjs/types/components/NumberInput/DecrementStepper.d.ts.map +1 -1
- package/dist/cjs/types/components/NumberInput/IncrementStepper.d.ts +2 -0
- package/dist/cjs/types/components/NumberInput/IncrementStepper.d.ts.map +1 -1
- package/dist/cjs/types/components/NumberInput/InternalInput.d.ts +18 -0
- package/dist/cjs/types/components/NumberInput/InternalInput.d.ts.map +1 -0
- package/dist/cjs/types/components/NumberInput/Stepper.d.ts +2 -0
- package/dist/cjs/types/components/NumberInput/Stepper.d.ts.map +1 -1
- package/dist/cjs/types/components/NumberInput/context.d.ts +3 -2
- package/dist/cjs/types/components/NumberInput/context.d.ts.map +1 -1
- package/dist/cjs/types/components/NumberInput/index.d.ts +12 -3
- package/dist/cjs/types/components/NumberInput/index.d.ts.map +1 -1
- package/dist/cjs/types/components/Piano/BlackKey.d.ts.map +1 -1
- package/dist/cjs/types/components/Piano/WhiteKey.d.ts.map +1 -1
- package/dist/cjs/types/components/Piano/index.d.ts +7 -4
- package/dist/cjs/types/components/Piano/index.d.ts.map +1 -1
- package/dist/cjs/types/components/Piano/key.d.ts +4 -0
- package/dist/cjs/types/components/Piano/key.d.ts.map +1 -1
- package/dist/cjs/types/components/Piano/keyboardShortcuts.d.ts +2 -2
- package/dist/cjs/types/components/Slider/Scale.d.ts +1 -3
- package/dist/cjs/types/components/Slider/Scale.d.ts.map +1 -1
- package/dist/cjs/types/components/Slider/Thumb.d.ts +1 -0
- package/dist/cjs/types/components/Slider/Thumb.d.ts.map +1 -1
- package/dist/cjs/types/components/Slider/Track.d.ts +2 -2
- package/dist/cjs/types/components/Slider/Track.d.ts.map +1 -1
- package/dist/cjs/types/components/Slider/index.d.ts +5 -1
- package/dist/cjs/types/components/Slider/index.d.ts.map +1 -1
- package/dist/cjs/types/components/WheelObserver/index.d.ts +3 -3
- package/dist/cjs/types/components/WheelObserver/index.d.ts.map +1 -1
- package/dist/cjs/types/components/XYPad/Area.d.ts +3 -3
- package/dist/cjs/types/components/XYPad/Area.d.ts.map +1 -1
- package/dist/cjs/types/components/XYPad/Thumb.d.ts +1 -0
- package/dist/cjs/types/components/XYPad/Thumb.d.ts.map +1 -1
- package/dist/cjs/types/components/XYPad/index.d.ts +6 -1
- package/dist/cjs/types/components/XYPad/index.d.ts.map +1 -1
- package/dist/cjs/types/hooks/useInterval.d.ts +2 -0
- package/dist/cjs/types/hooks/useInterval.d.ts.map +1 -0
- package/dist/cjs/types/hooks/useLongPress.d.ts +2 -0
- package/dist/cjs/types/hooks/useLongPress.d.ts.map +1 -0
- package/dist/cjs/types/index.d.ts +5 -0
- package/dist/cjs/types/index.d.ts.map +1 -1
- package/dist/esm/index.js +424 -197
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/types/components/AnimationCanvas/index.d.ts +2 -2
- package/dist/esm/types/components/AnimationCanvas/index.d.ts.map +1 -1
- package/dist/esm/types/components/AnimationKnob/index.d.ts +10 -3
- package/dist/esm/types/components/AnimationKnob/index.d.ts.map +1 -1
- package/dist/esm/types/components/Knob/index.d.ts +13 -3
- package/dist/esm/types/components/Knob/index.d.ts.map +1 -1
- package/dist/esm/types/components/NumberInput/DecrementStepper.d.ts +2 -0
- package/dist/esm/types/components/NumberInput/DecrementStepper.d.ts.map +1 -1
- package/dist/esm/types/components/NumberInput/IncrementStepper.d.ts +2 -0
- package/dist/esm/types/components/NumberInput/IncrementStepper.d.ts.map +1 -1
- package/dist/esm/types/components/NumberInput/InternalInput.d.ts +18 -0
- package/dist/esm/types/components/NumberInput/InternalInput.d.ts.map +1 -0
- package/dist/esm/types/components/NumberInput/Stepper.d.ts +2 -0
- package/dist/esm/types/components/NumberInput/Stepper.d.ts.map +1 -1
- package/dist/esm/types/components/NumberInput/context.d.ts +3 -2
- package/dist/esm/types/components/NumberInput/context.d.ts.map +1 -1
- package/dist/esm/types/components/NumberInput/index.d.ts +12 -3
- package/dist/esm/types/components/NumberInput/index.d.ts.map +1 -1
- package/dist/esm/types/components/Piano/BlackKey.d.ts.map +1 -1
- package/dist/esm/types/components/Piano/WhiteKey.d.ts.map +1 -1
- package/dist/esm/types/components/Piano/index.d.ts +7 -4
- package/dist/esm/types/components/Piano/index.d.ts.map +1 -1
- package/dist/esm/types/components/Piano/key.d.ts +4 -0
- package/dist/esm/types/components/Piano/key.d.ts.map +1 -1
- package/dist/esm/types/components/Piano/keyboardShortcuts.d.ts +2 -2
- package/dist/esm/types/components/Slider/Scale.d.ts +1 -3
- package/dist/esm/types/components/Slider/Scale.d.ts.map +1 -1
- package/dist/esm/types/components/Slider/Thumb.d.ts +1 -0
- package/dist/esm/types/components/Slider/Thumb.d.ts.map +1 -1
- package/dist/esm/types/components/Slider/Track.d.ts +2 -2
- package/dist/esm/types/components/Slider/Track.d.ts.map +1 -1
- package/dist/esm/types/components/Slider/index.d.ts +5 -1
- package/dist/esm/types/components/Slider/index.d.ts.map +1 -1
- package/dist/esm/types/components/WheelObserver/index.d.ts +3 -3
- package/dist/esm/types/components/WheelObserver/index.d.ts.map +1 -1
- package/dist/esm/types/components/XYPad/Area.d.ts +3 -3
- package/dist/esm/types/components/XYPad/Area.d.ts.map +1 -1
- package/dist/esm/types/components/XYPad/Thumb.d.ts +1 -0
- package/dist/esm/types/components/XYPad/Thumb.d.ts.map +1 -1
- package/dist/esm/types/components/XYPad/index.d.ts +6 -1
- package/dist/esm/types/components/XYPad/index.d.ts.map +1 -1
- package/dist/esm/types/hooks/useInterval.d.ts +2 -0
- package/dist/esm/types/hooks/useInterval.d.ts.map +1 -0
- package/dist/esm/types/hooks/useLongPress.d.ts +2 -0
- package/dist/esm/types/hooks/useLongPress.d.ts.map +1 -0
- package/dist/esm/types/index.d.ts +5 -0
- package/dist/esm/types/index.d.ts.map +1 -1
- package/dist/styles/index.css +115 -33
- package/package.json +2 -2
- package/src/components/AnimationCanvas/index.tsx +14 -6
- package/src/components/AnimationKnob/index.tsx +216 -187
- package/src/components/Knob/index.tsx +230 -171
- package/src/components/NumberInput/DecrementStepper.tsx +9 -2
- package/src/components/NumberInput/IncrementStepper.tsx +9 -2
- package/src/components/NumberInput/InternalInput.tsx +219 -0
- package/src/components/NumberInput/Stepper.tsx +2 -0
- package/src/components/NumberInput/context.tsx +20 -8
- package/src/components/NumberInput/index.css +76 -22
- package/src/components/NumberInput/index.tsx +94 -162
- package/src/components/Piano/BlackKey.tsx +14 -0
- package/src/components/Piano/WhiteKey.tsx +14 -0
- package/src/components/Piano/index.css +22 -6
- package/src/components/Piano/index.tsx +19 -21
- package/src/components/Piano/key.ts +5 -0
- package/src/components/Piano/keyboardShortcuts.ts +2 -2
- package/src/components/Slider/Scale.tsx +1 -4
- package/src/components/Slider/Thumb.tsx +4 -0
- package/src/components/Slider/Track.tsx +5 -2
- package/src/components/Slider/index.css +5 -2
- package/src/components/Slider/index.tsx +51 -26
- package/src/components/WheelObserver/index.tsx +4 -2
- package/src/components/XYPad/Area.tsx +7 -6
- package/src/components/XYPad/Thumb.tsx +6 -0
- package/src/components/XYPad/index.css +12 -2
- package/src/components/XYPad/index.tsx +57 -41
- package/src/hooks/useInterval.ts +27 -0
- package/src/hooks/useLongPress.ts +31 -0
- package/src/index.ts +6 -0
- package/src/styles/index.css +0 -1
|
@@ -63,12 +63,16 @@ export interface SliderProps {
|
|
|
63
63
|
className?: string
|
|
64
64
|
style?: CSSProperties
|
|
65
65
|
onChange?: (value: number) => void
|
|
66
|
+
onDragStart?: (value: number) => void
|
|
67
|
+
onDragEnd?: (value: number) => void
|
|
66
68
|
/** \<SliderThumb /> | \<SliderTrack /> */
|
|
67
69
|
children?: ReactElement | ReactElement[]
|
|
68
70
|
// ReactElement<typeof SliderThumb, typeof SliderTrack>[]
|
|
69
71
|
}
|
|
70
72
|
|
|
71
|
-
/**
|
|
73
|
+
/**
|
|
74
|
+
* @category Slider
|
|
75
|
+
*/
|
|
72
76
|
export interface SliderMethods {
|
|
73
77
|
focus: () => void
|
|
74
78
|
blur: () => void
|
|
@@ -91,15 +95,21 @@ export const Slider = forwardRef<SliderMethods, Props>(
|
|
|
91
95
|
skew = 1,
|
|
92
96
|
vertical = false,
|
|
93
97
|
reverse = false,
|
|
94
|
-
className,
|
|
95
|
-
style,
|
|
96
98
|
bodyNoSelect = true,
|
|
97
99
|
wheel = ['raw', 1],
|
|
98
100
|
keyboard = ['raw', 1],
|
|
99
101
|
disabled = false,
|
|
100
102
|
readonly = false,
|
|
101
103
|
onChange,
|
|
104
|
+
onDragStart,
|
|
105
|
+
onDragEnd,
|
|
106
|
+
className,
|
|
107
|
+
style,
|
|
102
108
|
children,
|
|
109
|
+
onFocus,
|
|
110
|
+
onBlur,
|
|
111
|
+
onPointerDown,
|
|
112
|
+
onKeyDown,
|
|
103
113
|
...props
|
|
104
114
|
}: Props,
|
|
105
115
|
ref,
|
|
@@ -171,9 +181,25 @@ export const Slider = forwardRef<SliderMethods, Props>(
|
|
|
171
181
|
? normalizeValue(mouseY, y1, y2)
|
|
172
182
|
: normalizeValue(mouseX, x1, x2)
|
|
173
183
|
const v = rawValue(displayReversed ? 1 - n : n, min, max, skew)
|
|
174
|
-
|
|
184
|
+
const v2 = clamp(stepValue(v, step), min, max)
|
|
185
|
+
onChange(v2)
|
|
186
|
+
return v2
|
|
175
187
|
}
|
|
176
188
|
|
|
189
|
+
const updateValueByEvent = useCallback(
|
|
190
|
+
(eventType: InputEventOption[0], x: number) => {
|
|
191
|
+
let newValue
|
|
192
|
+
if (eventType == 'normalized') {
|
|
193
|
+
const n = normalizeValue(value, min, max, skew)
|
|
194
|
+
newValue = rawValue(n + x, min, max, skew)
|
|
195
|
+
} else {
|
|
196
|
+
newValue = value + x
|
|
197
|
+
}
|
|
198
|
+
return clamp(stepValue(newValue, step), min, max)
|
|
199
|
+
},
|
|
200
|
+
[max, min, skew, step, value],
|
|
201
|
+
)
|
|
202
|
+
|
|
177
203
|
const handleKeyDown = useCallback(
|
|
178
204
|
(event: React.KeyboardEvent<HTMLDivElement>) => {
|
|
179
205
|
if (!keyboard || !onChange || readonly) return
|
|
@@ -183,17 +209,10 @@ export const Slider = forwardRef<SliderMethods, Props>(
|
|
|
183
209
|
let x =
|
|
184
210
|
key == 'ArrowRight' || key == 'ArrowUp' ? keyboard[1] : -keyboard[1]
|
|
185
211
|
if (reverse) x *= -1
|
|
186
|
-
|
|
187
|
-
if (keyboard[0] == 'normalized') {
|
|
188
|
-
const n = normalizeValue(value, min, max, skew)
|
|
189
|
-
v = rawValue(n + x, min, max, skew)
|
|
190
|
-
} else {
|
|
191
|
-
v = value + x
|
|
192
|
-
}
|
|
193
|
-
onChange(clamp(stepValue(v, step), min, max))
|
|
212
|
+
onChange(updateValueByEvent(keyboard[0], x))
|
|
194
213
|
}
|
|
195
214
|
},
|
|
196
|
-
[
|
|
215
|
+
[keyboard, onChange, readonly, reverse, updateValueByEvent],
|
|
197
216
|
)
|
|
198
217
|
|
|
199
218
|
// --- hooks ---
|
|
@@ -217,19 +236,12 @@ export const Slider = forwardRef<SliderMethods, Props>(
|
|
|
217
236
|
x = event.deltaY > 0 ? -wheel[1] : wheel[1]
|
|
218
237
|
}
|
|
219
238
|
if (vertical && reverse) x *= -1
|
|
220
|
-
|
|
221
|
-
if (wheel[0] == 'normalized') {
|
|
222
|
-
const n = normalizeValue(value, min, max, skew)
|
|
223
|
-
v = rawValue(n + x, min, max, skew)
|
|
224
|
-
} else {
|
|
225
|
-
v = value + x
|
|
226
|
-
}
|
|
227
|
-
onChange(clamp(stepValue(v, step), min, max))
|
|
239
|
+
onChange(updateValueByEvent(wheel[0], x))
|
|
228
240
|
},
|
|
229
241
|
{
|
|
230
242
|
passive: false,
|
|
231
243
|
},
|
|
232
|
-
[wheel,
|
|
244
|
+
[wheel, vertical, readonly, onChange, updateValueByEvent],
|
|
233
245
|
)
|
|
234
246
|
|
|
235
247
|
useEventListener(globalThis.window, 'mousemove', (event) => {
|
|
@@ -237,7 +249,9 @@ export const Slider = forwardRef<SliderMethods, Props>(
|
|
|
237
249
|
})
|
|
238
250
|
|
|
239
251
|
useEventListener(globalThis.window, 'mouseup', () => {
|
|
252
|
+
if (!thumbDragged.current || readonly) return
|
|
240
253
|
thumbDragged.current = false
|
|
254
|
+
onDragEnd?.(value)
|
|
241
255
|
if (bodyNoSelect) removeNoSelect()
|
|
242
256
|
})
|
|
243
257
|
|
|
@@ -283,11 +297,22 @@ export const Slider = forwardRef<SliderMethods, Props>(
|
|
|
283
297
|
}}
|
|
284
298
|
onPointerDown={(event) => {
|
|
285
299
|
thumbDragged.current = true
|
|
286
|
-
handleValue(event)
|
|
300
|
+
const v = handleValue(event)
|
|
301
|
+
if (!readonly) onDragStart?.(v ?? value)
|
|
302
|
+
onPointerDown?.(event)
|
|
303
|
+
}}
|
|
304
|
+
onKeyDown={(event) => {
|
|
305
|
+
handleKeyDown(event)
|
|
306
|
+
onKeyDown?.(event)
|
|
307
|
+
}}
|
|
308
|
+
onFocus={(event) => {
|
|
309
|
+
thumbRef.current?.focus()
|
|
310
|
+
onFocus?.(event)
|
|
311
|
+
}}
|
|
312
|
+
onBlur={(event) => {
|
|
313
|
+
thumbRef.current?.blur()
|
|
314
|
+
onBlur?.(event)
|
|
287
315
|
}}
|
|
288
|
-
onKeyDown={handleKeyDown}
|
|
289
|
-
onFocus={thumbRef.current?.focus}
|
|
290
|
-
onBlur={thumbRef.current?.blur}
|
|
291
316
|
{...props}
|
|
292
317
|
>
|
|
293
318
|
<div
|
|
@@ -14,7 +14,8 @@ import { useRefCallbackEvent } from '../../hooks/useRefCallbackEvent'
|
|
|
14
14
|
* </WheelObserver>
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
|
-
|
|
17
|
+
/** @category WheelObserver */
|
|
18
|
+
export interface WheelObserverProps<T extends ElementType> {
|
|
18
19
|
/**
|
|
19
20
|
* React.ElementType
|
|
20
21
|
* @default div
|
|
@@ -27,7 +28,8 @@ interface Props<T extends ElementType> {
|
|
|
27
28
|
|
|
28
29
|
/** @category WheelObserver */
|
|
29
30
|
export function WheelObserver<T extends ElementType = 'div'>(
|
|
30
|
-
props:
|
|
31
|
+
props: WheelObserverProps<T> &
|
|
32
|
+
Omit<ComponentPropsWithoutRef<T>, keyof WheelObserverProps<T>>,
|
|
31
33
|
) {
|
|
32
34
|
const { children, onWheel, as: Component = 'div', ...attributes } = props
|
|
33
35
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import clsx from 'clsx'
|
|
2
|
-
import { CSSProperties, ReactElement } from 'react'
|
|
2
|
+
import { ComponentPropsWithoutRef, CSSProperties, ReactElement } from 'react'
|
|
3
3
|
|
|
4
4
|
/** @category XYPad */
|
|
5
5
|
export interface AreaProps {
|
|
6
6
|
width?: number | string
|
|
7
7
|
height?: number | string
|
|
8
|
-
|
|
8
|
+
color?: string
|
|
9
9
|
className?: string
|
|
10
10
|
style?: CSSProperties
|
|
11
11
|
children?: ReactElement
|
|
@@ -18,22 +18,23 @@ export interface AreaProps {
|
|
|
18
18
|
export function XYPadArea({
|
|
19
19
|
width = 120,
|
|
20
20
|
height = 120,
|
|
21
|
-
|
|
21
|
+
color,
|
|
22
22
|
children,
|
|
23
23
|
className,
|
|
24
24
|
style,
|
|
25
25
|
__thumb,
|
|
26
|
-
|
|
26
|
+
...props
|
|
27
|
+
}: AreaProps & Omit<ComponentPropsWithoutRef<'div'>, keyof AreaProps>) {
|
|
27
28
|
return (
|
|
28
29
|
<div
|
|
29
30
|
className={clsx('tremolo-xy-pad-area', className)}
|
|
30
31
|
style={{
|
|
31
|
-
|
|
32
|
+
...{ '--color': color },
|
|
32
33
|
width: width,
|
|
33
34
|
height: height,
|
|
34
|
-
background: bg,
|
|
35
35
|
...style,
|
|
36
36
|
}}
|
|
37
|
+
{...props}
|
|
37
38
|
>
|
|
38
39
|
{children}
|
|
39
40
|
{__thumb}
|
|
@@ -14,6 +14,8 @@ export interface ThumbProps {
|
|
|
14
14
|
width?: number | string
|
|
15
15
|
height?: number | string
|
|
16
16
|
|
|
17
|
+
color?: string
|
|
18
|
+
|
|
17
19
|
wrapperClassName?: string
|
|
18
20
|
wrapperStyle?: CSSProperties
|
|
19
21
|
|
|
@@ -41,6 +43,7 @@ export const XYPadThumb = forwardRef<XYPadThumbMethods, Props>(
|
|
|
41
43
|
size,
|
|
42
44
|
width = 22,
|
|
43
45
|
height = 22,
|
|
46
|
+
color,
|
|
44
47
|
children,
|
|
45
48
|
wrapperClassName,
|
|
46
49
|
wrapperStyle,
|
|
@@ -48,6 +51,7 @@ export const XYPadThumb = forwardRef<XYPadThumbMethods, Props>(
|
|
|
48
51
|
style,
|
|
49
52
|
__disabled,
|
|
50
53
|
__css,
|
|
54
|
+
...props
|
|
51
55
|
}: Props,
|
|
52
56
|
ref,
|
|
53
57
|
) => {
|
|
@@ -71,6 +75,7 @@ export const XYPadThumb = forwardRef<XYPadThumbMethods, Props>(
|
|
|
71
75
|
...__css,
|
|
72
76
|
...wrapperStyle,
|
|
73
77
|
}}
|
|
78
|
+
{...props}
|
|
74
79
|
>
|
|
75
80
|
{children ? (
|
|
76
81
|
children
|
|
@@ -83,6 +88,7 @@ export const XYPadThumb = forwardRef<XYPadThumbMethods, Props>(
|
|
|
83
88
|
tabIndex={0}
|
|
84
89
|
aria-disabled={__disabled}
|
|
85
90
|
style={{
|
|
91
|
+
...{ '--color': color },
|
|
86
92
|
width: size ?? width,
|
|
87
93
|
height: size ?? height,
|
|
88
94
|
...style,
|
|
@@ -3,6 +3,13 @@
|
|
|
3
3
|
cursor: pointer;
|
|
4
4
|
}
|
|
5
5
|
|
|
6
|
+
.tremolo-xy-pad-area {
|
|
7
|
+
--color: #eee;
|
|
8
|
+
|
|
9
|
+
position: relative;
|
|
10
|
+
background-color: var(--color);
|
|
11
|
+
}
|
|
12
|
+
|
|
6
13
|
.tremolo-xy-pad-thumb-wrapper {
|
|
7
14
|
position: absolute;
|
|
8
15
|
translate: -50% -50%;
|
|
@@ -10,15 +17,18 @@
|
|
|
10
17
|
}
|
|
11
18
|
|
|
12
19
|
.tremolo-xy-pad-thumb {
|
|
20
|
+
--color: var(--tremolo-theme-color);
|
|
21
|
+
|
|
13
22
|
border-radius: 50%;
|
|
14
23
|
outline: none;
|
|
15
|
-
background-color:
|
|
24
|
+
background-color: var(--color);
|
|
16
25
|
|
|
17
26
|
&[aria-disabled='true'] {
|
|
18
27
|
background-color: #5d6478;
|
|
19
28
|
}
|
|
20
29
|
|
|
21
30
|
&:focus {
|
|
22
|
-
box-shadow: 0px 0px 0px 3px
|
|
31
|
+
box-shadow: 0px 0px 0px 3px
|
|
32
|
+
color-mix(in srgb, var(--color) 20%, transparent);
|
|
23
33
|
}
|
|
24
34
|
}
|
|
@@ -26,7 +26,10 @@ import { addNoSelect, removeNoSelect } from '../_util'
|
|
|
26
26
|
import { XYPadArea, AreaProps } from './Area'
|
|
27
27
|
import { XYPadThumb, XYPadThumbMethods, ThumbProps } from './Thumb'
|
|
28
28
|
|
|
29
|
-
/**
|
|
29
|
+
/**
|
|
30
|
+
* Two-dimensional slider component.
|
|
31
|
+
* @category XYPad
|
|
32
|
+
*/
|
|
30
33
|
export interface ValueOptions {
|
|
31
34
|
// required
|
|
32
35
|
value: number
|
|
@@ -56,6 +59,8 @@ export interface XYPadProps {
|
|
|
56
59
|
disabled?: boolean
|
|
57
60
|
readonly?: boolean
|
|
58
61
|
onChange?: (valueX: number, valueY: number) => void
|
|
62
|
+
onDragStart?: (valueX: number, valueY: number) => void
|
|
63
|
+
onDragEnd?: (valueX: number, valueY: number) => void
|
|
59
64
|
/** \<XYPadThumb /> | \<XYPadArea /> */
|
|
60
65
|
children?: ReactElement | ReactElement[]
|
|
61
66
|
}
|
|
@@ -92,6 +97,12 @@ export const XYPad = forwardRef<XYPadMethods, Props>(
|
|
|
92
97
|
disabled = false,
|
|
93
98
|
readonly = false,
|
|
94
99
|
onChange,
|
|
100
|
+
onDragStart,
|
|
101
|
+
onDragEnd,
|
|
102
|
+
onPointerDown,
|
|
103
|
+
onKeyDown,
|
|
104
|
+
onFocus,
|
|
105
|
+
onBlur,
|
|
95
106
|
children,
|
|
96
107
|
...props
|
|
97
108
|
}: Props,
|
|
@@ -162,8 +173,32 @@ export const XYPad = forwardRef<XYPadMethods, Props>(
|
|
|
162
173
|
const newX = clamp(stepValue(vx, x.step), x.min, x.max)
|
|
163
174
|
const newY = clamp(stepValue(vy, y.step), y.min, y.max)
|
|
164
175
|
onChange(newX, newY)
|
|
176
|
+
return [newX, newY]
|
|
165
177
|
}
|
|
166
178
|
|
|
179
|
+
const updateValueByEvent = useCallback(
|
|
180
|
+
(
|
|
181
|
+
eventType: InputEventOption[0],
|
|
182
|
+
target: Required<ValueOptions>,
|
|
183
|
+
x: number,
|
|
184
|
+
) => {
|
|
185
|
+
let v
|
|
186
|
+
if (eventType == 'normalized') {
|
|
187
|
+
const n = normalizeValue(
|
|
188
|
+
target.value,
|
|
189
|
+
target.min,
|
|
190
|
+
target.max,
|
|
191
|
+
target.skew,
|
|
192
|
+
)
|
|
193
|
+
v = rawValue(n + x, target.min, target.max, target.skew)
|
|
194
|
+
} else {
|
|
195
|
+
v = target.value + x
|
|
196
|
+
}
|
|
197
|
+
return clamp(stepValue(v, target.step), target.min, target.max)
|
|
198
|
+
},
|
|
199
|
+
[],
|
|
200
|
+
)
|
|
201
|
+
|
|
167
202
|
const handleKeyDown = useCallback(
|
|
168
203
|
(event: React.KeyboardEvent<HTMLDivElement>) => {
|
|
169
204
|
if (!onChange || readonly) return
|
|
@@ -176,23 +211,7 @@ export const XYPad = forwardRef<XYPadMethods, Props>(
|
|
|
176
211
|
let delta = target.keyboard[1]
|
|
177
212
|
if (key == 'ArrowLeft' || key == 'ArrowUp') delta *= -1
|
|
178
213
|
if (target.reverse) delta *= -1
|
|
179
|
-
|
|
180
|
-
if (target.keyboard[0] == 'normalized') {
|
|
181
|
-
const n = normalizeValue(
|
|
182
|
-
target.value,
|
|
183
|
-
target.min,
|
|
184
|
-
target.max,
|
|
185
|
-
target.skew,
|
|
186
|
-
)
|
|
187
|
-
v = rawValue(n + delta, target.min, target.max, target.skew)
|
|
188
|
-
} else {
|
|
189
|
-
v = target.value + delta
|
|
190
|
-
}
|
|
191
|
-
const newValue = clamp(
|
|
192
|
-
stepValue(v, target.step),
|
|
193
|
-
target.min,
|
|
194
|
-
target.max,
|
|
195
|
-
)
|
|
214
|
+
const newValue = updateValueByEvent(target.keyboard[0], target, delta)
|
|
196
215
|
if (isHorizontal) {
|
|
197
216
|
onChange(newValue, y.value)
|
|
198
217
|
} else {
|
|
@@ -200,7 +219,7 @@ export const XYPad = forwardRef<XYPadMethods, Props>(
|
|
|
200
219
|
}
|
|
201
220
|
}
|
|
202
221
|
},
|
|
203
|
-
[x, y,
|
|
222
|
+
[onChange, readonly, x, y, updateValueByEvent],
|
|
204
223
|
)
|
|
205
224
|
|
|
206
225
|
// --- hooks ---
|
|
@@ -221,23 +240,7 @@ export const XYPad = forwardRef<XYPadMethods, Props>(
|
|
|
221
240
|
let delta = target.wheel[1]
|
|
222
241
|
if (event.deltaY < 0) delta *= -1
|
|
223
242
|
if (target.reverse) delta *= -1
|
|
224
|
-
|
|
225
|
-
if (target.wheel[0] == 'normalized') {
|
|
226
|
-
const n = normalizeValue(
|
|
227
|
-
target.value,
|
|
228
|
-
target.min,
|
|
229
|
-
target.max,
|
|
230
|
-
target.skew,
|
|
231
|
-
)
|
|
232
|
-
v = rawValue(n + delta, target.min, target.max, target.skew)
|
|
233
|
-
} else {
|
|
234
|
-
v = target.value + delta
|
|
235
|
-
}
|
|
236
|
-
const newValue = clamp(
|
|
237
|
-
stepValue(v, target.step),
|
|
238
|
-
target.min,
|
|
239
|
-
target.max,
|
|
240
|
-
)
|
|
243
|
+
const newValue = updateValueByEvent(target.wheel[0], target, delta)
|
|
241
244
|
if (event.shiftKey) {
|
|
242
245
|
onChange(newValue, y.value)
|
|
243
246
|
} else {
|
|
@@ -247,7 +250,7 @@ export const XYPad = forwardRef<XYPadMethods, Props>(
|
|
|
247
250
|
{
|
|
248
251
|
passive: false,
|
|
249
252
|
},
|
|
250
|
-
[x, y],
|
|
253
|
+
[x, y, onChange, readonly, updateValueByEvent],
|
|
251
254
|
)
|
|
252
255
|
|
|
253
256
|
useEventListener(globalThis.window, 'mousemove', (event) => {
|
|
@@ -255,7 +258,9 @@ export const XYPad = forwardRef<XYPadMethods, Props>(
|
|
|
255
258
|
})
|
|
256
259
|
|
|
257
260
|
useEventListener(globalThis.window, 'mouseup', () => {
|
|
261
|
+
if (!thumbDragged.current || readonly) return
|
|
258
262
|
thumbDragged.current = false
|
|
263
|
+
onDragEnd?.(x.value, y.value)
|
|
259
264
|
if (bodyNoSelect) removeNoSelect()
|
|
260
265
|
})
|
|
261
266
|
|
|
@@ -289,11 +294,22 @@ export const XYPad = forwardRef<XYPadMethods, Props>(
|
|
|
289
294
|
}}
|
|
290
295
|
onPointerDown={(event) => {
|
|
291
296
|
thumbDragged.current = true
|
|
292
|
-
handleValue(event)
|
|
297
|
+
const v = handleValue(event)
|
|
298
|
+
if (!readonly) onDragStart?.(v?.[0] ?? x.value, v?.[1] ?? y.value)
|
|
299
|
+
onPointerDown?.(event)
|
|
300
|
+
}}
|
|
301
|
+
onKeyDown={(event) => {
|
|
302
|
+
handleKeyDown(event)
|
|
303
|
+
onKeyDown?.(event)
|
|
304
|
+
}}
|
|
305
|
+
onFocus={(event) => {
|
|
306
|
+
thumbRef.current?.focus()
|
|
307
|
+
onFocus?.(event)
|
|
308
|
+
}}
|
|
309
|
+
onBlur={(event) => {
|
|
310
|
+
thumbRef.current?.blur()
|
|
311
|
+
onBlur?.(event)
|
|
293
312
|
}}
|
|
294
|
-
onKeyDown={handleKeyDown}
|
|
295
|
-
onFocus={thumbRef.current?.focus}
|
|
296
|
-
onBlur={thumbRef.current?.blur}
|
|
297
313
|
{...props}
|
|
298
314
|
>
|
|
299
315
|
<div className="tremolo-xy-pad-area-wrapper" ref={areaElementRef}>
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { useEffect, useRef } from 'react'
|
|
2
|
+
|
|
3
|
+
export function useInterval(callback: () => void, delay: number | null) {
|
|
4
|
+
const savedCallback = useRef(callback)
|
|
5
|
+
|
|
6
|
+
// Remember the latest callback if it changes.
|
|
7
|
+
useEffect(() => {
|
|
8
|
+
savedCallback.current = callback
|
|
9
|
+
}, [callback])
|
|
10
|
+
|
|
11
|
+
// Set up the interval.
|
|
12
|
+
useEffect(() => {
|
|
13
|
+
// Don't schedule if no delay is specified.
|
|
14
|
+
// Note: 0 is a valid value for delay.
|
|
15
|
+
if (delay === null) {
|
|
16
|
+
return
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
const id = setInterval(() => {
|
|
20
|
+
savedCallback.current()
|
|
21
|
+
}, delay)
|
|
22
|
+
|
|
23
|
+
return () => {
|
|
24
|
+
clearInterval(id)
|
|
25
|
+
}
|
|
26
|
+
}, [delay])
|
|
27
|
+
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import { useCallback, useState } from 'react'
|
|
2
|
+
|
|
3
|
+
import { useEventListener } from './useEventListener'
|
|
4
|
+
import { useInterval } from './useInterval'
|
|
5
|
+
|
|
6
|
+
export function useLongPress(
|
|
7
|
+
callback: () => void,
|
|
8
|
+
initialDelay = 500,
|
|
9
|
+
interval = 40,
|
|
10
|
+
) {
|
|
11
|
+
const [pressed, setPressed] = useState(false)
|
|
12
|
+
const [delay, setDelay] = useState(initialDelay)
|
|
13
|
+
|
|
14
|
+
useInterval(
|
|
15
|
+
() => {
|
|
16
|
+
callback()
|
|
17
|
+
setDelay(interval)
|
|
18
|
+
},
|
|
19
|
+
pressed ? delay : null,
|
|
20
|
+
)
|
|
21
|
+
|
|
22
|
+
useEventListener(globalThis.window, 'pointerup', () => {
|
|
23
|
+
setPressed(false)
|
|
24
|
+
setDelay(initialDelay)
|
|
25
|
+
})
|
|
26
|
+
|
|
27
|
+
return useCallback(() => {
|
|
28
|
+
callback()
|
|
29
|
+
setPressed(true)
|
|
30
|
+
}, [callback])
|
|
31
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -14,3 +14,9 @@ export * from './components/Piano'
|
|
|
14
14
|
export * from './components/Slider'
|
|
15
15
|
export * from './components/WheelObserver'
|
|
16
16
|
export * from './components/XYPad'
|
|
17
|
+
|
|
18
|
+
export * from './hooks/useAnimationFrame'
|
|
19
|
+
export * from './hooks/useDrag'
|
|
20
|
+
export * from './hooks/useEventListener'
|
|
21
|
+
export * from './hooks/useInterval'
|
|
22
|
+
export * from './hooks/useLongPress'
|