@tremolo-ui/react 0.0.7 → 0.0.9

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 +675 -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 +4 -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 +658 -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 +4 -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 +242 -0
  94. package/package.json +5 -8
  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 +26 -0
  101. package/src/components/NumberInput/index.tsx +8 -41
  102. package/src/components/Piano/BlackKey.tsx +105 -98
  103. package/src/components/Piano/KeyLabel.tsx +18 -40
  104. package/src/components/Piano/WhiteKey.tsx +94 -87
  105. package/src/components/Piano/index.css +63 -0
  106. package/src/components/Piano/index.tsx +78 -61
  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,20 @@ 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 defaultWhiteKeyWidth = 40;
765
+ const WhiteKey = forwardRef((_a, ref) => {
766
+ var { width = defaultWhiteKeyWidth, 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"]);
601
767
  const [played, setPlayed] = useState(false);
602
768
  useImperativeHandle(ref, () => {
603
769
  return {
@@ -615,11 +781,10 @@ const WhiteKey = forwardRef(({ width = 40, height = '100%', bg = 'white', active
615
781
  },
616
782
  played() {
617
783
  return played;
618
- }
784
+ },
619
785
  };
620
- }, []);
621
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
622
- let keyLabelProps;
786
+ }, [__disabled, __note, __playNote, __stopNote, played]);
787
+ let keyLabelProps = {};
623
788
  if (children != undefined) {
624
789
  React.Children.forEach(children, (child) => {
625
790
  if (React.isValidElement(child)) {
@@ -635,7 +800,7 @@ const WhiteKey = forwardRef(({ width = 40, height = '100%', bg = 'white', active
635
800
  }
636
801
  });
637
802
  }
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: () => {
803
+ 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: () => {
639
804
  if (__disabled)
640
805
  return;
641
806
  setPlayed(true);
@@ -661,10 +826,11 @@ const WhiteKey = forwardRef(({ width = 40, height = '100%', bg = 'white', active
661
826
  setPlayed(false);
662
827
  if (__stopNote)
663
828
  __stopNote(__note);
664
- }, children: jsx(KeyLabel, Object.assign({ __note: __note, __label: __label, __index: __index }, keyLabelProps)) }));
829
+ } }, props, { children: jsx(KeyLabel, Object.assign({ __note: __note, __label: __label, __index: __index }, keyLabelProps)) })));
665
830
  });
666
831
 
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) => {
832
+ const BlackKey = forwardRef((_a, ref) => {
833
+ var { width = defaultWhiteKeyWidth * 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"]);
668
834
  const [played, setPlayed] = useState(false);
669
835
  useImperativeHandle(ref, () => {
670
836
  return {
@@ -682,11 +848,10 @@ const BlackKey = forwardRef(({ width = 40 * 0.65, height = '60%', bg = '#333', a
682
848
  },
683
849
  played() {
684
850
  return played;
685
- }
851
+ },
686
852
  };
687
- }, []);
688
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
689
- let keyLabelProps;
853
+ }, [__disabled, __note, __playNote, __stopNote, played]);
854
+ let keyLabelProps = {};
690
855
  if (children != undefined) {
691
856
  React.Children.forEach(children, (child) => {
692
857
  if (React.isValidElement(child)) {
@@ -702,7 +867,7 @@ const BlackKey = forwardRef(({ width = 40 * 0.65, height = '60%', bg = '#333', a
702
867
  }
703
868
  });
704
869
  }
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: () => {
870
+ 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: () => {
706
871
  if (__disabled)
707
872
  return;
708
873
  setPlayed(true);
@@ -728,16 +893,35 @@ const BlackKey = forwardRef(({ width = 40 * 0.65, height = '60%', bg = '#333', a
728
893
  setPlayed(false);
729
894
  if (__stopNote)
730
895
  __stopNote(__note);
731
- }, children: jsx(KeyLabel, Object.assign({ __note: __note, __label: __label, __index: __index }, keyLabelProps)) }));
896
+ } }, props, { children: jsx(KeyLabel, Object.assign({ __note: __note, __label: __label, __index: __index }, keyLabelProps)) })));
732
897
  });
733
898
 
734
899
  const Shortcuts = {
735
900
  HOME_ROW: {
736
- keys: ['a', 'w', 's', 'e', 'd', 'f', 't', 'g', 'y', 'h', 'u', 'j', 'k', 'o', 'l', 'p', ';']
737
- }
901
+ keys: [
902
+ 'a',
903
+ 'w',
904
+ 's',
905
+ 'e',
906
+ 'd',
907
+ 'f',
908
+ 't',
909
+ 'g',
910
+ 'y',
911
+ 'h',
912
+ 'u',
913
+ 'j',
914
+ 'k',
915
+ 'o',
916
+ 'l',
917
+ 'p',
918
+ ';',
919
+ ],
920
+ },
738
921
  };
739
922
 
740
- function Piano({ noteRange, glissando = true, midiMax = 127, keyboardShortcuts, fill = false, height = fill ? '100%' : 160, style, playNote, stopNote, label, children, }) {
923
+ function Piano(_a) {
924
+ 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
925
  // -- state and ref ---
742
926
  const [pressed, setPressed] = useState(false);
743
927
  const [whiteNoteWidth, setWhiteNoteWidth] = useState(-1);
@@ -749,8 +933,7 @@ function Piano({ noteRange, glissando = true, midiMax = 127, keyboardShortcuts,
749
933
  // --- interpret props ---
750
934
  const noteRangeArray = Array.from({ length: noteRange.last - noteRange.first + 1 }, (_, i) => i + noteRange.first);
751
935
  const whiteNoteCount = noteRangeArray.filter((v) => isWhiteKey(v)).length;
752
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
753
- let whiteKeyProps, blackKeyProps;
936
+ let whiteKeyProps = {}, blackKeyProps = {};
754
937
  if (children != undefined) {
755
938
  React.Children.forEach(children, (child) => {
756
939
  if (React.isValidElement(child)) {
@@ -810,9 +993,9 @@ function Piano({ noteRange, glissando = true, midiMax = 127, keyboardShortcuts,
810
993
  resizeObserver.observe(parent);
811
994
  }
812
995
  else {
813
- setWhiteNoteWidth((whiteKeyProps === null || whiteKeyProps === undefined ? undefined : whiteKeyProps.width) || 40);
996
+ setWhiteNoteWidth((whiteKeyProps === null || whiteKeyProps === void 0 ? void 0 : whiteKeyProps.width) || defaultWhiteKeyWidth);
814
997
  }
815
- }, []);
998
+ }, [fill, whiteKeyProps === null || whiteKeyProps === void 0 ? void 0 : whiteKeyProps.width, whiteNoteCount]);
816
999
  useEventListener(window, 'keydown', (e) => {
817
1000
  var _a, _b, _c, _d;
818
1001
  if (e.repeat)
@@ -821,8 +1004,8 @@ function Piano({ noteRange, glissando = true, midiMax = 127, keyboardShortcuts,
821
1004
  return;
822
1005
  const index = keyboardShortcuts.keys.indexOf(e.key);
823
1006
  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();
1007
+ if (!((_b = (_a = keyRefs.current[index]) === null || _a === void 0 ? void 0 : _a.current) === null || _b === void 0 ? void 0 : _b.played())) {
1008
+ (_d = (_c = keyRefs.current[index]) === null || _c === void 0 ? void 0 : _c.current) === null || _d === void 0 ? void 0 : _d.play();
826
1009
  }
827
1010
  }
828
1011
  });
@@ -834,18 +1017,48 @@ function Piano({ noteRange, glissando = true, midiMax = 127, keyboardShortcuts,
834
1017
  return;
835
1018
  const index = keyboardShortcuts.keys.indexOf(e.key);
836
1019
  if (index != -1) {
837
- (_b = (_a = keyRefs.current[index]) === null || _a === undefined ? undefined : _a.current) === null || _b === undefined ? undefined : _b.stop();
1020
+ (_b = (_a = keyRefs.current[index]) === null || _a === void 0 ? void 0 : _a.current) === null || _b === void 0 ? void 0 : _b.stop();
838
1021
  }
839
1022
  });
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: () => {
1023
+ return (jsx("div", Object.assign({ ref: pianoRef, className: clsx('tremolo-piano', className), style: Object.assign({ width: fill ? '100%' : (whiteNoteWidth + 3) * whiteNoteCount, height: height }, style), onPointerDown: (e) => {
1024
+ if (props.onPointerDown)
1025
+ props.onPointerDown(e);
841
1026
  setPressed(true);
842
- }, onPointerUp: () => {
1027
+ }, onPointerUp: (e) => {
1028
+ if (props.onPointerUp)
1029
+ props.onPointerUp(e);
843
1030
  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
- }) }));
1031
+ } }, props, { children: noteRangeArray.map((note, index) => {
1032
+ 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));
1033
+ }) })));
847
1034
  }
848
1035
 
1036
+ const minContext = createContext(0);
1037
+ const maxContext = createContext(0);
1038
+ const stepContext = createContext(0);
1039
+ const skewContext = createContext(0);
1040
+ const verticalContext = createContext(false);
1041
+ const reverseContext = createContext(false);
1042
+ const disabledContext = createContext(false);
1043
+ function SliderValuesProvider({ min: _min, max: _max, step: _step, skew: _skew, vertical: _vertical, reverse: _reverse, disabled: _disabled, children, }) {
1044
+ const [min] = useState(_min);
1045
+ const [max] = useState(_max);
1046
+ const [step] = useState(_step);
1047
+ const [skew] = useState(_skew);
1048
+ const [vertical] = useState(_vertical);
1049
+ const [reverse] = useState(_reverse);
1050
+ const [disabled] = useState(_disabled);
1051
+ 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 }) }) }) }) }) }) }));
1052
+ }
1053
+ const useMin = () => useContext(minContext);
1054
+ const useMax = () => useContext(maxContext);
1055
+ const useStep = () => useContext(stepContext);
1056
+ const useSkew = () => useContext(skewContext);
1057
+ const useVertical = () => useContext(verticalContext);
1058
+ // export const useSetVertical = () => useContext(setVerticalContext)
1059
+ const useReverse = () => useContext(reverseContext);
1060
+ const useDisabled = () => useContext(disabledContext);
1061
+
849
1062
  /**
850
1063
  * clamp value between min and max
851
1064
  * @category Math
@@ -867,105 +1080,119 @@ function decimalPart(x) {
867
1080
 
868
1081
  /**
869
1082
  * @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) {
1083
+ */
1084
+ function generateOptionsList(options, min, max, step) {
889
1085
  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
- }
1086
+ const optionsList = [];
1087
+ const per = options[0] == 'step' ? step : options[0];
1088
+ const count = Math.floor(max / per) - Math.ceil(min / per) + 1;
1089
+ for (let i = 0; i < count; i++) {
1090
+ const value = toFixed(per * (Math.ceil(min / per) + i), (_a = decimalPart(per)) === null || _a === void 0 ? void 0 : _a.length);
1091
+ optionsList.push({ value: value, type: options[1] });
902
1092
  }
903
- return scalesList;
1093
+ return optionsList;
1094
+ }
1095
+
1096
+ function ScaleOption(_a) {
1097
+ 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"]);
1098
+ const min = useMin();
1099
+ const max = useMax();
1100
+ const skew = useSkew();
1101
+ const vertical = useVertical();
1102
+ const reverse = useReverse();
1103
+ const calcPercent = useCallback((rawValue) => {
1104
+ return toFixed$2(xor(vertical, reverse)
1105
+ ? 100 - normalizeValue(rawValue, min, max, skew) * 100
1106
+ : normalizeValue(rawValue, min, max, skew) * 100);
1107
+ }, [vertical, reverse, max, min, skew]);
1108
+ 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
1109
  }
905
1110
 
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) => {
1111
+ function Scale(_a) {
1112
+ var { gap = 6, options, children, className, style } = _a, props = __rest(_a, ["gap", "options", "children", "className", "style"]);
1113
+ const min = useMin();
1114
+ const max = useMax();
1115
+ const step = useStep();
1116
+ const vertical = useVertical();
1117
+ const reverse = useReverse();
1118
+ const optionsList = options
1119
+ ? generateOptionsList(options, min, max, step)
1120
+ : [];
1121
+ if (xor(vertical, reverse))
1122
+ optionsList.reverse();
1123
+ 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
1124
+ ? optionsList.map(({ value, type }, index) => {
1125
+ return jsx(ScaleOption, { value: value, type: type }, index);
1126
+ })
1127
+ : children })));
1128
+ }
1129
+
1130
+ const defaultThumbSize = 22;
1131
+ const SliderThumb = forwardRef(({ size, width = defaultThumbSize, height = defaultThumbSize, children, className, style, __percent, }, ref) => {
907
1132
  const wrapperRef = useRef(null);
1133
+ const vertical = useVertical();
1134
+ const disabled = useDisabled();
908
1135
  useImperativeHandle(ref, () => {
909
1136
  return {
910
1137
  focus() {
911
1138
  var _a;
912
- (_a = wrapperRef.current) === null || _a === undefined ? undefined : _a.focus();
1139
+ (_a = wrapperRef.current) === null || _a === void 0 ? void 0 : _a.focus();
913
1140
  },
914
1141
  blur() {
915
1142
  var _a;
916
- (_a = wrapperRef.current) === null || _a === undefined ? undefined : _a.blur();
1143
+ (_a = wrapperRef.current) === null || _a === void 0 ? void 0 : _a.blur();
917
1144
  },
918
1145
  };
919
1146
  }, []);
920
- return (jsx("div", { className: "tremolo-slider-thumb-wrapper", css: css(Object.assign({ position: 'absolute', translate: '-50% -50%', zIndex: zIndex }, __css)), children: children ? (children) : (
1147
+ return (jsx("div", { className: "tremolo-slider-thumb-wrapper", style: {
1148
+ top: vertical ? `${__percent}%` : '50%',
1149
+ left: !vertical ? `${__percent}%` : '50%',
1150
+ }, children: children ? (children) : (
921
1151
  // default slider thumb
922
1152
  jsx("div", { ref: wrapperRef, className: clsx('tremolo-slider-thumb', className),
923
1153
  // 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)) })) }));
1154
+ 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
1155
  });
930
1156
 
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] }));
1157
+ const defaultLength = 140;
1158
+ const defaultThickness = 10;
1159
+ function SliderTrack({ length = defaultLength, thickness = defaultThickness, active, inactive, children, className, style, __thumb, __percent, }) {
1160
+ const vertical = useVertical();
1161
+ const reverse = useReverse();
1162
+ const disabled = useDisabled();
1163
+ const direction = vertical ? 'bottom' : 'right';
1164
+ const colors = {
1165
+ '--active': active,
1166
+ '--inactive': inactive,
1167
+ };
1168
+ return (jsxs("div", { className: clsx('tremolo-slider-track', className), "aria-disabled": disabled, style: Object.assign(Object.assign(Object.assign({}, colors), { background: xor(vertical, reverse)
1169
+ ? `linear-gradient(to ${direction}, var(--inactive, #eee) ${__percent}%, var(--active, #7998ec) ${__percent}%)`
1170
+ : `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
1171
  }
940
1172
 
941
1173
  /**
942
1174
  * Customizable slider
943
1175
  */
944
1176
  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"]);
1177
+ var _b, _c, _d;
1178
+ 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
1179
  // -- state and ref ---
948
1180
  const trackElementRef = useRef(null);
949
1181
  const thumbRef = useRef(null);
950
1182
  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;
1183
+ // --- interpret props ---
1184
+ const p = toFixed$2(normalizeValue(value, min, max, skew) * 100);
1185
+ const rev = toFixed$2(100 - p);
1186
+ // NOTE
1187
+ // normal -> normal (right)
1188
+ // vertical -> rev (up)
1189
+ // reverse -> rev (left)
1190
+ // vertical & reverse -> normal (down)
1191
+ const displayReversed = useMemo(() => xor(vertical, reverse), [vertical, reverse]);
1192
+ const percent = displayReversed ? rev : p;
1193
+ let trackProps = {};
1194
+ let thumbProps = {};
1195
+ let scaleComponent = undefined;
969
1196
  if (children != undefined) {
970
1197
  React.Children.forEach(children, (child) => {
971
1198
  if (React.isValidElement(child)) {
@@ -975,6 +1202,9 @@ const Slider = forwardRef((_a, ref) => {
975
1202
  else if (child.type == SliderTrack) {
976
1203
  trackProps = child.props;
977
1204
  }
1205
+ else if (child.type == Scale) {
1206
+ scaleComponent = child;
1207
+ }
978
1208
  else {
979
1209
  throw new Error('only <SliderThumb> or <SliderTrack>');
980
1210
  }
@@ -986,8 +1216,12 @@ const Slider = forwardRef((_a, ref) => {
986
1216
  }
987
1217
  // --- internal functions ---
988
1218
  const handleValue = (event) => {
989
- if (!trackElementRef.current || !thumbDragged.current || !onChange || readonly)
1219
+ if (!trackElementRef.current ||
1220
+ !thumbDragged.current ||
1221
+ !onChange ||
1222
+ readonly) {
990
1223
  return;
1224
+ }
991
1225
  const isTouch = event instanceof TouchEvent;
992
1226
  if (isTouch && event.cancelable)
993
1227
  event.preventDefault();
@@ -996,10 +1230,10 @@ const Slider = forwardRef((_a, ref) => {
996
1230
  const { left: x1, top: y1, right: x2, bottom: y2, } = trackElementRef.current.getBoundingClientRect();
997
1231
  const mouseX = isTouch ? event.touches[0].clientX : event.clientX;
998
1232
  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);
1233
+ const n = vertical
1234
+ ? normalizeValue(mouseY, y1, y2)
1235
+ : normalizeValue(mouseX, x1, x2);
1236
+ const v = rawValue(displayReversed ? 1 - n : n, min, max, skew);
1003
1237
  onChange(clamp(stepValue(v, step), min, max));
1004
1238
  };
1005
1239
  const handleKeyDown = useCallback((event) => {
@@ -1008,8 +1242,8 @@ const Slider = forwardRef((_a, ref) => {
1008
1242
  const key = event.key;
1009
1243
  if (['ArrowRight', 'ArrowLeft', 'ArrowUp', 'ArrowDown'].includes(key)) {
1010
1244
  event.preventDefault();
1011
- let x = (key == 'ArrowRight' || key == 'ArrowUp') ? keyboard[1] : -keyboard[1];
1012
- if (direction == 'down' || direction == 'left')
1245
+ let x = key == 'ArrowRight' || key == 'ArrowUp' ? keyboard[1] : -keyboard[1];
1246
+ if (reverse)
1013
1247
  x *= -1;
1014
1248
  let v;
1015
1249
  if (keyboard[0] == 'normalized') {
@@ -1021,15 +1255,23 @@ const Slider = forwardRef((_a, ref) => {
1021
1255
  }
1022
1256
  onChange(clamp(stepValue(v, step), min, max));
1023
1257
  }
1024
- }, [value, min, max, step, skew, direction, keyboard, onChange, readonly]);
1258
+ }, [value, min, max, step, skew, reverse, keyboard, onChange, readonly]);
1025
1259
  // --- hooks ---
1026
- const touchMoveRefCallback = useRefCallbackEvent('touchmove', handleValue, { passive: false }, [min, max, skew, step, direction, onChange, readonly]);
1260
+ const touchMoveRefCallback = useRefCallbackEvent('touchmove', handleValue, { passive: false }, [min, max, skew, step, vertical, reverse, onChange, readonly]);
1027
1261
  const wheelRefCallback = useRefCallbackEvent('wheel', (event) => {
1028
1262
  if (!wheel || !onChange || readonly)
1029
1263
  return;
1030
1264
  event.preventDefault();
1031
- let x = event.deltaY > 0 ? wheel[1] : -wheel[1];
1032
- if (isReversed(direction) || isHorizontal(direction))
1265
+ let x;
1266
+ if (!vertical && event.deltaX != 0) {
1267
+ x = event.deltaX > 0 ? wheel[1] : -wheel[1];
1268
+ }
1269
+ else {
1270
+ if (event.deltaY == 0)
1271
+ return;
1272
+ x = event.deltaY > 0 ? -wheel[1] : wheel[1];
1273
+ }
1274
+ if (vertical && reverse)
1033
1275
  x *= -1;
1034
1276
  let v;
1035
1277
  if (wheel[0] == 'normalized') {
@@ -1055,65 +1297,227 @@ const Slider = forwardRef((_a, ref) => {
1055
1297
  return {
1056
1298
  focus() {
1057
1299
  var _a;
1058
- (_a = thumbRef.current) === null || _a === undefined ? undefined : _a.focus();
1300
+ (_a = thumbRef.current) === null || _a === void 0 ? void 0 : _a.focus();
1301
+ },
1302
+ blur() {
1303
+ var _a;
1304
+ (_a = thumbRef.current) === null || _a === void 0 ? void 0 : _a.blur();
1305
+ },
1306
+ };
1307
+ }, []);
1308
+ 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) => {
1309
+ wheelRefCallback(div);
1310
+ touchMoveRefCallback(div);
1311
+ }, 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) => {
1312
+ thumbDragged.current = true;
1313
+ handleValue(event);
1314
+ }, 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: {
1315
+ display: 'flex',
1316
+ flexDirection: vertical ? 'row' : 'column',
1317
+ }, 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] }) })) }));
1318
+ });
1319
+
1320
+ function WheelObserver(props) {
1321
+ const { children, onWheel, as: Component = 'div' } = props, attributes = __rest(props, ["children", "onWheel", "as"]);
1322
+ const wheelRefCallback = useRefCallbackEvent('wheel', (event) => {
1323
+ if (onWheel)
1324
+ onWheel(event);
1325
+ }, { passive: false }, [onWheel]);
1326
+ return (jsx(Component, Object.assign({ ref: wheelRefCallback }, attributes, { children: children })));
1327
+ }
1328
+
1329
+ function XYPadArea({ width = 120, height = 120, bg = '#eee', children, className, style, __thumb, }) {
1330
+ 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] }));
1331
+ }
1332
+
1333
+ const XYPadThumb = forwardRef(({ size, width = 22, height = 22, children, wrapperClassName, wrapperStyle, className, style, __disabled, __css, }, ref) => {
1334
+ const wrapperRef = useRef(null);
1335
+ useImperativeHandle(ref, () => {
1336
+ return {
1337
+ focus() {
1338
+ var _a;
1339
+ (_a = wrapperRef.current) === null || _a === void 0 ? void 0 : _a.focus();
1059
1340
  },
1060
1341
  blur() {
1061
1342
  var _a;
1062
- (_a = thumbRef.current) === null || _a === undefined ? undefined : _a.blur();
1343
+ (_a = wrapperRef.current) === null || _a === void 0 ? void 0 : _a.blur();
1063
1344
  },
1064
1345
  };
1065
1346
  }, []);
1066
- return (jsxs("div", { className: clsx('tremolo-slider', className), ref: (div) => {
1347
+ return (jsx("div", { className: clsx('tremolo-xy-pad-thumb-wrapper', wrapperClassName), style: Object.assign(Object.assign({}, __css), wrapperStyle), children: children ? (children) : (
1348
+ // default thumb
1349
+ jsx("div", { ref: wrapperRef, className: clsx('tremolo-xy-pad-thumb', className),
1350
+ // eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex
1351
+ 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) })) }));
1352
+ });
1353
+
1354
+ const defaultValueOptions = {
1355
+ skew: 1,
1356
+ step: 1,
1357
+ reverse: false,
1358
+ wheel: ['raw', 1],
1359
+ keyboard: ['raw', 1],
1360
+ };
1361
+ /**
1362
+ * Simple XYPad
1363
+ */
1364
+ const XYPad = forwardRef((_a, ref) => {
1365
+ var _b, _c, _d;
1366
+ 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"]);
1367
+ const x = useMemo(() => {
1368
+ return Object.assign(Object.assign({}, defaultValueOptions), _x);
1369
+ }, [_x]);
1370
+ const y = useMemo(() => {
1371
+ return Object.assign(Object.assign({}, defaultValueOptions), _y);
1372
+ }, [_y]);
1373
+ // -- state and ref ---
1374
+ const areaElementRef = useRef(null);
1375
+ const thumbRef = useRef(null);
1376
+ const thumbDragged = useRef(false);
1377
+ // --- interpret props ---
1378
+ const nx = normalizeValue(x.value, x.min, x.max, x.skew);
1379
+ const ny = normalizeValue(y.value, y.min, y.max, y.skew);
1380
+ const percentX = toFixed$2((x.reverse ? 1 - nx : nx) * 100);
1381
+ const percentY = toFixed$2((y.reverse ? 1 - ny : ny) * 100);
1382
+ let areaProps = {}, thumbProps = {};
1383
+ if (children != undefined) {
1384
+ React.Children.forEach(children, (child) => {
1385
+ if (React.isValidElement(child)) {
1386
+ if (child.type == XYPadThumb) {
1387
+ thumbProps = child.props;
1388
+ }
1389
+ else if (child.type == XYPadArea) {
1390
+ areaProps = child.props;
1391
+ }
1392
+ else {
1393
+ throw new Error('only <XYPadThumb> or <XYPadArea>');
1394
+ }
1395
+ }
1396
+ else {
1397
+ throw new Error('children is an invalid element.');
1398
+ }
1399
+ });
1400
+ }
1401
+ // --- internal functions ---
1402
+ const handleValue = (event) => {
1403
+ if (!areaElementRef.current ||
1404
+ !thumbDragged.current ||
1405
+ !onChange ||
1406
+ readonly)
1407
+ return;
1408
+ const isTouch = event instanceof TouchEvent;
1409
+ if (isTouch && event.cancelable)
1410
+ event.preventDefault();
1411
+ if (bodyNoSelect)
1412
+ addNoSelect();
1413
+ const { left: x1, top: y1, right: x2, bottom: y2, } = areaElementRef.current.getBoundingClientRect();
1414
+ const mouseX = isTouch ? event.touches[0].clientX : event.clientX;
1415
+ const mouseY = isTouch ? event.touches[0].clientY : event.clientY;
1416
+ const nx = normalizeValue(mouseX, x1, x2);
1417
+ const ny = normalizeValue(mouseY, y1, y2);
1418
+ const vx = rawValue(x.reverse ? 1 - nx : nx, x.min, x.max, x.skew);
1419
+ const vy = rawValue(y.reverse ? 1 - ny : ny, y.min, y.max, y.skew);
1420
+ const newX = clamp(stepValue(vx, x.step), x.min, x.max);
1421
+ const newY = clamp(stepValue(vy, y.step), y.min, y.max);
1422
+ onChange(newX, newY);
1423
+ };
1424
+ const handleKeyDown = useCallback((event) => {
1425
+ if (!onChange || readonly)
1426
+ return;
1427
+ const key = event.key;
1428
+ if (['ArrowRight', 'ArrowLeft', 'ArrowUp', 'ArrowDown'].includes(key)) {
1429
+ const isHorizontal = key == 'ArrowRight' || key == 'ArrowLeft';
1430
+ const target = isHorizontal ? x : y;
1431
+ if (!target.keyboard)
1432
+ return;
1433
+ event.preventDefault();
1434
+ let delta = target.keyboard[1];
1435
+ if (key == 'ArrowLeft' || key == 'ArrowUp')
1436
+ delta *= -1;
1437
+ if (target.reverse)
1438
+ delta *= -1;
1439
+ let v;
1440
+ if (target.keyboard[0] == 'normalized') {
1441
+ const n = normalizeValue(target.value, target.min, target.max, target.skew);
1442
+ v = rawValue(n + delta, target.min, target.max, target.skew);
1443
+ }
1444
+ else {
1445
+ v = target.value + delta;
1446
+ }
1447
+ const newValue = clamp(stepValue(v, target.step), target.min, target.max);
1448
+ if (isHorizontal) {
1449
+ onChange(newValue, y.value);
1450
+ }
1451
+ else {
1452
+ onChange(x.value, newValue);
1453
+ }
1454
+ }
1455
+ }, [x, y, onChange, readonly]);
1456
+ // --- hooks ---
1457
+ const touchMoveRefCallback = useRefCallbackEvent('touchmove', handleValue, { passive: false }, [x, onChange, readonly]);
1458
+ const wheelRefCallback = useRefCallbackEvent('wheel', (event) => {
1459
+ if (!onChange || readonly)
1460
+ return;
1461
+ const target = event.shiftKey ? x : y;
1462
+ if (!target.wheel)
1463
+ return;
1464
+ event.preventDefault();
1465
+ let delta = target.wheel[1];
1466
+ if (event.deltaY < 0)
1467
+ delta *= -1;
1468
+ if (target.reverse)
1469
+ delta *= -1;
1470
+ let v;
1471
+ if (target.wheel[0] == 'normalized') {
1472
+ const n = normalizeValue(target.value, target.min, target.max, target.skew);
1473
+ v = rawValue(n + delta, target.min, target.max, target.skew);
1474
+ }
1475
+ else {
1476
+ v = target.value + delta;
1477
+ }
1478
+ const newValue = clamp(stepValue(v, target.step), target.min, target.max);
1479
+ if (event.shiftKey) {
1480
+ onChange(newValue, y.value);
1481
+ }
1482
+ else {
1483
+ onChange(x.value, newValue);
1484
+ }
1485
+ }, {
1486
+ passive: false,
1487
+ }, [x, y]);
1488
+ useEventListener(window, 'mousemove', (event) => {
1489
+ handleValue(event);
1490
+ });
1491
+ useEventListener(window, 'mouseup', () => {
1492
+ thumbDragged.current = false;
1493
+ if (bodyNoSelect)
1494
+ removeNoSelect();
1495
+ });
1496
+ useImperativeHandle(ref, () => {
1497
+ return {
1498
+ focus() {
1499
+ var _a;
1500
+ (_a = thumbRef.current) === null || _a === void 0 ? void 0 : _a.focus();
1501
+ },
1502
+ blur() {
1503
+ var _a;
1504
+ (_a = thumbRef.current) === null || _a === void 0 ? void 0 : _a.blur();
1505
+ },
1506
+ };
1507
+ }, []);
1508
+ return (
1509
+ // eslint-disable-next-line jsx-a11y/no-static-element-interactions
1510
+ jsx("div", Object.assign({ className: clsx('tremolo-xy-pad', className), ref: (div) => {
1067
1511
  wheelRefCallback(div);
1068
1512
  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) => {
1513
+ }, 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
1514
  thumbDragged.current = true;
1071
1515
  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
- }) }))] })] }));
1516
+ }, 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: {
1517
+ top: `${percentY}%`,
1518
+ left: `${percentX}%`,
1519
+ } }, thumbProps)) }, areaProps)) }) })));
1116
1520
  });
1117
1521
 
1118
- export { AnimationCanvas, BlackKey, KeyLabel, Knob, NumberInput, Piano, Shortcuts, Slider, SliderThumb, SliderTrack, WhiteKey, gradientDirection };
1522
+ 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
1523
  //# sourceMappingURL=index.js.map