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