@tremolo-ui/react 0.0.7 → 0.0.8

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 (133) hide show
  1. package/dist/cjs/index.js +674 -253
  2. package/dist/cjs/index.js.map +1 -1
  3. package/dist/cjs/types/components/AnimationCanvas/index.d.ts +16 -9
  4. package/dist/cjs/types/components/AnimationCanvas/index.d.ts.map +1 -1
  5. package/dist/cjs/types/components/AnimationKnob/index.d.ts +53 -0
  6. package/dist/cjs/types/components/AnimationKnob/index.d.ts.map +1 -0
  7. package/dist/cjs/types/components/DragObserver/index.d.ts +19 -0
  8. package/dist/cjs/types/components/DragObserver/index.d.ts.map +1 -0
  9. package/dist/cjs/types/components/Knob/index.d.ts +26 -26
  10. package/dist/cjs/types/components/Knob/index.d.ts.map +1 -1
  11. package/dist/cjs/types/components/NumberInput/index.d.ts +2 -5
  12. package/dist/cjs/types/components/NumberInput/index.d.ts.map +1 -1
  13. package/dist/cjs/types/components/Piano/BlackKey.d.ts +3 -3
  14. package/dist/cjs/types/components/Piano/BlackKey.d.ts.map +1 -1
  15. package/dist/cjs/types/components/Piano/KeyLabel.d.ts +5 -8
  16. package/dist/cjs/types/components/Piano/KeyLabel.d.ts.map +1 -1
  17. package/dist/cjs/types/components/Piano/WhiteKey.d.ts +3 -3
  18. package/dist/cjs/types/components/Piano/WhiteKey.d.ts.map +1 -1
  19. package/dist/cjs/types/components/Piano/index.d.ts +3 -4
  20. package/dist/cjs/types/components/Piano/index.d.ts.map +1 -1
  21. package/dist/cjs/types/components/Piano/key.d.ts +4 -7
  22. package/dist/cjs/types/components/Piano/key.d.ts.map +1 -1
  23. package/dist/cjs/types/components/Piano/keyboardShortcuts.d.ts.map +1 -1
  24. package/dist/cjs/types/components/Slider/Scale.d.ts +11 -0
  25. package/dist/cjs/types/components/Slider/Scale.d.ts.map +1 -0
  26. package/dist/cjs/types/components/Slider/ScaleOption.d.ts +25 -0
  27. package/dist/cjs/types/components/Slider/ScaleOption.d.ts.map +1 -0
  28. package/dist/cjs/types/components/Slider/Thumb.d.ts +5 -13
  29. package/dist/cjs/types/components/Slider/Thumb.d.ts.map +1 -1
  30. package/dist/cjs/types/components/Slider/Track.d.ts +10 -21
  31. package/dist/cjs/types/components/Slider/Track.d.ts.map +1 -1
  32. package/dist/cjs/types/components/Slider/context.d.ts +21 -0
  33. package/dist/cjs/types/components/Slider/context.d.ts.map +1 -0
  34. package/dist/cjs/types/components/Slider/index.d.ts +18 -12
  35. package/dist/cjs/types/components/Slider/index.d.ts.map +1 -1
  36. package/dist/cjs/types/components/WheelObserver/index.d.ts +24 -0
  37. package/dist/cjs/types/components/WheelObserver/index.d.ts.map +1 -0
  38. package/dist/cjs/types/components/XYPad/Area.d.ts +13 -0
  39. package/dist/cjs/types/components/XYPad/Area.d.ts.map +1 -0
  40. package/dist/cjs/types/components/XYPad/Thumb.d.ts +19 -0
  41. package/dist/cjs/types/components/XYPad/Thumb.d.ts.map +1 -0
  42. package/dist/cjs/types/components/XYPad/index.d.ts +39 -0
  43. package/dist/cjs/types/components/XYPad/index.d.ts.map +1 -0
  44. package/dist/cjs/types/hooks/useCallbackRef.d.ts.map +1 -1
  45. package/dist/cjs/types/index.d.ts +10 -0
  46. package/dist/cjs/types/index.d.ts.map +1 -1
  47. package/dist/esm/index.js +657 -254
  48. package/dist/esm/index.js.map +1 -1
  49. package/dist/esm/types/components/AnimationCanvas/index.d.ts +16 -9
  50. package/dist/esm/types/components/AnimationCanvas/index.d.ts.map +1 -1
  51. package/dist/esm/types/components/AnimationKnob/index.d.ts +53 -0
  52. package/dist/esm/types/components/AnimationKnob/index.d.ts.map +1 -0
  53. package/dist/esm/types/components/DragObserver/index.d.ts +19 -0
  54. package/dist/esm/types/components/DragObserver/index.d.ts.map +1 -0
  55. package/dist/esm/types/components/Knob/index.d.ts +26 -26
  56. package/dist/esm/types/components/Knob/index.d.ts.map +1 -1
  57. package/dist/esm/types/components/NumberInput/index.d.ts +2 -5
  58. package/dist/esm/types/components/NumberInput/index.d.ts.map +1 -1
  59. package/dist/esm/types/components/Piano/BlackKey.d.ts +3 -3
  60. package/dist/esm/types/components/Piano/BlackKey.d.ts.map +1 -1
  61. package/dist/esm/types/components/Piano/KeyLabel.d.ts +5 -8
  62. package/dist/esm/types/components/Piano/KeyLabel.d.ts.map +1 -1
  63. package/dist/esm/types/components/Piano/WhiteKey.d.ts +3 -3
  64. package/dist/esm/types/components/Piano/WhiteKey.d.ts.map +1 -1
  65. package/dist/esm/types/components/Piano/index.d.ts +3 -4
  66. package/dist/esm/types/components/Piano/index.d.ts.map +1 -1
  67. package/dist/esm/types/components/Piano/key.d.ts +4 -7
  68. package/dist/esm/types/components/Piano/key.d.ts.map +1 -1
  69. package/dist/esm/types/components/Piano/keyboardShortcuts.d.ts.map +1 -1
  70. package/dist/esm/types/components/Slider/Scale.d.ts +11 -0
  71. package/dist/esm/types/components/Slider/Scale.d.ts.map +1 -0
  72. package/dist/esm/types/components/Slider/ScaleOption.d.ts +25 -0
  73. package/dist/esm/types/components/Slider/ScaleOption.d.ts.map +1 -0
  74. package/dist/esm/types/components/Slider/Thumb.d.ts +5 -13
  75. package/dist/esm/types/components/Slider/Thumb.d.ts.map +1 -1
  76. package/dist/esm/types/components/Slider/Track.d.ts +10 -21
  77. package/dist/esm/types/components/Slider/Track.d.ts.map +1 -1
  78. package/dist/esm/types/components/Slider/context.d.ts +21 -0
  79. package/dist/esm/types/components/Slider/context.d.ts.map +1 -0
  80. package/dist/esm/types/components/Slider/index.d.ts +18 -12
  81. package/dist/esm/types/components/Slider/index.d.ts.map +1 -1
  82. package/dist/esm/types/components/WheelObserver/index.d.ts +24 -0
  83. package/dist/esm/types/components/WheelObserver/index.d.ts.map +1 -0
  84. package/dist/esm/types/components/XYPad/Area.d.ts +13 -0
  85. package/dist/esm/types/components/XYPad/Area.d.ts.map +1 -0
  86. package/dist/esm/types/components/XYPad/Thumb.d.ts +19 -0
  87. package/dist/esm/types/components/XYPad/Thumb.d.ts.map +1 -0
  88. package/dist/esm/types/components/XYPad/index.d.ts +39 -0
  89. package/dist/esm/types/components/XYPad/index.d.ts.map +1 -0
  90. package/dist/esm/types/hooks/useCallbackRef.d.ts.map +1 -1
  91. package/dist/esm/types/index.d.ts +10 -0
  92. package/dist/esm/types/index.d.ts.map +1 -1
  93. package/dist/styles/index.css +241 -0
  94. package/package.json +2 -5
  95. package/src/components/AnimationCanvas/index.tsx +87 -57
  96. package/src/components/AnimationKnob/index.tsx +305 -0
  97. package/src/components/DragObserver/index.tsx +94 -0
  98. package/src/components/Knob/index.css +48 -0
  99. package/src/components/Knob/index.tsx +152 -165
  100. package/src/components/NumberInput/index.css +25 -0
  101. package/src/components/NumberInput/index.tsx +8 -41
  102. package/src/components/Piano/BlackKey.tsx +104 -98
  103. package/src/components/Piano/KeyLabel.tsx +18 -40
  104. package/src/components/Piano/WhiteKey.tsx +92 -87
  105. package/src/components/Piano/index.css +63 -0
  106. package/src/components/Piano/index.tsx +76 -59
  107. package/src/components/Piano/key.ts +4 -7
  108. package/src/components/Piano/keyboardShortcuts.ts +23 -4
  109. package/src/components/Slider/Scale.tsx +55 -0
  110. package/src/components/Slider/ScaleOption.tsx +103 -0
  111. package/src/components/Slider/Thumb.tsx +69 -76
  112. package/src/components/Slider/Track.tsx +37 -48
  113. package/src/components/Slider/context.tsx +66 -0
  114. package/src/components/Slider/index.css +76 -0
  115. package/src/components/Slider/index.tsx +256 -298
  116. package/src/components/WheelObserver/index.tsx +47 -0
  117. package/src/components/XYPad/Area.tsx +40 -0
  118. package/src/components/XYPad/Thumb.tsx +92 -0
  119. package/src/components/XYPad/index.css +24 -0
  120. package/src/components/XYPad/index.tsx +317 -0
  121. package/src/hooks/useCallbackRef.ts +1 -0
  122. package/src/hooks/useRefCallbackEvent.ts +1 -0
  123. package/src/index.ts +11 -0
  124. package/dist/cjs/types/components/Slider/type.d.ts +0 -7
  125. package/dist/cjs/types/components/Slider/type.d.ts.map +0 -1
  126. package/dist/cjs/types/system/pseudo.d.ts +0 -14
  127. package/dist/cjs/types/system/pseudo.d.ts.map +0 -1
  128. package/dist/esm/types/components/Slider/type.d.ts +0 -7
  129. package/dist/esm/types/components/Slider/type.d.ts.map +0 -1
  130. package/dist/esm/types/system/pseudo.d.ts +0 -14
  131. package/dist/esm/types/system/pseudo.d.ts.map +0 -1
  132. package/src/components/Slider/type.ts +0 -16
  133. package/src/system/pseudo.ts +0 -55
package/dist/esm/index.js CHANGED
@@ -1,6 +1,5 @@
1
- import { jsxs, Fragment, jsx } from '@emotion/react/jsx-runtime';
2
- import { css, Global } from '@emotion/react';
3
- import React, { useRef, useEffect, useInsertionEffect, useCallback, useMemo, useState, forwardRef, useImperativeHandle, createRef } from 'react';
1
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
2
+ import React, { useRef, useCallback, useEffect, useInsertionEffect, useMemo, useState, forwardRef, useImperativeHandle, createRef, createContext, useContext } from 'react';
4
3
 
5
4
  /******************************************************************************
6
5
  Copyright (c) Microsoft Corporation.
@@ -67,20 +66,17 @@ function setDprConfig(canvas, context, width, height, dpr) {
67
66
  canvas.style.width = `${width}px`;
68
67
  canvas.style.height = `${height}px`;
69
68
  }
70
- /**
71
- * A simple animatable canvas with requestAnimationFrame()
72
- */
73
69
  function AnimationCanvas(_a) {
74
- var { width = 100, height = 100, style, relativeSize = false, reduceFlickering = true, options, init, draw, className } = _a, props = __rest(_a, ["width", "height", "style", "relativeSize", "reduceFlickering", "options", "init", "draw", "className"]);
70
+ var { width = 100, height = 100, relativeSize = false, reduceFlickering = true, options, init, draw, className } = _a, props = __rest(_a, ["width", "height", "relativeSize", "reduceFlickering", "options", "init", "draw", "className"]);
75
71
  const canvasRef = useRef(null);
76
72
  const memoCanvasRef = useRef(null);
77
73
  const reqIdRef = useRef();
78
74
  const widthRef = useRef(0);
79
75
  const heightRef = useRef(0);
80
- const loop = (context, width, height, count) => {
76
+ const loop = useCallback((context, width, height, count) => {
81
77
  reqIdRef.current = requestAnimationFrame(() => loop(context, width, height, count + 1));
82
78
  draw(context, width, height, count + 1);
83
- };
79
+ }, [draw]);
84
80
  useEffect(() => {
85
81
  if (!canvasRef.current)
86
82
  return;
@@ -94,30 +90,34 @@ function AnimationCanvas(_a) {
94
90
  if (!parent)
95
91
  throw new Error("Canvas doesn't have a parent element.");
96
92
  const memoCanvas = memoCanvasRef.current;
97
- const memoContext = memoCanvas === null || memoCanvas === undefined ? undefined : memoCanvas.getContext('2d', options);
98
- const resizeObserver = new ResizeObserver(() => {
99
- // console.log('resize')
100
- // Prevents loss of some context when the canvas is resized
101
- const contextMemo = {};
102
- for (const prop of drawingState) {
103
- contextMemo[prop] = context[prop];
104
- }
105
- const w = Math.floor(parent.clientWidth);
106
- const h = Math.floor(parent.clientHeight);
107
- if (reduceFlickering && memoCanvas && memoContext) {
108
- memoCanvas.width = w * dpr;
109
- memoCanvas.height = h * dpr;
110
- memoContext.scale(1 / dpr, 1 / dpr);
111
- memoContext.drawImage(context.canvas, 0, 0);
112
- }
113
- setDprConfig(canvas, context, w, h, dpr);
114
- widthRef.current = w;
115
- heightRef.current = h;
116
- for (const prop of drawingState) {
117
- context[prop] = contextMemo[prop];
118
- }
119
- if (reduceFlickering && memoContext) {
120
- context.drawImage(memoContext.canvas, 0, 0);
93
+ const memoContext = memoCanvas === null || memoCanvas === void 0 ? void 0 : memoCanvas.getContext('2d', options);
94
+ const resizeObserver = new ResizeObserver((entries) => {
95
+ // TODO: If the parent element has no absolute height, the height increases infinitely.
96
+ // : 親要素に絶対的な高さを持たない場合、高さは無限に増加します。
97
+ // https://zenn.dev/megeton/articles/be1c677e174c84#%E6%A0%B9%E6%9C%AC%E7%9A%84%E3%81%AB-resizeobserver-loop-limit-exceeded-%E3%81%8C%E5%87%BA%E3%82%8B%E5%95%8F%E9%A1%8C%E3%81%AB%E5%90%91%E3%81%8D%E5%90%88%E3%81%86
98
+ for (const entry of entries) {
99
+ // Prevents loss of some context when the canvas is resized
100
+ const contextMemo = {};
101
+ for (const prop of drawingState) {
102
+ contextMemo[prop] = context[prop];
103
+ }
104
+ const w = Math.floor(entry.contentRect.width);
105
+ const h = Math.floor(entry.contentRect.height);
106
+ if (reduceFlickering && memoCanvas && memoContext) {
107
+ memoCanvas.width = w * dpr;
108
+ memoCanvas.height = h * dpr;
109
+ memoContext.scale(1 / dpr, 1 / dpr);
110
+ memoContext.drawImage(context.canvas, 0, 0);
111
+ }
112
+ setDprConfig(canvas, context, w, h, dpr);
113
+ widthRef.current = w;
114
+ heightRef.current = h;
115
+ for (const prop of drawingState) {
116
+ context[prop] = contextMemo[prop];
117
+ }
118
+ if (reduceFlickering && memoContext) {
119
+ context.drawImage(memoContext.canvas, 0, 0);
120
+ }
121
121
  }
122
122
  });
123
123
  resizeObserver.observe(parent);
@@ -146,8 +146,8 @@ function AnimationCanvas(_a) {
146
146
  cancelAnimationFrame(reqIdRef.current);
147
147
  };
148
148
  }
149
- }, [loop]);
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 }))] }));
149
+ }, [loop, init, options, reduceFlickering, relativeSize]);
150
+ return (jsxs(Fragment, { children: [jsx("canvas", Object.assign({ className: clsx('tremolo-animation-canvas', className), width: relativeSize ? 0 : width, height: relativeSize ? 0 : height, ref: canvasRef }, props)), relativeSize && reduceFlickering && (jsx("canvas", { style: { display: 'none' }, ref: memoCanvasRef }))] }));
151
151
  }
152
152
 
153
153
  /**
@@ -188,7 +188,7 @@ function stepValue(value, step) {
188
188
  if (step <= 0)
189
189
  throw new RangeError('requirements: step > 0');
190
190
  const quotient = Math.floor(value / step);
191
- const decimalDigits = (_a = decimalPart$1(step)) === null || _a === undefined ? undefined : _a.length;
191
+ const decimalDigits = (_a = decimalPart$1(step)) === null || _a === void 0 ? void 0 : _a.length;
192
192
  const v = toFixed$2(quotient * step, decimalDigits);
193
193
  const next = toFixed$2((quotient + 1) * step, decimalDigits);
194
194
  return Math.abs(value - v) < Math.abs(value - next) ? v : next;
@@ -244,12 +244,31 @@ function styleHelper(value, op, influencer) {
244
244
  * @category Utility
245
245
  */
246
246
  function mod(n, m) {
247
- return (((n % m) + m) % m);
247
+ return ((n % m) + m) % m;
248
+ }
249
+ /**
250
+ * @category Utility
251
+ */
252
+ function xor(a = false, b = false) {
253
+ return (a || b) && a != b;
248
254
  }
249
255
  /**
250
256
  * @category MIDI
251
257
  */
252
- const noteNames = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'];
258
+ const noteNames = [
259
+ 'C',
260
+ 'C#',
261
+ 'D',
262
+ 'D#',
263
+ 'E',
264
+ 'F',
265
+ 'F#',
266
+ 'G',
267
+ 'G#',
268
+ 'A',
269
+ 'A#',
270
+ 'B',
271
+ ];
253
272
  /**
254
273
  * @category MIDI
255
274
  */
@@ -269,7 +288,7 @@ function parseNoteName(noteName) {
269
288
  * @category MIDI
270
289
  */
271
290
  function noteNumber(noteName) {
272
- const { letter, accidental, octave, } = parseNoteName(noteName);
291
+ const { letter, accidental, octave } = parseNoteName(noteName);
273
292
  const noteIndex = noteNames.indexOf(letter.toLocaleUpperCase());
274
293
  const accidentalValue = (accidental[0] == 'b' ? -1 : 1) * accidental.length;
275
294
  return noteIndex + 12 * (Number(octave) + 1) + accidentalValue;
@@ -308,13 +327,14 @@ function useCallbackRef(callback, deps = []) {
308
327
  useInsertionEffect(() => {
309
328
  callbackRef.current = callback;
310
329
  });
311
- return useCallback((...args) => { var _a; return (_a = callbackRef.current) === null || _a === undefined ? undefined : _a.call(callbackRef, ...args); }, deps);
330
+ // eslint-disable-next-line react-hooks/exhaustive-deps
331
+ return useCallback((...args) => { var _a; return (_a = callbackRef.current) === null || _a === void 0 ? void 0 : _a.call(callbackRef, ...args); }, deps);
312
332
  }
313
333
 
314
334
  function useEventListener(target, event, handler, options) {
315
335
  const listener = useCallbackRef(handler);
316
336
  useEffect(() => {
317
- const node = typeof target === 'function' ? target() : (target !== null && target !== undefined ? target : document);
337
+ const node = typeof target === 'function' ? target() : (target !== null && target !== void 0 ? target : document);
318
338
  if (!handler || !node)
319
339
  return;
320
340
  node.addEventListener(event, listener, options);
@@ -323,8 +343,8 @@ function useEventListener(target, event, handler, options) {
323
343
  };
324
344
  }, [event, target, options, listener, handler]);
325
345
  return () => {
326
- const node = typeof target === 'function' ? target() : (target !== null && target !== undefined ? target : document);
327
- node === null || node === undefined ? undefined : node.removeEventListener(event, listener, options);
346
+ const node = typeof target === 'function' ? target() : (target !== null && target !== void 0 ? target : document);
347
+ node === null || node === void 0 ? void 0 : node.removeEventListener(event, listener, options);
328
348
  };
329
349
  }
330
350
 
@@ -333,7 +353,7 @@ function useRefCallbackEvent(event, handler, options, deps = []) {
333
353
  let cleanup;
334
354
  return (node) => {
335
355
  if (!node) {
336
- cleanup === null || cleanup === undefined ? undefined : cleanup();
356
+ cleanup === null || cleanup === void 0 ? void 0 : cleanup();
337
357
  return;
338
358
  }
339
359
  node.addEventListener(event, handler, options);
@@ -341,6 +361,7 @@ function useRefCallbackEvent(event, handler, options, deps = []) {
341
361
  node.removeEventListener(event, handler, options);
342
362
  };
343
363
  };
364
+ // eslint-disable-next-line react-hooks/exhaustive-deps
344
365
  }, deps);
345
366
  }
346
367
 
@@ -351,34 +372,17 @@ function removeNoSelect() {
351
372
  document.body.classList.remove('tremolo-no-select');
352
373
  }
353
374
 
354
- const defaultOptions = {
355
- active: '#7998ec',
356
- inactive: '#eee',
357
- bg: '#ccc',
358
- thumb: '#4e76e6',
359
- lineWeight: 6,
360
- thumbWeight: 4,
361
- };
362
375
  /**
363
376
  * simple rotary Knob.
364
377
  */
365
- function Knob(_a) {
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"]);
378
+ function AnimationKnob(_a) {
379
+ var { value, min, max, defaultValue = min, startValue = min, step = 1, skew = 1, size, width = 50, height = 50, activeColor = '#7998ec', inactiveColor = '#eee', bg = '#ccc', thumb = '#4e76e6', lineWeight = 6, thumbWeight = 4, draw, bodyNoSelect = true, wheel = ['raw', 1], keyboard = ['raw', 1], enableDoubleClickDefault = true, style, className, onChange } = _a, props = __rest(_a, ["value", "min", "max", "defaultValue", "startValue", "step", "skew", "size", "width", "height", "activeColor", "inactiveColor", "bg", "thumb", "lineWeight", "thumbWeight", "draw", "bodyNoSelect", "wheel", "keyboard", "enableDoubleClickDefault", "style", "className", "onChange"]);
367
380
  // -- state and ref ---
368
381
  // const [privateValue, setPrivateValue] = useState(value);
369
382
  const dragOffsetY = useRef(undefined);
370
383
  // --- interpret props ---
371
- const opts = Object.assign(Object.assign({}, defaultOptions), options);
372
384
  // const percent = normalizeValue(value, min, max, skew)
373
- const isRelativeSize = typeof (size !== null && size !== undefined ? size : width) == 'string';
374
- const adaptSize = (size) => {
375
- if (typeof size == 'string') {
376
- return Number(size.slice(0, -1));
377
- }
378
- else {
379
- return size;
380
- }
381
- };
385
+ const isRelativeSize = typeof (size !== null && size !== void 0 ? size : width) == 'string' || typeof height == 'string';
382
386
  const handleEvent = (event) => {
383
387
  const isTouch = event instanceof TouchEvent;
384
388
  if (isTouch && event.cancelable)
@@ -388,6 +392,8 @@ function Knob(_a) {
388
392
  addNoSelect();
389
393
  const screenY = isTouch ? event.touches[0].screenY : event.screenY;
390
394
  const delta = dragOffsetY.current - screenY;
395
+ if (Math.abs(delta) < 1)
396
+ return;
391
397
  dragOffsetY.current = screenY;
392
398
  const n = normalizeValue(value, min, max, skew);
393
399
  const v = rawValue(n + delta / 100, min, max, skew);
@@ -396,6 +402,24 @@ function Knob(_a) {
396
402
  onChange(v2);
397
403
  }
398
404
  };
405
+ const handleKeyDown = useCallback((event) => {
406
+ if (!keyboard || !onChange)
407
+ return;
408
+ const key = event.key;
409
+ if (['ArrowRight', 'ArrowLeft', 'ArrowUp', 'ArrowDown'].includes(key)) {
410
+ event.preventDefault();
411
+ const x = key == 'ArrowRight' || key == 'ArrowUp' ? keyboard[1] : -keyboard[1];
412
+ let v;
413
+ if (keyboard[0] == 'normalized') {
414
+ const n = normalizeValue(value, min, max, skew);
415
+ v = rawValue(n + x, min, max, skew);
416
+ }
417
+ else {
418
+ v = value + x;
419
+ }
420
+ onChange(clamp(stepValue(v, step), min, max));
421
+ }
422
+ }, [value, min, max, step, skew, keyboard, onChange]);
399
423
  // --- hooks ---
400
424
  const wheelRefCallback = useRefCallbackEvent('wheel', (event) => {
401
425
  if (!wheel)
@@ -420,24 +444,24 @@ function Knob(_a) {
420
444
  if (bodyNoSelect)
421
445
  removeNoSelect();
422
446
  });
423
- return (jsxs("div", Object.assign({ className: clsx('tremolo-knob', className), ref: (div) => {
447
+ return (jsx("div", Object.assign({ className: clsx('tremolo-animation-knob', className), ref: (div) => {
424
448
  wheelRefCallback(div);
425
449
  touchMoveRefCallback(div);
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) => {
450
+ }, role: "slider", tabIndex: 0, "aria-valuenow": value, "aria-valuemax": max, "aria-valuemin": min, style: Object.assign({ display: 'inline-block', width: size !== null && size !== void 0 ? size : width, height: size !== null && size !== void 0 ? size : height, cursor: 'pointer', WebkitTapHighlightColor: 'transparent' }, style), onPointerDown: (event) => {
427
451
  dragOffsetY.current = event.screenY;
428
452
  handleEvent(event);
429
453
  }, onDoubleClick: () => {
430
454
  if (enableDoubleClickDefault && onChange) {
431
455
  onChange(defaultValue);
432
456
  }
433
- } }, props, { children: [jsx(Global, { styles: {
434
- '.no-select': {
435
- userSelect: 'none',
436
- },
437
- } }), jsx(AnimationCanvas, { width: adaptSize(size !== null && size !== undefined ? size : width), height: adaptSize(size !== null && size !== undefined ? size : height), relativeSize: isRelativeSize,
438
- // TODO
439
- // reduceFlickering={false}
440
- draw: draw ? draw : (ctx, width, height) => {
457
+ }, onKeyDown: handleKeyDown, onContextMenu: (e) => e.preventDefault() }, props, { children: jsx(AnimationCanvas, Object.assign({}, (isRelativeSize
458
+ ? { relativeSize: true }
459
+ : {
460
+ width: size !== null && size !== void 0 ? size : width,
461
+ height: size !== null && size !== void 0 ? size : height,
462
+ }), { draw: draw
463
+ ? draw
464
+ : (ctx, width, height) => {
441
465
  const p = normalizeValue(value, min, max, skew);
442
466
  const startP = normalizeValue(startValue, min, max, skew);
443
467
  const w = width.current, cx = w / 2;
@@ -450,33 +474,172 @@ function Knob(_a) {
450
474
  ctx.lineCap = 'butt';
451
475
  // bg
452
476
  ctx.beginPath();
453
- ctx.fillStyle = opts.bg;
477
+ ctx.fillStyle = bg;
454
478
  ctx.arc(cx, cy, r - 0.5, 0, 2 * Math.PI);
455
479
  ctx.fill();
456
- ctx.lineCap = 'round';
457
- ctx.lineWidth = opts.lineWeight;
480
+ ctx.lineWidth = lineWeight;
458
481
  // inactive rotary
459
482
  ctx.beginPath();
460
- ctx.strokeStyle = opts.inactive;
461
- ctx.arc(cx, cy, r - 0.5 - opts.lineWeight / 2, radian(135), radian(45));
483
+ ctx.strokeStyle = inactiveColor;
484
+ ctx.arc(cx, cy, r - 0.5 - lineWeight / 2, radian(135), radian(45));
462
485
  ctx.stroke();
463
486
  // active rotary
464
487
  ctx.beginPath();
465
- ctx.strokeStyle = opts.active;
466
- ctx.arc(cx, cy, r - 0.5 - opts.lineWeight / 2, radian(135 + 270 * startP), radian(135 + 270 * p), p < startP);
488
+ ctx.strokeStyle = activeColor;
489
+ ctx.arc(cx, cy, r - 0.5 - lineWeight / 2, radian(135 + 270 * startP), radian(135 + 270 * p), p < startP);
467
490
  ctx.stroke();
468
491
  // thumb
492
+ ctx.lineCap = 'round';
469
493
  ctx.beginPath();
470
494
  ctx.moveTo(cx, cy);
471
495
  ctx.lineTo(cx +
472
496
  Math.cos(radian(135 + 270 * p)) *
473
- (r - 0.5 - opts.thumbWeight / 2), cy +
497
+ (r - 0.5 - thumbWeight / 2), cy +
474
498
  Math.sin(radian(135 + 270 * p)) *
475
- (r - 0.5 - opts.thumbWeight / 2));
476
- ctx.strokeStyle = opts.thumb;
477
- ctx.lineWidth = opts.thumbWeight;
499
+ (r - 0.5 - thumbWeight / 2));
500
+ ctx.strokeStyle = thumb;
501
+ ctx.lineWidth = thumbWeight;
478
502
  ctx.stroke();
479
- } })] })));
503
+ } })) })));
504
+ }
505
+
506
+ function DragObserver(props) {
507
+ const { children, onDrag, onDragStart, onDragEnd, as: Component = 'div' } = props, attributes = __rest(props, ["children", "onDrag", "onDragStart", "onDragEnd", "as"]);
508
+ const dragOffsetX = useRef(undefined);
509
+ const dragOffsetY = useRef(undefined);
510
+ const handleEvent = (event) => {
511
+ const isTouch = event instanceof TouchEvent;
512
+ if (isTouch && event.cancelable)
513
+ event.preventDefault();
514
+ const screenX = isTouch ? event.touches[0].screenX : event.screenX;
515
+ const screenY = isTouch ? event.touches[0].screenY : event.screenY;
516
+ let deltaX = 0, deltaY = 0;
517
+ if (dragOffsetX.current) {
518
+ deltaX = screenX - dragOffsetX.current;
519
+ dragOffsetX.current = screenX;
520
+ }
521
+ if (dragOffsetY.current) {
522
+ deltaY = screenY - dragOffsetY.current;
523
+ dragOffsetY.current = screenY;
524
+ }
525
+ if (Math.abs(deltaX) < 1 && Math.abs(deltaY) < 1)
526
+ return;
527
+ if (onDrag)
528
+ onDrag(deltaX, deltaY);
529
+ };
530
+ const touchMoveRefCallback = useRefCallbackEvent('touchmove', handleEvent, { passive: false }, [onDrag]);
531
+ useEventListener(window, 'mousemove', handleEvent);
532
+ useEventListener(window, 'pointerup', () => {
533
+ dragOffsetX.current = undefined;
534
+ dragOffsetY.current = undefined;
535
+ onDragEnd === null || onDragEnd === void 0 ? void 0 : onDragEnd();
536
+ });
537
+ return (jsx(Component, Object.assign({ ref: touchMoveRefCallback, onPointerDown: (event) => {
538
+ dragOffsetX.current = event.screenX;
539
+ dragOffsetY.current = event.screenY;
540
+ handleEvent(event);
541
+ onDragStart === null || onDragStart === void 0 ? void 0 : onDragStart();
542
+ } }, attributes, { children: children })));
543
+ }
544
+
545
+ function Knob(_a) {
546
+ var { value, min, max, step = 1, skew = 1, defaultValue = min, startValue = min, size = 50, bodyNoSelect = true, wheel = ['raw', 1], keyboard = ['raw', 1], enableDoubleClickDefault = true, disabled = false, readonly = false, activeLine, inactiveLine, thumb, thumbLine, onChange, className, classes } = _a, props = __rest(_a, ["value", "min", "max", "step", "skew", "defaultValue", "startValue", "size", "bodyNoSelect", "wheel", "keyboard", "enableDoubleClickDefault", "disabled", "readonly", "activeLine", "inactiveLine", "thumb", "thumbLine", "onChange", "className", "classes"]);
547
+ // -- state and ref ---
548
+ const dragOffsetY = useRef(undefined);
549
+ // --- interpret props ---
550
+ const padding = 8; // %
551
+ const thumbLineWeight = 6; // %
552
+ const thumbLength = 35; // %
553
+ const lineWeight = 3; // px
554
+ const p = normalizeValue(value, min, max, skew);
555
+ const s = normalizeValue(startValue, min, max, skew);
556
+ // --- internal functions ---
557
+ const handleEvent = (event) => {
558
+ if (!onChange || readonly)
559
+ return;
560
+ const isTouch = event instanceof TouchEvent;
561
+ if (isTouch && event.cancelable)
562
+ event.preventDefault();
563
+ if (dragOffsetY.current) {
564
+ if (bodyNoSelect)
565
+ addNoSelect();
566
+ const screenY = isTouch ? event.touches[0].screenY : event.screenY;
567
+ const delta = dragOffsetY.current - screenY;
568
+ if (Math.abs(delta) < 1)
569
+ return;
570
+ dragOffsetY.current = screenY;
571
+ const n = normalizeValue(value, min, max, skew);
572
+ const v = rawValue(n + delta / 100, min, max, skew);
573
+ const v2 = clamp(stepValue(v, step), min, max);
574
+ onChange(v2);
575
+ }
576
+ };
577
+ const handleKeyDown = useCallback((event) => {
578
+ if (!keyboard || !onChange || readonly)
579
+ return;
580
+ const key = event.key;
581
+ if (['ArrowRight', 'ArrowLeft', 'ArrowUp', 'ArrowDown'].includes(key)) {
582
+ event.preventDefault();
583
+ const x = key == 'ArrowRight' || key == 'ArrowUp' ? keyboard[1] : -keyboard[1];
584
+ let v;
585
+ if (keyboard[0] == 'normalized') {
586
+ const n = normalizeValue(value, min, max, skew);
587
+ v = rawValue(n + x, min, max, skew);
588
+ }
589
+ else {
590
+ v = value + x;
591
+ }
592
+ onChange(clamp(stepValue(v, step), min, max));
593
+ }
594
+ }, [value, min, max, step, skew, keyboard, readonly, onChange]);
595
+ // --- hooks ---
596
+ const wheelRefCallback = useRefCallbackEvent('wheel', (event) => {
597
+ if (!wheel)
598
+ return;
599
+ event.preventDefault();
600
+ const x = event.deltaY > 0 ? -wheel[1] : wheel[1];
601
+ let v;
602
+ if (wheel[0] == 'normalized') {
603
+ const n = normalizeValue(value, min, max, skew);
604
+ v = rawValue(n + x, min, max, skew);
605
+ }
606
+ else {
607
+ v = value + x;
608
+ }
609
+ if (onChange)
610
+ onChange(clamp(stepValue(v, step), min, max));
611
+ }, { passive: false }, [wheel, value, min, max, skew, step, onChange]);
612
+ const touchMoveRefCallback = useRefCallbackEvent('touchmove', handleEvent, { passive: false }, [value, min, max, skew, step, onChange, bodyNoSelect]);
613
+ useEventListener(window, 'mousemove', handleEvent);
614
+ useEventListener(window, 'pointerup', () => {
615
+ dragOffsetY.current = undefined;
616
+ if (bodyNoSelect)
617
+ removeNoSelect();
618
+ });
619
+ const center = size / 2;
620
+ const r1 = -135;
621
+ const r2 = -135 + Math.min(p, s) * 270;
622
+ const r3 = -135 + Math.max(p, s) * 270;
623
+ const r4 = 135;
624
+ const x1 = center + center * Math.cos(radian(r1 - 90));
625
+ const y1 = center + center * Math.sin(radian(r1 - 90));
626
+ const x2 = center + center * Math.cos(radian(r2 - 90));
627
+ const y2 = center + center * Math.sin(radian(r2 - 90));
628
+ const x3 = center + center * Math.cos(radian(r3 - 90));
629
+ const y3 = center + center * Math.sin(radian(r3 - 90));
630
+ const x4 = center + center * Math.cos(radian(r4 - 90));
631
+ const y4 = center + center * Math.sin(radian(r4 - 90));
632
+ return (jsxs("svg", Object.assign({ className: clsx('tremolo-knob', className), ref: (div) => {
633
+ wheelRefCallback(div);
634
+ touchMoveRefCallback(div);
635
+ }, width: size, height: size, tabIndex: 0, "aria-valuenow": value, "aria-valuemin": min, "aria-valuemax": max, "aria-disabled": disabled, "aria-readonly": readonly, onPointerDown: (event) => {
636
+ dragOffsetY.current = event.screenY;
637
+ handleEvent(event);
638
+ }, onDoubleClick: () => {
639
+ if (enableDoubleClickDefault && onChange) {
640
+ onChange(defaultValue);
641
+ }
642
+ }, onKeyDown: handleKeyDown, onContextMenu: (e) => e.preventDefault() }, props, { children: [startValue > min && (jsx("path", { className: clsx('tremolo-knob-inactive-line', classes === null || classes === void 0 ? void 0 : classes.inactiveLine), d: `M ${x1} ${y1} A ${center} ${center} -135 ${r2 - r1 > 180 ? 1 : 0} 1 ${x2}, ${y2}`, fill: "none", stroke: inactiveLine || 'currentColor', strokeWidth: lineWeight })), jsx("path", { className: clsx('tremolo-knob-active-line', classes === null || classes === void 0 ? void 0 : classes.activeLine), d: `M ${x2} ${y2} A ${center} ${center} -135 ${r3 - r2 > 180 ? 1 : 0} 1 ${x3}, ${y3}`, fill: "none", stroke: activeLine || 'currentColor', strokeWidth: lineWeight }), startValue < max && (jsx("path", { className: clsx('tremolo-knob-inactive-line', classes === null || classes === void 0 ? void 0 : classes.inactiveLine), d: `M ${x3} ${y3} A ${center} ${center} -135 ${r4 - r3 > 180 ? 1 : 0} 1 ${x4}, ${y4}`, fill: "none", stroke: inactiveLine || 'currentColor', strokeWidth: lineWeight })), jsxs("svg", { className: clsx('tremolo-knob-thumb', classes === null || classes === void 0 ? void 0 : classes.thumb), children: [jsx("circle", { cx: "50%", cy: "50%", r: `${50 - padding}%`, fill: thumb || 'currentColor' }), jsx("line", { className: clsx('tremolo-knob-thumb-line', classes === null || classes === void 0 ? void 0 : classes.thumbLine), x1: "50%", y1: `${padding}%`, x2: "50%", y2: `${thumbLength}%`, stroke: thumbLine || 'currentColor', strokeWidth: `${thumbLineWeight}%`, transform: `rotate(${ -135 + p * 270})`, "transform-origin": "50% 50%" })] })] })));
480
643
  }
481
644
 
482
645
  /**
@@ -493,7 +656,7 @@ function toFixed$1(x, fractionDigits) {
493
656
 
494
657
  /**
495
658
  * @module NumberInput
496
- */
659
+ */
497
660
  function selectUnit(units, value) {
498
661
  if (typeof units == 'string')
499
662
  return [units, 1];
@@ -556,14 +719,13 @@ function parseValue(inputString, units, digit, defaultValue = 0) {
556
719
  * Input with some useful functions for entering numerical values.
557
720
  */
558
721
  function NumberInput(_a) {
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"]);
722
+ var { value, min, max, step, defaultValue = min, units, disabled = false, placeholder, readOnly, tabIndex, typeNumber = false, digit, selectWithFocus = 'none', blurWithEnter = true, className, onChange, onFocus, onBlur } = _a, props = __rest(_a, ["value", "min", "max", "step", "defaultValue", "units", "disabled", "placeholder", "readOnly", "tabIndex", "typeNumber", "digit", "selectWithFocus", "blurWithEnter", "className", "onChange", "onFocus", "onBlur"]);
560
723
  const [showValue, setShowValue] = useState(parseValue(String(value), units, digit, defaultValue).formatValue);
561
724
  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) => {
725
+ 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, onChange: (event) => {
564
726
  const v = event.currentTarget.value;
565
727
  setShowValue(v);
566
- const newValue = clamp(parseValue(v, units, digit, defaultValue).rawValue, min !== null && min !== undefined ? min : -Infinity, max !== null && max !== undefined ? max : Infinity);
728
+ const newValue = clamp(parseValue(v, units, digit, defaultValue).rawValue, min !== null && min !== void 0 ? min : -Infinity, max !== null && max !== void 0 ? max : Infinity);
567
729
  if (onChange)
568
730
  onChange(newValue, event);
569
731
  }, onFocus: (event) => {
@@ -588,16 +750,19 @@ function NumberInput(_a) {
588
750
  if (blurWithEnter && event.key == 'Enter') {
589
751
  event.currentTarget.blur();
590
752
  }
591
- } }, rest)));
753
+ } }, props)));
592
754
  }
593
755
 
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 }) }));
756
+ function KeyLabel(_a) {
757
+ var { label, className, wrapperClassName, wrapperStyle, __note, __index, __label } = _a, props = __rest(_a, ["label", "className", "wrapperClassName", "wrapperStyle", "__note", "__index", "__label"]);
758
+ const content = label
759
+ ? label(__note, __index)
760
+ : __label && __label(__note, __index);
761
+ return ((content != undefined || content != null) && (jsx("div", { className: clsx('tremolo-piano-key-label-wrapper', wrapperClassName), style: wrapperStyle, children: jsx("div", Object.assign({ className: clsx('tremolo-piano-key-label', className) }, props, { children: content })) })));
598
762
  }
599
763
 
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) => {
764
+ const BlackKey = forwardRef((_a, ref) => {
765
+ var { width = 40 * 0.65, height = '60%', className, style, children, __glissando, __position, __note, __disabled, __index, __fill, __width, __playNote, __stopNote, __label } = _a, props = __rest(_a, ["width", "height", "className", "style", "children", "__glissando", "__position", "__note", "__disabled", "__index", "__fill", "__width", "__playNote", "__stopNote", "__label"]);
601
766
  const [played, setPlayed] = useState(false);
602
767
  useImperativeHandle(ref, () => {
603
768
  return {
@@ -615,11 +780,10 @@ const WhiteKey = forwardRef(({ width = 40, height = '100%', bg = 'white', active
615
780
  },
616
781
  played() {
617
782
  return played;
618
- }
783
+ },
619
784
  };
620
- }, []);
621
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
622
- let keyLabelProps;
785
+ }, [__disabled, __note, __playNote, __stopNote, played]);
786
+ let keyLabelProps = {};
623
787
  if (children != undefined) {
624
788
  React.Children.forEach(children, (child) => {
625
789
  if (React.isValidElement(child)) {
@@ -635,7 +799,7 @@ const WhiteKey = forwardRef(({ width = 40, height = '100%', bg = 'white', active
635
799
  }
636
800
  });
637
801
  }
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: () => {
802
+ return (jsx("div", Object.assign({ className: clsx(`tremolo-piano-black-key`, className), "aria-disabled": __disabled, "data-active": played, style: Object.assign({ left: __position, width: __fill ? __width : (width !== null && width !== void 0 ? width : __width), height: height }, style), onPointerDown: () => {
639
803
  if (__disabled)
640
804
  return;
641
805
  setPlayed(true);
@@ -661,10 +825,11 @@ const WhiteKey = forwardRef(({ width = 40, height = '100%', bg = 'white', active
661
825
  setPlayed(false);
662
826
  if (__stopNote)
663
827
  __stopNote(__note);
664
- }, children: jsx(KeyLabel, Object.assign({ __note: __note, __label: __label, __index: __index }, keyLabelProps)) }));
828
+ } }, props, { children: jsx(KeyLabel, Object.assign({ __note: __note, __label: __label, __index: __index }, keyLabelProps)) })));
665
829
  });
666
830
 
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) => {
831
+ const WhiteKey = forwardRef((_a, ref) => {
832
+ var { width = 40, height = '100%', className, style, children, __glissando, __position, __note, __disabled, __index, __fill, __width, __playNote, __stopNote, __label } = _a, props = __rest(_a, ["width", "height", "className", "style", "children", "__glissando", "__position", "__note", "__disabled", "__index", "__fill", "__width", "__playNote", "__stopNote", "__label"]);
668
833
  const [played, setPlayed] = useState(false);
669
834
  useImperativeHandle(ref, () => {
670
835
  return {
@@ -682,11 +847,10 @@ const BlackKey = forwardRef(({ width = 40 * 0.65, height = '60%', bg = '#333', a
682
847
  },
683
848
  played() {
684
849
  return played;
685
- }
850
+ },
686
851
  };
687
- }, []);
688
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
689
- let keyLabelProps;
852
+ }, [__disabled, __note, __playNote, __stopNote, played]);
853
+ let keyLabelProps = {};
690
854
  if (children != undefined) {
691
855
  React.Children.forEach(children, (child) => {
692
856
  if (React.isValidElement(child)) {
@@ -702,7 +866,7 @@ const BlackKey = forwardRef(({ width = 40 * 0.65, height = '60%', bg = '#333', a
702
866
  }
703
867
  });
704
868
  }
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: () => {
869
+ return (jsx("div", Object.assign({ className: clsx(`tremolo-piano-white-key`, className), "aria-disabled": __disabled, "data-active": played, style: Object.assign({ left: __position, width: __fill ? __width : (width !== null && width !== void 0 ? width : __width), height: height }, style), onPointerDown: () => {
706
870
  if (__disabled)
707
871
  return;
708
872
  setPlayed(true);
@@ -728,16 +892,35 @@ const BlackKey = forwardRef(({ width = 40 * 0.65, height = '60%', bg = '#333', a
728
892
  setPlayed(false);
729
893
  if (__stopNote)
730
894
  __stopNote(__note);
731
- }, children: jsx(KeyLabel, Object.assign({ __note: __note, __label: __label, __index: __index }, keyLabelProps)) }));
895
+ } }, props, { children: jsx(KeyLabel, Object.assign({ __note: __note, __label: __label, __index: __index }, keyLabelProps)) })));
732
896
  });
733
897
 
734
898
  const Shortcuts = {
735
899
  HOME_ROW: {
736
- keys: ['a', 'w', 's', 'e', 'd', 'f', 't', 'g', 'y', 'h', 'u', 'j', 'k', 'o', 'l', 'p', ';']
737
- }
900
+ keys: [
901
+ 'a',
902
+ 'w',
903
+ 's',
904
+ 'e',
905
+ 'd',
906
+ 'f',
907
+ 't',
908
+ 'g',
909
+ 'y',
910
+ 'h',
911
+ 'u',
912
+ 'j',
913
+ 'k',
914
+ 'o',
915
+ 'l',
916
+ 'p',
917
+ ';',
918
+ ],
919
+ },
738
920
  };
739
921
 
740
- function Piano({ noteRange, glissando = true, midiMax = 127, keyboardShortcuts, fill = false, height = fill ? '100%' : 160, style, playNote, stopNote, label, children, }) {
922
+ function Piano(_a) {
923
+ var { noteRange, glissando = true, midiMax = 127, keyboardShortcuts, fill = false, height = fill ? '100%' : 160, style, className, playNote, stopNote, label, children } = _a, props = __rest(_a, ["noteRange", "glissando", "midiMax", "keyboardShortcuts", "fill", "height", "style", "className", "playNote", "stopNote", "label", "children"]);
741
924
  // -- state and ref ---
742
925
  const [pressed, setPressed] = useState(false);
743
926
  const [whiteNoteWidth, setWhiteNoteWidth] = useState(-1);
@@ -749,8 +932,7 @@ function Piano({ noteRange, glissando = true, midiMax = 127, keyboardShortcuts,
749
932
  // --- interpret props ---
750
933
  const noteRangeArray = Array.from({ length: noteRange.last - noteRange.first + 1 }, (_, i) => i + noteRange.first);
751
934
  const whiteNoteCount = noteRangeArray.filter((v) => isWhiteKey(v)).length;
752
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
753
- let whiteKeyProps, blackKeyProps;
935
+ let whiteKeyProps = {}, blackKeyProps = {};
754
936
  if (children != undefined) {
755
937
  React.Children.forEach(children, (child) => {
756
938
  if (React.isValidElement(child)) {
@@ -810,9 +992,9 @@ function Piano({ noteRange, glissando = true, midiMax = 127, keyboardShortcuts,
810
992
  resizeObserver.observe(parent);
811
993
  }
812
994
  else {
813
- setWhiteNoteWidth((whiteKeyProps === null || whiteKeyProps === undefined ? undefined : whiteKeyProps.width) || 40);
995
+ setWhiteNoteWidth((whiteKeyProps === null || whiteKeyProps === void 0 ? void 0 : whiteKeyProps.width) || 40);
814
996
  }
815
- }, []);
997
+ }, [fill, whiteKeyProps === null || whiteKeyProps === void 0 ? void 0 : whiteKeyProps.width, whiteNoteCount]);
816
998
  useEventListener(window, 'keydown', (e) => {
817
999
  var _a, _b, _c, _d;
818
1000
  if (e.repeat)
@@ -821,8 +1003,8 @@ function Piano({ noteRange, glissando = true, midiMax = 127, keyboardShortcuts,
821
1003
  return;
822
1004
  const index = keyboardShortcuts.keys.indexOf(e.key);
823
1005
  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();
1006
+ if (!((_b = (_a = keyRefs.current[index]) === null || _a === void 0 ? void 0 : _a.current) === null || _b === void 0 ? void 0 : _b.played())) {
1007
+ (_d = (_c = keyRefs.current[index]) === null || _c === void 0 ? void 0 : _c.current) === null || _d === void 0 ? void 0 : _d.play();
826
1008
  }
827
1009
  }
828
1010
  });
@@ -834,18 +1016,48 @@ function Piano({ noteRange, glissando = true, midiMax = 127, keyboardShortcuts,
834
1016
  return;
835
1017
  const index = keyboardShortcuts.keys.indexOf(e.key);
836
1018
  if (index != -1) {
837
- (_b = (_a = keyRefs.current[index]) === null || _a === undefined ? undefined : _a.current) === null || _b === undefined ? undefined : _b.stop();
1019
+ (_b = (_a = keyRefs.current[index]) === null || _a === void 0 ? void 0 : _a.current) === null || _b === void 0 ? void 0 : _b.stop();
838
1020
  }
839
1021
  });
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: () => {
1022
+ return (jsx("div", Object.assign({ ref: pianoRef, className: clsx('tremolo-piano', className), style: Object.assign({ width: fill ? '100%' : undefined, height: height }, style), onPointerDown: (e) => {
1023
+ if (props.onPointerDown)
1024
+ props.onPointerDown(e);
841
1025
  setPressed(true);
842
- }, onPointerUp: () => {
1026
+ }, onPointerUp: (e) => {
1027
+ if (props.onPointerUp)
1028
+ props.onPointerUp(e);
843
1029
  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
- }) }));
1030
+ } }, props, { children: noteRangeArray.map((note, index) => {
1031
+ 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));
1032
+ }) })));
847
1033
  }
848
1034
 
1035
+ const minContext = createContext(0);
1036
+ const maxContext = createContext(0);
1037
+ const stepContext = createContext(0);
1038
+ const skewContext = createContext(0);
1039
+ const verticalContext = createContext(false);
1040
+ const reverseContext = createContext(false);
1041
+ const disabledContext = createContext(false);
1042
+ function SliderValuesProvider({ min: _min, max: _max, step: _step, skew: _skew, vertical: _vertical, reverse: _reverse, disabled: _disabled, children, }) {
1043
+ const [min] = useState(_min);
1044
+ const [max] = useState(_max);
1045
+ const [step] = useState(_step);
1046
+ const [skew] = useState(_skew);
1047
+ const [vertical] = useState(_vertical);
1048
+ const [reverse] = useState(_reverse);
1049
+ const [disabled] = useState(_disabled);
1050
+ return (jsx(minContext.Provider, { value: min, children: jsx(maxContext.Provider, { value: max, children: jsx(stepContext.Provider, { value: step, children: jsx(skewContext.Provider, { value: skew, children: jsx(verticalContext.Provider, { value: vertical, children: jsx(reverseContext.Provider, { value: reverse, children: jsx(disabledContext.Provider, { value: disabled, children: children }) }) }) }) }) }) }));
1051
+ }
1052
+ const useMin = () => useContext(minContext);
1053
+ const useMax = () => useContext(maxContext);
1054
+ const useStep = () => useContext(stepContext);
1055
+ const useSkew = () => useContext(skewContext);
1056
+ const useVertical = () => useContext(verticalContext);
1057
+ // export const useSetVertical = () => useContext(setVerticalContext)
1058
+ const useReverse = () => useContext(reverseContext);
1059
+ const useDisabled = () => useContext(disabledContext);
1060
+
849
1061
  /**
850
1062
  * clamp value between min and max
851
1063
  * @category Math
@@ -867,105 +1079,119 @@ function decimalPart(x) {
867
1079
 
868
1080
  /**
869
1081
  * @module Slider
870
- */
871
- function isHorizontal(d) {
872
- return d == 'right' || d == 'left';
873
- }
874
- function isVertical(d) {
875
- return d == 'up' || d == 'down';
876
- }
877
- function isReversed(d) {
878
- return d == 'left' || d == 'up';
879
- }
880
- function gradientDirection(d) {
881
- if (d == 'left' || d == 'right')
882
- return d;
883
- if (d == 'up')
884
- return 'top';
885
- if (d == 'down')
886
- return 'bottom';
887
- }
888
- function parseScaleOrderList(scale, min, max, step) {
1082
+ */
1083
+ function generateOptionsList(options, min, max, step) {
889
1084
  var _a;
890
- let scalesList = [];
891
- if (!scale) ;
892
- else if (typeof scale[0] == 'object') {
893
- scalesList = scale;
894
- }
895
- else {
896
- const per = scale[0] == 'step' ? step : scale[0];
897
- const count = Math.floor(max / per) - Math.ceil(min / per) + 1;
898
- for (let i = 0; i < count; i++) {
899
- const at = toFixed(per * (Math.ceil(min / per) + i), (_a = decimalPart(per)) === null || _a === undefined ? undefined : _a.length);
900
- scalesList.push({ at: at, type: scale[1] });
901
- }
1085
+ const optionsList = [];
1086
+ const per = options[0] == 'step' ? step : options[0];
1087
+ const count = Math.floor(max / per) - Math.ceil(min / per) + 1;
1088
+ for (let i = 0; i < count; i++) {
1089
+ const value = toFixed(per * (Math.ceil(min / per) + i), (_a = decimalPart(per)) === null || _a === void 0 ? void 0 : _a.length);
1090
+ optionsList.push({ value: value, type: options[1] });
902
1091
  }
903
- return scalesList;
1092
+ return optionsList;
1093
+ }
1094
+
1095
+ function ScaleOption(_a) {
1096
+ var { value, type = 'mark-number', label, thickness = 1, length = '0.5rem', gap = 2, labelWidth, classes, styles, className, style } = _a, props = __rest(_a, ["value", "type", "label", "thickness", "length", "gap", "labelWidth", "classes", "styles", "className", "style"]);
1097
+ const min = useMin();
1098
+ const max = useMax();
1099
+ const skew = useSkew();
1100
+ const vertical = useVertical();
1101
+ const reverse = useReverse();
1102
+ const calcPercent = useCallback((rawValue) => {
1103
+ return toFixed$2(xor(vertical, reverse)
1104
+ ? 100 - normalizeValue(rawValue, min, max, skew) * 100
1105
+ : normalizeValue(rawValue, min, max, skew) * 100);
1106
+ }, [vertical, reverse, max, min, skew]);
1107
+ return (jsxs("div", Object.assign({ className: clsx('tremolo-slider-scale-option', className), style: Object.assign({ left: !vertical ? `${calcPercent(value)}%` : undefined, top: vertical ? `${calcPercent(value)}%` : undefined }, style), "data-vertical": vertical }, props, { children: [type != 'number' && (jsx("div", { className: clsx('tremolo-slider-scale-option-mark', classes === null || classes === void 0 ? void 0 : classes.mark), style: Object.assign({ width: !vertical ? thickness : length, height: vertical ? thickness : length, marginBottom: !vertical ? gap : undefined, marginRight: vertical ? gap : undefined }, styles === null || styles === void 0 ? void 0 : styles.mark), "data-vertical": vertical })), type != 'mark' && (jsx("div", { className: clsx('tremolo-slider-scale-option-label', classes === null || classes === void 0 ? void 0 : classes.label), style: Object.assign({ width: labelWidth }, styles === null || styles === void 0 ? void 0 : styles.label), children: label || value }))] })));
904
1108
  }
905
1109
 
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) => {
1110
+ function Scale(_a) {
1111
+ var { gap = 6, options, children, className, style } = _a, props = __rest(_a, ["gap", "options", "children", "className", "style"]);
1112
+ const min = useMin();
1113
+ const max = useMax();
1114
+ const step = useStep();
1115
+ const vertical = useVertical();
1116
+ const reverse = useReverse();
1117
+ const optionsList = options
1118
+ ? generateOptionsList(options, min, max, step)
1119
+ : [];
1120
+ if (xor(vertical, reverse))
1121
+ optionsList.reverse();
1122
+ return (jsx("div", Object.assign({ className: clsx('tremolo-slider-scale', className), style: Object.assign({ marginLeft: vertical ? gap : undefined, marginTop: !vertical ? gap : undefined }, style) }, props, { children: options
1123
+ ? optionsList.map(({ value, type }, index) => {
1124
+ return jsx(ScaleOption, { value: value, type: type }, index);
1125
+ })
1126
+ : children })));
1127
+ }
1128
+
1129
+ const defaultThumbSize = 22;
1130
+ const SliderThumb = forwardRef(({ size, width = defaultThumbSize, height = defaultThumbSize, children, className, style, __percent, }, ref) => {
907
1131
  const wrapperRef = useRef(null);
1132
+ const vertical = useVertical();
1133
+ const disabled = useDisabled();
908
1134
  useImperativeHandle(ref, () => {
909
1135
  return {
910
1136
  focus() {
911
1137
  var _a;
912
- (_a = wrapperRef.current) === null || _a === undefined ? undefined : _a.focus();
1138
+ (_a = wrapperRef.current) === null || _a === void 0 ? void 0 : _a.focus();
913
1139
  },
914
1140
  blur() {
915
1141
  var _a;
916
- (_a = wrapperRef.current) === null || _a === undefined ? undefined : _a.blur();
1142
+ (_a = wrapperRef.current) === null || _a === void 0 ? void 0 : _a.blur();
917
1143
  },
918
1144
  };
919
1145
  }, []);
920
- return (jsx("div", { className: "tremolo-slider-thumb-wrapper", css: css(Object.assign({ position: 'absolute', translate: '-50% -50%', zIndex: zIndex }, __css)), children: children ? (children) : (
1146
+ return (jsx("div", { className: "tremolo-slider-thumb-wrapper", style: {
1147
+ top: vertical ? `${__percent}%` : '50%',
1148
+ left: !vertical ? `${__percent}%` : '50%',
1149
+ }, children: children ? (children) : (
921
1150
  // default slider thumb
922
1151
  jsx("div", { ref: wrapperRef, className: clsx('tremolo-slider-thumb', className),
923
1152
  // eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex
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 && {
927
- boxShadow: '0px 0px 0px 3px rgba(var(--tremolo-theme-color-rgb), 0.2)',
928
- } }, style)) })) }));
1153
+ tabIndex: 0, "aria-disabled": disabled, style: Object.assign({ width: size !== null && size !== void 0 ? size : width, height: size !== null && size !== void 0 ? size : height }, style) })) }));
929
1154
  });
930
1155
 
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] }));
1156
+ const defaultLength = 140;
1157
+ const defaultThickness = 10;
1158
+ function SliderTrack({ length = defaultLength, thickness = defaultThickness, active, inactive, children, className, style, __thumb, __percent, }) {
1159
+ const vertical = useVertical();
1160
+ const reverse = useReverse();
1161
+ const disabled = useDisabled();
1162
+ const direction = vertical ? 'bottom' : 'right';
1163
+ const colors = {
1164
+ '--active': active,
1165
+ '--inactive': inactive,
1166
+ };
1167
+ return (jsxs("div", { className: clsx('tremolo-slider-track', className), "aria-disabled": disabled, style: Object.assign(Object.assign(Object.assign({}, colors), { background: xor(vertical, reverse)
1168
+ ? `linear-gradient(to ${direction}, var(--inactive, #eee) ${__percent}%, var(--active, #7998ec) ${__percent}%)`
1169
+ : `linear-gradient(to ${direction}, var(--active, #7998ec) ${__percent}%, var(--inactive, #eee) ${__percent}%)`, borderRadius: styleHelper(thickness, '/', 2), width: !vertical ? length : thickness, height: vertical ? length : thickness }), style), children: [children, __thumb] }));
939
1170
  }
940
1171
 
941
1172
  /**
942
1173
  * Customizable slider
943
1174
  */
944
1175
  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"]);
1176
+ var _b, _c, _d;
1177
+ var { value, min, max, step = 1, skew = 1, vertical = false, reverse = false, className, style, bodyNoSelect = true, wheel = ['raw', 1], keyboard = ['raw', 1], disabled = false, readonly = false, onChange, children } = _a, props = __rest(_a, ["value", "min", "max", "step", "skew", "vertical", "reverse", "className", "style", "bodyNoSelect", "wheel", "keyboard", "disabled", "readonly", "onChange", "children"]);
947
1178
  // -- state and ref ---
948
1179
  const trackElementRef = useRef(null);
949
1180
  const thumbRef = useRef(null);
950
1181
  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
- }
964
- const scalesList = parseScaleOrderList(scale, min, max, step);
965
- if (isReversed(direction))
966
- scalesList.reverse();
967
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
968
- let trackProps, thumbProps;
1182
+ // --- interpret props ---
1183
+ const p = toFixed$2(normalizeValue(value, min, max, skew) * 100);
1184
+ const rev = toFixed$2(100 - p);
1185
+ // NOTE
1186
+ // normal -> normal (right)
1187
+ // vertical -> rev (up)
1188
+ // reverse -> rev (left)
1189
+ // vertical & reverse -> normal (down)
1190
+ const displayReversed = useMemo(() => xor(vertical, reverse), [vertical, reverse]);
1191
+ const percent = displayReversed ? rev : p;
1192
+ let trackProps = {};
1193
+ let thumbProps = {};
1194
+ let scaleComponent = undefined;
969
1195
  if (children != undefined) {
970
1196
  React.Children.forEach(children, (child) => {
971
1197
  if (React.isValidElement(child)) {
@@ -975,6 +1201,9 @@ const Slider = forwardRef((_a, ref) => {
975
1201
  else if (child.type == SliderTrack) {
976
1202
  trackProps = child.props;
977
1203
  }
1204
+ else if (child.type == Scale) {
1205
+ scaleComponent = child;
1206
+ }
978
1207
  else {
979
1208
  throw new Error('only <SliderThumb> or <SliderTrack>');
980
1209
  }
@@ -986,8 +1215,12 @@ const Slider = forwardRef((_a, ref) => {
986
1215
  }
987
1216
  // --- internal functions ---
988
1217
  const handleValue = (event) => {
989
- if (!trackElementRef.current || !thumbDragged.current || !onChange || readonly)
1218
+ if (!trackElementRef.current ||
1219
+ !thumbDragged.current ||
1220
+ !onChange ||
1221
+ readonly) {
990
1222
  return;
1223
+ }
991
1224
  const isTouch = event instanceof TouchEvent;
992
1225
  if (isTouch && event.cancelable)
993
1226
  event.preventDefault();
@@ -996,10 +1229,10 @@ const Slider = forwardRef((_a, ref) => {
996
1229
  const { left: x1, top: y1, right: x2, bottom: y2, } = trackElementRef.current.getBoundingClientRect();
997
1230
  const mouseX = isTouch ? event.touches[0].clientX : event.clientX;
998
1231
  const mouseY = isTouch ? event.touches[0].clientY : event.clientY;
999
- const n = isHorizontal(direction)
1000
- ? normalizeValue(mouseX, x1, x2)
1001
- : normalizeValue(mouseY, y1, y2);
1002
- const v = rawValue(isReversed(direction) ? 1 - n : n, min, max, skew);
1232
+ const n = vertical
1233
+ ? normalizeValue(mouseY, y1, y2)
1234
+ : normalizeValue(mouseX, x1, x2);
1235
+ const v = rawValue(displayReversed ? 1 - n : n, min, max, skew);
1003
1236
  onChange(clamp(stepValue(v, step), min, max));
1004
1237
  };
1005
1238
  const handleKeyDown = useCallback((event) => {
@@ -1008,8 +1241,8 @@ const Slider = forwardRef((_a, ref) => {
1008
1241
  const key = event.key;
1009
1242
  if (['ArrowRight', 'ArrowLeft', 'ArrowUp', 'ArrowDown'].includes(key)) {
1010
1243
  event.preventDefault();
1011
- let x = (key == 'ArrowRight' || key == 'ArrowUp') ? keyboard[1] : -keyboard[1];
1012
- if (direction == 'down' || direction == 'left')
1244
+ let x = key == 'ArrowRight' || key == 'ArrowUp' ? keyboard[1] : -keyboard[1];
1245
+ if (reverse)
1013
1246
  x *= -1;
1014
1247
  let v;
1015
1248
  if (keyboard[0] == 'normalized') {
@@ -1021,15 +1254,23 @@ const Slider = forwardRef((_a, ref) => {
1021
1254
  }
1022
1255
  onChange(clamp(stepValue(v, step), min, max));
1023
1256
  }
1024
- }, [value, min, max, step, skew, direction, keyboard, onChange, readonly]);
1257
+ }, [value, min, max, step, skew, reverse, keyboard, onChange, readonly]);
1025
1258
  // --- hooks ---
1026
- const touchMoveRefCallback = useRefCallbackEvent('touchmove', handleValue, { passive: false }, [min, max, skew, step, direction, onChange, readonly]);
1259
+ const touchMoveRefCallback = useRefCallbackEvent('touchmove', handleValue, { passive: false }, [min, max, skew, step, vertical, reverse, onChange, readonly]);
1027
1260
  const wheelRefCallback = useRefCallbackEvent('wheel', (event) => {
1028
1261
  if (!wheel || !onChange || readonly)
1029
1262
  return;
1030
1263
  event.preventDefault();
1031
- let x = event.deltaY > 0 ? wheel[1] : -wheel[1];
1032
- if (isReversed(direction) || isHorizontal(direction))
1264
+ let x;
1265
+ if (!vertical && event.deltaX != 0) {
1266
+ x = event.deltaX > 0 ? wheel[1] : -wheel[1];
1267
+ }
1268
+ else {
1269
+ if (event.deltaY == 0)
1270
+ return;
1271
+ x = event.deltaY > 0 ? -wheel[1] : wheel[1];
1272
+ }
1273
+ if (vertical && reverse)
1033
1274
  x *= -1;
1034
1275
  let v;
1035
1276
  if (wheel[0] == 'normalized') {
@@ -1055,65 +1296,227 @@ const Slider = forwardRef((_a, ref) => {
1055
1296
  return {
1056
1297
  focus() {
1057
1298
  var _a;
1058
- (_a = thumbRef.current) === null || _a === undefined ? undefined : _a.focus();
1299
+ (_a = thumbRef.current) === null || _a === void 0 ? void 0 : _a.focus();
1300
+ },
1301
+ blur() {
1302
+ var _a;
1303
+ (_a = thumbRef.current) === null || _a === void 0 ? void 0 : _a.blur();
1304
+ },
1305
+ };
1306
+ }, []);
1307
+ return (jsx(SliderValuesProvider, { min: min, max: max, step: step, skew: skew, vertical: vertical, reverse: reverse, disabled: disabled, children: jsx("div", Object.assign({ className: clsx('tremolo-slider', className), ref: (div) => {
1308
+ wheelRefCallback(div);
1309
+ touchMoveRefCallback(div);
1310
+ }, tabIndex: -1, role: "slider", "aria-valuenow": value, "aria-valuemin": min, "aria-valuemax": max, "aria-orientation": vertical ? 'vertical' : 'horizontal', "aria-disabled": disabled, "aria-readonly": readonly, style: Object.assign({ margin: `calc(${styleHelper((_b = thumbProps === null || thumbProps === void 0 ? void 0 : thumbProps.size) !== null && _b !== void 0 ? _b : 22)} / 2)` }, style), onPointerDown: (event) => {
1311
+ thumbDragged.current = true;
1312
+ handleValue(event);
1313
+ }, onKeyDown: handleKeyDown, onFocus: (_c = thumbRef.current) === null || _c === void 0 ? void 0 : _c.focus, onBlur: (_d = thumbRef.current) === null || _d === void 0 ? void 0 : _d.blur }, props, { children: jsxs("div", { style: {
1314
+ display: 'flex',
1315
+ flexDirection: vertical ? 'row' : 'column',
1316
+ }, children: [jsx("div", { className: "tremolo-slider-track-wrapper", ref: trackElementRef, children: jsx(SliderTrack, Object.assign({ __percent: percent, __thumb: jsx(SliderThumb, Object.assign({ ref: thumbRef, __percent: percent }, thumbProps)) }, trackProps)) }), scaleComponent] }) })) }));
1317
+ });
1318
+
1319
+ function WheelObserver(props) {
1320
+ const { children, onWheel, as: Component = 'div' } = props, attributes = __rest(props, ["children", "onWheel", "as"]);
1321
+ const wheelRefCallback = useRefCallbackEvent('wheel', (event) => {
1322
+ if (onWheel)
1323
+ onWheel(event);
1324
+ }, { passive: false }, [onWheel]);
1325
+ return (jsx(Component, Object.assign({ ref: wheelRefCallback }, attributes, { children: children })));
1326
+ }
1327
+
1328
+ function XYPadArea({ width = 120, height = 120, bg = '#eee', children, className, style, __thumb, }) {
1329
+ return (jsxs("div", { className: clsx('tremolo-xy-pad-area', className), style: Object.assign({ position: 'relative', width: width, height: height, background: bg }, style), children: [children, __thumb] }));
1330
+ }
1331
+
1332
+ const XYPadThumb = forwardRef(({ size, width = 22, height = 22, children, wrapperClassName, wrapperStyle, className, style, __disabled, __css, }, ref) => {
1333
+ const wrapperRef = useRef(null);
1334
+ useImperativeHandle(ref, () => {
1335
+ return {
1336
+ focus() {
1337
+ var _a;
1338
+ (_a = wrapperRef.current) === null || _a === void 0 ? void 0 : _a.focus();
1059
1339
  },
1060
1340
  blur() {
1061
1341
  var _a;
1062
- (_a = thumbRef.current) === null || _a === undefined ? undefined : _a.blur();
1342
+ (_a = wrapperRef.current) === null || _a === void 0 ? void 0 : _a.blur();
1063
1343
  },
1064
1344
  };
1065
1345
  }, []);
1066
- return (jsxs("div", { className: clsx('tremolo-slider', className), ref: (div) => {
1346
+ return (jsx("div", { className: clsx('tremolo-xy-pad-thumb-wrapper', wrapperClassName), style: Object.assign(Object.assign({}, __css), wrapperStyle), children: children ? (children) : (
1347
+ // default thumb
1348
+ jsx("div", { ref: wrapperRef, className: clsx('tremolo-xy-pad-thumb', className),
1349
+ // eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex
1350
+ tabIndex: 0, "aria-disabled": __disabled, style: Object.assign({ width: size !== null && size !== void 0 ? size : width, height: size !== null && size !== void 0 ? size : height }, style) })) }));
1351
+ });
1352
+
1353
+ const defaultValueOptions = {
1354
+ skew: 1,
1355
+ step: 1,
1356
+ reverse: false,
1357
+ wheel: ['raw', 1],
1358
+ keyboard: ['raw', 1],
1359
+ };
1360
+ /**
1361
+ * Simple XYPad
1362
+ */
1363
+ const XYPad = forwardRef((_a, ref) => {
1364
+ var _b, _c, _d;
1365
+ var { x: _x, y: _y, className, style, bodyNoSelect = true, disabled = false, readonly = false, onChange, children } = _a, props = __rest(_a, ["x", "y", "className", "style", "bodyNoSelect", "disabled", "readonly", "onChange", "children"]);
1366
+ const x = useMemo(() => {
1367
+ return Object.assign(Object.assign({}, defaultValueOptions), _x);
1368
+ }, [_x]);
1369
+ const y = useMemo(() => {
1370
+ return Object.assign(Object.assign({}, defaultValueOptions), _y);
1371
+ }, [_y]);
1372
+ // -- state and ref ---
1373
+ const areaElementRef = useRef(null);
1374
+ const thumbRef = useRef(null);
1375
+ const thumbDragged = useRef(false);
1376
+ // --- interpret props ---
1377
+ const nx = normalizeValue(x.value, x.min, x.max, x.skew);
1378
+ const ny = normalizeValue(y.value, y.min, y.max, y.skew);
1379
+ const percentX = toFixed$2((x.reverse ? 1 - nx : nx) * 100);
1380
+ const percentY = toFixed$2((y.reverse ? 1 - ny : ny) * 100);
1381
+ let areaProps = {}, thumbProps = {};
1382
+ if (children != undefined) {
1383
+ React.Children.forEach(children, (child) => {
1384
+ if (React.isValidElement(child)) {
1385
+ if (child.type == XYPadThumb) {
1386
+ thumbProps = child.props;
1387
+ }
1388
+ else if (child.type == XYPadArea) {
1389
+ areaProps = child.props;
1390
+ }
1391
+ else {
1392
+ throw new Error('only <XYPadThumb> or <XYPadArea>');
1393
+ }
1394
+ }
1395
+ else {
1396
+ throw new Error('children is an invalid element.');
1397
+ }
1398
+ });
1399
+ }
1400
+ // --- internal functions ---
1401
+ const handleValue = (event) => {
1402
+ if (!areaElementRef.current ||
1403
+ !thumbDragged.current ||
1404
+ !onChange ||
1405
+ readonly)
1406
+ return;
1407
+ const isTouch = event instanceof TouchEvent;
1408
+ if (isTouch && event.cancelable)
1409
+ event.preventDefault();
1410
+ if (bodyNoSelect)
1411
+ addNoSelect();
1412
+ const { left: x1, top: y1, right: x2, bottom: y2, } = areaElementRef.current.getBoundingClientRect();
1413
+ const mouseX = isTouch ? event.touches[0].clientX : event.clientX;
1414
+ const mouseY = isTouch ? event.touches[0].clientY : event.clientY;
1415
+ const nx = normalizeValue(mouseX, x1, x2);
1416
+ const ny = normalizeValue(mouseY, y1, y2);
1417
+ const vx = rawValue(x.reverse ? 1 - nx : nx, x.min, x.max, x.skew);
1418
+ const vy = rawValue(y.reverse ? 1 - ny : ny, y.min, y.max, y.skew);
1419
+ const newX = clamp(stepValue(vx, x.step), x.min, x.max);
1420
+ const newY = clamp(stepValue(vy, y.step), y.min, y.max);
1421
+ onChange(newX, newY);
1422
+ };
1423
+ const handleKeyDown = useCallback((event) => {
1424
+ if (!onChange || readonly)
1425
+ return;
1426
+ const key = event.key;
1427
+ if (['ArrowRight', 'ArrowLeft', 'ArrowUp', 'ArrowDown'].includes(key)) {
1428
+ const isHorizontal = key == 'ArrowRight' || key == 'ArrowLeft';
1429
+ const target = isHorizontal ? x : y;
1430
+ if (!target.keyboard)
1431
+ return;
1432
+ event.preventDefault();
1433
+ let delta = target.keyboard[1];
1434
+ if (key == 'ArrowLeft' || key == 'ArrowUp')
1435
+ delta *= -1;
1436
+ if (target.reverse)
1437
+ delta *= -1;
1438
+ let v;
1439
+ if (target.keyboard[0] == 'normalized') {
1440
+ const n = normalizeValue(target.value, target.min, target.max, target.skew);
1441
+ v = rawValue(n + delta, target.min, target.max, target.skew);
1442
+ }
1443
+ else {
1444
+ v = target.value + delta;
1445
+ }
1446
+ const newValue = clamp(stepValue(v, target.step), target.min, target.max);
1447
+ if (isHorizontal) {
1448
+ onChange(newValue, y.value);
1449
+ }
1450
+ else {
1451
+ onChange(x.value, newValue);
1452
+ }
1453
+ }
1454
+ }, [x, y, onChange, readonly]);
1455
+ // --- hooks ---
1456
+ const touchMoveRefCallback = useRefCallbackEvent('touchmove', handleValue, { passive: false }, [x, onChange, readonly]);
1457
+ const wheelRefCallback = useRefCallbackEvent('wheel', (event) => {
1458
+ if (!onChange || readonly)
1459
+ return;
1460
+ const target = event.shiftKey ? x : y;
1461
+ if (!target.wheel)
1462
+ return;
1463
+ event.preventDefault();
1464
+ let delta = target.wheel[1];
1465
+ if (event.deltaY < 0)
1466
+ delta *= -1;
1467
+ if (target.reverse)
1468
+ delta *= -1;
1469
+ let v;
1470
+ if (target.wheel[0] == 'normalized') {
1471
+ const n = normalizeValue(target.value, target.min, target.max, target.skew);
1472
+ v = rawValue(n + delta, target.min, target.max, target.skew);
1473
+ }
1474
+ else {
1475
+ v = target.value + delta;
1476
+ }
1477
+ const newValue = clamp(stepValue(v, target.step), target.min, target.max);
1478
+ if (event.shiftKey) {
1479
+ onChange(newValue, y.value);
1480
+ }
1481
+ else {
1482
+ onChange(x.value, newValue);
1483
+ }
1484
+ }, {
1485
+ passive: false,
1486
+ }, [x, y]);
1487
+ useEventListener(window, 'mousemove', (event) => {
1488
+ handleValue(event);
1489
+ });
1490
+ useEventListener(window, 'mouseup', () => {
1491
+ thumbDragged.current = false;
1492
+ if (bodyNoSelect)
1493
+ removeNoSelect();
1494
+ });
1495
+ useImperativeHandle(ref, () => {
1496
+ return {
1497
+ focus() {
1498
+ var _a;
1499
+ (_a = thumbRef.current) === null || _a === void 0 ? void 0 : _a.focus();
1500
+ },
1501
+ blur() {
1502
+ var _a;
1503
+ (_a = thumbRef.current) === null || _a === void 0 ? void 0 : _a.blur();
1504
+ },
1505
+ };
1506
+ }, []);
1507
+ return (
1508
+ // eslint-disable-next-line jsx-a11y/no-static-element-interactions
1509
+ jsx("div", Object.assign({ className: clsx('tremolo-xy-pad', className), ref: (div) => {
1067
1510
  wheelRefCallback(div);
1068
1511
  touchMoveRefCallback(div);
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) => {
1512
+ }, tabIndex: -1, "aria-disabled": disabled, "aria-readonly": readonly, style: Object.assign({ margin: `calc(${styleHelper((_b = thumbProps === null || thumbProps === void 0 ? void 0 : thumbProps.size) !== null && _b !== void 0 ? _b : 22)} / 2)`, cursor: readonly ? 'not-allowed' : 'pointer', WebkitTapHighlightColor: 'transparent' }, style), onPointerDown: (event) => {
1070
1513
  thumbDragged.current = true;
1071
1514
  handleValue(event);
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: {
1073
- '.no-select': {
1074
- userSelect: 'none',
1075
- },
1076
- } }), jsxs("div", { css: css({
1077
- display: 'flex',
1078
- flexDirection: isHorizontal(direction) ? 'column' : 'row',
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: {
1080
- top: isHorizontal(direction) ? '50%' : `${percentRev}%`,
1081
- left: isHorizontal(direction) ? `${percentRev}%` : '50%',
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) => {
1087
- var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
1088
- return (jsxs("div", { css: css({
1089
- display: 'flex',
1090
- flexDirection: isHorizontal(direction) ? 'column' : 'row',
1091
- justifyContent: 'center',
1092
- alignItems: 'center',
1093
- position: 'absolute',
1094
- left: isHorizontal(direction) ? `${calcPercent(item.at)}%` : undefined,
1095
- top: isVertical(direction) ? `${calcPercent(item.at)}%` : undefined,
1096
- translate: isHorizontal(direction) ? '-50% 0' : '0 -50%',
1097
- zIndex: 10,
1098
- }), children: [((_b = (_a = item.type) !== null && _a !== undefined ? _a : scaleOption === null || scaleOption === undefined ? undefined : scaleOption.defaultType) !== null && _b !== undefined ? _b : 'mark-number') !=
1099
- 'number' && (jsx("div", { className: "tremolo-slider-scale-mark", css: css({
1100
- width: isHorizontal(direction)
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'),
1103
- height: isVertical(direction)
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',
1107
- marginBottom: isHorizontal(direction) ? 2 : undefined,
1108
- marginRight: isVertical(direction) ? 2 : undefined,
1109
- }) })), ((_q = (_p = item.type) !== null && _p !== undefined ? _p : scaleOption === null || scaleOption === undefined ? undefined : scaleOption.defaultType) !== null && _q !== undefined ? _q : 'mark-number') !=
1110
- 'mark' && (jsx("div", { className: "tremolo-slider-scale-number", css: css({
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,
1113
- textAlign: 'right',
1114
- }), children: (_t = item.text) !== null && _t !== undefined ? _t : item.at }))] }, index));
1115
- }) }))] })] }));
1515
+ }, onKeyDown: handleKeyDown, onFocus: (_c = thumbRef.current) === null || _c === void 0 ? void 0 : _c.focus, onBlur: (_d = thumbRef.current) === null || _d === void 0 ? void 0 : _d.blur }, props, { children: jsx("div", { className: "tremolo-xy-pad-area-wrapper", ref: areaElementRef, children: jsx(XYPadArea, Object.assign({ __thumb: jsx(XYPadThumb, Object.assign({ ref: thumbRef, __disabled: disabled, __css: {
1516
+ top: `${percentY}%`,
1517
+ left: `${percentX}%`,
1518
+ } }, thumbProps)) }, areaProps)) }) })));
1116
1519
  });
1117
1520
 
1118
- export { AnimationCanvas, BlackKey, KeyLabel, Knob, NumberInput, Piano, Shortcuts, Slider, SliderThumb, SliderTrack, WhiteKey, gradientDirection };
1521
+ export { AnimationCanvas, AnimationKnob, BlackKey, DragObserver, KeyLabel, Knob, NumberInput, Piano, Scale, ScaleOption, Shortcuts, Slider, SliderThumb, SliderTrack, SliderValuesProvider, WheelObserver, WhiteKey, XYPad, XYPadArea, XYPadThumb, defaultLength, defaultThickness, defaultThumbSize, useDisabled, useMax, useMin, useReverse, useSkew, useStep, useVertical };
1119
1522
  //# sourceMappingURL=index.js.map