@tremolo-ui/react 0.0.5 → 0.0.7

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 (77) hide show
  1. package/dist/cjs/index.js +512 -93
  2. package/dist/cjs/index.js.map +1 -1
  3. package/dist/cjs/types/components/AnimationCanvas/index.d.ts +3 -4
  4. package/dist/cjs/types/components/AnimationCanvas/index.d.ts.map +1 -1
  5. package/dist/cjs/types/components/Knob/index.d.ts +6 -7
  6. package/dist/cjs/types/components/Knob/index.d.ts.map +1 -1
  7. package/dist/cjs/types/components/NumberInput/index.d.ts +10 -7
  8. package/dist/cjs/types/components/NumberInput/index.d.ts.map +1 -1
  9. package/dist/cjs/types/components/Piano/BlackKey.d.ts +4 -0
  10. package/dist/cjs/types/components/Piano/BlackKey.d.ts.map +1 -0
  11. package/dist/cjs/types/components/Piano/KeyLabel.d.ts +20 -0
  12. package/dist/cjs/types/components/Piano/KeyLabel.d.ts.map +1 -0
  13. package/dist/cjs/types/components/Piano/WhiteKey.d.ts +4 -0
  14. package/dist/cjs/types/components/Piano/WhiteKey.d.ts.map +1 -0
  15. package/dist/cjs/types/components/Piano/index.d.ts +35 -0
  16. package/dist/cjs/types/components/Piano/index.d.ts.map +1 -0
  17. package/dist/cjs/types/components/Piano/key.d.ts +39 -0
  18. package/dist/cjs/types/components/Piano/key.d.ts.map +1 -0
  19. package/dist/cjs/types/components/Piano/keyboardShortcuts.d.ts +12 -0
  20. package/dist/cjs/types/components/Piano/keyboardShortcuts.d.ts.map +1 -0
  21. package/dist/cjs/types/components/Slider/Thumb.d.ts +17 -2
  22. package/dist/cjs/types/components/Slider/Thumb.d.ts.map +1 -1
  23. package/dist/cjs/types/components/Slider/Track.d.ts +21 -2
  24. package/dist/cjs/types/components/Slider/Track.d.ts.map +1 -1
  25. package/dist/cjs/types/components/Slider/index.d.ts +18 -10
  26. package/dist/cjs/types/components/Slider/index.d.ts.map +1 -1
  27. package/dist/cjs/types/components/_util/index.d.ts +4 -0
  28. package/dist/cjs/types/components/_util/index.d.ts.map +1 -0
  29. package/dist/cjs/types/index.d.ts +1 -0
  30. package/dist/cjs/types/index.d.ts.map +1 -1
  31. package/dist/esm/index.js +509 -95
  32. package/dist/esm/index.js.map +1 -1
  33. package/dist/esm/types/components/AnimationCanvas/index.d.ts +3 -4
  34. package/dist/esm/types/components/AnimationCanvas/index.d.ts.map +1 -1
  35. package/dist/esm/types/components/Knob/index.d.ts +6 -7
  36. package/dist/esm/types/components/Knob/index.d.ts.map +1 -1
  37. package/dist/esm/types/components/NumberInput/index.d.ts +10 -7
  38. package/dist/esm/types/components/NumberInput/index.d.ts.map +1 -1
  39. package/dist/esm/types/components/Piano/BlackKey.d.ts +4 -0
  40. package/dist/esm/types/components/Piano/BlackKey.d.ts.map +1 -0
  41. package/dist/esm/types/components/Piano/KeyLabel.d.ts +20 -0
  42. package/dist/esm/types/components/Piano/KeyLabel.d.ts.map +1 -0
  43. package/dist/esm/types/components/Piano/WhiteKey.d.ts +4 -0
  44. package/dist/esm/types/components/Piano/WhiteKey.d.ts.map +1 -0
  45. package/dist/esm/types/components/Piano/index.d.ts +35 -0
  46. package/dist/esm/types/components/Piano/index.d.ts.map +1 -0
  47. package/dist/esm/types/components/Piano/key.d.ts +39 -0
  48. package/dist/esm/types/components/Piano/key.d.ts.map +1 -0
  49. package/dist/esm/types/components/Piano/keyboardShortcuts.d.ts +12 -0
  50. package/dist/esm/types/components/Piano/keyboardShortcuts.d.ts.map +1 -0
  51. package/dist/esm/types/components/Slider/Thumb.d.ts +17 -2
  52. package/dist/esm/types/components/Slider/Thumb.d.ts.map +1 -1
  53. package/dist/esm/types/components/Slider/Track.d.ts +21 -2
  54. package/dist/esm/types/components/Slider/Track.d.ts.map +1 -1
  55. package/dist/esm/types/components/Slider/index.d.ts +18 -10
  56. package/dist/esm/types/components/Slider/index.d.ts.map +1 -1
  57. package/dist/esm/types/components/_util/index.d.ts +4 -0
  58. package/dist/esm/types/components/_util/index.d.ts.map +1 -0
  59. package/dist/esm/types/index.d.ts +1 -0
  60. package/dist/esm/types/index.d.ts.map +1 -1
  61. package/dist/styles/{variables.css → index.css} +4 -0
  62. package/package.json +7 -7
  63. package/src/components/AnimationCanvas/index.tsx +3 -7
  64. package/src/components/Knob/index.tsx +15 -19
  65. package/src/components/NumberInput/index.tsx +18 -11
  66. package/src/components/Piano/BlackKey.tsx +108 -0
  67. package/src/components/Piano/KeyLabel.tsx +69 -0
  68. package/src/components/Piano/WhiteKey.tsx +109 -0
  69. package/src/components/Piano/index.tsx +222 -0
  70. package/src/components/Piano/key.ts +43 -0
  71. package/src/components/Piano/keyboardShortcuts.ts +12 -0
  72. package/src/components/Slider/Thumb.tsx +56 -15
  73. package/src/components/Slider/Track.tsx +62 -3
  74. package/src/components/Slider/index.tsx +125 -89
  75. package/src/components/_util/index.ts +11 -0
  76. package/src/index.ts +1 -0
  77. package/src/styles/{variables.css → index.css} +4 -0
package/dist/cjs/index.js CHANGED
@@ -96,7 +96,7 @@ function AnimationCanvas(_a) {
96
96
  if (!parent)
97
97
  throw new Error("Canvas doesn't have a parent element.");
98
98
  const memoCanvas = memoCanvasRef.current;
99
- const memoContext = memoCanvas === null || memoCanvas === void 0 ? void 0 : memoCanvas.getContext('2d', options);
99
+ const memoContext = memoCanvas === null || memoCanvas === undefined ? undefined : memoCanvas.getContext('2d', options);
100
100
  const resizeObserver = new ResizeObserver(() => {
101
101
  // console.log('resize')
102
102
  // Prevents loss of some context when the canvas is resized
@@ -152,15 +152,27 @@ function AnimationCanvas(_a) {
152
152
  return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("canvas", Object.assign({ className: clsx('tremolo-animation-canvas', className), width: relativeSize ? 0 : width, height: relativeSize ? 0 : height, css: react.css(style), ref: canvasRef }, props)), relativeSize && reduceFlickering && (jsxRuntime.jsx("canvas", { style: { display: 'none' }, width: relativeSize ? 0 : width, height: relativeSize ? 0 : height, ref: memoCanvasRef }))] }));
153
153
  }
154
154
 
155
+ /**
156
+ * clamp value between min and max
157
+ * @category Math
158
+ */
155
159
  function clamp(value, min, max) {
156
160
  return Math.max(min, Math.min(value, max));
157
161
  }
162
+ /**
163
+ * Normalize the value from 0 to 1
164
+ * @category Math
165
+ */
158
166
  function normalizeValue(rawValue, min, max, skew = 1) {
159
167
  if (min >= max)
160
168
  throw new RangeError('requirements: min < max');
161
169
  const v = clamp((rawValue - min) / (max - min), 0, 1);
162
170
  return Math.pow(v, skew);
163
171
  }
172
+ /**
173
+ * Convert normalized values back to raw values.
174
+ * @category Math
175
+ */
164
176
  function rawValue(normalizedValue, min, max, skew = 1) {
165
177
  if (min >= max)
166
178
  throw new RangeError('requirements: min < max');
@@ -169,22 +181,38 @@ function rawValue(normalizedValue, min, max, skew = 1) {
169
181
  : Math.exp(Math.log(clamp(normalizedValue, 0, 1)) / skew);
170
182
  return min + v * (max - min);
171
183
  }
184
+ /**
185
+ *
186
+ * @category Math
187
+ */
172
188
  function stepValue(value, step) {
173
189
  var _a;
174
190
  if (step <= 0)
175
191
  throw new RangeError('requirements: step > 0');
176
192
  const quotient = Math.floor(value / step);
177
- const decimalDigits = (_a = decimalPart$1(step)) === null || _a === void 0 ? void 0 : _a.length;
193
+ const decimalDigits = (_a = decimalPart$1(step)) === null || _a === undefined ? undefined : _a.length;
178
194
  const v = toFixed$2(quotient * step, decimalDigits);
179
195
  const next = toFixed$2((quotient + 1) * step, decimalDigits);
180
196
  return Math.abs(value - v) < Math.abs(value - next) ? v : next;
181
197
  }
198
+ /**
199
+ *
200
+ * @category Math
201
+ */
182
202
  function toFixed$2(x, fractionDigits) {
183
203
  return Number(x.toFixed(fractionDigits));
184
204
  }
205
+ /**
206
+ *
207
+ * @category Math
208
+ */
185
209
  function decimalPart$1(x) {
186
210
  return String(x).split('.')[1];
187
211
  }
212
+ /**
213
+ *
214
+ * @category Math
215
+ */
188
216
  function radian(degree) {
189
217
  return (Math.PI * degree) / 180;
190
218
  }
@@ -214,6 +242,62 @@ function styleHelper(value, op, influencer) {
214
242
  }
215
243
  }
216
244
  }
245
+ /**
246
+ * @category Utility
247
+ */
248
+ function mod(n, m) {
249
+ return (((n % m) + m) % m);
250
+ }
251
+ /**
252
+ * @category MIDI
253
+ */
254
+ const noteNames = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'];
255
+ /**
256
+ * @category MIDI
257
+ */
258
+ function parseNoteName(noteName) {
259
+ const m = noteName.match(/^([a-g])(#{0,2}|b{0,2})(-?\d+)$/i);
260
+ if (!m)
261
+ throw new Error('Invalid note name');
262
+ const [, letter, accidental, octave] = m;
263
+ return {
264
+ letter: letter.toLocaleUpperCase(),
265
+ accidental: accidental,
266
+ octave: Number(octave),
267
+ };
268
+ }
269
+ /**
270
+ *
271
+ * @category MIDI
272
+ */
273
+ function noteNumber(noteName) {
274
+ const { letter, accidental, octave, } = parseNoteName(noteName);
275
+ const noteIndex = noteNames.indexOf(letter.toLocaleUpperCase());
276
+ const accidentalValue = (accidental[0] == 'b' ? -1 : 1) * accidental.length;
277
+ return noteIndex + 12 * (Number(octave) + 1) + accidentalValue;
278
+ }
279
+ /**
280
+ *
281
+ * @category MIDI
282
+ */
283
+ function noteName(noteNumber) {
284
+ const noteIndex = mod(noteNumber, 12);
285
+ const octave = Math.floor(noteNumber / 12) - 1;
286
+ return noteNames[noteIndex] + octave;
287
+ }
288
+ /**
289
+ * @category MIDI
290
+ */
291
+ function isWhiteKey(note) {
292
+ const n = typeof note == 'string' ? noteNumber(note) : note;
293
+ return (mod(n, 12) == 0 ||
294
+ mod(n, 12) == 2 ||
295
+ mod(n, 12) == 4 ||
296
+ mod(n, 12) == 5 ||
297
+ mod(n, 12) == 7 ||
298
+ mod(n, 12) == 9 ||
299
+ mod(n, 12) == 11);
300
+ }
217
301
 
218
302
  /**
219
303
  * This hook is user-land implementation of the experimental `useEffectEvent` hook.
@@ -226,13 +310,13 @@ function useCallbackRef(callback, deps = []) {
226
310
  React.useInsertionEffect(() => {
227
311
  callbackRef.current = callback;
228
312
  });
229
- return React.useCallback((...args) => { var _a; return (_a = callbackRef.current) === null || _a === void 0 ? void 0 : _a.call(callbackRef, ...args); }, deps);
313
+ return React.useCallback((...args) => { var _a; return (_a = callbackRef.current) === null || _a === undefined ? undefined : _a.call(callbackRef, ...args); }, deps);
230
314
  }
231
315
 
232
316
  function useEventListener(target, event, handler, options) {
233
317
  const listener = useCallbackRef(handler);
234
318
  React.useEffect(() => {
235
- const node = typeof target === 'function' ? target() : (target !== null && target !== void 0 ? target : document);
319
+ const node = typeof target === 'function' ? target() : (target !== null && target !== undefined ? target : document);
236
320
  if (!handler || !node)
237
321
  return;
238
322
  node.addEventListener(event, listener, options);
@@ -241,8 +325,8 @@ function useEventListener(target, event, handler, options) {
241
325
  };
242
326
  }, [event, target, options, listener, handler]);
243
327
  return () => {
244
- const node = typeof target === 'function' ? target() : (target !== null && target !== void 0 ? target : document);
245
- node === null || node === void 0 ? void 0 : node.removeEventListener(event, listener, options);
328
+ const node = typeof target === 'function' ? target() : (target !== null && target !== undefined ? target : document);
329
+ node === null || node === undefined ? undefined : node.removeEventListener(event, listener, options);
246
330
  };
247
331
  }
248
332
 
@@ -251,7 +335,7 @@ function useRefCallbackEvent(event, handler, options, deps = []) {
251
335
  let cleanup;
252
336
  return (node) => {
253
337
  if (!node) {
254
- cleanup === null || cleanup === void 0 ? void 0 : cleanup();
338
+ cleanup === null || cleanup === undefined ? undefined : cleanup();
255
339
  return;
256
340
  }
257
341
  node.addEventListener(event, handler, options);
@@ -262,6 +346,13 @@ function useRefCallbackEvent(event, handler, options, deps = []) {
262
346
  }, deps);
263
347
  }
264
348
 
349
+ function addNoSelect() {
350
+ document.body.classList.add('tremolo-no-select');
351
+ }
352
+ function removeNoSelect() {
353
+ document.body.classList.remove('tremolo-no-select');
354
+ }
355
+
265
356
  const defaultOptions = {
266
357
  active: '#7998ec',
267
358
  inactive: '#eee',
@@ -274,14 +365,14 @@ const defaultOptions = {
274
365
  * simple rotary Knob.
275
366
  */
276
367
  function Knob(_a) {
277
- var { value, min, max, defaultValue = min, startValue = min, step = 1, skew = 1, size, width = 50, height = 50, options = defaultOptions, draw, bodyNoSelect = true, enableWheel, enableDoubleClickDefault = true, style, className, onChange, _active, _focus, _hover } = _a, props = __rest(_a, ["value", "min", "max", "defaultValue", "startValue", "step", "skew", "size", "width", "height", "options", "draw", "bodyNoSelect", "enableWheel", "enableDoubleClickDefault", "style", "className", "onChange", "_active", "_focus", "_hover"]);
368
+ var { value, min, max, defaultValue = min, startValue = min, step = 1, skew = 1, size, width = 50, height = 50, options = defaultOptions, draw, bodyNoSelect = true, wheel, enableDoubleClickDefault = true, style, className, onChange, _active, _focus, _hover } = _a, props = __rest(_a, ["value", "min", "max", "defaultValue", "startValue", "step", "skew", "size", "width", "height", "options", "draw", "bodyNoSelect", "wheel", "enableDoubleClickDefault", "style", "className", "onChange", "_active", "_focus", "_hover"]);
278
369
  // -- state and ref ---
279
370
  // const [privateValue, setPrivateValue] = useState(value);
280
371
  const dragOffsetY = React.useRef(undefined);
281
372
  // --- interpret props ---
282
373
  const opts = Object.assign(Object.assign({}, defaultOptions), options);
283
374
  // const percent = normalizeValue(value, min, max, skew)
284
- const isRelativeSize = typeof (size !== null && size !== void 0 ? size : width) == 'string';
375
+ const isRelativeSize = typeof (size !== null && size !== undefined ? size : width) == 'string';
285
376
  const adaptSize = (size) => {
286
377
  if (typeof size == 'string') {
287
378
  return Number(size.slice(0, -1));
@@ -296,7 +387,7 @@ function Knob(_a) {
296
387
  event.preventDefault();
297
388
  if (dragOffsetY.current) {
298
389
  if (bodyNoSelect)
299
- document.body.classList.add('no-select');
390
+ addNoSelect();
300
391
  const screenY = isTouch ? event.touches[0].screenY : event.screenY;
301
392
  const delta = dragOffsetY.current - screenY;
302
393
  dragOffsetY.current = screenY;
@@ -309,12 +400,12 @@ function Knob(_a) {
309
400
  };
310
401
  // --- hooks ---
311
402
  const wheelRefCallback = useRefCallbackEvent('wheel', (event) => {
312
- if (!enableWheel)
403
+ if (!wheel)
313
404
  return;
314
405
  event.preventDefault();
315
- const x = event.deltaY > 0 ? -enableWheel[1] : enableWheel[1];
406
+ const x = event.deltaY > 0 ? -wheel[1] : wheel[1];
316
407
  let v;
317
- if (enableWheel[0] == 'normalized') {
408
+ if (wheel[0] == 'normalized') {
318
409
  const n = normalizeValue(value, min, max, skew);
319
410
  v = rawValue(n + x, min, max, skew);
320
411
  }
@@ -323,18 +414,18 @@ function Knob(_a) {
323
414
  }
324
415
  if (onChange)
325
416
  onChange(clamp(stepValue(v, step), min, max));
326
- }, { passive: false }, [enableWheel, value, min, max, skew, step, onChange]);
417
+ }, { passive: false }, [wheel, value, min, max, skew, step, onChange]);
327
418
  const touchMoveRefCallback = useRefCallbackEvent('touchmove', handleEvent, { passive: false }, [value, min, max, skew, step, onChange, bodyNoSelect]);
328
419
  useEventListener(window, 'mousemove', handleEvent);
329
420
  useEventListener(window, 'pointerup', () => {
330
421
  dragOffsetY.current = undefined;
331
422
  if (bodyNoSelect)
332
- document.body.classList.remove('no-select');
423
+ removeNoSelect();
333
424
  });
334
425
  return (jsxRuntime.jsxs("div", Object.assign({ className: clsx('tremolo-knob', className), ref: (div) => {
335
426
  wheelRefCallback(div);
336
427
  touchMoveRefCallback(div);
337
- }, role: "slider", tabIndex: 0, "aria-valuenow": value, "aria-valuemax": max, "aria-valuemin": min, css: react.css(Object.assign(Object.assign({ display: 'inline-block', width: size !== null && size !== void 0 ? size : width, height: size !== null && size !== void 0 ? size : height, cursor: 'pointer' }, style), { ':active': Object.assign({}, _active), ':focus': Object.assign({}, _focus), ':hover': Object.assign({}, _hover) })), onPointerDown: (event) => {
428
+ }, role: "slider", tabIndex: 0, "aria-valuenow": value, "aria-valuemax": max, "aria-valuemin": min, css: react.css(Object.assign(Object.assign({ display: 'inline-block', width: size !== null && size !== undefined ? size : width, height: size !== null && size !== undefined ? size : height, cursor: 'pointer' }, style), { ':active': Object.assign({}, _active), ':focus': Object.assign({}, _focus), ':hover': Object.assign({}, _hover) })), onPointerDown: (event) => {
338
429
  dragOffsetY.current = event.screenY;
339
430
  handleEvent(event);
340
431
  }, onDoubleClick: () => {
@@ -345,7 +436,7 @@ function Knob(_a) {
345
436
  '.no-select': {
346
437
  userSelect: 'none',
347
438
  },
348
- } }), jsxRuntime.jsx(AnimationCanvas, { width: adaptSize(size !== null && size !== void 0 ? size : width), height: adaptSize(size !== null && size !== void 0 ? size : height), relativeSize: isRelativeSize,
439
+ } }), jsxRuntime.jsx(AnimationCanvas, { width: adaptSize(size !== null && size !== undefined ? size : width), height: adaptSize(size !== null && size !== undefined ? size : height), relativeSize: isRelativeSize,
349
440
  // TODO
350
441
  // reduceFlickering={false}
351
442
  draw: draw ? draw : (ctx, width, height) => {
@@ -390,10 +481,21 @@ function Knob(_a) {
390
481
  } })] })));
391
482
  }
392
483
 
484
+ /**
485
+ * clamp value between min and max
486
+ * @category Math
487
+ */
488
+ /**
489
+ *
490
+ * @category Math
491
+ */
393
492
  function toFixed$1(x, fractionDigits) {
394
493
  return Number(x.toFixed(fractionDigits));
395
494
  }
396
495
 
496
+ /**
497
+ * @module NumberInput
498
+ */
397
499
  function selectUnit(units, value) {
398
500
  if (typeof units == 'string')
399
501
  return [units, 1];
@@ -456,14 +558,14 @@ function parseValue(inputString, units, digit, defaultValue = 0) {
456
558
  * Input with some useful functions for entering numerical values.
457
559
  */
458
560
  function NumberInput(_a) {
459
- var { value, min, max, step, defaultValue = min, units, disabled = false, placeholder, readOnly, tabIndex, strict = false, digit, selectWithFocus = 'none', blurWithEnter = true, className, style, onChange, onFocus, onBlur } = _a, pseudo = __rest(_a, ["value", "min", "max", "step", "defaultValue", "units", "disabled", "placeholder", "readOnly", "tabIndex", "strict", "digit", "selectWithFocus", "blurWithEnter", "className", "style", "onChange", "onFocus", "onBlur"]);
561
+ var { value, min, max, step, defaultValue = min, units, disabled = false, placeholder, readOnly, tabIndex, typeNumber = false, digit, selectWithFocus = 'none', blurWithEnter = true, className, style, onChange, onFocus, onBlur } = _a, props = __rest(_a, ["value", "min", "max", "step", "defaultValue", "units", "disabled", "placeholder", "readOnly", "tabIndex", "typeNumber", "digit", "selectWithFocus", "blurWithEnter", "className", "style", "onChange", "onFocus", "onBlur"]);
460
562
  const [showValue, setShowValue] = React.useState(parseValue(String(value), units, digit, defaultValue).formatValue);
461
- const calculatedStrict = units ? false : strict;
462
- const { _active, _focus, _hover } = pseudo;
463
- return (jsxRuntime.jsx("input", { className: clsx('tremolo-number-input', className), value: showValue, min: min, max: max, step: step, type: calculatedStrict ? 'number' : 'text', spellCheck: 'false', disabled: disabled, placeholder: placeholder, readOnly: readOnly, tabIndex: tabIndex, css: react.css(Object.assign(Object.assign({ display: 'inline-block', font: 'inherit', margin: 0, paddingTop: 6, paddingBottom: 6, paddingLeft: 10, paddingRight: 10, borderStyle: 'solid', borderWidth: 1, borderColor: '#bbb', borderRadius: 4, outline: 0, transition: 'all 0.1s linear', appearance: 'textfield', '&:hover': Object.assign({ borderColor: 'var(--tremolo-theme-color)' }, _hover), '&:focus': Object.assign({ borderColor: 'var(--tremolo-theme-color)', boxShadow: '0px 0px 0px 2px rgba(var(--tremolo-theme-color-rgb), 0.1)' }, _focus) }, (_active && { '&:active': Object.assign({}, _active) })), style)), onChange: (event) => {
563
+ const calculatedTypeNumber = units ? false : typeNumber;
564
+ const { _active, _focus, _hover } = props, rest = __rest(props, ["_active", "_focus", "_hover"]);
565
+ return (jsxRuntime.jsx("input", Object.assign({ className: clsx('tremolo-number-input', className), value: showValue, min: min, max: max, step: step, type: calculatedTypeNumber ? 'number' : 'text', spellCheck: 'false', disabled: disabled, placeholder: placeholder, readOnly: readOnly, tabIndex: tabIndex, css: react.css(Object.assign(Object.assign({ display: 'inline-block', font: 'inherit', margin: 0, paddingTop: 6, paddingBottom: 6, paddingLeft: 10, paddingRight: 10, borderStyle: 'solid', borderWidth: 1, borderColor: '#bbb', borderRadius: 4, outline: 0, transition: 'all 0.1s linear', appearance: 'textfield', '&:hover': Object.assign({ borderColor: 'var(--tremolo-theme-color)' }, _hover), '&:focus': Object.assign({ borderColor: 'var(--tremolo-theme-color)', boxShadow: '0px 0px 0px 2px rgba(var(--tremolo-theme-color-rgb), 0.1)' }, _focus) }, (_active && { '&:active': Object.assign({}, _active) })), style)), onChange: (event) => {
464
566
  const v = event.currentTarget.value;
465
567
  setShowValue(v);
466
- const newValue = clamp(parseValue(v, units, digit, defaultValue).rawValue, min !== null && min !== void 0 ? min : -Infinity, max !== null && max !== void 0 ? max : Infinity);
568
+ const newValue = clamp(parseValue(v, units, digit, defaultValue).rawValue, min !== null && min !== undefined ? min : -Infinity, max !== null && max !== undefined ? max : Infinity);
467
569
  if (onChange)
468
570
  onChange(newValue, event);
469
571
  }, onFocus: (event) => {
@@ -488,16 +590,286 @@ function NumberInput(_a) {
488
590
  if (blurWithEnter && event.key == 'Enter') {
489
591
  event.currentTarget.blur();
490
592
  }
491
- } }));
593
+ } }, rest)));
594
+ }
595
+
596
+ function KeyLabel({ label, className, style, wrapperStyle, __note, __index, __label, }) {
597
+ const content = label ? label(__note, __index) : __label && __label(__note, __index);
598
+ return ((content != undefined || content != null) &&
599
+ jsxRuntime.jsx("div", { className: 'tremolo-piano-key-label-wrapper', css: react.css(Object.assign({ display: 'flex', justifyContent: 'center', alignItems: 'end', height: '100%' }, wrapperStyle)), children: jsxRuntime.jsx("div", { className: clsx('tremolo-piano-key-label', className), css: react.css(Object.assign({ display: 'flex', justifyContent: 'center', alignItems: 'center', fontSize: '0.6rem', height: 10, marginBottom: 10, padding: 4, borderRadius: 4, borderStyle: 'solid', borderWidth: 1, borderColor: '#888', aspectRatio: 1, maxWidth: 'calc(100% - 16px)' }, style)), children: content }) }));
492
600
  }
493
601
 
602
+ const WhiteKey = React.forwardRef(({ width = 40, height = '100%', bg = 'white', activeBg = '#ccc', style, children, __glissando, __position, __note, __disabled, __index, __fill, __width, __playNote, __stopNote, __label, }, ref) => {
603
+ const [played, setPlayed] = React.useState(false);
604
+ React.useImperativeHandle(ref, () => {
605
+ return {
606
+ play() {
607
+ if (__disabled)
608
+ return;
609
+ setPlayed(true);
610
+ if (__playNote)
611
+ __playNote(__note);
612
+ },
613
+ stop() {
614
+ setPlayed(false);
615
+ if (__stopNote)
616
+ __stopNote(__note);
617
+ },
618
+ played() {
619
+ return played;
620
+ }
621
+ };
622
+ }, []);
623
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
624
+ let keyLabelProps;
625
+ if (children != undefined) {
626
+ React.Children.forEach(children, (child) => {
627
+ if (React.isValidElement(child)) {
628
+ if (child.type == KeyLabel) {
629
+ keyLabelProps = child.props;
630
+ }
631
+ else {
632
+ throw new Error('only <KeyLabel>');
633
+ }
634
+ }
635
+ else {
636
+ throw new Error('children is an invalid element.');
637
+ }
638
+ });
639
+ }
640
+ return (jsxRuntime.jsx("div", { className: `tremolo-piano-white-key`, "aria-disabled": __disabled, css: react.css(Object.assign({ position: 'absolute', backgroundColor: played ? activeBg : bg, color: 'black', left: __position, width: __fill ? __width : (width !== null && width !== undefined ? width : __width), height: height, border: '1px solid #555', borderRadius: '0 0 8px 8px', cursor: __disabled ? 'not-allowed' : 'pointer', zIndex: 1 }, style)), onPointerDown: () => {
641
+ if (__disabled)
642
+ return;
643
+ setPlayed(true);
644
+ if (__playNote)
645
+ __playNote(__note);
646
+ }, onPointerEnter: () => {
647
+ if (__disabled)
648
+ return;
649
+ if (__glissando) {
650
+ setPlayed(true);
651
+ if (__playNote)
652
+ __playNote(__note);
653
+ }
654
+ }, onPointerUp: () => {
655
+ if (__disabled)
656
+ return;
657
+ setPlayed(false);
658
+ if (__stopNote)
659
+ __stopNote(__note);
660
+ }, onPointerLeave: () => {
661
+ if (__disabled)
662
+ return;
663
+ setPlayed(false);
664
+ if (__stopNote)
665
+ __stopNote(__note);
666
+ }, children: jsxRuntime.jsx(KeyLabel, Object.assign({ __note: __note, __label: __label, __index: __index }, keyLabelProps)) }));
667
+ });
668
+
669
+ const BlackKey = React.forwardRef(({ width = 40 * 0.65, height = '60%', bg = '#333', activeBg = '#666', style, children, __glissando, __position, __note, __disabled, __index, __fill, __width, __playNote, __stopNote, __label, }, ref) => {
670
+ const [played, setPlayed] = React.useState(false);
671
+ React.useImperativeHandle(ref, () => {
672
+ return {
673
+ play() {
674
+ if (__disabled)
675
+ return;
676
+ setPlayed(true);
677
+ if (__playNote)
678
+ __playNote(__note);
679
+ },
680
+ stop() {
681
+ setPlayed(false);
682
+ if (__stopNote)
683
+ __stopNote(__note);
684
+ },
685
+ played() {
686
+ return played;
687
+ }
688
+ };
689
+ }, []);
690
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
691
+ let keyLabelProps;
692
+ if (children != undefined) {
693
+ React.Children.forEach(children, (child) => {
694
+ if (React.isValidElement(child)) {
695
+ if (child.type == KeyLabel) {
696
+ keyLabelProps = child.props;
697
+ }
698
+ else {
699
+ throw new Error('only <KeyLabel>');
700
+ }
701
+ }
702
+ else {
703
+ throw new Error('children is an invalid element.');
704
+ }
705
+ });
706
+ }
707
+ return (jsxRuntime.jsx("div", { className: `tremolo-piano-black-key`, "aria-disabled": __disabled, css: react.css(Object.assign({ position: 'absolute', backgroundColor: played ? activeBg : bg, color: 'white', left: __position, width: __fill ? __width : (width !== null && width !== undefined ? width : __width), height: height, border: '1px solid #555', borderRadius: '0 0 8px 8px', cursor: __disabled ? 'not-allowed' : 'pointer', zIndex: 2 }, style)), onPointerDown: () => {
708
+ if (__disabled)
709
+ return;
710
+ setPlayed(true);
711
+ if (__playNote)
712
+ __playNote(__note);
713
+ }, onPointerEnter: () => {
714
+ if (__disabled)
715
+ return;
716
+ if (__glissando) {
717
+ setPlayed(true);
718
+ if (__playNote)
719
+ __playNote(__note);
720
+ }
721
+ }, onPointerUp: () => {
722
+ if (__disabled)
723
+ return;
724
+ setPlayed(false);
725
+ if (__stopNote)
726
+ __stopNote(__note);
727
+ }, onPointerLeave: () => {
728
+ if (__disabled)
729
+ return;
730
+ setPlayed(false);
731
+ if (__stopNote)
732
+ __stopNote(__note);
733
+ }, children: jsxRuntime.jsx(KeyLabel, Object.assign({ __note: __note, __label: __label, __index: __index }, keyLabelProps)) }));
734
+ });
735
+
736
+ const Shortcuts = {
737
+ HOME_ROW: {
738
+ keys: ['a', 'w', 's', 'e', 'd', 'f', 't', 'g', 'y', 'h', 'u', 'j', 'k', 'o', 'l', 'p', ';']
739
+ }
740
+ };
741
+
742
+ function Piano({ noteRange, glissando = true, midiMax = 127, keyboardShortcuts, fill = false, height = fill ? '100%' : 160, style, playNote, stopNote, label, children, }) {
743
+ // -- state and ref ---
744
+ const [pressed, setPressed] = React.useState(false);
745
+ const [whiteNoteWidth, setWhiteNoteWidth] = React.useState(-1);
746
+ const keyRefs = React.useRef([]);
747
+ for (let i = 0; i < noteRange.last - noteRange.first + 1; i++) {
748
+ keyRefs.current[i] = React.createRef();
749
+ }
750
+ const pianoRef = React.useRef(null);
751
+ // --- interpret props ---
752
+ const noteRangeArray = Array.from({ length: noteRange.last - noteRange.first + 1 }, (_, i) => i + noteRange.first);
753
+ const whiteNoteCount = noteRangeArray.filter((v) => isWhiteKey(v)).length;
754
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
755
+ let whiteKeyProps, blackKeyProps;
756
+ if (children != undefined) {
757
+ React.Children.forEach(children, (child) => {
758
+ if (React.isValidElement(child)) {
759
+ if (child.type == WhiteKey) {
760
+ whiteKeyProps = child.props;
761
+ }
762
+ else if (child.type == BlackKey) {
763
+ blackKeyProps = child.props;
764
+ }
765
+ else {
766
+ throw new Error('only <WhiteKey> or <BlackKey>');
767
+ }
768
+ }
769
+ else {
770
+ throw new Error('children is an invalid element.');
771
+ }
772
+ });
773
+ }
774
+ // --- internal functions ---
775
+ function notePosition(note) {
776
+ const pitchPositions = {
777
+ C: 0,
778
+ 'C#': 0.55,
779
+ D: 1,
780
+ 'D#': 1.8,
781
+ E: 2,
782
+ F: 3,
783
+ 'F#': 3.5,
784
+ G: 4,
785
+ 'G#': 4.7,
786
+ A: 5,
787
+ 'A#': 5.85,
788
+ B: 6,
789
+ };
790
+ const toNoteName = (n) => {
791
+ const { letter, accidental } = parseNoteName(noteName(n));
792
+ return (letter + accidental);
793
+ };
794
+ const _noteName = toNoteName(note);
795
+ const firstNoteName = toNoteName(noteRange.first);
796
+ const pos = pitchPositions[_noteName] - pitchPositions[firstNoteName];
797
+ const octave = Math.floor((note - noteRange.first) / 12);
798
+ const octaveOffset = noteNames.indexOf(firstNoteName) > noteNames.indexOf(_noteName) ? 1 : 0;
799
+ const length = whiteNoteWidth + 3;
800
+ return pos * length + (octave + octaveOffset) * 7 * length;
801
+ }
802
+ // --- hooks ---
803
+ React.useEffect(() => {
804
+ if (fill && pianoRef.current) {
805
+ const parent = pianoRef.current.parentElement;
806
+ if (!parent)
807
+ throw new Error("doesn't have a parent element.");
808
+ const resizeObserver = new ResizeObserver(() => {
809
+ const w = pianoRef.current.clientWidth;
810
+ setWhiteNoteWidth(w / whiteNoteCount - 3);
811
+ });
812
+ resizeObserver.observe(parent);
813
+ }
814
+ else {
815
+ setWhiteNoteWidth((whiteKeyProps === null || whiteKeyProps === undefined ? undefined : whiteKeyProps.width) || 40);
816
+ }
817
+ }, []);
818
+ useEventListener(window, 'keydown', (e) => {
819
+ var _a, _b, _c, _d;
820
+ if (e.repeat)
821
+ return;
822
+ if (!keyboardShortcuts)
823
+ return;
824
+ const index = keyboardShortcuts.keys.indexOf(e.key);
825
+ if (index != -1) {
826
+ if (!((_b = (_a = keyRefs.current[index]) === null || _a === undefined ? undefined : _a.current) === null || _b === undefined ? undefined : _b.played())) {
827
+ (_d = (_c = keyRefs.current[index]) === null || _c === undefined ? undefined : _c.current) === null || _d === undefined ? undefined : _d.play();
828
+ }
829
+ }
830
+ });
831
+ useEventListener(window, 'keyup', (e) => {
832
+ var _a, _b;
833
+ if (e.repeat)
834
+ return;
835
+ if (!keyboardShortcuts)
836
+ return;
837
+ const index = keyboardShortcuts.keys.indexOf(e.key);
838
+ if (index != -1) {
839
+ (_b = (_a = keyRefs.current[index]) === null || _a === undefined ? undefined : _a.current) === null || _b === undefined ? undefined : _b.stop();
840
+ }
841
+ });
842
+ return (jsxRuntime.jsx("div", { ref: pianoRef, className: "tremolo-piano", css: react.css(Object.assign({ display: 'inline-block', boxSizing: 'border-box', userSelect: 'none', width: fill ? '100%' : undefined, height: height, position: 'relative' }, style)), onPointerDown: () => {
843
+ setPressed(true);
844
+ }, onPointerUp: () => {
845
+ setPressed(false);
846
+ }, children: noteRangeArray.map((note, index) => {
847
+ return (isWhiteKey(note) ? (jsxRuntime.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, __playNote: playNote, __stopNote: stopNote, __label: label }, whiteKeyProps), note)) : (jsxRuntime.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, __playNote: playNote, __stopNote: stopNote, __label: label }, blackKeyProps), note)));
848
+ }) }));
849
+ }
850
+
851
+ /**
852
+ * clamp value between min and max
853
+ * @category Math
854
+ */
855
+ /**
856
+ *
857
+ * @category Math
858
+ */
494
859
  function toFixed(x, fractionDigits) {
495
860
  return Number(x.toFixed(fractionDigits));
496
861
  }
862
+ /**
863
+ *
864
+ * @category Math
865
+ */
497
866
  function decimalPart(x) {
498
867
  return String(x).split('.')[1];
499
868
  }
500
869
 
870
+ /**
871
+ * @module Slider
872
+ */
501
873
  function isHorizontal(d) {
502
874
  return d == 'right' || d == 'left';
503
875
  }
@@ -526,46 +898,76 @@ function parseScaleOrderList(scale, min, max, step) {
526
898
  const per = scale[0] == 'step' ? step : scale[0];
527
899
  const count = Math.floor(max / per) - Math.ceil(min / per) + 1;
528
900
  for (let i = 0; i < count; i++) {
529
- const at = toFixed(per * (Math.ceil(min / per) + i), (_a = decimalPart(per)) === null || _a === void 0 ? void 0 : _a.length);
901
+ const at = toFixed(per * (Math.ceil(min / per) + i), (_a = decimalPart(per)) === null || _a === undefined ? undefined : _a.length);
530
902
  scalesList.push({ at: at, type: scale[1] });
531
903
  }
532
904
  }
533
905
  return scalesList;
534
906
  }
535
907
 
536
- function SliderThumb({ color, children, style, __css, }) {
537
- return (jsxRuntime.jsx("div", { className: "tremolo-slider-thumb-wrapper", css: react.css(Object.assign({ width: 'fit-content', height: 'fit-content', position: 'absolute', translate: '-50% -50%', zIndex: 100 }, __css)), children: children ? (children) : (
908
+ const SliderThumb = React.forwardRef(({ size, width = 22, height = 22, color = '#4e76e6', hoverColor = color, disabledColor = '#5d6478', disabledHoverColor = disabledColor, zIndex = 100, children, className, style, __disabled, __css, }, ref) => {
909
+ const wrapperRef = React.useRef(null);
910
+ React.useImperativeHandle(ref, () => {
911
+ return {
912
+ focus() {
913
+ var _a;
914
+ (_a = wrapperRef.current) === null || _a === undefined ? undefined : _a.focus();
915
+ },
916
+ blur() {
917
+ var _a;
918
+ (_a = wrapperRef.current) === null || _a === undefined ? undefined : _a.blur();
919
+ },
920
+ };
921
+ }, []);
922
+ return (jsxRuntime.jsx("div", { className: "tremolo-slider-thumb-wrapper", css: react.css(Object.assign({ position: 'absolute', translate: '-50% -50%', zIndex: zIndex }, __css)), children: children ? (children) : (
538
923
  // default slider thumb
539
- jsxRuntime.jsx("div", { className: "tremolo-slider-thumb",
924
+ jsxRuntime.jsx("div", { ref: wrapperRef, className: clsx('tremolo-slider-thumb', className),
540
925
  // eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex
541
- tabIndex: 0, css: react.css(Object.assign({ background: color, width: '1.4rem', height: '1.4rem', borderRadius: '50%', '&:hover': {
542
- background: `color-mix(in srgb, ${color} 95%, black)`
543
- }, '&:active': {
926
+ tabIndex: 0, css: react.css(Object.assign({ background: __disabled ? disabledColor : color, width: size !== null && size !== undefined ? size : width, height: size !== null && size !== undefined ? size : height, borderRadius: '50%', outline: 'none', '&:hover': {
927
+ background: __disabled ? disabledHoverColor : hoverColor
928
+ }, '&:focus': !__disabled && {
544
929
  boxShadow: '0px 0px 0px 3px rgba(var(--tremolo-theme-color-rgb), 0.2)',
545
930
  } }, style)) })) }));
546
- }
931
+ });
547
932
 
548
- function SliderTrack({ children, style, __css, }) {
549
- return (jsxRuntime.jsx("div", { className: "tremolo-slider-track", css: react.css(Object.assign(Object.assign({}, __css), style)), children: children }));
933
+ function SliderTrack({ length = 140, thickness = 10, activeBg = '#7998ec', inactiveBg = '#eee', activeHoverBg = '#6387e9', inactiveHoverBg = '#e0e0e0', disabledActiveBg = '#858890', disabledInactiveBg = '#ddd', disabledActiveHoverBg = disabledActiveBg, disabledInactiveHoverBg = disabledInactiveBg, children, className, style, __thumb, __direction, __disabled, __percent, }) {
934
+ const active = __disabled ? disabledActiveBg : activeBg;
935
+ const inactive = __disabled ? disabledInactiveBg : inactiveBg;
936
+ const activeHover = __disabled ? disabledActiveHoverBg : activeHoverBg;
937
+ const inactiveHover = __disabled ? disabledInactiveHoverBg : inactiveHoverBg;
938
+ return (jsxRuntime.jsxs("div", { className: clsx('tremolo-slider-track', className), css: react.css(Object.assign({ position: 'relative', background: `linear-gradient(to ${gradientDirection(__direction)}, ${active} ${__percent}%, ${inactive} ${__percent}%)`, borderRadius: styleHelper(thickness, '/', 2), width: isHorizontal(__direction) ? length : thickness, height: isHorizontal(__direction) ? thickness : length, ':hover': {
939
+ background: `linear-gradient(to ${gradientDirection(__direction)}, ${activeHover} ${__percent}%, ${inactiveHover} ${__percent}%)`
940
+ } }, style)), children: [children, __thumb] }));
550
941
  }
551
942
 
552
943
  /**
553
944
  * Customizable slider
554
945
  */
555
- function Slider(_a) {
556
- var _b, _c;
557
- var { value, min, max, step = 1, skew = 1, length = 140, thickness = 10, direction = 'right', scale, scaleOption, color = '#4e76e6', bg = '#eee', className, style, bodyNoSelect = true, enableWheel, onChange, children } = _a; __rest(_a, ["value", "min", "max", "step", "skew", "length", "thickness", "direction", "scale", "scaleOption", "color", "bg", "className", "style", "bodyNoSelect", "enableWheel", "onChange", "children"]);
946
+ const Slider = React.forwardRef((_a, ref) => {
947
+ var _b, _c, _d, _e, _f, _g, _h;
948
+ var { value, min, max, step = 1, skew = 1, direction = 'right', scale, scaleOption, className, style, bodyNoSelect = true, wheel = ['raw', 1], keyboard = ['raw', 1], disabled = false, readonly = false, onChange, children } = _a; __rest(_a, ["value", "min", "max", "step", "skew", "direction", "scale", "scaleOption", "className", "style", "bodyNoSelect", "wheel", "keyboard", "disabled", "readonly", "onChange", "children"]);
558
949
  // -- state and ref ---
559
950
  const trackElementRef = React.useRef(null);
560
- const percent = normalizeValue(value, min, max, skew) * 100;
561
- const percentRev = isReversed(direction) ? 100 - percent : percent;
951
+ const thumbRef = React.useRef(null);
952
+ const thumbDragged = React.useRef(false);
953
+ const percent = toFixed$2(normalizeValue(value, min, max, skew) * 100);
954
+ const percentRev = isReversed(direction) ? toFixed$2(100 - percent) : percent;
955
+ const calcPercent = (v) => {
956
+ return toFixed$2(isReversed(direction)
957
+ ? 100 - normalizeValue(v, min, max, skew) * 100
958
+ : normalizeValue(v, min, max, skew) * 100);
959
+ };
960
+ if (wheel.length != 2) {
961
+ throw new Error(`Slider.wheel expect ['normalized' | 'raw', number]`);
962
+ }
963
+ if (keyboard.length != 2) {
964
+ throw new Error(`Slider.keyboard expect ['normalized' | 'raw', number]`);
965
+ }
562
966
  const scalesList = parseScaleOrderList(scale, min, max, step);
563
967
  if (isReversed(direction))
564
968
  scalesList.reverse();
565
969
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
566
- let trackProps;
567
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
568
- let thumbProps;
970
+ let trackProps, thumbProps;
569
971
  if (children != undefined) {
570
972
  React.Children.forEach(children, (child) => {
571
973
  if (React.isValidElement(child)) {
@@ -584,15 +986,15 @@ function Slider(_a) {
584
986
  }
585
987
  });
586
988
  }
587
- const thumbDragged = React.useRef(false);
989
+ // --- internal functions ---
588
990
  const handleValue = (event) => {
589
- if (!trackElementRef.current || !thumbDragged.current)
991
+ if (!trackElementRef.current || !thumbDragged.current || !onChange || readonly)
590
992
  return;
591
993
  const isTouch = event instanceof TouchEvent;
592
994
  if (isTouch && event.cancelable)
593
995
  event.preventDefault();
594
996
  if (bodyNoSelect)
595
- document.body.classList.add('no-select');
997
+ addNoSelect();
596
998
  const { left: x1, top: y1, right: x2, bottom: y2, } = trackElementRef.current.getBoundingClientRect();
597
999
  const mouseX = isTouch ? event.touches[0].clientX : event.clientX;
598
1000
  const mouseY = isTouch ? event.touches[0].clientY : event.clientY;
@@ -600,70 +1002,90 @@ function Slider(_a) {
600
1002
  ? normalizeValue(mouseX, x1, x2)
601
1003
  : normalizeValue(mouseY, y1, y2);
602
1004
  const v = rawValue(isReversed(direction) ? 1 - n : n, min, max, skew);
603
- const v2 = clamp(stepValue(v, step), min, max);
604
- if (onChange)
605
- onChange(v2);
1005
+ onChange(clamp(stepValue(v, step), min, max));
606
1006
  };
1007
+ const handleKeyDown = React.useCallback((event) => {
1008
+ if (!keyboard || !onChange || readonly)
1009
+ return;
1010
+ const key = event.key;
1011
+ if (['ArrowRight', 'ArrowLeft', 'ArrowUp', 'ArrowDown'].includes(key)) {
1012
+ event.preventDefault();
1013
+ let x = (key == 'ArrowRight' || key == 'ArrowUp') ? keyboard[1] : -keyboard[1];
1014
+ if (direction == 'down' || direction == 'left')
1015
+ x *= -1;
1016
+ let v;
1017
+ if (keyboard[0] == 'normalized') {
1018
+ const n = normalizeValue(value, min, max, skew);
1019
+ v = rawValue(n + x, min, max, skew);
1020
+ }
1021
+ else {
1022
+ v = value + x;
1023
+ }
1024
+ onChange(clamp(stepValue(v, step), min, max));
1025
+ }
1026
+ }, [value, min, max, step, skew, direction, keyboard, onChange, readonly]);
607
1027
  // --- hooks ---
608
- const touchMoveRefCallback = useRefCallbackEvent('touchmove', handleValue, { passive: false }, [min, max, skew, step, direction, onChange]);
1028
+ const touchMoveRefCallback = useRefCallbackEvent('touchmove', handleValue, { passive: false }, [min, max, skew, step, direction, onChange, readonly]);
609
1029
  const wheelRefCallback = useRefCallbackEvent('wheel', (event) => {
610
- if (!enableWheel)
1030
+ if (!wheel || !onChange || readonly)
611
1031
  return;
612
1032
  event.preventDefault();
613
- let x = event.deltaY > 0 ? enableWheel[1] : -enableWheel[1];
1033
+ let x = event.deltaY > 0 ? wheel[1] : -wheel[1];
614
1034
  if (isReversed(direction) || isHorizontal(direction))
615
1035
  x *= -1;
616
1036
  let v;
617
- if (enableWheel[0] == 'normalized') {
1037
+ if (wheel[0] == 'normalized') {
618
1038
  const n = normalizeValue(value, min, max, skew);
619
1039
  v = rawValue(n + x, min, max, skew);
620
1040
  }
621
1041
  else {
622
1042
  v = value + x;
623
1043
  }
624
- if (onChange)
625
- onChange(clamp(stepValue(v, step), min, max));
1044
+ onChange(clamp(stepValue(v, step), min, max));
626
1045
  }, {
627
1046
  passive: false,
628
- }, [enableWheel, value, min, max, skew, step]);
1047
+ }, [wheel, value, min, max, skew, step]);
629
1048
  useEventListener(window, 'mousemove', (event) => {
630
1049
  handleValue(event);
631
1050
  });
632
1051
  useEventListener(window, 'mouseup', () => {
633
1052
  thumbDragged.current = false;
634
1053
  if (bodyNoSelect)
635
- document.body.classList.remove('no-select');
1054
+ removeNoSelect();
636
1055
  });
1056
+ React.useImperativeHandle(ref, () => {
1057
+ return {
1058
+ focus() {
1059
+ var _a;
1060
+ (_a = thumbRef.current) === null || _a === undefined ? undefined : _a.focus();
1061
+ },
1062
+ blur() {
1063
+ var _a;
1064
+ (_a = thumbRef.current) === null || _a === undefined ? undefined : _a.blur();
1065
+ },
1066
+ };
1067
+ }, []);
637
1068
  return (jsxRuntime.jsxs("div", { className: clsx('tremolo-slider', className), ref: (div) => {
638
1069
  wheelRefCallback(div);
639
1070
  touchMoveRefCallback(div);
640
- }, tabIndex: -1, role: "slider", "aria-valuenow": value, "aria-valuemax": max, "aria-valuemin": min, "aria-orientation": isHorizontal(direction) ? 'horizontal' : 'vertical', css: react.css(Object.assign({ display: 'inline-block', boxSizing: 'border-box', margin: '0.7rem', padding: 0, cursor: 'pointer' }, style)), onPointerDown: (event) => {
1071
+ }, tabIndex: -1, role: "slider", "aria-valuenow": value, "aria-valuemin": min, "aria-valuemax": max, "aria-orientation": isHorizontal(direction) ? 'horizontal' : 'vertical', "aria-disabled": disabled, "aria-readonly": readonly, css: react.css(Object.assign({ display: 'inline-block', margin: `calc(${styleHelper((_b = thumbProps === null || thumbProps === undefined ? undefined : thumbProps.size) !== null && _b !== undefined ? _b : 22)} / 2)`, cursor: readonly ? 'not-allowed' : 'pointer', outline: 0 }, style)), onPointerDown: (event) => {
641
1072
  thumbDragged.current = true;
642
1073
  handleValue(event);
643
- }, children: [jsxRuntime.jsx(react.Global, { styles: {
1074
+ }, onKeyDown: handleKeyDown, onFocus: (_c = thumbRef.current) === null || _c === undefined ? undefined : _c.focus, onBlur: (_d = thumbRef.current) === null || _d === undefined ? undefined : _d.blur, children: [jsxRuntime.jsx(react.Global, { styles: {
644
1075
  '.no-select': {
645
1076
  userSelect: 'none',
646
1077
  },
647
1078
  } }), jsxRuntime.jsxs("div", { css: react.css({
648
1079
  display: 'flex',
649
1080
  flexDirection: isHorizontal(direction) ? 'column' : 'row',
650
- }), children: [jsxRuntime.jsxs("div", { className: "tremolo-slider-track-wrapper", ref: trackElementRef, css: react.css({ position: 'relative' }), children: [jsxRuntime.jsx(SliderTrack, Object.assign({ __css: {
651
- background: `linear-gradient(to ${gradientDirection(direction)}, ${color} ${percent}%, ${bg} ${percent}%)`,
652
- borderRadius: styleHelper(thickness, '/', 2),
653
- borderStyle: 'solid',
654
- borderColor: '#ccc',
655
- borderWidth: 2,
656
- width: isHorizontal(direction) ? length : thickness,
657
- height: isHorizontal(direction) ? thickness : length,
658
- zIndex: 1,
659
- } }, trackProps)), jsxRuntime.jsx(SliderThumb, Object.assign({ color: color, __css: {
1081
+ }), children: [jsxRuntime.jsx("div", { className: "tremolo-slider-track-wrapper", ref: trackElementRef, children: jsxRuntime.jsx(SliderTrack, Object.assign({ __direction: direction, __disabled: disabled, __percent: percent, __thumb: jsxRuntime.jsx(SliderThumb, Object.assign({ ref: thumbRef, __disabled: disabled, __css: {
660
1082
  top: isHorizontal(direction) ? '50%' : `${percentRev}%`,
661
1083
  left: isHorizontal(direction) ? `${percentRev}%` : '50%',
662
- } }, thumbProps))] }), scale && (jsxRuntime.jsx("div", { className: "tremolo-slider-scale-wrapper", css: react.css(Object.assign({ position: 'relative', width: isHorizontal(direction) ? length : undefined, height: isVertical(direction) ? length : undefined, marginLeft: isHorizontal(direction)
663
- ? 2
664
- : ((_b = scaleOption === null || scaleOption === void 0 ? void 0 : scaleOption.gap) !== null && _b !== void 0 ? _b : `calc((1.4rem - ${styleHelper(thickness)}) / 2)`), marginTop: isVertical(direction)
665
- ? 2
666
- : ((_c = scaleOption === null || scaleOption === void 0 ? void 0 : scaleOption.gap) !== null && _c !== void 0 ? _c : `calc((1.4rem - ${styleHelper(thickness)}) / 2)`) }, scaleOption === null || scaleOption === void 0 ? void 0 : scaleOption.style)), children: scalesList.map((item, index) => {
1084
+ } }, thumbProps)) }, trackProps)) }), scale && (jsxRuntime.jsx("div", { className: "tremolo-slider-scale-wrapper", css: react.css(Object.assign({ display: 'block', position: 'relative', marginLeft: isVertical(direction)
1085
+ ? ((_e = scaleOption === null || scaleOption === undefined ? undefined : scaleOption.gap) !== null && _e !== undefined ? _e : `calc((22px - ${styleHelper((_f = trackProps === null || trackProps === undefined ? undefined : trackProps.thickness) !== null && _f !== undefined ? _f : 10)}) / 2)`)
1086
+ : undefined, marginTop: isHorizontal(direction)
1087
+ ? ((_g = scaleOption === null || scaleOption === undefined ? undefined : scaleOption.gap) !== null && _g !== undefined ? _g : `calc((22px - ${styleHelper((_h = trackProps === null || trackProps === undefined ? undefined : trackProps.thickness) !== null && _h !== undefined ? _h : 10)}) / 2)`)
1088
+ : undefined }, scaleOption === null || scaleOption === undefined ? undefined : scaleOption.style)), children: scalesList.map((item, index) => {
667
1089
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
668
1090
  return (jsxRuntime.jsxs("div", { css: react.css({
669
1091
  display: 'flex',
@@ -671,43 +1093,40 @@ function Slider(_a) {
671
1093
  justifyContent: 'center',
672
1094
  alignItems: 'center',
673
1095
  position: 'absolute',
674
- left: isHorizontal(direction)
675
- ? `${isReversed(direction)
676
- ? 100 - normalizeValue(item.at, min, max, skew) * 100
677
- : normalizeValue(item.at, min, max, skew) * 100}%`
678
- : undefined,
679
- top: isVertical(direction)
680
- ? `${isReversed(direction)
681
- ? 100 - normalizeValue(item.at, min, max, skew) * 100
682
- : normalizeValue(item.at, min, max, skew) * 100}%`
683
- : undefined,
1096
+ left: isHorizontal(direction) ? `${calcPercent(item.at)}%` : undefined,
1097
+ top: isVertical(direction) ? `${calcPercent(item.at)}%` : undefined,
684
1098
  translate: isHorizontal(direction) ? '-50% 0' : '0 -50%',
685
1099
  zIndex: 10,
686
- }), children: [((_b = (_a = item.type) !== null && _a !== void 0 ? _a : scaleOption === null || scaleOption === void 0 ? void 0 : scaleOption.defaultType) !== null && _b !== void 0 ? _b : 'mark-number') !=
1100
+ }), children: [((_b = (_a = item.type) !== null && _a !== undefined ? _a : scaleOption === null || scaleOption === undefined ? undefined : scaleOption.defaultType) !== null && _b !== undefined ? _b : 'mark-number') !=
687
1101
  'number' && (jsxRuntime.jsx("div", { className: "tremolo-slider-scale-mark", css: react.css({
688
1102
  width: isHorizontal(direction)
689
- ? ((_d = (_c = item.style) === null || _c === void 0 ? void 0 : _c.thickness) !== null && _d !== void 0 ? _d : 1)
690
- : ((_f = (_e = item.style) === null || _e === void 0 ? void 0 : _e.length) !== null && _f !== void 0 ? _f : '0.5rem'),
1103
+ ? ((_d = (_c = item.style) === null || _c === undefined ? undefined : _c.thickness) !== null && _d !== undefined ? _d : 1)
1104
+ : ((_f = (_e = item.style) === null || _e === undefined ? undefined : _e.length) !== null && _f !== undefined ? _f : '0.5rem'),
691
1105
  height: isVertical(direction)
692
- ? ((_h = (_g = item.style) === null || _g === void 0 ? void 0 : _g.thickness) !== null && _h !== void 0 ? _h : 1)
693
- : ((_k = (_j = item.style) === null || _j === void 0 ? void 0 : _j.length) !== null && _k !== void 0 ? _k : '0.5rem'),
694
- backgroundColor: (_o = (_m = (_l = item.style) === null || _l === void 0 ? void 0 : _l.markColor) !== null && _m !== void 0 ? _m : scaleOption === null || scaleOption === void 0 ? void 0 : scaleOption.markColor) !== null && _o !== void 0 ? _o : '#222',
1106
+ ? ((_h = (_g = item.style) === null || _g === undefined ? undefined : _g.thickness) !== null && _h !== undefined ? _h : 1)
1107
+ : ((_k = (_j = item.style) === null || _j === undefined ? undefined : _j.length) !== null && _k !== undefined ? _k : '0.5rem'),
1108
+ backgroundColor: (_o = (_m = (_l = item.style) === null || _l === undefined ? undefined : _l.markColor) !== null && _m !== undefined ? _m : scaleOption === null || scaleOption === undefined ? undefined : scaleOption.markColor) !== null && _o !== undefined ? _o : '#222',
695
1109
  marginBottom: isHorizontal(direction) ? 2 : undefined,
696
1110
  marginRight: isVertical(direction) ? 2 : undefined,
697
- }) })), ((_q = (_p = item.type) !== null && _p !== void 0 ? _p : scaleOption === null || scaleOption === void 0 ? void 0 : scaleOption.defaultType) !== null && _q !== void 0 ? _q : 'mark-number') !=
1111
+ }) })), ((_q = (_p = item.type) !== null && _p !== undefined ? _p : scaleOption === null || scaleOption === undefined ? undefined : scaleOption.defaultType) !== null && _q !== undefined ? _q : 'mark-number') !=
698
1112
  'mark' && (jsxRuntime.jsx("div", { className: "tremolo-slider-scale-number", css: react.css({
699
- color: (_s = (_r = item.style) === null || _r === void 0 ? void 0 : _r.labelColor) !== null && _s !== void 0 ? _s : scaleOption === null || scaleOption === void 0 ? void 0 : scaleOption.labelColor,
700
- width: scaleOption === null || scaleOption === void 0 ? void 0 : scaleOption.labelWidth,
1113
+ color: (_s = (_r = item.style) === null || _r === undefined ? undefined : _r.labelColor) !== null && _s !== undefined ? _s : scaleOption === null || scaleOption === undefined ? undefined : scaleOption.labelColor,
1114
+ width: scaleOption === null || scaleOption === undefined ? undefined : scaleOption.labelWidth,
701
1115
  textAlign: 'right',
702
- }), children: (_t = item.text) !== null && _t !== void 0 ? _t : item.at }))] }, index));
1116
+ }), children: (_t = item.text) !== null && _t !== undefined ? _t : item.at }))] }, index));
703
1117
  }) }))] })] }));
704
- }
1118
+ });
705
1119
 
706
1120
  exports.AnimationCanvas = AnimationCanvas;
1121
+ exports.BlackKey = BlackKey;
1122
+ exports.KeyLabel = KeyLabel;
707
1123
  exports.Knob = Knob;
708
1124
  exports.NumberInput = NumberInput;
1125
+ exports.Piano = Piano;
1126
+ exports.Shortcuts = Shortcuts;
709
1127
  exports.Slider = Slider;
710
1128
  exports.SliderThumb = SliderThumb;
711
1129
  exports.SliderTrack = SliderTrack;
1130
+ exports.WhiteKey = WhiteKey;
712
1131
  exports.gradientDirection = gradientDirection;
713
1132
  //# sourceMappingURL=index.js.map