@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
package/dist/esm/index.js CHANGED
@@ -319,6 +319,13 @@ function isWhiteKey(note) {
319
319
  mod(n, 12) == 9 ||
320
320
  mod(n, 12) == 11);
321
321
  }
322
+ /**
323
+ * @param note noteNumber: 0 ~ 127 or noteName e.g. 'C3'
324
+ * @category MIDI
325
+ */
326
+ function isBlackKey(note) {
327
+ return !isWhiteKey(note);
328
+ }
322
329
 
323
330
  /**
324
331
  * This hook is user-land implementation of the experimental `useEffectEvent` hook.
@@ -399,8 +406,7 @@ function useDrag({ threshold = 1, onDrag, onDragStart, onDragEnd, }) {
399
406
  }
400
407
  if (Math.abs(deltaX) < threshold && Math.abs(deltaY) < threshold)
401
408
  return;
402
- if (onDrag)
403
- onDrag(screenX - dragStartX.current, screenY - dragStartY.current, deltaX, deltaY);
409
+ onDrag(screenX - dragStartX.current, screenY - dragStartY.current, deltaX, deltaY);
404
410
  }, [threshold, onDrag]);
405
411
  const refHandler = useRefCallbackEvent('touchmove', handleDrag, { passive: false }, [onDrag]);
406
412
  const pointerDownHandler = useCallback((event) => {
@@ -667,7 +673,7 @@ const Knob = forwardRef((_a, ref) => {
667
673
  elmRef.current = div;
668
674
  wheelRefCallback(div);
669
675
  touchMoveRefCallback(div);
670
- }, width: size, height: size, tabIndex: 0, "aria-valuenow": value, "aria-valuemin": min, "aria-valuemax": max, "aria-disabled": disabled, "aria-readonly": readonly, onPointerDown: (event) => {
676
+ }, width: size, height: size, tabIndex: 0, role: "slider", "aria-valuenow": value, "aria-valuemin": min, "aria-valuemax": max, "aria-disabled": disabled, "aria-readonly": readonly, onPointerDown: (event) => {
671
677
  pointerDownHandler(event);
672
678
  onPointerDown === null || onPointerDown === void 0 ? void 0 : onPointerDown(event);
673
679
  }, onDoubleClick: (event) => {
@@ -1057,21 +1063,73 @@ const NumberInput = forwardRef((_a, ref) => {
1057
1063
  tabIndex: 0, style: Object.assign({}, colors), "data-stepper": !!children, "data-variant": variant, children: [jsx(InternalInput, Object.assign({ ref: ref, readonly: readonly, disabled: disabled, selectWithFocus: selectWithFocus, blurOnEnter: blurOnEnter, clampValueOnBlur: clampValueOnBlur, wheel: wheel, keyboard: keyboard, className: className, onChange: onChange, onFocus: onFocus, onBlur: onBlur }, props)), children] }) }));
1058
1064
  });
1059
1065
 
1066
+ /**
1067
+ * @returns [refCallback, pointerDownHandler]
1068
+ */
1069
+ function useDragWithElement({ baseElementRef, onDrag, onDragStart, onDragEnd, }) {
1070
+ const dragged = useRef(false);
1071
+ const normalizedX = useRef(0);
1072
+ const normalizedY = useRef(0);
1073
+ const handleDrag = useCallback((event) => {
1074
+ if (!baseElementRef.current || !dragged.current) {
1075
+ return;
1076
+ }
1077
+ const isTouch = event instanceof TouchEvent;
1078
+ if (isTouch && event.cancelable)
1079
+ event.preventDefault();
1080
+ const { left, top, right, bottom } = baseElementRef.current.getBoundingClientRect();
1081
+ const mouseX = isTouch ? event.touches[0].clientX : event.clientX;
1082
+ const mouseY = isTouch ? event.touches[0].clientY : event.clientY;
1083
+ const nx = normalizeValue(mouseX, left, right);
1084
+ const ny = normalizeValue(mouseY, top, bottom);
1085
+ normalizedX.current = nx;
1086
+ normalizedY.current = ny;
1087
+ onDrag(nx, ny);
1088
+ }, [onDrag, baseElementRef]);
1089
+ const refHandler = useRefCallbackEvent('touchmove', handleDrag, { passive: false }, [onDrag]);
1090
+ const pointerDownHandler = useCallback((event) => {
1091
+ dragged.current = true;
1092
+ handleDrag(event);
1093
+ onDragStart === null || onDragStart === void 0 ? void 0 : onDragStart(normalizedX.current, normalizedY.current);
1094
+ }, [handleDrag, onDragStart]);
1095
+ useEventListener(globalThis.window, 'pointermove', handleDrag);
1096
+ useEventListener(globalThis.window, 'pointerup', () => {
1097
+ if (!dragged.current)
1098
+ return;
1099
+ dragged.current = false;
1100
+ onDragEnd === null || onDragEnd === void 0 ? void 0 : onDragEnd(normalizedX.current, normalizedY.current);
1101
+ });
1102
+ return [refHandler, pointerDownHandler];
1103
+ }
1104
+
1060
1105
  /** @category Piano */
1061
1106
  function KeyLabel(_a) {
1062
- var { label, className, wrapperClassName, wrapperStyle, __note, __index, __label } = _a, props = __rest(_a, ["label", "className", "wrapperClassName", "wrapperStyle", "__note", "__index", "__label"]);
1107
+ var { label, className, wrapperClassName, wrapperStyle, __note, __label } = _a, props = __rest(_a, ["label", "className", "wrapperClassName", "wrapperStyle", "__note", "__label"]);
1108
+ const noteRange = usePianoContext((s) => s.noteRange);
1109
+ const noteRangeArray = getNoteRangeArray(noteRange);
1110
+ const index = noteRangeArray.indexOf(__note);
1063
1111
  const content = label
1064
- ? label(__note, __index)
1065
- : __label && __label(__note, __index);
1112
+ ? label(__note, index)
1113
+ : __label && __label(__note, index);
1066
1114
  return ((content != undefined || content != null) && (jsx("div", { className: clsx('tremolo-piano-key-label-wrapper', wrapperClassName), style: wrapperStyle, children: jsx("div", Object.assign({ className: clsx('tremolo-piano-key-label', className) }, props, { children: content })) })));
1067
1115
  }
1068
1116
 
1069
1117
  /** @category Piano */
1070
1118
  const defaultWhiteKeyWidth = 40;
1071
1119
  /** @category Piano */
1072
- const WhiteKey = forwardRef((_a, ref) => {
1073
- var { width = defaultWhiteKeyWidth, height = '100%', bg, color, activeBg, activeColor, className, style, children, __glissando, __position, __note, __disabled, __index, __fill, __width, __onPlayNote, __onStopNote, __label, onContextMenu = (e) => e.preventDefault() } = _a, props = __rest(_a, ["width", "height", "bg", "color", "activeBg", "activeColor", "className", "style", "children", "__glissando", "__position", "__note", "__disabled", "__index", "__fill", "__width", "__onPlayNote", "__onStopNote", "__label", "onContextMenu"]);
1120
+ const defaultBlackKeyWidth = 26;
1121
+ const KeyImpl = forwardRef((_a, ref) => {
1122
+ var { keyType, noteNumber, width, height, bg, color, activeBg, activeColor, className, style, children, __width } = _a, props = __rest(_a, ["keyType", "noteNumber", "width", "height", "bg", "color", "activeBg", "activeColor", "className", "style", "children", "__width"]);
1074
1123
  const [played, setPlayed] = useState(false);
1124
+ const midiMax = usePianoContext((s) => s.midiMax);
1125
+ const fill = usePianoContext((s) => s.fill);
1126
+ // const glissando = usePianoContext(s => s.glissando)
1127
+ const onPlayNote = usePianoContext((s) => s.onPlayNote);
1128
+ const onStopNote = usePianoContext((s) => s.onStopNote);
1129
+ const label = usePianoContext((s) => s.label);
1130
+ const notePosition = usePianoContext((s) => s.notePosition);
1131
+ const position = notePosition(noteNumber);
1132
+ const disabled = noteNumber > midiMax;
1075
1133
  const colors = {
1076
1134
  '--bg': bg,
1077
1135
  '--color': color,
@@ -1081,22 +1139,22 @@ const WhiteKey = forwardRef((_a, ref) => {
1081
1139
  useImperativeHandle(ref, () => {
1082
1140
  return {
1083
1141
  play() {
1084
- if (__disabled)
1142
+ if (disabled)
1085
1143
  return;
1086
1144
  setPlayed(true);
1087
- if (__onPlayNote)
1088
- __onPlayNote(__note);
1145
+ if (onPlayNote)
1146
+ onPlayNote(noteNumber);
1089
1147
  },
1090
1148
  stop() {
1091
1149
  setPlayed(false);
1092
- if (__onStopNote)
1093
- __onStopNote(__note);
1150
+ if (onStopNote)
1151
+ onStopNote(noteNumber);
1094
1152
  },
1095
1153
  played() {
1096
1154
  return played;
1097
1155
  },
1098
1156
  };
1099
- }, [__disabled, __note, __onPlayNote, __onStopNote, played]);
1157
+ }, [disabled, noteNumber, onPlayNote, onStopNote, played]);
1100
1158
  let keyLabelProps = {};
1101
1159
  if (children != undefined) {
1102
1160
  React.Children.forEach(children, (child) => {
@@ -1113,112 +1171,82 @@ const WhiteKey = forwardRef((_a, ref) => {
1113
1171
  }
1114
1172
  });
1115
1173
  }
1116
- return (jsx("div", Object.assign({ className: clsx(`tremolo-piano-white-key`, className), "aria-disabled": __disabled, "data-active": played, style: Object.assign(Object.assign(Object.assign({}, colors), { left: __position, width: __fill ? __width : (width !== null && width !== void 0 ? width : __width), height: height }), style), onPointerDown: () => {
1117
- if (__disabled)
1118
- return;
1119
- setPlayed(true);
1120
- if (__onPlayNote)
1121
- __onPlayNote(__note);
1122
- }, onPointerEnter: () => {
1123
- if (__disabled)
1124
- return;
1125
- if (__glissando) {
1126
- setPlayed(true);
1127
- if (__onPlayNote)
1128
- __onPlayNote(__note);
1129
- }
1130
- }, onPointerUp: () => {
1131
- if (__disabled)
1132
- return;
1133
- setPlayed(false);
1134
- if (__onStopNote)
1135
- __onStopNote(__note);
1136
- }, onPointerLeave: () => {
1137
- if (__disabled)
1138
- return;
1139
- if (__glissando) {
1140
- setPlayed(false);
1141
- if (__onStopNote)
1142
- __onStopNote(__note);
1143
- }
1144
- }, onContextMenu: onContextMenu }, props, { children: jsx(KeyLabel, Object.assign({ __note: __note, __label: __label, __index: __index }, keyLabelProps)) })));
1174
+ return (jsx("div", Object.assign({ className: clsx(`tremolo-piano-${keyType}-key`, className), "aria-disabled": disabled, "data-active": played, style: Object.assign(Object.assign(Object.assign({}, colors), { left: position, width: fill ? __width : width, height: height }), style) }, props, { children: jsx(KeyLabel, Object.assign({ label: label, __note: noteNumber }, keyLabelProps)) })));
1175
+ });
1176
+ /** @category Piano */
1177
+ const WhiteKey = forwardRef((_a, ref) => {
1178
+ var { width = defaultWhiteKeyWidth, height = '100%', onContextMenu = (e) => e.preventDefault() } = _a, props = __rest(_a, ["width", "height", "onContextMenu"]);
1179
+ return (jsx(KeyImpl, Object.assign({ ref: ref, keyType: "white", width: width, height: height, onContextMenu: onContextMenu }, props)));
1145
1180
  });
1146
-
1147
1181
  /** @category Piano */
1148
1182
  const BlackKey = forwardRef((_a, ref) => {
1149
- var { width = defaultWhiteKeyWidth * 0.65, height = '60%', bg, color, activeBg, activeColor, className, style, children, __glissando, __position, __note, __disabled, __index, __fill, __width, __onPlayNote, __onStopNote, __label, onContextMenu = (e) => e.preventDefault() } = _a, props = __rest(_a, ["width", "height", "bg", "color", "activeBg", "activeColor", "className", "style", "children", "__glissando", "__position", "__note", "__disabled", "__index", "__fill", "__width", "__onPlayNote", "__onStopNote", "__label", "onContextMenu"]);
1150
- const [played, setPlayed] = useState(false);
1151
- const colors = {
1152
- '--bg': bg,
1153
- '--color': color,
1154
- '--active-bg': activeBg,
1155
- '--active-color': activeColor,
1183
+ var { width = defaultBlackKeyWidth, height = '60%', onContextMenu = (e) => e.preventDefault() } = _a, props = __rest(_a, ["width", "height", "onContextMenu"]);
1184
+ return (jsx(KeyImpl, Object.assign({ ref: ref, keyType: "black", width: width, height: height, onContextMenu: onContextMenu }, props)));
1185
+ });
1186
+
1187
+ const createPianoStore = (initProps) => {
1188
+ const noteRange = (initProps === null || initProps === void 0 ? void 0 : initProps.noteRange) || { first: 0};
1189
+ const DEFAULT_PROPS = {
1190
+ noteRange: { first: 0, last: 127 },
1191
+ glissando: true,
1192
+ midiMax: 127,
1193
+ fill: false,
1194
+ label: () => undefined,
1195
+ onPlayNote: () => { },
1196
+ onStopNote: () => { },
1156
1197
  };
1157
- useImperativeHandle(ref, () => {
1158
- return {
1159
- play() {
1160
- if (__disabled)
1161
- return;
1162
- setPlayed(true);
1163
- if (__onPlayNote)
1164
- __onPlayNote(__note);
1165
- },
1166
- stop() {
1167
- setPlayed(false);
1168
- if (__onStopNote)
1169
- __onStopNote(__note);
1170
- },
1171
- played() {
1172
- return played;
1173
- },
1174
- };
1175
- }, [__disabled, __note, __onPlayNote, __onStopNote, played]);
1176
- let keyLabelProps = {};
1177
- if (children != undefined) {
1178
- React.Children.forEach(children, (child) => {
1179
- if (React.isValidElement(child)) {
1180
- if (child.type == KeyLabel) {
1181
- keyLabelProps = child.props;
1182
- }
1183
- else {
1184
- throw new Error('only <KeyLabel>');
1185
- }
1186
- }
1187
- else {
1188
- throw new Error('children is an invalid element.');
1189
- }
1190
- });
1198
+ return createStore()(() => (Object.assign(Object.assign(Object.assign({}, DEFAULT_PROPS), initProps), { notePosition: (note) => {
1199
+ const pitchPositions = {
1200
+ C: 0,
1201
+ 'C#': 1,
1202
+ D: 1,
1203
+ 'D#': 2,
1204
+ E: 2,
1205
+ F: 3,
1206
+ 'F#': 4,
1207
+ G: 4,
1208
+ 'G#': 5,
1209
+ A: 5,
1210
+ 'A#': 6,
1211
+ B: 6,
1212
+ };
1213
+ const whiteNoteWidth = defaultWhiteKeyWidth;
1214
+ const blackNoteWidth = defaultBlackKeyWidth;
1215
+ const padding = 1;
1216
+ const targetNoteKey = noteKey(note);
1217
+ const firstNoteKey = noteKey(noteRange.first);
1218
+ const octave = Math.floor((note - noteRange.first) / 12);
1219
+ const octaveOffset = noteKeys.indexOf(firstNoteKey) > noteKeys.indexOf(targetNoteKey) ? 1 : 0;
1220
+ const w = whiteNoteWidth + padding;
1221
+ const pos = pitchPositions[targetNoteKey] - pitchPositions[firstNoteKey];
1222
+ const blackKeyOffset = isBlackKey(note) ? blackNoteWidth / 2 : 0;
1223
+ return pos * w + (octave + octaveOffset) * 7 * w - blackKeyOffset;
1224
+ } })));
1225
+ };
1226
+ const PianoContext = createContext(null);
1227
+ function PianoProvider(_a) {
1228
+ var { children } = _a, props = __rest(_a, ["children"]);
1229
+ const storeRef = useRef(null);
1230
+ if (!storeRef.current) {
1231
+ storeRef.current = createPianoStore(props);
1191
1232
  }
1192
- return (jsx("div", Object.assign({ className: clsx(`tremolo-piano-black-key`, className), "aria-disabled": __disabled, "data-active": played, style: Object.assign(Object.assign(Object.assign({}, colors), { left: __position, width: __fill ? __width : (width !== null && width !== void 0 ? width : __width), height: height }), style), onPointerDown: () => {
1193
- if (__disabled)
1194
- return;
1195
- setPlayed(true);
1196
- if (__onPlayNote)
1197
- __onPlayNote(__note);
1198
- }, onPointerEnter: () => {
1199
- if (__disabled)
1200
- return;
1201
- if (__glissando) {
1202
- setPlayed(true);
1203
- if (__onPlayNote)
1204
- __onPlayNote(__note);
1205
- }
1206
- }, onPointerUp: () => {
1207
- if (__disabled)
1208
- return;
1209
- setPlayed(false);
1210
- if (__onStopNote)
1211
- __onStopNote(__note);
1212
- }, onPointerLeave: () => {
1213
- if (__disabled)
1214
- return;
1215
- if (__glissando) {
1216
- setPlayed(false);
1217
- if (__onStopNote)
1218
- __onStopNote(__note);
1219
- }
1220
- }, onContextMenu: onContextMenu }, props, { children: jsx(KeyLabel, Object.assign({ __note: __note, __label: __label, __index: __index }, keyLabelProps)) })));
1221
- });
1233
+ useEffect(() => {
1234
+ if (storeRef.current) {
1235
+ storeRef.current.setState(props);
1236
+ }
1237
+ else {
1238
+ storeRef.current = createPianoStore(props);
1239
+ }
1240
+ }, [props]);
1241
+ return (jsx(PianoContext.Provider, { value: storeRef.current, children: children }));
1242
+ }
1243
+ /** @category Piano */
1244
+ function usePianoContext(selector) {
1245
+ const store = useContext(PianoContext);
1246
+ if (!store)
1247
+ throw new Error('Missing PianoContext.Provider in the tree');
1248
+ return useStore(store, selector);
1249
+ }
1222
1250
 
1223
1251
  /** @category Piano */
1224
1252
  const SHORTCUTS = {
@@ -1245,66 +1273,121 @@ const SHORTCUTS = {
1245
1273
  },
1246
1274
  };
1247
1275
 
1276
+ /**
1277
+ * Piano component
1278
+ *
1279
+ * TODO:
1280
+ * - add scale highlight
1281
+ */
1282
+ /** @category Piano */
1283
+ function getNoteRangeArray(noteRange) {
1284
+ return Array.from({ length: noteRange.last - noteRange.first + 1 }, (_, i) => i + noteRange.first);
1285
+ }
1248
1286
  /**
1249
1287
  * Customizable piano component.
1250
1288
  * @category Piano
1251
1289
  */
1252
1290
  function Piano(_a) {
1253
- var { noteRange, glissando = true, midiMax = 127, keyboardShortcuts, fill = false, height = fill ? '100%' : 160, style, className, onPlayNote, onStopNote, label, children, onPointerUp, onPointerDown } = _a, props = __rest(_a, ["noteRange", "glissando", "midiMax", "keyboardShortcuts", "fill", "height", "style", "className", "onPlayNote", "onStopNote", "label", "children", "onPointerUp", "onPointerDown"]);
1291
+ var { noteRange, glissando = true, midiMax = 127, keyboardShortcuts, fill = false, height = fill ? '100%' : 160, whiteNoteWidth: _whiteNoteWidth = defaultWhiteKeyWidth, style, className, onPlayNote, onStopNote, label, children, onPointerDown } = _a, props = __rest(_a, ["noteRange", "glissando", "midiMax", "keyboardShortcuts", "fill", "height", "whiteNoteWidth", "style", "className", "onPlayNote", "onStopNote", "label", "children", "onPointerDown"]);
1254
1292
  // -- state and ref ---
1255
- const [pressed, setPressed] = useState(false);
1256
- const [whiteNoteWidth, setWhiteNoteWidth] = useState(-1);
1293
+ const [whiteNoteWidth, setWhiteNoteWidth] = useState(_whiteNoteWidth);
1257
1294
  const keyRefs = useRef([]);
1258
1295
  for (let i = 0; i < noteRange.last - noteRange.first + 1; i++) {
1259
1296
  keyRefs.current[i] = createRef();
1260
1297
  }
1261
1298
  const pianoRef = useRef(null);
1299
+ const hitKeyIndex = useRef(-1);
1262
1300
  // --- interpret props ---
1263
- const noteRangeArray = Array.from({ length: noteRange.last - noteRange.first + 1 }, (_, i) => i + noteRange.first);
1264
- const whiteNoteCount = noteRangeArray.filter((v) => isWhiteKey(v)).length;
1265
- let whiteKeyProps = {}, blackKeyProps = {};
1266
- if (children != undefined) {
1267
- React.Children.forEach(children, (child) => {
1268
- if (React.isValidElement(child)) {
1269
- if (child.type == WhiteKey) {
1270
- whiteKeyProps = child.props;
1271
- }
1272
- else if (child.type == BlackKey) {
1273
- blackKeyProps = child.props;
1274
- }
1275
- else {
1276
- throw new Error('only <WhiteKey> or <BlackKey>');
1301
+ const noteRangeArray = getNoteRangeArray(noteRange);
1302
+ const whiteNotes = noteRangeArray.filter((v) => isWhiteKey(v));
1303
+ const blackNotes = noteRangeArray.filter((v) => isBlackKey(v));
1304
+ const whiteNoteCount = whiteNotes.length;
1305
+ const padding = 1;
1306
+ const staticWidth = (whiteNoteWidth + padding) * whiteNoteCount;
1307
+ // const blackNoteShiftPercent = 0.3
1308
+ // TODO: if fill setWhiteNoteWidth
1309
+ // useMemo
1310
+ // __width
1311
+ const childrenWithProps = useMemo(() => {
1312
+ return (children &&
1313
+ React.Children.map(children, (child, index) => {
1314
+ if (React.isValidElement(child)) {
1315
+ const props = { ref: keyRefs.current[index] };
1316
+ return React.cloneElement(child, props);
1277
1317
  }
1278
- }
1279
- else {
1280
- throw new Error('children is an invalid element.');
1281
- }
1282
- });
1283
- }
1318
+ return child;
1319
+ }));
1320
+ }, [children]);
1284
1321
  // --- internal functions ---
1285
- function notePosition(note) {
1322
+ const notePosition = useCallback((note) => {
1286
1323
  const pitchPositions = {
1287
1324
  C: 0,
1288
- 'C#': 0.55,
1325
+ 'C#': 1,
1289
1326
  D: 1,
1290
- 'D#': 1.8,
1327
+ 'D#': 2,
1291
1328
  E: 2,
1292
1329
  F: 3,
1293
- 'F#': 3.5,
1330
+ 'F#': 4,
1294
1331
  G: 4,
1295
- 'G#': 4.7,
1332
+ 'G#': 5,
1296
1333
  A: 5,
1297
- 'A#': 5.85,
1334
+ 'A#': 6,
1298
1335
  B: 6,
1299
1336
  };
1337
+ const whiteNoteWidth = defaultWhiteKeyWidth;
1338
+ const blackNoteWidth = defaultBlackKeyWidth;
1339
+ const padding = 1;
1300
1340
  const targetNoteKey = noteKey(note);
1301
1341
  const firstNoteKey = noteKey(noteRange.first);
1302
- const pos = pitchPositions[targetNoteKey] - pitchPositions[firstNoteKey];
1303
1342
  const octave = Math.floor((note - noteRange.first) / 12);
1304
1343
  const octaveOffset = noteKeys.indexOf(firstNoteKey) > noteKeys.indexOf(targetNoteKey) ? 1 : 0;
1305
- const length = whiteNoteWidth + 3;
1306
- return pos * length + (octave + octaveOffset) * 7 * length;
1307
- }
1344
+ const w = whiteNoteWidth + padding;
1345
+ const pos = pitchPositions[targetNoteKey] - pitchPositions[firstNoteKey];
1346
+ const blackKeyOffset = isBlackKey(note) ? blackNoteWidth / 2 : 0;
1347
+ return pos * w + (octave + octaveOffset) * 7 * w - blackKeyOffset;
1348
+ }, [noteRange.first]);
1349
+ const getHitKeyIndex = useCallback((x, y) => {
1350
+ if (!pianoRef.current)
1351
+ return -1;
1352
+ const containerHeight = pianoRef.current.clientHeight;
1353
+ const notes = [...blackNotes, ...whiteNotes];
1354
+ for (let i = 0; i < notes.length; i++) {
1355
+ const note = notes[i];
1356
+ const pos = notePosition(note);
1357
+ const w = isWhiteKey(note) ? defaultWhiteKeyWidth : defaultBlackKeyWidth;
1358
+ const h = isWhiteKey(note) ? containerHeight : containerHeight * 0.6;
1359
+ if (pos <= x && x < pos + w && 0 <= y && y < h) {
1360
+ return note;
1361
+ }
1362
+ }
1363
+ return -1;
1364
+ }, [blackNotes, notePosition, whiteNotes]);
1365
+ // TODO: 単一のポインターに対しては、useDragで対応可能だが、
1366
+ // マルチタッチに対しては、TouchEventを使う必要がありそう
1367
+ // 取り敢えず、シングルタッチだけ対応
1368
+ const onDrag = useCallback((perX, perY) => {
1369
+ var _a, _b, _c, _d;
1370
+ if (!pianoRef.current)
1371
+ return;
1372
+ const x = perX * staticWidth;
1373
+ const y = perY * pianoRef.current.clientHeight;
1374
+ const note = getHitKeyIndex(x, y);
1375
+ const index = noteRangeArray.indexOf(note);
1376
+ if (index == -1)
1377
+ return;
1378
+ if (hitKeyIndex.current != index) {
1379
+ (_b = (_a = keyRefs.current[hitKeyIndex.current]) === null || _a === void 0 ? void 0 : _a.current) === null || _b === void 0 ? void 0 : _b.stop();
1380
+ (_d = (_c = keyRefs.current[index]) === null || _c === void 0 ? void 0 : _c.current) === null || _d === void 0 ? void 0 : _d.play();
1381
+ hitKeyIndex.current = index;
1382
+ }
1383
+ }, [getHitKeyIndex, noteRangeArray, staticWidth]);
1384
+ const onDragEnd = useCallback(() => {
1385
+ var _a, _b, _c, _d;
1386
+ if ((_b = (_a = keyRefs.current[hitKeyIndex.current]) === null || _a === void 0 ? void 0 : _a.current) === null || _b === void 0 ? void 0 : _b.played()) {
1387
+ (_d = (_c = keyRefs.current[hitKeyIndex.current]) === null || _c === void 0 ? void 0 : _c.current) === null || _d === void 0 ? void 0 : _d.stop();
1388
+ }
1389
+ hitKeyIndex.current = -1;
1390
+ }, [keyRefs]);
1308
1391
  // --- hooks ---
1309
1392
  useEffect(() => {
1310
1393
  if (fill && pianoRef.current) {
@@ -1313,7 +1396,7 @@ function Piano(_a) {
1313
1396
  throw new Error("doesn't have a parent element.");
1314
1397
  const resizeObserver = new ResizeObserver(() => {
1315
1398
  const w = pianoRef.current.clientWidth;
1316
- setWhiteNoteWidth(w / whiteNoteCount - 3);
1399
+ setWhiteNoteWidth(w / whiteNoteCount - padding);
1317
1400
  });
1318
1401
  resizeObserver.observe(parent);
1319
1402
  return () => {
@@ -1321,9 +1404,14 @@ function Piano(_a) {
1321
1404
  };
1322
1405
  }
1323
1406
  else {
1324
- setWhiteNoteWidth((whiteKeyProps === null || whiteKeyProps === void 0 ? void 0 : whiteKeyProps.width) || defaultWhiteKeyWidth);
1407
+ setWhiteNoteWidth(_whiteNoteWidth);
1325
1408
  }
1326
- }, [fill, whiteKeyProps === null || whiteKeyProps === void 0 ? void 0 : whiteKeyProps.width, whiteNoteCount]);
1409
+ }, [fill, _whiteNoteWidth, whiteNoteCount]);
1410
+ const [touchMoveRefCallback, pointerDownHandler] = useDragWithElement({
1411
+ baseElementRef: pianoRef,
1412
+ onDrag: onDrag,
1413
+ onDragEnd: onDragEnd,
1414
+ });
1327
1415
  useEventListener(globalThis.window, 'keydown', (e) => {
1328
1416
  var _a, _b, _c, _d;
1329
1417
  if (e.repeat)
@@ -1348,15 +1436,14 @@ function Piano(_a) {
1348
1436
  (_b = (_a = keyRefs.current[index]) === null || _a === void 0 ? void 0 : _a.current) === null || _b === void 0 ? void 0 : _b.stop();
1349
1437
  }
1350
1438
  });
1351
- return (jsx("div", Object.assign({ ref: pianoRef, className: clsx('tremolo-piano', className), style: Object.assign({ width: fill ? '100%' : (whiteNoteWidth + 3) * whiteNoteCount, height: height }, style), onPointerDown: (e) => {
1352
- setPressed(true);
1353
- onPointerDown === null || onPointerDown === void 0 ? void 0 : onPointerDown(e);
1354
- }, onPointerUp: (e) => {
1355
- setPressed(false);
1356
- onPointerUp === null || onPointerUp === void 0 ? void 0 : onPointerUp(e);
1357
- } }, props, { children: noteRangeArray.map((note, index) => {
1358
- return isWhiteKey(note) ? (jsx(WhiteKey, Object.assign({ ref: keyRefs.current[index], __glissando: glissando && pressed, __position: notePosition(note), __note: note, __disabled: note > midiMax, __index: index, __fill: fill, __width: whiteNoteWidth, __onPlayNote: onPlayNote, __onStopNote: onStopNote, __label: label }, whiteKeyProps), note)) : (jsx(BlackKey, Object.assign({ ref: keyRefs.current[index], __glissando: glissando && pressed, __position: notePosition(note), __note: note, __disabled: note > midiMax, __index: index, __fill: fill, __width: whiteNoteWidth * 0.65, __onPlayNote: onPlayNote, __onStopNote: onStopNote, __label: label }, blackKeyProps), note));
1359
- }) })));
1439
+ return (jsx(PianoProvider, { noteRange: noteRange, glissando: glissando, midiMax: midiMax, fill: fill, onPlayNote: onPlayNote, onStopNote: onStopNote, label: label, children: jsx("div", Object.assign({ ref: (div) => {
1440
+ pianoRef.current = div;
1441
+ touchMoveRefCallback(div);
1442
+ }, className: clsx('tremolo-piano', className), style: Object.assign({ width: fill ? '100%' : staticWidth, height: height }, style), onPointerDown: (event) => {
1443
+ pointerDownHandler(event);
1444
+ onPointerDown === null || onPointerDown === void 0 ? void 0 : onPointerDown(event);
1445
+ } }, props, { children: childrenWithProps ||
1446
+ getNoteRangeArray(noteRange).map((note, index) => isWhiteKey(note) ? (jsx(WhiteKey, { ref: keyRefs.current[index], noteNumber: note }, note)) : (jsx(BlackKey, { ref: keyRefs.current[index], noteNumber: note }, note))) })) }));
1360
1447
  }
1361
1448
 
1362
1449
  const createSliderStore = (initProps) => {
@@ -1527,7 +1614,6 @@ const Slider = forwardRef((_a, ref) => {
1527
1614
  // -- state and ref ---
1528
1615
  const trackElementRef = useRef(null);
1529
1616
  const thumbRef = useRef(null);
1530
- const thumbDragged = useRef(false);
1531
1617
  // --- interpret props ---
1532
1618
  const p = toFixed$1(normalizeValue(value, min, max, skew) * 100);
1533
1619
  const rev = toFixed$1(100 - p);
@@ -1563,29 +1649,14 @@ const Slider = forwardRef((_a, ref) => {
1563
1649
  });
1564
1650
  }
1565
1651
  // --- internal functions ---
1566
- const handleValue = (event) => {
1567
- if (!trackElementRef.current ||
1568
- !thumbDragged.current ||
1569
- !onChange ||
1570
- readonly) {
1652
+ const onDrag = useCallback((nx, ny) => {
1653
+ if (!onChange || readonly)
1571
1654
  return;
1572
- }
1573
- const isTouch = event instanceof TouchEvent;
1574
- if (isTouch && event.cancelable)
1575
- event.preventDefault();
1576
- if (bodyNoSelect)
1577
- addNoSelect();
1578
- const { left: x1, top: y1, right: x2, bottom: y2, } = trackElementRef.current.getBoundingClientRect();
1579
- const mouseX = isTouch ? event.touches[0].clientX : event.clientX;
1580
- const mouseY = isTouch ? event.touches[0].clientY : event.clientY;
1581
- const n = vertical
1582
- ? normalizeValue(mouseY, y1, y2)
1583
- : normalizeValue(mouseX, x1, x2);
1655
+ const n = vertical ? ny : nx;
1584
1656
  const v = rawValue(displayReversed ? 1 - n : n, min, max, skew);
1585
1657
  const v2 = clamp(stepValue(v, step), min, max);
1586
1658
  onChange(v2);
1587
- return v2;
1588
- };
1659
+ }, [displayReversed, max, min, onChange, readonly, skew, step, vertical]);
1589
1660
  const updateValueByEvent = useCallback((eventType, x) => {
1590
1661
  let newValue;
1591
1662
  if (eventType == 'normalized') {
@@ -1610,7 +1681,26 @@ const Slider = forwardRef((_a, ref) => {
1610
1681
  }
1611
1682
  }, [keyboard, onChange, readonly, reverse, updateValueByEvent]);
1612
1683
  // --- hooks ---
1613
- const touchMoveRefCallback = useRefCallbackEvent('touchmove', handleValue, { passive: false }, [min, max, skew, step, vertical, reverse, onChange, readonly]);
1684
+ const [touchMoveRefCallback, pointerDownHandler] = useDragWithElement({
1685
+ baseElementRef: trackElementRef,
1686
+ onDrag: onDrag,
1687
+ onDragStart: (nx, ny) => {
1688
+ var _a;
1689
+ if (readonly)
1690
+ return;
1691
+ if (bodyNoSelect)
1692
+ addNoSelect();
1693
+ (_a = thumbRef.current) === null || _a === void 0 ? void 0 : _a.focus();
1694
+ onDragStart === null || onDragStart === void 0 ? void 0 : onDragStart(clamp(stepValue(rawValue(vertical ? ny : nx, min, max, skew), step), min, max));
1695
+ },
1696
+ onDragEnd: (nx, ny) => {
1697
+ if (readonly)
1698
+ return;
1699
+ if (bodyNoSelect)
1700
+ removeNoSelect();
1701
+ onDragEnd === null || onDragEnd === void 0 ? void 0 : onDragEnd(clamp(stepValue(rawValue(vertical ? ny : nx, min, max, skew), step), min, max));
1702
+ },
1703
+ });
1614
1704
  const wheelRefCallback = useRefCallbackEvent('wheel', (event) => {
1615
1705
  if (!wheel || !onChange || readonly)
1616
1706
  return;
@@ -1630,17 +1720,6 @@ const Slider = forwardRef((_a, ref) => {
1630
1720
  }, {
1631
1721
  passive: false,
1632
1722
  }, [wheel, vertical, readonly, onChange, updateValueByEvent]);
1633
- useEventListener(globalThis.window, 'mousemove', (event) => {
1634
- handleValue(event);
1635
- });
1636
- useEventListener(globalThis.window, 'mouseup', () => {
1637
- if (!thumbDragged.current || readonly)
1638
- return;
1639
- thumbDragged.current = false;
1640
- onDragEnd === null || onDragEnd === void 0 ? void 0 : onDragEnd(value);
1641
- if (bodyNoSelect)
1642
- removeNoSelect();
1643
- });
1644
1723
  useImperativeHandle(ref, () => {
1645
1724
  return {
1646
1725
  focus() {
@@ -1657,10 +1736,7 @@ const Slider = forwardRef((_a, ref) => {
1657
1736
  wheelRefCallback(div);
1658
1737
  touchMoveRefCallback(div);
1659
1738
  }, tabIndex: -1, role: "slider", "aria-valuenow": value, "aria-valuemin": min, "aria-valuemax": max, "aria-orientation": vertical ? 'vertical' : 'horizontal', "aria-disabled": disabled, "aria-readonly": readonly, style: Object.assign({ margin: `calc(${styleHelper((_b = thumbProps === null || thumbProps === void 0 ? void 0 : thumbProps.size) !== null && _b !== void 0 ? _b : 22)} / 2)` }, style), onPointerDown: (event) => {
1660
- thumbDragged.current = true;
1661
- const v = handleValue(event);
1662
- if (!readonly)
1663
- onDragStart === null || onDragStart === void 0 ? void 0 : onDragStart(v !== null && v !== void 0 ? v : value);
1739
+ pointerDownHandler(event);
1664
1740
  onPointerDown === null || onPointerDown === void 0 ? void 0 : onPointerDown(event);
1665
1741
  }, onKeyDown: (event) => {
1666
1742
  handleKeyDown(event);
@@ -1743,13 +1819,13 @@ const XYPad = forwardRef((_a, ref) => {
1743
1819
  // -- state and ref ---
1744
1820
  const areaElementRef = useRef(null);
1745
1821
  const thumbRef = useRef(null);
1746
- const thumbDragged = useRef(false);
1747
1822
  // --- interpret props ---
1748
1823
  const nx = normalizeValue(x.value, x.min, x.max, x.skew);
1749
1824
  const ny = normalizeValue(y.value, y.min, y.max, y.skew);
1750
1825
  const percentX = toFixed$1((x.reverse ? 1 - nx : nx) * 100);
1751
1826
  const percentY = toFixed$1((y.reverse ? 1 - ny : ny) * 100);
1752
- let areaProps = {}, thumbProps = {};
1827
+ let areaProps = {};
1828
+ let thumbProps = {};
1753
1829
  if (children != undefined) {
1754
1830
  React.Children.forEach(children, (child) => {
1755
1831
  if (React.isValidElement(child)) {
@@ -1769,29 +1845,28 @@ const XYPad = forwardRef((_a, ref) => {
1769
1845
  });
1770
1846
  }
1771
1847
  // --- internal functions ---
1772
- const handleValue = (event) => {
1773
- if (!areaElementRef.current ||
1774
- !thumbDragged.current ||
1775
- !onChange ||
1776
- readonly)
1848
+ const onDrag = useCallback((nx, ny) => {
1849
+ if (!onChange || readonly)
1777
1850
  return;
1778
- const isTouch = event instanceof TouchEvent;
1779
- if (isTouch && event.cancelable)
1780
- event.preventDefault();
1781
- if (bodyNoSelect)
1782
- addNoSelect();
1783
- const { left: x1, top: y1, right: x2, bottom: y2, } = areaElementRef.current.getBoundingClientRect();
1784
- const mouseX = isTouch ? event.touches[0].clientX : event.clientX;
1785
- const mouseY = isTouch ? event.touches[0].clientY : event.clientY;
1786
- const nx = normalizeValue(mouseX, x1, x2);
1787
- const ny = normalizeValue(mouseY, y1, y2);
1788
1851
  const vx = rawValue(x.reverse ? 1 - nx : nx, x.min, x.max, x.skew);
1789
1852
  const vy = rawValue(y.reverse ? 1 - ny : ny, y.min, y.max, y.skew);
1790
1853
  const newX = clamp(stepValue(vx, x.step), x.min, x.max);
1791
1854
  const newY = clamp(stepValue(vy, y.step), y.min, y.max);
1792
1855
  onChange(newX, newY);
1793
- return [newX, newY];
1794
- };
1856
+ }, [
1857
+ onChange,
1858
+ readonly,
1859
+ x.max,
1860
+ x.min,
1861
+ x.reverse,
1862
+ x.skew,
1863
+ x.step,
1864
+ y.max,
1865
+ y.min,
1866
+ y.reverse,
1867
+ y.skew,
1868
+ y.step,
1869
+ ]);
1795
1870
  const updateValueByEvent = useCallback((eventType, target, x) => {
1796
1871
  let v;
1797
1872
  if (eventType == 'normalized') {
@@ -1828,7 +1903,30 @@ const XYPad = forwardRef((_a, ref) => {
1828
1903
  }
1829
1904
  }, [onChange, readonly, x, y, updateValueByEvent]);
1830
1905
  // --- hooks ---
1831
- const touchMoveRefCallback = useRefCallbackEvent('touchmove', handleValue, { passive: false }, [x, onChange, readonly]);
1906
+ const [touchMoveRefCallback, pointerDownHandler] = useDragWithElement({
1907
+ baseElementRef: areaElementRef,
1908
+ onDrag: onDrag,
1909
+ onDragStart: (nx, ny) => {
1910
+ var _a;
1911
+ if (readonly)
1912
+ return;
1913
+ if (bodyNoSelect)
1914
+ addNoSelect();
1915
+ (_a = thumbRef.current) === null || _a === void 0 ? void 0 : _a.focus();
1916
+ const valueX = clamp(stepValue(rawValue(nx, x.min, x.max, x.skew), x.step), x.min, x.max);
1917
+ const valueY = clamp(stepValue(rawValue(ny, y.min, y.max, y.skew), y.step), y.min, y.max);
1918
+ onDragStart === null || onDragStart === void 0 ? void 0 : onDragStart(valueX, valueY);
1919
+ },
1920
+ onDragEnd: (nx, ny) => {
1921
+ if (readonly)
1922
+ return;
1923
+ if (bodyNoSelect)
1924
+ removeNoSelect();
1925
+ const valueX = clamp(stepValue(rawValue(nx, x.min, x.max, x.skew), x.step), x.min, x.max);
1926
+ const valueY = clamp(stepValue(rawValue(ny, y.min, y.max, y.skew), y.step), y.min, y.max);
1927
+ onDragEnd === null || onDragEnd === void 0 ? void 0 : onDragEnd(valueX, valueY);
1928
+ },
1929
+ });
1832
1930
  const wheelRefCallback = useRefCallbackEvent('wheel', (event) => {
1833
1931
  if (!onChange || readonly)
1834
1932
  return;
@@ -1851,17 +1949,6 @@ const XYPad = forwardRef((_a, ref) => {
1851
1949
  }, {
1852
1950
  passive: false,
1853
1951
  }, [x, y, onChange, readonly, updateValueByEvent]);
1854
- useEventListener(globalThis.window, 'mousemove', (event) => {
1855
- handleValue(event);
1856
- });
1857
- useEventListener(globalThis.window, 'mouseup', () => {
1858
- if (!thumbDragged.current || readonly)
1859
- return;
1860
- thumbDragged.current = false;
1861
- onDragEnd === null || onDragEnd === void 0 ? void 0 : onDragEnd(x.value, y.value);
1862
- if (bodyNoSelect)
1863
- removeNoSelect();
1864
- });
1865
1952
  useImperativeHandle(ref, () => {
1866
1953
  return {
1867
1954
  focus() {
@@ -1880,11 +1967,7 @@ const XYPad = forwardRef((_a, ref) => {
1880
1967
  wheelRefCallback(div);
1881
1968
  touchMoveRefCallback(div);
1882
1969
  }, tabIndex: -1, "aria-disabled": disabled, "aria-readonly": readonly, style: Object.assign({ margin: `calc(${styleHelper((_b = thumbProps === null || thumbProps === void 0 ? void 0 : thumbProps.size) !== null && _b !== void 0 ? _b : 22)} / 2)`, cursor: readonly ? 'not-allowed' : 'pointer', WebkitTapHighlightColor: 'transparent' }, style), onPointerDown: (event) => {
1883
- var _a, _b;
1884
- thumbDragged.current = true;
1885
- const v = handleValue(event);
1886
- if (!readonly)
1887
- onDragStart === null || onDragStart === void 0 ? void 0 : onDragStart((_a = v === null || v === void 0 ? void 0 : v[0]) !== null && _a !== void 0 ? _a : x.value, (_b = v === null || v === void 0 ? void 0 : v[1]) !== null && _b !== void 0 ? _b : y.value);
1970
+ pointerDownHandler(event);
1888
1971
  onPointerDown === null || onPointerDown === void 0 ? void 0 : onPointerDown(event);
1889
1972
  }, onKeyDown: (event) => {
1890
1973
  handleKeyDown(event);
@@ -1916,5 +1999,5 @@ const useAnimationFrame = (callback = () => { }, deps = []) => {
1916
1999
  }, [loop]);
1917
2000
  };
1918
2001
 
1919
- export { AnimationCanvas, AnimationKnob, BlackKey, DecrementStepper, DragObserver, IncrementStepper, KeyLabel, Knob, NumberInput, Piano, SHORTCUTS, Scale, ScaleOption, Slider, SliderThumb, SliderTrack, Stepper, WheelObserver, WhiteKey, XYPad, XYPadArea, XYPadThumb, useAnimationFrame, useDrag, useEventListener, useInterval, useLongPress, useSliderContext };
2002
+ export { AnimationCanvas, AnimationKnob, BlackKey, DecrementStepper, DragObserver, IncrementStepper, KeyLabel, Knob, NumberInput, Piano, SHORTCUTS, Scale, ScaleOption, Slider, SliderThumb, SliderTrack, Stepper, WheelObserver, WhiteKey, XYPad, XYPadArea, XYPadThumb, getNoteRangeArray, useAnimationFrame, useDrag, useEventListener, useInterval, useLongPress, useSliderContext };
1920
2003
  //# sourceMappingURL=index.js.map