@tremolo-ui/react 0.0.12 → 0.1.0-alpha.0

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.
Files changed (57) hide show
  1. package/dist/cjs/index.js +316 -232
  2. package/dist/cjs/index.js.map +1 -1
  3. package/dist/cjs/types/components/Knob/index.d.ts +12 -0
  4. package/dist/cjs/types/components/Knob/index.d.ts.map +1 -1
  5. package/dist/cjs/types/components/Piano/KeyLabel.d.ts +1 -3
  6. package/dist/cjs/types/components/Piano/KeyLabel.d.ts.map +1 -1
  7. package/dist/cjs/types/components/Piano/context.d.ts +24 -0
  8. package/dist/cjs/types/components/Piano/context.d.ts.map +1 -0
  9. package/dist/cjs/types/components/Piano/index.d.ts +9 -9
  10. package/dist/cjs/types/components/Piano/index.d.ts.map +1 -1
  11. package/dist/cjs/types/components/Piano/key.d.ts +10 -19
  12. package/dist/cjs/types/components/Piano/key.d.ts.map +1 -1
  13. package/dist/cjs/types/components/Slider/index.d.ts.map +1 -1
  14. package/dist/cjs/types/components/XYPad/index.d.ts.map +1 -1
  15. package/dist/cjs/types/hooks/useDrag.d.ts.map +1 -1
  16. package/dist/cjs/types/hooks/useDragWithElement.d.ts +16 -0
  17. package/dist/cjs/types/hooks/useDragWithElement.d.ts.map +1 -0
  18. package/dist/esm/index.js +316 -233
  19. package/dist/esm/index.js.map +1 -1
  20. package/dist/esm/types/components/Knob/index.d.ts +12 -0
  21. package/dist/esm/types/components/Knob/index.d.ts.map +1 -1
  22. package/dist/esm/types/components/Piano/KeyLabel.d.ts +1 -3
  23. package/dist/esm/types/components/Piano/KeyLabel.d.ts.map +1 -1
  24. package/dist/esm/types/components/Piano/context.d.ts +24 -0
  25. package/dist/esm/types/components/Piano/context.d.ts.map +1 -0
  26. package/dist/esm/types/components/Piano/index.d.ts +9 -9
  27. package/dist/esm/types/components/Piano/index.d.ts.map +1 -1
  28. package/dist/esm/types/components/Piano/key.d.ts +10 -19
  29. package/dist/esm/types/components/Piano/key.d.ts.map +1 -1
  30. package/dist/esm/types/components/Slider/index.d.ts.map +1 -1
  31. package/dist/esm/types/components/XYPad/index.d.ts.map +1 -1
  32. package/dist/esm/types/hooks/useDrag.d.ts.map +1 -1
  33. package/dist/esm/types/hooks/useDragWithElement.d.ts +16 -0
  34. package/dist/esm/types/hooks/useDragWithElement.d.ts.map +1 -0
  35. package/dist/styles/index.css +2 -0
  36. package/package.json +2 -1
  37. package/src/components/Knob/index.tsx +14 -0
  38. package/src/components/Piano/KeyLabel.tsx +9 -5
  39. package/src/components/Piano/context.tsx +108 -0
  40. package/src/components/Piano/index.css +2 -0
  41. package/src/components/Piano/index.tsx +186 -114
  42. package/src/components/Piano/key.tsx +215 -0
  43. package/src/components/Slider/index.tsx +40 -52
  44. package/src/components/XYPad/index.tsx +64 -54
  45. package/src/hooks/useDrag.ts +6 -7
  46. package/src/hooks/useDragWithElement.ts +76 -0
  47. package/dist/cjs/types/components/Piano/BlackKey.d.ts +0 -5
  48. package/dist/cjs/types/components/Piano/BlackKey.d.ts.map +0 -1
  49. package/dist/cjs/types/components/Piano/WhiteKey.d.ts +0 -7
  50. package/dist/cjs/types/components/Piano/WhiteKey.d.ts.map +0 -1
  51. package/dist/esm/types/components/Piano/BlackKey.d.ts +0 -5
  52. package/dist/esm/types/components/Piano/BlackKey.d.ts.map +0 -1
  53. package/dist/esm/types/components/Piano/WhiteKey.d.ts +0 -7
  54. package/dist/esm/types/components/Piano/WhiteKey.d.ts.map +0 -1
  55. package/src/components/Piano/BlackKey.tsx +0 -132
  56. package/src/components/Piano/WhiteKey.tsx +0 -134
  57. package/src/components/Piano/key.ts +0 -51
@@ -21,7 +21,7 @@ import {
21
21
  xor,
22
22
  } from '@tremolo-ui/functions'
23
23
 
24
- import { useEventListener } from '../../hooks/useEventListener'
24
+ import { useDragWithElement } from '../../hooks/useDragWithElement'
25
25
  import { useRefCallbackEvent } from '../../hooks/useRefCallbackEvent'
26
26
  import { addNoSelect, removeNoSelect } from '../_util'
27
27
 
@@ -117,7 +117,6 @@ export const Slider = forwardRef<SliderMethods, Props>(
117
117
  // -- state and ref ---
118
118
  const trackElementRef = useRef<HTMLDivElement>(null)
119
119
  const thumbRef = useRef<SliderThumbMethods>(null)
120
- const thumbDragged = useRef(false)
121
120
 
122
121
  // --- interpret props ---
123
122
  const p = toFixed(normalizeValue(value, min, max, skew) * 100)
@@ -155,36 +154,16 @@ export const Slider = forwardRef<SliderMethods, Props>(
155
154
  }
156
155
 
157
156
  // --- internal functions ---
158
- const handleValue = (
159
- event: MouseEvent | React.PointerEvent<HTMLDivElement> | TouchEvent,
160
- ) => {
161
- if (
162
- !trackElementRef.current ||
163
- !thumbDragged.current ||
164
- !onChange ||
165
- readonly
166
- ) {
167
- return
168
- }
169
- const isTouch = event instanceof TouchEvent
170
- if (isTouch && event.cancelable) event.preventDefault()
171
- if (bodyNoSelect) addNoSelect()
172
- const {
173
- left: x1,
174
- top: y1,
175
- right: x2,
176
- bottom: y2,
177
- } = trackElementRef.current.getBoundingClientRect()
178
- const mouseX = isTouch ? event.touches[0].clientX : event.clientX
179
- const mouseY = isTouch ? event.touches[0].clientY : event.clientY
180
- const n = vertical
181
- ? normalizeValue(mouseY, y1, y2)
182
- : normalizeValue(mouseX, x1, x2)
183
- const v = rawValue(displayReversed ? 1 - n : n, min, max, skew)
184
- const v2 = clamp(stepValue(v, step), min, max)
185
- onChange(v2)
186
- return v2
187
- }
157
+ const onDrag = useCallback(
158
+ (nx: number, ny: number) => {
159
+ if (!onChange || readonly) return
160
+ const n = vertical ? ny : nx
161
+ const v = rawValue(displayReversed ? 1 - n : n, min, max, skew)
162
+ const v2 = clamp(stepValue(v, step), min, max)
163
+ onChange(v2)
164
+ },
165
+ [displayReversed, max, min, onChange, readonly, skew, step, vertical],
166
+ )
188
167
 
189
168
  const updateValueByEvent = useCallback(
190
169
  (eventType: InputEventOption[0], x: number) => {
@@ -216,12 +195,34 @@ export const Slider = forwardRef<SliderMethods, Props>(
216
195
  )
217
196
 
218
197
  // --- hooks ---
219
- const touchMoveRefCallback = useRefCallbackEvent(
220
- 'touchmove',
221
- handleValue,
222
- { passive: false },
223
- [min, max, skew, step, vertical, reverse, onChange, readonly],
224
- )
198
+ const [touchMoveRefCallback, pointerDownHandler] =
199
+ useDragWithElement<HTMLDivElement>({
200
+ baseElementRef: trackElementRef,
201
+ onDrag: onDrag,
202
+ onDragStart: (nx, ny) => {
203
+ if (readonly) return
204
+ if (bodyNoSelect) addNoSelect()
205
+ thumbRef.current?.focus()
206
+ onDragStart?.(
207
+ clamp(
208
+ stepValue(rawValue(vertical ? ny : nx, min, max, skew), step),
209
+ min,
210
+ max,
211
+ ),
212
+ )
213
+ },
214
+ onDragEnd: (nx, ny) => {
215
+ if (readonly) return
216
+ if (bodyNoSelect) removeNoSelect()
217
+ onDragEnd?.(
218
+ clamp(
219
+ stepValue(rawValue(vertical ? ny : nx, min, max, skew), step),
220
+ min,
221
+ max,
222
+ ),
223
+ )
224
+ },
225
+ })
225
226
 
226
227
  const wheelRefCallback = useRefCallbackEvent(
227
228
  'wheel',
@@ -244,17 +245,6 @@ export const Slider = forwardRef<SliderMethods, Props>(
244
245
  [wheel, vertical, readonly, onChange, updateValueByEvent],
245
246
  )
246
247
 
247
- useEventListener(globalThis.window, 'mousemove', (event) => {
248
- handleValue(event)
249
- })
250
-
251
- useEventListener(globalThis.window, 'mouseup', () => {
252
- if (!thumbDragged.current || readonly) return
253
- thumbDragged.current = false
254
- onDragEnd?.(value)
255
- if (bodyNoSelect) removeNoSelect()
256
- })
257
-
258
248
  useImperativeHandle(ref, () => {
259
249
  return {
260
250
  focus() {
@@ -296,9 +286,7 @@ export const Slider = forwardRef<SliderMethods, Props>(
296
286
  ...style,
297
287
  }}
298
288
  onPointerDown={(event) => {
299
- thumbDragged.current = true
300
- const v = handleValue(event)
301
- if (!readonly) onDragStart?.(v ?? value)
289
+ pointerDownHandler(event)
302
290
  onPointerDown?.(event)
303
291
  }}
304
292
  onKeyDown={(event) => {
@@ -19,7 +19,7 @@ import {
19
19
  styleHelper,
20
20
  } from '@tremolo-ui/functions'
21
21
 
22
- import { useEventListener } from '../../hooks/useEventListener'
22
+ import { useDragWithElement } from '../../hooks/useDragWithElement'
23
23
  import { useRefCallbackEvent } from '../../hooks/useRefCallbackEvent'
24
24
  import { addNoSelect, removeNoSelect } from '../_util'
25
25
 
@@ -118,7 +118,6 @@ export const XYPad = forwardRef<XYPadMethods, Props>(
118
118
  // -- state and ref ---
119
119
  const areaElementRef = useRef<HTMLDivElement>(null)
120
120
  const thumbRef = useRef<XYPadThumbMethods>(null)
121
- const thumbDragged = useRef(false)
122
121
 
123
122
  // --- interpret props ---
124
123
  const nx = normalizeValue(x.value, x.min, x.max, x.skew)
@@ -126,8 +125,8 @@ export const XYPad = forwardRef<XYPadMethods, Props>(
126
125
  const percentX = toFixed((x.reverse ? 1 - nx : nx) * 100)
127
126
  const percentY = toFixed((y.reverse ? 1 - ny : ny) * 100)
128
127
 
129
- let areaProps: AreaProps = {},
130
- thumbProps: ThumbProps = {}
128
+ let areaProps: AreaProps = {}
129
+ let thumbProps: ThumbProps = {}
131
130
  if (children != undefined) {
132
131
  React.Children.forEach(children, (child) => {
133
132
  if (React.isValidElement(child)) {
@@ -145,36 +144,30 @@ export const XYPad = forwardRef<XYPadMethods, Props>(
145
144
  }
146
145
 
147
146
  // --- internal functions ---
148
- const handleValue = (
149
- event: MouseEvent | React.PointerEvent<HTMLDivElement> | TouchEvent,
150
- ) => {
151
- if (
152
- !areaElementRef.current ||
153
- !thumbDragged.current ||
154
- !onChange ||
155
- readonly
156
- )
157
- return
158
- const isTouch = event instanceof TouchEvent
159
- if (isTouch && event.cancelable) event.preventDefault()
160
- if (bodyNoSelect) addNoSelect()
161
- const {
162
- left: x1,
163
- top: y1,
164
- right: x2,
165
- bottom: y2,
166
- } = areaElementRef.current.getBoundingClientRect()
167
- const mouseX = isTouch ? event.touches[0].clientX : event.clientX
168
- const mouseY = isTouch ? event.touches[0].clientY : event.clientY
169
- const nx = normalizeValue(mouseX, x1, x2)
170
- const ny = normalizeValue(mouseY, y1, y2)
171
- const vx = rawValue(x.reverse ? 1 - nx : nx, x.min, x.max, x.skew)
172
- const vy = rawValue(y.reverse ? 1 - ny : ny, y.min, y.max, y.skew)
173
- const newX = clamp(stepValue(vx, x.step), x.min, x.max)
174
- const newY = clamp(stepValue(vy, y.step), y.min, y.max)
175
- onChange(newX, newY)
176
- return [newX, newY]
177
- }
147
+ const onDrag = useCallback(
148
+ (nx: number, ny: number) => {
149
+ if (!onChange || readonly) return
150
+ const vx = rawValue(x.reverse ? 1 - nx : nx, x.min, x.max, x.skew)
151
+ const vy = rawValue(y.reverse ? 1 - ny : ny, y.min, y.max, y.skew)
152
+ const newX = clamp(stepValue(vx, x.step), x.min, x.max)
153
+ const newY = clamp(stepValue(vy, y.step), y.min, y.max)
154
+ onChange(newX, newY)
155
+ },
156
+ [
157
+ onChange,
158
+ readonly,
159
+ x.max,
160
+ x.min,
161
+ x.reverse,
162
+ x.skew,
163
+ x.step,
164
+ y.max,
165
+ y.min,
166
+ y.reverse,
167
+ y.skew,
168
+ y.step,
169
+ ],
170
+ )
178
171
 
179
172
  const updateValueByEvent = useCallback(
180
173
  (
@@ -223,12 +216,42 @@ export const XYPad = forwardRef<XYPadMethods, Props>(
223
216
  )
224
217
 
225
218
  // --- hooks ---
226
- const touchMoveRefCallback = useRefCallbackEvent(
227
- 'touchmove',
228
- handleValue,
229
- { passive: false },
230
- [x, onChange, readonly],
231
- )
219
+ const [touchMoveRefCallback, pointerDownHandler] =
220
+ useDragWithElement<HTMLDivElement>({
221
+ baseElementRef: areaElementRef,
222
+ onDrag: onDrag,
223
+ onDragStart: (nx, ny) => {
224
+ if (readonly) return
225
+ if (bodyNoSelect) addNoSelect()
226
+ thumbRef.current?.focus()
227
+ const valueX = clamp(
228
+ stepValue(rawValue(nx, x.min, x.max, x.skew), x.step),
229
+ x.min,
230
+ x.max,
231
+ )
232
+ const valueY = clamp(
233
+ stepValue(rawValue(ny, y.min, y.max, y.skew), y.step),
234
+ y.min,
235
+ y.max,
236
+ )
237
+ onDragStart?.(valueX, valueY)
238
+ },
239
+ onDragEnd: (nx, ny) => {
240
+ if (readonly) return
241
+ if (bodyNoSelect) removeNoSelect()
242
+ const valueX = clamp(
243
+ stepValue(rawValue(nx, x.min, x.max, x.skew), x.step),
244
+ x.min,
245
+ x.max,
246
+ )
247
+ const valueY = clamp(
248
+ stepValue(rawValue(ny, y.min, y.max, y.skew), y.step),
249
+ y.min,
250
+ y.max,
251
+ )
252
+ onDragEnd?.(valueX, valueY)
253
+ },
254
+ })
232
255
 
233
256
  const wheelRefCallback = useRefCallbackEvent(
234
257
  'wheel',
@@ -253,17 +276,6 @@ export const XYPad = forwardRef<XYPadMethods, Props>(
253
276
  [x, y, onChange, readonly, updateValueByEvent],
254
277
  )
255
278
 
256
- useEventListener(globalThis.window, 'mousemove', (event) => {
257
- handleValue(event)
258
- })
259
-
260
- useEventListener(globalThis.window, 'mouseup', () => {
261
- if (!thumbDragged.current || readonly) return
262
- thumbDragged.current = false
263
- onDragEnd?.(x.value, y.value)
264
- if (bodyNoSelect) removeNoSelect()
265
- })
266
-
267
279
  useImperativeHandle(ref, () => {
268
280
  return {
269
281
  focus() {
@@ -293,9 +305,7 @@ export const XYPad = forwardRef<XYPadMethods, Props>(
293
305
  ...style,
294
306
  }}
295
307
  onPointerDown={(event) => {
296
- thumbDragged.current = true
297
- const v = handleValue(event)
298
- if (!readonly) onDragStart?.(v?.[0] ?? x.value, v?.[1] ?? y.value)
308
+ pointerDownHandler(event)
299
309
  onPointerDown?.(event)
300
310
  }}
301
311
  onKeyDown={(event) => {
@@ -52,13 +52,12 @@ export function useDrag<T extends Element>({
52
52
  dragOffsetY.current = screenY
53
53
  }
54
54
  if (Math.abs(deltaX) < threshold && Math.abs(deltaY) < threshold) return
55
- if (onDrag)
56
- onDrag(
57
- screenX - dragStartX.current,
58
- screenY - dragStartY.current,
59
- deltaX,
60
- deltaY,
61
- )
55
+ onDrag(
56
+ screenX - dragStartX.current,
57
+ screenY - dragStartY.current,
58
+ deltaX,
59
+ deltaY,
60
+ )
62
61
  },
63
62
  [threshold, onDrag],
64
63
  )
@@ -0,0 +1,76 @@
1
+ import { useRef, useCallback, RefObject } from 'react'
2
+
3
+ import { normalizeValue } from '@tremolo-ui/functions'
4
+
5
+ import { useEventListener } from './useEventListener'
6
+ import { useRefCallbackEvent } from './useRefCallbackEvent'
7
+
8
+ interface Props<T extends Element> {
9
+ baseElementRef: RefObject<T | null>
10
+ onDrag: (normalizedX: number, normalizedY: number) => void
11
+ onDragStart?: (normalizedX: number, normalizedY: number) => void
12
+ onDragEnd?: (normalizedX: number, normalizedY: number) => void
13
+ }
14
+
15
+ /**
16
+ * @returns [refCallback, pointerDownHandler]
17
+ */
18
+ export function useDragWithElement<T extends Element>({
19
+ baseElementRef,
20
+ onDrag,
21
+ onDragStart,
22
+ onDragEnd,
23
+ }: Props<T>): [
24
+ (div: EventTarget | null) => void,
25
+ (event: React.PointerEvent<T>) => void,
26
+ ] {
27
+ const dragged = useRef(false)
28
+ const normalizedX = useRef(0)
29
+ const normalizedY = useRef(0)
30
+
31
+ const handleDrag = useCallback(
32
+ (event: MouseEvent | React.PointerEvent<T> | TouchEvent) => {
33
+ if (!baseElementRef.current || !dragged.current) {
34
+ return
35
+ }
36
+ const isTouch = event instanceof TouchEvent
37
+ if (isTouch && event.cancelable) event.preventDefault()
38
+ const { left, top, right, bottom } =
39
+ baseElementRef.current.getBoundingClientRect()
40
+ const mouseX = isTouch ? event.touches[0].clientX : event.clientX
41
+ const mouseY = isTouch ? event.touches[0].clientY : event.clientY
42
+ const nx = normalizeValue(mouseX, left, right)
43
+ const ny = normalizeValue(mouseY, top, bottom)
44
+ normalizedX.current = nx
45
+ normalizedY.current = ny
46
+ onDrag(nx, ny)
47
+ },
48
+ [onDrag, baseElementRef],
49
+ )
50
+
51
+ const refHandler = useRefCallbackEvent(
52
+ 'touchmove',
53
+ handleDrag,
54
+ { passive: false },
55
+ [onDrag],
56
+ )
57
+
58
+ const pointerDownHandler = useCallback(
59
+ (event: React.PointerEvent<T>) => {
60
+ dragged.current = true
61
+ handleDrag(event)
62
+ onDragStart?.(normalizedX.current, normalizedY.current)
63
+ },
64
+ [handleDrag, onDragStart],
65
+ )
66
+
67
+ useEventListener(globalThis.window, 'pointermove', handleDrag)
68
+
69
+ useEventListener(globalThis.window, 'pointerup', () => {
70
+ if (!dragged.current) return
71
+ dragged.current = false
72
+ onDragEnd?.(normalizedX.current, normalizedY.current)
73
+ })
74
+
75
+ return [refHandler, pointerDownHandler]
76
+ }
@@ -1,5 +0,0 @@
1
- import React from 'react';
2
- import { KeyMethods, KeyProps } from './key';
3
- /** @category Piano */
4
- export declare const BlackKey: React.ForwardRefExoticComponent<KeyProps & Omit<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref">, keyof KeyProps> & React.RefAttributes<KeyMethods>>;
5
- //# sourceMappingURL=BlackKey.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"BlackKey.d.ts","sourceRoot":"","sources":["../../../../../src/components/Piano/BlackKey.tsx"],"names":[],"mappings":"AACA,OAAO,KAKN,MAAM,OAAO,CAAA;AAEd,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAM5C,sBAAsB;AACtB,eAAO,MAAM,QAAQ,gMAoHpB,CAAA"}
@@ -1,7 +0,0 @@
1
- import React from 'react';
2
- import { KeyMethods, KeyProps } from './key';
3
- /** @category Piano */
4
- export declare const defaultWhiteKeyWidth = 40;
5
- /** @category Piano */
6
- export declare const WhiteKey: React.ForwardRefExoticComponent<KeyProps & Omit<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref">, keyof KeyProps> & React.RefAttributes<KeyMethods>>;
7
- //# sourceMappingURL=WhiteKey.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"WhiteKey.d.ts","sourceRoot":"","sources":["../../../../../src/components/Piano/WhiteKey.tsx"],"names":[],"mappings":"AACA,OAAO,KAKN,MAAM,OAAO,CAAA;AAEd,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAK5C,sBAAsB;AACtB,eAAO,MAAM,oBAAoB,KAAK,CAAA;AAEtC,sBAAsB;AACtB,eAAO,MAAM,QAAQ,gMAoHpB,CAAA"}
@@ -1,5 +0,0 @@
1
- import React from 'react';
2
- import { KeyMethods, KeyProps } from './key';
3
- /** @category Piano */
4
- export declare const BlackKey: React.ForwardRefExoticComponent<KeyProps & Omit<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref">, keyof KeyProps> & React.RefAttributes<KeyMethods>>;
5
- //# sourceMappingURL=BlackKey.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"BlackKey.d.ts","sourceRoot":"","sources":["../../../../../src/components/Piano/BlackKey.tsx"],"names":[],"mappings":"AACA,OAAO,KAKN,MAAM,OAAO,CAAA;AAEd,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAM5C,sBAAsB;AACtB,eAAO,MAAM,QAAQ,gMAoHpB,CAAA"}
@@ -1,7 +0,0 @@
1
- import React from 'react';
2
- import { KeyMethods, KeyProps } from './key';
3
- /** @category Piano */
4
- export declare const defaultWhiteKeyWidth = 40;
5
- /** @category Piano */
6
- export declare const WhiteKey: React.ForwardRefExoticComponent<KeyProps & Omit<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref">, keyof KeyProps> & React.RefAttributes<KeyMethods>>;
7
- //# sourceMappingURL=WhiteKey.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"WhiteKey.d.ts","sourceRoot":"","sources":["../../../../../src/components/Piano/WhiteKey.tsx"],"names":[],"mappings":"AACA,OAAO,KAKN,MAAM,OAAO,CAAA;AAEd,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAK5C,sBAAsB;AACtB,eAAO,MAAM,oBAAoB,KAAK,CAAA;AAEtC,sBAAsB;AACtB,eAAO,MAAM,QAAQ,gMAoHpB,CAAA"}
@@ -1,132 +0,0 @@
1
- import clsx from 'clsx'
2
- import React, {
3
- ComponentPropsWithoutRef,
4
- forwardRef,
5
- useImperativeHandle,
6
- useState,
7
- } from 'react'
8
-
9
- import { KeyMethods, KeyProps } from './key'
10
- import { KeyLabel, KeyLabelProps } from './KeyLabel'
11
- import { defaultWhiteKeyWidth } from './WhiteKey'
12
-
13
- type Props = KeyProps & Omit<ComponentPropsWithoutRef<'div'>, keyof KeyProps>
14
-
15
- /** @category Piano */
16
- export const BlackKey = forwardRef<KeyMethods, Props>(
17
- (
18
- {
19
- width = defaultWhiteKeyWidth * 0.65,
20
- height = '60%',
21
- bg,
22
- color,
23
- activeBg,
24
- activeColor,
25
- className,
26
- style,
27
- children,
28
- __glissando,
29
- __position,
30
- __note,
31
- __disabled,
32
- __index,
33
- __fill,
34
- __width,
35
- __onPlayNote,
36
- __onStopNote,
37
- __label,
38
- onContextMenu = (e) => e.preventDefault(),
39
- ...props
40
- }: Props,
41
- ref,
42
- ) => {
43
- const [played, setPlayed] = useState(false)
44
-
45
- const colors = {
46
- '--bg': bg,
47
- '--color': color,
48
- '--active-bg': activeBg,
49
- '--active-color': activeColor,
50
- }
51
-
52
- useImperativeHandle(ref, () => {
53
- return {
54
- play() {
55
- if (__disabled) return
56
- setPlayed(true)
57
- if (__onPlayNote) __onPlayNote(__note!)
58
- },
59
- stop() {
60
- setPlayed(false)
61
- if (__onStopNote) __onStopNote(__note!)
62
- },
63
- played() {
64
- return played
65
- },
66
- }
67
- }, [__disabled, __note, __onPlayNote, __onStopNote, played])
68
-
69
- let keyLabelProps: KeyLabelProps = {}
70
- if (children != undefined) {
71
- React.Children.forEach(children, (child) => {
72
- if (React.isValidElement(child)) {
73
- if (child.type == KeyLabel) {
74
- keyLabelProps = child.props as KeyLabelProps
75
- } else {
76
- throw new Error('only <KeyLabel>')
77
- }
78
- } else {
79
- throw new Error('children is an invalid element.')
80
- }
81
- })
82
- }
83
-
84
- return (
85
- <div
86
- className={clsx(`tremolo-piano-black-key`, className)}
87
- aria-disabled={__disabled}
88
- data-active={played}
89
- style={{
90
- ...colors,
91
- left: __position,
92
- width: __fill ? __width : (width ?? __width),
93
- height: height,
94
- ...style,
95
- }}
96
- onPointerDown={() => {
97
- if (__disabled) return
98
- setPlayed(true)
99
- if (__onPlayNote) __onPlayNote(__note!)
100
- }}
101
- onPointerEnter={() => {
102
- if (__disabled) return
103
- if (__glissando) {
104
- setPlayed(true)
105
- if (__onPlayNote) __onPlayNote(__note!)
106
- }
107
- }}
108
- onPointerUp={() => {
109
- if (__disabled) return
110
- setPlayed(false)
111
- if (__onStopNote) __onStopNote(__note!)
112
- }}
113
- onPointerLeave={() => {
114
- if (__disabled) return
115
- if (__glissando) {
116
- setPlayed(false)
117
- if (__onStopNote) __onStopNote(__note!)
118
- }
119
- }}
120
- onContextMenu={onContextMenu}
121
- {...props}
122
- >
123
- <KeyLabel
124
- __note={__note}
125
- __label={__label}
126
- __index={__index}
127
- {...keyLabelProps}
128
- />
129
- </div>
130
- )
131
- },
132
- )