@tremolo-ui/react 0.0.4 → 0.0.6

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 (73) hide show
  1. package/LICENSE +21 -0
  2. package/dist/cjs/index.js +196 -93
  3. package/dist/cjs/index.js.map +1 -1
  4. package/dist/cjs/types/components/AnimationCanvas/index.d.ts +3 -4
  5. package/dist/cjs/types/components/AnimationCanvas/index.d.ts.map +1 -1
  6. package/dist/cjs/types/components/Knob/index.d.ts +6 -7
  7. package/dist/cjs/types/components/Knob/index.d.ts.map +1 -1
  8. package/dist/cjs/types/components/NumberInput/index.d.ts +10 -7
  9. package/dist/cjs/types/components/NumberInput/index.d.ts.map +1 -1
  10. package/dist/cjs/types/components/Piano/BlackKey.d.ts +4 -0
  11. package/dist/cjs/types/components/Piano/BlackKey.d.ts.map +1 -0
  12. package/dist/cjs/types/components/Piano/KeyLabel.d.ts +20 -0
  13. package/dist/cjs/types/components/Piano/KeyLabel.d.ts.map +1 -0
  14. package/dist/cjs/types/components/Piano/WhiteKey.d.ts +4 -0
  15. package/dist/cjs/types/components/Piano/WhiteKey.d.ts.map +1 -0
  16. package/dist/cjs/types/components/Piano/index.d.ts +35 -0
  17. package/dist/cjs/types/components/Piano/index.d.ts.map +1 -0
  18. package/dist/cjs/types/components/Piano/key.d.ts +39 -0
  19. package/dist/cjs/types/components/Piano/key.d.ts.map +1 -0
  20. package/dist/cjs/types/components/Piano/keyboardShortcuts.d.ts +12 -0
  21. package/dist/cjs/types/components/Piano/keyboardShortcuts.d.ts.map +1 -0
  22. package/dist/cjs/types/components/Slider/Thumb.d.ts +17 -2
  23. package/dist/cjs/types/components/Slider/Thumb.d.ts.map +1 -1
  24. package/dist/cjs/types/components/Slider/Track.d.ts +21 -2
  25. package/dist/cjs/types/components/Slider/Track.d.ts.map +1 -1
  26. package/dist/cjs/types/components/Slider/index.d.ts +18 -10
  27. package/dist/cjs/types/components/Slider/index.d.ts.map +1 -1
  28. package/dist/cjs/types/components/_util/index.d.ts +4 -0
  29. package/dist/cjs/types/components/_util/index.d.ts.map +1 -0
  30. package/dist/esm/index.js +197 -94
  31. package/dist/esm/index.js.map +1 -1
  32. package/dist/esm/types/components/AnimationCanvas/index.d.ts +3 -4
  33. package/dist/esm/types/components/AnimationCanvas/index.d.ts.map +1 -1
  34. package/dist/esm/types/components/Knob/index.d.ts +6 -7
  35. package/dist/esm/types/components/Knob/index.d.ts.map +1 -1
  36. package/dist/esm/types/components/NumberInput/index.d.ts +10 -7
  37. package/dist/esm/types/components/NumberInput/index.d.ts.map +1 -1
  38. package/dist/esm/types/components/Piano/BlackKey.d.ts +4 -0
  39. package/dist/esm/types/components/Piano/BlackKey.d.ts.map +1 -0
  40. package/dist/esm/types/components/Piano/KeyLabel.d.ts +20 -0
  41. package/dist/esm/types/components/Piano/KeyLabel.d.ts.map +1 -0
  42. package/dist/esm/types/components/Piano/WhiteKey.d.ts +4 -0
  43. package/dist/esm/types/components/Piano/WhiteKey.d.ts.map +1 -0
  44. package/dist/esm/types/components/Piano/index.d.ts +35 -0
  45. package/dist/esm/types/components/Piano/index.d.ts.map +1 -0
  46. package/dist/esm/types/components/Piano/key.d.ts +39 -0
  47. package/dist/esm/types/components/Piano/key.d.ts.map +1 -0
  48. package/dist/esm/types/components/Piano/keyboardShortcuts.d.ts +12 -0
  49. package/dist/esm/types/components/Piano/keyboardShortcuts.d.ts.map +1 -0
  50. package/dist/esm/types/components/Slider/Thumb.d.ts +17 -2
  51. package/dist/esm/types/components/Slider/Thumb.d.ts.map +1 -1
  52. package/dist/esm/types/components/Slider/Track.d.ts +21 -2
  53. package/dist/esm/types/components/Slider/Track.d.ts.map +1 -1
  54. package/dist/esm/types/components/Slider/index.d.ts +18 -10
  55. package/dist/esm/types/components/Slider/index.d.ts.map +1 -1
  56. package/dist/esm/types/components/_util/index.d.ts +4 -0
  57. package/dist/esm/types/components/_util/index.d.ts.map +1 -0
  58. package/dist/styles/{variables.css → index.css} +4 -0
  59. package/package.json +12 -16
  60. package/src/components/AnimationCanvas/index.tsx +3 -7
  61. package/src/components/Knob/index.tsx +16 -20
  62. package/src/components/NumberInput/index.tsx +19 -12
  63. package/src/components/Piano/BlackKey.tsx +108 -0
  64. package/src/components/Piano/KeyLabel.tsx +69 -0
  65. package/src/components/Piano/WhiteKey.tsx +109 -0
  66. package/src/components/Piano/index.tsx +222 -0
  67. package/src/components/Piano/key.ts +43 -0
  68. package/src/components/Piano/keyboardShortcuts.ts +12 -0
  69. package/src/components/Slider/Thumb.tsx +56 -15
  70. package/src/components/Slider/Track.tsx +62 -3
  71. package/src/components/Slider/index.tsx +125 -89
  72. package/src/components/_util/index.ts +11 -0
  73. package/src/styles/{variables.css → index.css} +4 -0
package/dist/esm/index.js CHANGED
@@ -1,6 +1,6 @@
1
1
  import { jsxs, Fragment, jsx } from '@emotion/react/jsx-runtime';
2
2
  import { css, Global } from '@emotion/react';
3
- import React, { useRef, useEffect, useInsertionEffect, useCallback, useMemo, useState } from 'react';
3
+ import React, { useRef, useEffect, useInsertionEffect, useCallback, useMemo, useState, forwardRef, useImperativeHandle } from 'react';
4
4
 
5
5
  /******************************************************************************
6
6
  Copyright (c) Microsoft Corporation.
@@ -94,7 +94,7 @@ function AnimationCanvas(_a) {
94
94
  if (!parent)
95
95
  throw new Error("Canvas doesn't have a parent element.");
96
96
  const memoCanvas = memoCanvasRef.current;
97
- const memoContext = memoCanvas === null || memoCanvas === void 0 ? void 0 : memoCanvas.getContext('2d', options);
97
+ const memoContext = memoCanvas === null || memoCanvas === undefined ? undefined : memoCanvas.getContext('2d', options);
98
98
  const resizeObserver = new ResizeObserver(() => {
99
99
  // console.log('resize')
100
100
  // Prevents loss of some context when the canvas is resized
@@ -150,15 +150,27 @@ function AnimationCanvas(_a) {
150
150
  return (jsxs(Fragment, { children: [jsx("canvas", Object.assign({ className: clsx('tremolo-animation-canvas', className), width: relativeSize ? 0 : width, height: relativeSize ? 0 : height, css: css(style), ref: canvasRef }, props)), relativeSize && reduceFlickering && (jsx("canvas", { style: { display: 'none' }, width: relativeSize ? 0 : width, height: relativeSize ? 0 : height, ref: memoCanvasRef }))] }));
151
151
  }
152
152
 
153
+ /**
154
+ * clamp value between min and max
155
+ * @category Math
156
+ */
153
157
  function clamp(value, min, max) {
154
158
  return Math.max(min, Math.min(value, max));
155
159
  }
160
+ /**
161
+ * Normalize the value from 0 to 1
162
+ * @category Math
163
+ */
156
164
  function normalizeValue(rawValue, min, max, skew = 1) {
157
165
  if (min >= max)
158
166
  throw new RangeError('requirements: min < max');
159
167
  const v = clamp((rawValue - min) / (max - min), 0, 1);
160
168
  return Math.pow(v, skew);
161
169
  }
170
+ /**
171
+ * Convert normalized values back to raw values.
172
+ * @category Math
173
+ */
162
174
  function rawValue(normalizedValue, min, max, skew = 1) {
163
175
  if (min >= max)
164
176
  throw new RangeError('requirements: min < max');
@@ -167,22 +179,38 @@ function rawValue(normalizedValue, min, max, skew = 1) {
167
179
  : Math.exp(Math.log(clamp(normalizedValue, 0, 1)) / skew);
168
180
  return min + v * (max - min);
169
181
  }
182
+ /**
183
+ *
184
+ * @category Math
185
+ */
170
186
  function stepValue(value, step) {
171
187
  var _a;
172
188
  if (step <= 0)
173
189
  throw new RangeError('requirements: step > 0');
174
190
  const quotient = Math.floor(value / step);
175
- const decimalDigits = (_a = decimalPart$1(step)) === null || _a === void 0 ? void 0 : _a.length;
191
+ const decimalDigits = (_a = decimalPart$1(step)) === null || _a === undefined ? undefined : _a.length;
176
192
  const v = toFixed$2(quotient * step, decimalDigits);
177
193
  const next = toFixed$2((quotient + 1) * step, decimalDigits);
178
194
  return Math.abs(value - v) < Math.abs(value - next) ? v : next;
179
195
  }
196
+ /**
197
+ *
198
+ * @category Math
199
+ */
180
200
  function toFixed$2(x, fractionDigits) {
181
201
  return Number(x.toFixed(fractionDigits));
182
202
  }
203
+ /**
204
+ *
205
+ * @category Math
206
+ */
183
207
  function decimalPart$1(x) {
184
208
  return String(x).split('.')[1];
185
209
  }
210
+ /**
211
+ *
212
+ * @category Math
213
+ */
186
214
  function radian(degree) {
187
215
  return (Math.PI * degree) / 180;
188
216
  }
@@ -224,13 +252,13 @@ function useCallbackRef(callback, deps = []) {
224
252
  useInsertionEffect(() => {
225
253
  callbackRef.current = callback;
226
254
  });
227
- return useCallback((...args) => { var _a; return (_a = callbackRef.current) === null || _a === void 0 ? void 0 : _a.call(callbackRef, ...args); }, deps);
255
+ return useCallback((...args) => { var _a; return (_a = callbackRef.current) === null || _a === undefined ? undefined : _a.call(callbackRef, ...args); }, deps);
228
256
  }
229
257
 
230
258
  function useEventListener(target, event, handler, options) {
231
259
  const listener = useCallbackRef(handler);
232
260
  useEffect(() => {
233
- const node = typeof target === 'function' ? target() : (target !== null && target !== void 0 ? target : document);
261
+ const node = typeof target === 'function' ? target() : (target !== null && target !== undefined ? target : document);
234
262
  if (!handler || !node)
235
263
  return;
236
264
  node.addEventListener(event, listener, options);
@@ -239,8 +267,8 @@ function useEventListener(target, event, handler, options) {
239
267
  };
240
268
  }, [event, target, options, listener, handler]);
241
269
  return () => {
242
- const node = typeof target === 'function' ? target() : (target !== null && target !== void 0 ? target : document);
243
- node === null || node === void 0 ? void 0 : node.removeEventListener(event, listener, options);
270
+ const node = typeof target === 'function' ? target() : (target !== null && target !== undefined ? target : document);
271
+ node === null || node === undefined ? undefined : node.removeEventListener(event, listener, options);
244
272
  };
245
273
  }
246
274
 
@@ -249,7 +277,7 @@ function useRefCallbackEvent(event, handler, options, deps = []) {
249
277
  let cleanup;
250
278
  return (node) => {
251
279
  if (!node) {
252
- cleanup === null || cleanup === void 0 ? void 0 : cleanup();
280
+ cleanup === null || cleanup === undefined ? undefined : cleanup();
253
281
  return;
254
282
  }
255
283
  node.addEventListener(event, handler, options);
@@ -260,6 +288,13 @@ function useRefCallbackEvent(event, handler, options, deps = []) {
260
288
  }, deps);
261
289
  }
262
290
 
291
+ function addNoSelect() {
292
+ document.body.classList.add('tremolo-no-select');
293
+ }
294
+ function removeNoSelect() {
295
+ document.body.classList.remove('tremolo-no-select');
296
+ }
297
+
263
298
  const defaultOptions = {
264
299
  active: '#7998ec',
265
300
  inactive: '#eee',
@@ -272,14 +307,14 @@ const defaultOptions = {
272
307
  * simple rotary Knob.
273
308
  */
274
309
  function Knob(_a) {
275
- var { value, min, max, defaultValue = min, startValue = min, step = 1, skew = 1, size, width = 50, height = 50, options = defaultOptions, draw, bodyNoSelect = true, enableWheel, enableDoubleClickDefault = true, style, className, onChange, _active, _focus, _hover } = _a, props = __rest(_a, ["value", "min", "max", "defaultValue", "startValue", "step", "skew", "size", "width", "height", "options", "draw", "bodyNoSelect", "enableWheel", "enableDoubleClickDefault", "style", "className", "onChange", "_active", "_focus", "_hover"]);
310
+ var { value, min, max, defaultValue = min, startValue = min, step = 1, skew = 1, size, width = 50, height = 50, options = defaultOptions, draw, bodyNoSelect = true, wheel, enableDoubleClickDefault = true, style, className, onChange, _active, _focus, _hover } = _a, props = __rest(_a, ["value", "min", "max", "defaultValue", "startValue", "step", "skew", "size", "width", "height", "options", "draw", "bodyNoSelect", "wheel", "enableDoubleClickDefault", "style", "className", "onChange", "_active", "_focus", "_hover"]);
276
311
  // -- state and ref ---
277
312
  // const [privateValue, setPrivateValue] = useState(value);
278
313
  const dragOffsetY = useRef(undefined);
279
314
  // --- interpret props ---
280
315
  const opts = Object.assign(Object.assign({}, defaultOptions), options);
281
316
  // const percent = normalizeValue(value, min, max, skew)
282
- const isRelativeSize = typeof (size !== null && size !== void 0 ? size : width) == 'string';
317
+ const isRelativeSize = typeof (size !== null && size !== undefined ? size : width) == 'string';
283
318
  const adaptSize = (size) => {
284
319
  if (typeof size == 'string') {
285
320
  return Number(size.slice(0, -1));
@@ -294,7 +329,7 @@ function Knob(_a) {
294
329
  event.preventDefault();
295
330
  if (dragOffsetY.current) {
296
331
  if (bodyNoSelect)
297
- document.body.classList.add('no-select');
332
+ addNoSelect();
298
333
  const screenY = isTouch ? event.touches[0].screenY : event.screenY;
299
334
  const delta = dragOffsetY.current - screenY;
300
335
  dragOffsetY.current = screenY;
@@ -307,12 +342,12 @@ function Knob(_a) {
307
342
  };
308
343
  // --- hooks ---
309
344
  const wheelRefCallback = useRefCallbackEvent('wheel', (event) => {
310
- if (!enableWheel)
345
+ if (!wheel)
311
346
  return;
312
347
  event.preventDefault();
313
- const x = event.deltaY > 0 ? -enableWheel[1] : enableWheel[1];
348
+ const x = event.deltaY > 0 ? -wheel[1] : wheel[1];
314
349
  let v;
315
- if (enableWheel[0] == 'normalized') {
350
+ if (wheel[0] == 'normalized') {
316
351
  const n = normalizeValue(value, min, max, skew);
317
352
  v = rawValue(n + x, min, max, skew);
318
353
  }
@@ -321,18 +356,18 @@ function Knob(_a) {
321
356
  }
322
357
  if (onChange)
323
358
  onChange(clamp(stepValue(v, step), min, max));
324
- }, { passive: false }, [enableWheel, value, min, max, skew, step, onChange]);
359
+ }, { passive: false }, [wheel, value, min, max, skew, step, onChange]);
325
360
  const touchMoveRefCallback = useRefCallbackEvent('touchmove', handleEvent, { passive: false }, [value, min, max, skew, step, onChange, bodyNoSelect]);
326
361
  useEventListener(window, 'mousemove', handleEvent);
327
362
  useEventListener(window, 'pointerup', () => {
328
363
  dragOffsetY.current = undefined;
329
364
  if (bodyNoSelect)
330
- document.body.classList.remove('no-select');
365
+ removeNoSelect();
331
366
  });
332
367
  return (jsxs("div", Object.assign({ className: clsx('tremolo-knob', className), ref: (div) => {
333
368
  wheelRefCallback(div);
334
369
  touchMoveRefCallback(div);
335
- }, role: "slider", tabIndex: 0, "aria-valuenow": value, "aria-valuemax": max, "aria-valuemin": min, css: css(Object.assign(Object.assign({ display: 'block', width: size !== null && size !== void 0 ? size : width, height: size !== null && size !== void 0 ? size : height, cursor: 'pointer' }, style), { ':active': Object.assign({}, _active), ':focus': Object.assign({}, _focus), ':hover': Object.assign({}, _hover) })), onPointerDown: (event) => {
370
+ }, role: "slider", tabIndex: 0, "aria-valuenow": value, "aria-valuemax": max, "aria-valuemin": min, css: css(Object.assign(Object.assign({ display: 'inline-block', width: size !== null && size !== undefined ? size : width, height: size !== null && size !== undefined ? size : height, cursor: 'pointer' }, style), { ':active': Object.assign({}, _active), ':focus': Object.assign({}, _focus), ':hover': Object.assign({}, _hover) })), onPointerDown: (event) => {
336
371
  dragOffsetY.current = event.screenY;
337
372
  handleEvent(event);
338
373
  }, onDoubleClick: () => {
@@ -343,7 +378,7 @@ function Knob(_a) {
343
378
  '.no-select': {
344
379
  userSelect: 'none',
345
380
  },
346
- } }), jsx(AnimationCanvas, { width: adaptSize(size !== null && size !== void 0 ? size : width), height: adaptSize(size !== null && size !== void 0 ? size : height), relativeSize: isRelativeSize,
381
+ } }), jsx(AnimationCanvas, { width: adaptSize(size !== null && size !== undefined ? size : width), height: adaptSize(size !== null && size !== undefined ? size : height), relativeSize: isRelativeSize,
347
382
  // TODO
348
383
  // reduceFlickering={false}
349
384
  draw: draw ? draw : (ctx, width, height) => {
@@ -388,10 +423,21 @@ function Knob(_a) {
388
423
  } })] })));
389
424
  }
390
425
 
426
+ /**
427
+ * clamp value between min and max
428
+ * @category Math
429
+ */
430
+ /**
431
+ *
432
+ * @category Math
433
+ */
391
434
  function toFixed$1(x, fractionDigits) {
392
435
  return Number(x.toFixed(fractionDigits));
393
436
  }
394
437
 
438
+ /**
439
+ * @module NumberInput
440
+ */
395
441
  function selectUnit(units, value) {
396
442
  if (typeof units == 'string')
397
443
  return [units, 1];
@@ -454,14 +500,14 @@ function parseValue(inputString, units, digit, defaultValue = 0) {
454
500
  * Input with some useful functions for entering numerical values.
455
501
  */
456
502
  function NumberInput(_a) {
457
- var { value, min, max, step, defaultValue = min, units, disabled = false, placeholder, readOnly, tabIndex, strict = false, digit, selectWithFocus = 'none', blurWithEnter = true, className, style, onChange, onFocus, onBlur } = _a, pseudo = __rest(_a, ["value", "min", "max", "step", "defaultValue", "units", "disabled", "placeholder", "readOnly", "tabIndex", "strict", "digit", "selectWithFocus", "blurWithEnter", "className", "style", "onChange", "onFocus", "onBlur"]);
503
+ var { value, min, max, step, defaultValue = min, units, disabled = false, placeholder, readOnly, tabIndex, typeNumber = false, digit, selectWithFocus = 'none', blurWithEnter = true, className, style, onChange, onFocus, onBlur } = _a, props = __rest(_a, ["value", "min", "max", "step", "defaultValue", "units", "disabled", "placeholder", "readOnly", "tabIndex", "typeNumber", "digit", "selectWithFocus", "blurWithEnter", "className", "style", "onChange", "onFocus", "onBlur"]);
458
504
  const [showValue, setShowValue] = useState(parseValue(String(value), units, digit, defaultValue).formatValue);
459
- const calculatedStrict = units ? false : strict;
460
- const { _active, _focus, _hover } = pseudo;
461
- return (jsx("input", { className: clsx('tremolo-number-input', className), value: showValue, min: min, max: max, step: step, type: calculatedStrict ? 'number' : 'text', spellCheck: 'false', disabled: disabled, placeholder: placeholder, readOnly: readOnly, tabIndex: tabIndex, css: css(Object.assign(Object.assign({ display: '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) => {
505
+ const calculatedTypeNumber = units ? false : typeNumber;
506
+ const { _active, _focus, _hover } = props, rest = __rest(props, ["_active", "_focus", "_hover"]);
507
+ return (jsx("input", Object.assign({ className: clsx('tremolo-number-input', className), value: showValue, min: min, max: max, step: step, type: calculatedTypeNumber ? 'number' : 'text', spellCheck: 'false', disabled: disabled, placeholder: placeholder, readOnly: readOnly, tabIndex: tabIndex, css: css(Object.assign(Object.assign({ display: 'inline-block', font: 'inherit', margin: 0, paddingTop: 6, paddingBottom: 6, paddingLeft: 10, paddingRight: 10, borderStyle: 'solid', borderWidth: 1, borderColor: '#bbb', borderRadius: 4, outline: 0, transition: 'all 0.1s linear', appearance: 'textfield', '&:hover': Object.assign({ borderColor: 'var(--tremolo-theme-color)' }, _hover), '&:focus': Object.assign({ borderColor: 'var(--tremolo-theme-color)', boxShadow: '0px 0px 0px 2px rgba(var(--tremolo-theme-color-rgb), 0.1)' }, _focus) }, (_active && { '&:active': Object.assign({}, _active) })), style)), onChange: (event) => {
462
508
  const v = event.currentTarget.value;
463
509
  setShowValue(v);
464
- const newValue = clamp(parseValue(v, units, digit, defaultValue).rawValue, min !== null && min !== void 0 ? min : -Infinity, max !== null && max !== void 0 ? max : Infinity);
510
+ const newValue = clamp(parseValue(v, units, digit, defaultValue).rawValue, min !== null && min !== undefined ? min : -Infinity, max !== null && max !== undefined ? max : Infinity);
465
511
  if (onChange)
466
512
  onChange(newValue, event);
467
513
  }, onFocus: (event) => {
@@ -486,16 +532,31 @@ function NumberInput(_a) {
486
532
  if (blurWithEnter && event.key == 'Enter') {
487
533
  event.currentTarget.blur();
488
534
  }
489
- } }));
535
+ } }, rest)));
490
536
  }
491
537
 
538
+ /**
539
+ * clamp value between min and max
540
+ * @category Math
541
+ */
542
+ /**
543
+ *
544
+ * @category Math
545
+ */
492
546
  function toFixed(x, fractionDigits) {
493
547
  return Number(x.toFixed(fractionDigits));
494
548
  }
549
+ /**
550
+ *
551
+ * @category Math
552
+ */
495
553
  function decimalPart(x) {
496
554
  return String(x).split('.')[1];
497
555
  }
498
556
 
557
+ /**
558
+ * @module Slider
559
+ */
499
560
  function isHorizontal(d) {
500
561
  return d == 'right' || d == 'left';
501
562
  }
@@ -524,46 +585,76 @@ function parseScaleOrderList(scale, min, max, step) {
524
585
  const per = scale[0] == 'step' ? step : scale[0];
525
586
  const count = Math.floor(max / per) - Math.ceil(min / per) + 1;
526
587
  for (let i = 0; i < count; i++) {
527
- const at = toFixed(per * (Math.ceil(min / per) + i), (_a = decimalPart(per)) === null || _a === void 0 ? void 0 : _a.length);
588
+ const at = toFixed(per * (Math.ceil(min / per) + i), (_a = decimalPart(per)) === null || _a === undefined ? undefined : _a.length);
528
589
  scalesList.push({ at: at, type: scale[1] });
529
590
  }
530
591
  }
531
592
  return scalesList;
532
593
  }
533
594
 
534
- function SliderThumb({ color, children, style, __css, }) {
535
- return (jsx("div", { className: "tremolo-slider-thumb-wrapper", css: css(Object.assign({ width: 'fit-content', height: 'fit-content', position: 'absolute', translate: '-50% -50%', zIndex: 100 }, __css)), children: children ? (children) : (
595
+ const SliderThumb = forwardRef(({ size, width = 22, height = 22, color = '#4e76e6', hoverColor = color, disabledColor = '#5d6478', disabledHoverColor = disabledColor, zIndex = 100, children, className, style, __disabled, __css, }, ref) => {
596
+ const wrapperRef = useRef(null);
597
+ useImperativeHandle(ref, () => {
598
+ return {
599
+ focus() {
600
+ var _a;
601
+ (_a = wrapperRef.current) === null || _a === undefined ? undefined : _a.focus();
602
+ },
603
+ blur() {
604
+ var _a;
605
+ (_a = wrapperRef.current) === null || _a === undefined ? undefined : _a.blur();
606
+ },
607
+ };
608
+ }, []);
609
+ return (jsx("div", { className: "tremolo-slider-thumb-wrapper", css: css(Object.assign({ position: 'absolute', translate: '-50% -50%', zIndex: zIndex }, __css)), children: children ? (children) : (
536
610
  // default slider thumb
537
- jsx("div", { className: "tremolo-slider-thumb",
611
+ jsx("div", { ref: wrapperRef, className: clsx('tremolo-slider-thumb', className),
538
612
  // eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex
539
- tabIndex: 0, css: css(Object.assign({ background: color, width: '1.4rem', height: '1.4rem', borderRadius: '50%', '&:hover': {
540
- background: `color-mix(in srgb, ${color} 95%, black)`
541
- }, '&:active': {
613
+ 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': {
614
+ background: __disabled ? disabledHoverColor : hoverColor
615
+ }, '&:focus': !__disabled && {
542
616
  boxShadow: '0px 0px 0px 3px rgba(var(--tremolo-theme-color-rgb), 0.2)',
543
617
  } }, style)) })) }));
544
- }
618
+ });
545
619
 
546
- function SliderTrack({ children, style, __css, }) {
547
- return (jsx("div", { className: "tremolo-slider-track", css: css(Object.assign(Object.assign({}, __css), style)), children: children }));
620
+ 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, }) {
621
+ const active = __disabled ? disabledActiveBg : activeBg;
622
+ const inactive = __disabled ? disabledInactiveBg : inactiveBg;
623
+ const activeHover = __disabled ? disabledActiveHoverBg : activeHoverBg;
624
+ const inactiveHover = __disabled ? disabledInactiveHoverBg : inactiveHoverBg;
625
+ 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': {
626
+ background: `linear-gradient(to ${gradientDirection(__direction)}, ${activeHover} ${__percent}%, ${inactiveHover} ${__percent}%)`
627
+ } }, style)), children: [children, __thumb] }));
548
628
  }
549
629
 
550
630
  /**
551
631
  * Customizable slider
552
632
  */
553
- function Slider(_a) {
554
- var _b, _c;
555
- var { value, min, max, step = 1, skew = 1, length = 140, thickness = 10, direction = 'right', scale, scaleOption, color = '#4e76e6', bg = '#eee', className, style, bodyNoSelect = true, enableWheel, onChange, children } = _a; __rest(_a, ["value", "min", "max", "step", "skew", "length", "thickness", "direction", "scale", "scaleOption", "color", "bg", "className", "style", "bodyNoSelect", "enableWheel", "onChange", "children"]);
633
+ const Slider = forwardRef((_a, ref) => {
634
+ var _b, _c, _d, _e, _f, _g, _h;
635
+ var { value, min, max, step = 1, skew = 1, direction = 'right', scale, scaleOption, className, style, bodyNoSelect = true, wheel = ['raw', 1], keyboard = ['raw', 1], disabled = false, readonly = false, onChange, children } = _a; __rest(_a, ["value", "min", "max", "step", "skew", "direction", "scale", "scaleOption", "className", "style", "bodyNoSelect", "wheel", "keyboard", "disabled", "readonly", "onChange", "children"]);
556
636
  // -- state and ref ---
557
637
  const trackElementRef = useRef(null);
558
- const percent = normalizeValue(value, min, max, skew) * 100;
559
- const percentRev = isReversed(direction) ? 100 - percent : percent;
638
+ const thumbRef = useRef(null);
639
+ const thumbDragged = useRef(false);
640
+ const percent = toFixed$2(normalizeValue(value, min, max, skew) * 100);
641
+ const percentRev = isReversed(direction) ? toFixed$2(100 - percent) : percent;
642
+ const calcPercent = (v) => {
643
+ return toFixed$2(isReversed(direction)
644
+ ? 100 - normalizeValue(v, min, max, skew) * 100
645
+ : normalizeValue(v, min, max, skew) * 100);
646
+ };
647
+ if (wheel.length != 2) {
648
+ throw new Error(`Slider.wheel expect ['normalized' | 'raw', number]`);
649
+ }
650
+ if (keyboard.length != 2) {
651
+ throw new Error(`Slider.keyboard expect ['normalized' | 'raw', number]`);
652
+ }
560
653
  const scalesList = parseScaleOrderList(scale, min, max, step);
561
654
  if (isReversed(direction))
562
655
  scalesList.reverse();
563
656
  // eslint-disable-next-line @typescript-eslint/no-explicit-any
564
- let trackProps;
565
- // eslint-disable-next-line @typescript-eslint/no-explicit-any
566
- let thumbProps;
657
+ let trackProps, thumbProps;
567
658
  if (children != undefined) {
568
659
  React.Children.forEach(children, (child) => {
569
660
  if (React.isValidElement(child)) {
@@ -582,15 +673,15 @@ function Slider(_a) {
582
673
  }
583
674
  });
584
675
  }
585
- const thumbDragged = useRef(false);
676
+ // --- internal functions ---
586
677
  const handleValue = (event) => {
587
- if (!trackElementRef.current || !thumbDragged.current)
678
+ if (!trackElementRef.current || !thumbDragged.current || !onChange || readonly)
588
679
  return;
589
680
  const isTouch = event instanceof TouchEvent;
590
681
  if (isTouch && event.cancelable)
591
682
  event.preventDefault();
592
683
  if (bodyNoSelect)
593
- document.body.classList.add('no-select');
684
+ addNoSelect();
594
685
  const { left: x1, top: y1, right: x2, bottom: y2, } = trackElementRef.current.getBoundingClientRect();
595
686
  const mouseX = isTouch ? event.touches[0].clientX : event.clientX;
596
687
  const mouseY = isTouch ? event.touches[0].clientY : event.clientY;
@@ -598,70 +689,90 @@ function Slider(_a) {
598
689
  ? normalizeValue(mouseX, x1, x2)
599
690
  : normalizeValue(mouseY, y1, y2);
600
691
  const v = rawValue(isReversed(direction) ? 1 - n : n, min, max, skew);
601
- const v2 = clamp(stepValue(v, step), min, max);
602
- if (onChange)
603
- onChange(v2);
692
+ onChange(clamp(stepValue(v, step), min, max));
604
693
  };
694
+ const handleKeyDown = useCallback((event) => {
695
+ if (!keyboard || !onChange || readonly)
696
+ return;
697
+ const key = event.key;
698
+ if (['ArrowRight', 'ArrowLeft', 'ArrowUp', 'ArrowDown'].includes(key)) {
699
+ event.preventDefault();
700
+ let x = (key == 'ArrowRight' || key == 'ArrowUp') ? keyboard[1] : -keyboard[1];
701
+ if (direction == 'down' || direction == 'left')
702
+ x *= -1;
703
+ let v;
704
+ if (keyboard[0] == 'normalized') {
705
+ const n = normalizeValue(value, min, max, skew);
706
+ v = rawValue(n + x, min, max, skew);
707
+ }
708
+ else {
709
+ v = value + x;
710
+ }
711
+ onChange(clamp(stepValue(v, step), min, max));
712
+ }
713
+ }, [value, min, max, step, skew, direction, keyboard, onChange, readonly]);
605
714
  // --- hooks ---
606
- const touchMoveRefCallback = useRefCallbackEvent('touchmove', handleValue, { passive: false }, [min, max, skew, step, direction, onChange]);
715
+ const touchMoveRefCallback = useRefCallbackEvent('touchmove', handleValue, { passive: false }, [min, max, skew, step, direction, onChange, readonly]);
607
716
  const wheelRefCallback = useRefCallbackEvent('wheel', (event) => {
608
- if (!enableWheel)
717
+ if (!wheel || !onChange || readonly)
609
718
  return;
610
719
  event.preventDefault();
611
- let x = event.deltaY > 0 ? enableWheel[1] : -enableWheel[1];
720
+ let x = event.deltaY > 0 ? wheel[1] : -wheel[1];
612
721
  if (isReversed(direction) || isHorizontal(direction))
613
722
  x *= -1;
614
723
  let v;
615
- if (enableWheel[0] == 'normalized') {
724
+ if (wheel[0] == 'normalized') {
616
725
  const n = normalizeValue(value, min, max, skew);
617
726
  v = rawValue(n + x, min, max, skew);
618
727
  }
619
728
  else {
620
729
  v = value + x;
621
730
  }
622
- if (onChange)
623
- onChange(clamp(stepValue(v, step), min, max));
731
+ onChange(clamp(stepValue(v, step), min, max));
624
732
  }, {
625
733
  passive: false,
626
- }, [enableWheel, value, min, max, skew, step]);
734
+ }, [wheel, value, min, max, skew, step]);
627
735
  useEventListener(window, 'mousemove', (event) => {
628
736
  handleValue(event);
629
737
  });
630
738
  useEventListener(window, 'mouseup', () => {
631
739
  thumbDragged.current = false;
632
740
  if (bodyNoSelect)
633
- document.body.classList.remove('no-select');
741
+ removeNoSelect();
634
742
  });
743
+ useImperativeHandle(ref, () => {
744
+ return {
745
+ focus() {
746
+ var _a;
747
+ (_a = thumbRef.current) === null || _a === undefined ? undefined : _a.focus();
748
+ },
749
+ blur() {
750
+ var _a;
751
+ (_a = thumbRef.current) === null || _a === undefined ? undefined : _a.blur();
752
+ },
753
+ };
754
+ }, []);
635
755
  return (jsxs("div", { className: clsx('tremolo-slider', className), ref: (div) => {
636
756
  wheelRefCallback(div);
637
757
  touchMoveRefCallback(div);
638
- }, tabIndex: -1, role: "slider", "aria-valuenow": value, "aria-valuemax": max, "aria-valuemin": min, "aria-orientation": isHorizontal(direction) ? 'horizontal' : 'vertical', css: css(Object.assign({ display: 'inline-block', boxSizing: 'border-box', margin: '0.7rem', padding: 0, cursor: 'pointer' }, style)), onPointerDown: (event) => {
758
+ }, tabIndex: -1, role: "slider", "aria-valuenow": value, "aria-valuemin": min, "aria-valuemax": max, "aria-orientation": isHorizontal(direction) ? 'horizontal' : 'vertical', "aria-disabled": disabled, "aria-readonly": readonly, css: css(Object.assign({ display: 'inline-block', margin: `calc(${styleHelper((_b = thumbProps === null || thumbProps === undefined ? undefined : thumbProps.size) !== null && _b !== undefined ? _b : 22)} / 2)`, cursor: readonly ? 'not-allowed' : 'pointer', outline: 0 }, style)), onPointerDown: (event) => {
639
759
  thumbDragged.current = true;
640
760
  handleValue(event);
641
- }, children: [jsx(Global, { styles: {
761
+ }, onKeyDown: handleKeyDown, onFocus: (_c = thumbRef.current) === null || _c === undefined ? undefined : _c.focus, onBlur: (_d = thumbRef.current) === null || _d === undefined ? undefined : _d.blur, children: [jsx(Global, { styles: {
642
762
  '.no-select': {
643
763
  userSelect: 'none',
644
764
  },
645
765
  } }), jsxs("div", { css: css({
646
766
  display: 'flex',
647
767
  flexDirection: isHorizontal(direction) ? 'column' : 'row',
648
- }), children: [jsxs("div", { className: "tremolo-slider-track-wrapper", ref: trackElementRef, css: css({ position: 'relative' }), children: [jsx(SliderTrack, Object.assign({ __css: {
649
- background: `linear-gradient(to ${gradientDirection(direction)}, ${color} ${percent}%, ${bg} ${percent}%)`,
650
- borderRadius: styleHelper(thickness, '/', 2),
651
- borderStyle: 'solid',
652
- borderColor: '#ccc',
653
- borderWidth: 2,
654
- width: isHorizontal(direction) ? length : thickness,
655
- height: isHorizontal(direction) ? thickness : length,
656
- zIndex: 1,
657
- } }, trackProps)), jsx(SliderThumb, Object.assign({ color: color, __css: {
768
+ }), children: [jsx("div", { className: "tremolo-slider-track-wrapper", ref: trackElementRef, children: jsx(SliderTrack, Object.assign({ __direction: direction, __disabled: disabled, __percent: percent, __thumb: jsx(SliderThumb, Object.assign({ ref: thumbRef, __disabled: disabled, __css: {
658
769
  top: isHorizontal(direction) ? '50%' : `${percentRev}%`,
659
770
  left: isHorizontal(direction) ? `${percentRev}%` : '50%',
660
- } }, thumbProps))] }), scale && (jsx("div", { className: "tremolo-slider-scale-wrapper", css: css(Object.assign({ position: 'relative', width: isHorizontal(direction) ? length : undefined, height: isVertical(direction) ? length : undefined, marginLeft: isHorizontal(direction)
661
- ? 2
662
- : ((_b = scaleOption === null || scaleOption === void 0 ? void 0 : scaleOption.gap) !== null && _b !== void 0 ? _b : `calc((1.4rem - ${styleHelper(thickness)}) / 2)`), marginTop: isVertical(direction)
663
- ? 2
664
- : ((_c = scaleOption === null || scaleOption === void 0 ? void 0 : scaleOption.gap) !== null && _c !== void 0 ? _c : `calc((1.4rem - ${styleHelper(thickness)}) / 2)`) }, scaleOption === null || scaleOption === void 0 ? void 0 : scaleOption.style)), children: scalesList.map((item, index) => {
771
+ } }, thumbProps)) }, trackProps)) }), scale && (jsx("div", { className: "tremolo-slider-scale-wrapper", css: css(Object.assign({ display: 'block', position: 'relative', marginLeft: isVertical(direction)
772
+ ? ((_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)`)
773
+ : undefined, marginTop: isHorizontal(direction)
774
+ ? ((_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)`)
775
+ : undefined }, scaleOption === null || scaleOption === undefined ? undefined : scaleOption.style)), children: scalesList.map((item, index) => {
665
776
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
666
777
  return (jsxs("div", { css: css({
667
778
  display: 'flex',
@@ -669,37 +780,29 @@ function Slider(_a) {
669
780
  justifyContent: 'center',
670
781
  alignItems: 'center',
671
782
  position: 'absolute',
672
- left: isHorizontal(direction)
673
- ? `${isReversed(direction)
674
- ? 100 - normalizeValue(item.at, min, max, skew) * 100
675
- : normalizeValue(item.at, min, max, skew) * 100}%`
676
- : undefined,
677
- top: isVertical(direction)
678
- ? `${isReversed(direction)
679
- ? 100 - normalizeValue(item.at, min, max, skew) * 100
680
- : normalizeValue(item.at, min, max, skew) * 100}%`
681
- : undefined,
783
+ left: isHorizontal(direction) ? `${calcPercent(item.at)}%` : undefined,
784
+ top: isVertical(direction) ? `${calcPercent(item.at)}%` : undefined,
682
785
  translate: isHorizontal(direction) ? '-50% 0' : '0 -50%',
683
786
  zIndex: 10,
684
- }), children: [((_b = (_a = item.type) !== null && _a !== void 0 ? _a : scaleOption === null || scaleOption === void 0 ? void 0 : scaleOption.defaultType) !== null && _b !== void 0 ? _b : 'mark-number') !=
787
+ }), children: [((_b = (_a = item.type) !== null && _a !== undefined ? _a : scaleOption === null || scaleOption === undefined ? undefined : scaleOption.defaultType) !== null && _b !== undefined ? _b : 'mark-number') !=
685
788
  'number' && (jsx("div", { className: "tremolo-slider-scale-mark", css: css({
686
789
  width: isHorizontal(direction)
687
- ? ((_d = (_c = item.style) === null || _c === void 0 ? void 0 : _c.thickness) !== null && _d !== void 0 ? _d : 1)
688
- : ((_f = (_e = item.style) === null || _e === void 0 ? void 0 : _e.length) !== null && _f !== void 0 ? _f : '0.5rem'),
790
+ ? ((_d = (_c = item.style) === null || _c === undefined ? undefined : _c.thickness) !== null && _d !== undefined ? _d : 1)
791
+ : ((_f = (_e = item.style) === null || _e === undefined ? undefined : _e.length) !== null && _f !== undefined ? _f : '0.5rem'),
689
792
  height: isVertical(direction)
690
- ? ((_h = (_g = item.style) === null || _g === void 0 ? void 0 : _g.thickness) !== null && _h !== void 0 ? _h : 1)
691
- : ((_k = (_j = item.style) === null || _j === void 0 ? void 0 : _j.length) !== null && _k !== void 0 ? _k : '0.5rem'),
692
- backgroundColor: (_o = (_m = (_l = item.style) === null || _l === void 0 ? void 0 : _l.markColor) !== null && _m !== void 0 ? _m : scaleOption === null || scaleOption === void 0 ? void 0 : scaleOption.markColor) !== null && _o !== void 0 ? _o : '#222',
793
+ ? ((_h = (_g = item.style) === null || _g === undefined ? undefined : _g.thickness) !== null && _h !== undefined ? _h : 1)
794
+ : ((_k = (_j = item.style) === null || _j === undefined ? undefined : _j.length) !== null && _k !== undefined ? _k : '0.5rem'),
795
+ backgroundColor: (_o = (_m = (_l = item.style) === null || _l === undefined ? undefined : _l.markColor) !== null && _m !== undefined ? _m : scaleOption === null || scaleOption === undefined ? undefined : scaleOption.markColor) !== null && _o !== undefined ? _o : '#222',
693
796
  marginBottom: isHorizontal(direction) ? 2 : undefined,
694
797
  marginRight: isVertical(direction) ? 2 : undefined,
695
- }) })), ((_q = (_p = item.type) !== null && _p !== void 0 ? _p : scaleOption === null || scaleOption === void 0 ? void 0 : scaleOption.defaultType) !== null && _q !== void 0 ? _q : 'mark-number') !=
798
+ }) })), ((_q = (_p = item.type) !== null && _p !== undefined ? _p : scaleOption === null || scaleOption === undefined ? undefined : scaleOption.defaultType) !== null && _q !== undefined ? _q : 'mark-number') !=
696
799
  'mark' && (jsx("div", { className: "tremolo-slider-scale-number", css: css({
697
- color: (_s = (_r = item.style) === null || _r === void 0 ? void 0 : _r.labelColor) !== null && _s !== void 0 ? _s : scaleOption === null || scaleOption === void 0 ? void 0 : scaleOption.labelColor,
698
- width: scaleOption === null || scaleOption === void 0 ? void 0 : scaleOption.labelWidth,
800
+ color: (_s = (_r = item.style) === null || _r === undefined ? undefined : _r.labelColor) !== null && _s !== undefined ? _s : scaleOption === null || scaleOption === undefined ? undefined : scaleOption.labelColor,
801
+ width: scaleOption === null || scaleOption === undefined ? undefined : scaleOption.labelWidth,
699
802
  textAlign: 'right',
700
- }), children: (_t = item.text) !== null && _t !== void 0 ? _t : item.at }))] }, index));
803
+ }), children: (_t = item.text) !== null && _t !== undefined ? _t : item.at }))] }, index));
701
804
  }) }))] })] }));
702
- }
805
+ });
703
806
 
704
807
  export { AnimationCanvas, Knob, NumberInput, Slider, SliderThumb, SliderTrack, gradientDirection };
705
808
  //# sourceMappingURL=index.js.map