@tremolo-ui/react 0.1.1 → 0.1.3

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 (163) hide show
  1. package/dist/index.cjs +2082 -0
  2. package/dist/index.cjs.map +1 -0
  3. package/dist/{styles/index.css → index.css} +3 -0
  4. package/dist/index.css.map +1 -0
  5. package/dist/index.d.cts +827 -0
  6. package/dist/index.d.cts.map +1 -0
  7. package/dist/index.d.ts +827 -0
  8. package/dist/index.d.ts.map +1 -0
  9. package/dist/index.js +2030 -0
  10. package/dist/index.js.map +1 -0
  11. package/package.json +14 -14
  12. package/src/hooks/useAnimationFrame.ts +2 -2
  13. package/src/hooks/useDrag.ts +2 -2
  14. package/src/hooks/useDragWithElement.ts +2 -2
  15. package/src/index.ts +79 -15
  16. package/dist/cjs/index.js +0 -2041
  17. package/dist/cjs/index.js.map +0 -1
  18. package/dist/cjs/types/components/AnimationCanvas/canvas.d.ts +0 -6
  19. package/dist/cjs/types/components/AnimationCanvas/canvas.d.ts.map +0 -1
  20. package/dist/cjs/types/components/AnimationCanvas/index.d.ts +0 -51
  21. package/dist/cjs/types/components/AnimationCanvas/index.d.ts.map +0 -1
  22. package/dist/cjs/types/components/AnimationKnob/index.d.ts +0 -62
  23. package/dist/cjs/types/components/AnimationKnob/index.d.ts.map +0 -1
  24. package/dist/cjs/types/components/DragObserver/index.d.ts +0 -21
  25. package/dist/cjs/types/components/DragObserver/index.d.ts.map +0 -1
  26. package/dist/cjs/types/components/Knob/index.d.ts +0 -71
  27. package/dist/cjs/types/components/Knob/index.d.ts.map +0 -1
  28. package/dist/cjs/types/components/NumberInput/DecrementStepper.d.ts +0 -9
  29. package/dist/cjs/types/components/NumberInput/DecrementStepper.d.ts.map +0 -1
  30. package/dist/cjs/types/components/NumberInput/IncrementStepper.d.ts +0 -9
  31. package/dist/cjs/types/components/NumberInput/IncrementStepper.d.ts.map +0 -1
  32. package/dist/cjs/types/components/NumberInput/InternalInput.d.ts +0 -18
  33. package/dist/cjs/types/components/NumberInput/InternalInput.d.ts.map +0 -1
  34. package/dist/cjs/types/components/NumberInput/Stepper.d.ts +0 -10
  35. package/dist/cjs/types/components/NumberInput/Stepper.d.ts.map +0 -1
  36. package/dist/cjs/types/components/NumberInput/context.d.ts +0 -28
  37. package/dist/cjs/types/components/NumberInput/context.d.ts.map +0 -1
  38. package/dist/cjs/types/components/NumberInput/index.d.ts +0 -69
  39. package/dist/cjs/types/components/NumberInput/index.d.ts.map +0 -1
  40. package/dist/cjs/types/components/Piano/KeyLabel.d.ts +0 -17
  41. package/dist/cjs/types/components/Piano/KeyLabel.d.ts.map +0 -1
  42. package/dist/cjs/types/components/Piano/context.d.ts +0 -24
  43. package/dist/cjs/types/components/Piano/context.d.ts.map +0 -1
  44. package/dist/cjs/types/components/Piano/index.d.ts +0 -39
  45. package/dist/cjs/types/components/Piano/index.d.ts.map +0 -1
  46. package/dist/cjs/types/components/Piano/key.d.ts +0 -37
  47. package/dist/cjs/types/components/Piano/key.d.ts.map +0 -1
  48. package/dist/cjs/types/components/Piano/keyboardShortcuts.d.ts +0 -14
  49. package/dist/cjs/types/components/Piano/keyboardShortcuts.d.ts.map +0 -1
  50. package/dist/cjs/types/components/Slider/Scale.d.ts +0 -11
  51. package/dist/cjs/types/components/Slider/Scale.d.ts.map +0 -1
  52. package/dist/cjs/types/components/Slider/ScaleOption.d.ts +0 -27
  53. package/dist/cjs/types/components/Slider/ScaleOption.d.ts.map +0 -1
  54. package/dist/cjs/types/components/Slider/Thumb.d.ts +0 -23
  55. package/dist/cjs/types/components/Slider/Thumb.d.ts.map +0 -1
  56. package/dist/cjs/types/components/Slider/Track.d.ts +0 -21
  57. package/dist/cjs/types/components/Slider/Track.d.ts.map +0 -1
  58. package/dist/cjs/types/components/Slider/context.d.ts +0 -16
  59. package/dist/cjs/types/components/Slider/context.d.ts.map +0 -1
  60. package/dist/cjs/types/components/Slider/index.d.ts +0 -55
  61. package/dist/cjs/types/components/Slider/index.d.ts.map +0 -1
  62. package/dist/cjs/types/components/WheelObserver/index.d.ts +0 -25
  63. package/dist/cjs/types/components/WheelObserver/index.d.ts.map +0 -1
  64. package/dist/cjs/types/components/XYPad/Area.d.ts +0 -15
  65. package/dist/cjs/types/components/XYPad/Area.d.ts.map +0 -1
  66. package/dist/cjs/types/components/XYPad/Thumb.d.ts +0 -23
  67. package/dist/cjs/types/components/XYPad/Thumb.d.ts.map +0 -1
  68. package/dist/cjs/types/components/XYPad/index.d.ts +0 -48
  69. package/dist/cjs/types/components/XYPad/index.d.ts.map +0 -1
  70. package/dist/cjs/types/components/_util/index.d.ts +0 -4
  71. package/dist/cjs/types/components/_util/index.d.ts.map +0 -1
  72. package/dist/cjs/types/hooks/useAnimationFrame.d.ts +0 -3
  73. package/dist/cjs/types/hooks/useAnimationFrame.d.ts.map +0 -1
  74. package/dist/cjs/types/hooks/useCallbackRef.d.ts +0 -6
  75. package/dist/cjs/types/hooks/useCallbackRef.d.ts.map +0 -1
  76. package/dist/cjs/types/hooks/useDrag.d.ts +0 -15
  77. package/dist/cjs/types/hooks/useDrag.d.ts.map +0 -1
  78. package/dist/cjs/types/hooks/useDragWithElement.d.ts +0 -16
  79. package/dist/cjs/types/hooks/useDragWithElement.d.ts.map +0 -1
  80. package/dist/cjs/types/hooks/useEventListener.d.ts +0 -7
  81. package/dist/cjs/types/hooks/useEventListener.d.ts.map +0 -1
  82. package/dist/cjs/types/hooks/useInterval.d.ts +0 -2
  83. package/dist/cjs/types/hooks/useInterval.d.ts.map +0 -1
  84. package/dist/cjs/types/hooks/useLongPress.d.ts +0 -2
  85. package/dist/cjs/types/hooks/useLongPress.d.ts.map +0 -1
  86. package/dist/cjs/types/hooks/useRefCallbackEvent.d.ts +0 -2
  87. package/dist/cjs/types/hooks/useRefCallbackEvent.d.ts.map +0 -1
  88. package/dist/cjs/types/index.d.ts +0 -22
  89. package/dist/cjs/types/index.d.ts.map +0 -1
  90. package/dist/esm/index.js +0 -2010
  91. package/dist/esm/index.js.map +0 -1
  92. package/dist/esm/types/components/AnimationCanvas/canvas.d.ts +0 -6
  93. package/dist/esm/types/components/AnimationCanvas/canvas.d.ts.map +0 -1
  94. package/dist/esm/types/components/AnimationCanvas/index.d.ts +0 -51
  95. package/dist/esm/types/components/AnimationCanvas/index.d.ts.map +0 -1
  96. package/dist/esm/types/components/AnimationKnob/index.d.ts +0 -62
  97. package/dist/esm/types/components/AnimationKnob/index.d.ts.map +0 -1
  98. package/dist/esm/types/components/DragObserver/index.d.ts +0 -21
  99. package/dist/esm/types/components/DragObserver/index.d.ts.map +0 -1
  100. package/dist/esm/types/components/Knob/index.d.ts +0 -71
  101. package/dist/esm/types/components/Knob/index.d.ts.map +0 -1
  102. package/dist/esm/types/components/NumberInput/DecrementStepper.d.ts +0 -9
  103. package/dist/esm/types/components/NumberInput/DecrementStepper.d.ts.map +0 -1
  104. package/dist/esm/types/components/NumberInput/IncrementStepper.d.ts +0 -9
  105. package/dist/esm/types/components/NumberInput/IncrementStepper.d.ts.map +0 -1
  106. package/dist/esm/types/components/NumberInput/InternalInput.d.ts +0 -18
  107. package/dist/esm/types/components/NumberInput/InternalInput.d.ts.map +0 -1
  108. package/dist/esm/types/components/NumberInput/Stepper.d.ts +0 -10
  109. package/dist/esm/types/components/NumberInput/Stepper.d.ts.map +0 -1
  110. package/dist/esm/types/components/NumberInput/context.d.ts +0 -28
  111. package/dist/esm/types/components/NumberInput/context.d.ts.map +0 -1
  112. package/dist/esm/types/components/NumberInput/index.d.ts +0 -69
  113. package/dist/esm/types/components/NumberInput/index.d.ts.map +0 -1
  114. package/dist/esm/types/components/Piano/KeyLabel.d.ts +0 -17
  115. package/dist/esm/types/components/Piano/KeyLabel.d.ts.map +0 -1
  116. package/dist/esm/types/components/Piano/context.d.ts +0 -24
  117. package/dist/esm/types/components/Piano/context.d.ts.map +0 -1
  118. package/dist/esm/types/components/Piano/index.d.ts +0 -39
  119. package/dist/esm/types/components/Piano/index.d.ts.map +0 -1
  120. package/dist/esm/types/components/Piano/key.d.ts +0 -37
  121. package/dist/esm/types/components/Piano/key.d.ts.map +0 -1
  122. package/dist/esm/types/components/Piano/keyboardShortcuts.d.ts +0 -14
  123. package/dist/esm/types/components/Piano/keyboardShortcuts.d.ts.map +0 -1
  124. package/dist/esm/types/components/Slider/Scale.d.ts +0 -11
  125. package/dist/esm/types/components/Slider/Scale.d.ts.map +0 -1
  126. package/dist/esm/types/components/Slider/ScaleOption.d.ts +0 -27
  127. package/dist/esm/types/components/Slider/ScaleOption.d.ts.map +0 -1
  128. package/dist/esm/types/components/Slider/Thumb.d.ts +0 -23
  129. package/dist/esm/types/components/Slider/Thumb.d.ts.map +0 -1
  130. package/dist/esm/types/components/Slider/Track.d.ts +0 -21
  131. package/dist/esm/types/components/Slider/Track.d.ts.map +0 -1
  132. package/dist/esm/types/components/Slider/context.d.ts +0 -16
  133. package/dist/esm/types/components/Slider/context.d.ts.map +0 -1
  134. package/dist/esm/types/components/Slider/index.d.ts +0 -55
  135. package/dist/esm/types/components/Slider/index.d.ts.map +0 -1
  136. package/dist/esm/types/components/WheelObserver/index.d.ts +0 -25
  137. package/dist/esm/types/components/WheelObserver/index.d.ts.map +0 -1
  138. package/dist/esm/types/components/XYPad/Area.d.ts +0 -15
  139. package/dist/esm/types/components/XYPad/Area.d.ts.map +0 -1
  140. package/dist/esm/types/components/XYPad/Thumb.d.ts +0 -23
  141. package/dist/esm/types/components/XYPad/Thumb.d.ts.map +0 -1
  142. package/dist/esm/types/components/XYPad/index.d.ts +0 -48
  143. package/dist/esm/types/components/XYPad/index.d.ts.map +0 -1
  144. package/dist/esm/types/components/_util/index.d.ts +0 -4
  145. package/dist/esm/types/components/_util/index.d.ts.map +0 -1
  146. package/dist/esm/types/hooks/useAnimationFrame.d.ts +0 -3
  147. package/dist/esm/types/hooks/useAnimationFrame.d.ts.map +0 -1
  148. package/dist/esm/types/hooks/useCallbackRef.d.ts +0 -6
  149. package/dist/esm/types/hooks/useCallbackRef.d.ts.map +0 -1
  150. package/dist/esm/types/hooks/useDrag.d.ts +0 -15
  151. package/dist/esm/types/hooks/useDrag.d.ts.map +0 -1
  152. package/dist/esm/types/hooks/useDragWithElement.d.ts +0 -16
  153. package/dist/esm/types/hooks/useDragWithElement.d.ts.map +0 -1
  154. package/dist/esm/types/hooks/useEventListener.d.ts +0 -7
  155. package/dist/esm/types/hooks/useEventListener.d.ts.map +0 -1
  156. package/dist/esm/types/hooks/useInterval.d.ts +0 -2
  157. package/dist/esm/types/hooks/useInterval.d.ts.map +0 -1
  158. package/dist/esm/types/hooks/useLongPress.d.ts +0 -2
  159. package/dist/esm/types/hooks/useLongPress.d.ts.map +0 -1
  160. package/dist/esm/types/hooks/useRefCallbackEvent.d.ts +0 -2
  161. package/dist/esm/types/hooks/useRefCallbackEvent.d.ts.map +0 -1
  162. package/dist/esm/types/index.d.ts +0 -22
  163. package/dist/esm/types/index.d.ts.map +0 -1
package/dist/cjs/index.js DELETED
@@ -1,2041 +0,0 @@
1
- 'use strict';
2
-
3
- var jsxRuntime = require('react/jsx-runtime');
4
- var React = require('react');
5
-
6
- /******************************************************************************
7
- Copyright (c) Microsoft Corporation.
8
-
9
- Permission to use, copy, modify, and/or distribute this software for any
10
- purpose with or without fee is hereby granted.
11
-
12
- THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
13
- REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
14
- AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
15
- INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
16
- LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
17
- OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
18
- PERFORMANCE OF THIS SOFTWARE.
19
- ***************************************************************************** */
20
- /* global Reflect, Promise, SuppressedError, Symbol, Iterator */
21
-
22
-
23
- function __rest(s, e) {
24
- var t = {};
25
- for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
26
- t[p] = s[p];
27
- if (s != null && typeof Object.getOwnPropertySymbols === "function")
28
- for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
29
- if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
30
- t[p[i]] = s[p[i]];
31
- }
32
- return t;
33
- }
34
-
35
- typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
36
- var e = new Error(message);
37
- return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
38
- };
39
-
40
- function r(e){var t,f,n="";if("string"==typeof e||"number"==typeof e)n+=e;else if("object"==typeof e)if(Array.isArray(e)){var o=e.length;for(t=0;t<o;t++)e[t]&&(f=r(e[t]))&&(n&&(n+=" "),n+=f);}else for(f in e)e[f]&&(n&&(n+=" "),n+=f);return n}function clsx(){for(var e,t,f=0,n="",o=arguments.length;f<o;f++)(e=arguments[f])&&(t=r(e))&&(n&&(n+=" "),n+=t);return n}
41
-
42
- // https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/save
43
- const drawingState = [
44
- 'strokeStyle',
45
- 'fillStyle',
46
- 'globalAlpha',
47
- 'lineWidth',
48
- 'lineCap',
49
- 'lineJoin',
50
- 'miterLimit',
51
- 'lineDashOffset',
52
- 'shadowOffsetX',
53
- 'shadowOffsetY',
54
- 'shadowBlur',
55
- 'shadowColor',
56
- 'globalCompositeOperation',
57
- 'font',
58
- 'textAlign',
59
- 'textBaseline',
60
- 'direction',
61
- 'imageSmoothingEnabled',
62
- ];
63
-
64
- /*
65
- TODO
66
- AbsoluteSizingProps, RelativeSizingPropsの型付けを強くする
67
- AbsoluteSizingPropsの場合、width, heightは必須
68
- RelativeSizingPropsのの場合、relativeSizeは必須、reduceFlickeringはオプショナル
69
- */
70
- function setDprConfig(canvas, context, width, height, dpr) {
71
- canvas.width = width * dpr;
72
- canvas.height = height * dpr;
73
- // Reset current transformation matrix to the identity matrix
74
- context.setTransform(1, 0, 0, 1, 0, 0);
75
- context.scale(dpr, dpr);
76
- canvas.style.width = `${width}px`;
77
- canvas.style.height = `${height}px`;
78
- }
79
- function AnimationCanvas(_a) {
80
- var {
81
- // common
82
- options, init, draw,
83
- // absolute
84
- width = 100, height = 100,
85
- // relative
86
- relativeSize, reduceFlickering = true,
87
- // canvas props
88
- className, onContextMenu = (event) => event.preventDefault() } = _a, props = __rest(_a, ["options", "init", "draw", "width", "height", "relativeSize", "reduceFlickering", "className", "onContextMenu"]);
89
- const canvasRef = React.useRef(null);
90
- const memoCanvasRef = React.useRef(null);
91
- const reqIdRef = React.useRef(-1);
92
- const widthRef = React.useRef(0);
93
- const heightRef = React.useRef(0);
94
- const deltaMemoRef = React.useRef(-1);
95
- const startTimeRef = React.useRef(-1);
96
- const loop = React.useCallback((context, width, height, count) => {
97
- const now = performance.now();
98
- const deltaTime = now - deltaMemoRef.current;
99
- const elapsedTime = now - startTimeRef.current;
100
- deltaMemoRef.current = now;
101
- reqIdRef.current = requestAnimationFrame(() => loop(context, width, height, count + 1));
102
- draw(context, {
103
- width: width.current,
104
- height: height.current,
105
- count: count + 1,
106
- deltaTime,
107
- elapsedTime,
108
- fps: 1000 / deltaTime,
109
- });
110
- }, [draw]);
111
- React.useEffect(() => {
112
- if (!canvasRef.current)
113
- return;
114
- const canvas = canvasRef.current;
115
- const context = canvas.getContext('2d', options);
116
- if (!context)
117
- throw new Error('Cannot get canvas context.');
118
- const dpr = globalThis.devicePixelRatio;
119
- if (relativeSize) {
120
- const parent = canvas.parentElement;
121
- if (!parent)
122
- throw new Error("Canvas doesn't have a parent element.");
123
- const memoCanvas = memoCanvasRef.current;
124
- const memoContext = memoCanvas === null || memoCanvas === void 0 ? void 0 : memoCanvas.getContext('2d', options);
125
- const ro = new ResizeObserver((entries) => {
126
- for (const entry of entries) {
127
- // Prevents loss of some context when the canvas is resized
128
- const contextMemo = {};
129
- for (const prop of drawingState) {
130
- contextMemo[prop] = context[prop];
131
- }
132
- const w = entry.contentRect.width;
133
- const h = entry.contentRect.height;
134
- if (reduceFlickering && memoCanvas && memoContext) {
135
- memoCanvas.width = w * dpr;
136
- memoCanvas.height = h * dpr;
137
- memoContext.scale(1 / dpr, 1 / dpr);
138
- if (canvas.width > 0 && canvas.height > 0) {
139
- memoContext.drawImage(canvas, 0, 0);
140
- }
141
- }
142
- setDprConfig(canvas, context, w, h, dpr);
143
- widthRef.current = w;
144
- heightRef.current = h;
145
- for (const prop of drawingState) {
146
- context[prop] = contextMemo[prop];
147
- }
148
- if (reduceFlickering &&
149
- memoContext &&
150
- memoCanvas &&
151
- memoCanvas.width > 0 &&
152
- memoCanvas.height > 0) {
153
- context.drawImage(memoContext.canvas, 0, 0);
154
- }
155
- }
156
- });
157
- ro.observe(parent);
158
- const w = parent.clientWidth;
159
- const h = parent.clientHeight;
160
- setDprConfig(canvas, context, w, h, dpr);
161
- if (init)
162
- init(context, { width: widthRef.current, height: heightRef.current });
163
- const now = performance.now();
164
- deltaMemoRef.current = now;
165
- startTimeRef.current = now;
166
- loop(context, widthRef, heightRef, -1);
167
- return () => {
168
- if (reqIdRef.current)
169
- cancelAnimationFrame(reqIdRef.current);
170
- ro.disconnect();
171
- };
172
- }
173
- else {
174
- const rect = canvas.getBoundingClientRect();
175
- setDprConfig(canvas, context, rect.width, rect.height, dpr);
176
- widthRef.current = rect.width;
177
- heightRef.current = rect.height;
178
- if (init)
179
- init(context, { width: widthRef.current, height: heightRef.current });
180
- const now = performance.now();
181
- deltaMemoRef.current = now;
182
- startTimeRef.current = now;
183
- loop(context, widthRef, heightRef, -1);
184
- return () => {
185
- if (reqIdRef.current)
186
- cancelAnimationFrame(reqIdRef.current);
187
- };
188
- }
189
- }, [loop, init, options, reduceFlickering, relativeSize]);
190
- return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("canvas", Object.assign({ className: clsx('tremolo-animation-canvas', className), width: relativeSize ? 0 : width, height: relativeSize ? 0 : height, ref: canvasRef, onContextMenu: onContextMenu }, props)), relativeSize && reduceFlickering && (jsxRuntime.jsx("canvas", { style: { display: 'none' }, ref: memoCanvasRef }))] }));
191
- }
192
-
193
- /**
194
- * clamp value between min and max
195
- * @category Math
196
- */
197
- function clamp(value, min, max) {
198
- return Math.max(min, Math.min(value, max));
199
- }
200
- /**
201
- * Normalize the value from 0 to 1
202
- * @category Math
203
- */
204
- function normalizeValue(rawValue, min, max, skew = 1) {
205
- if (min >= max)
206
- throw new RangeError('requirements: min < max');
207
- const v = clamp((rawValue - min) / (max - min), 0, 1);
208
- return Math.pow(v, skew);
209
- }
210
- /**
211
- * Convert normalized values back to raw values.
212
- * @category Math
213
- */
214
- function rawValue(normalizedValue, min, max, skew = 1) {
215
- if (min >= max)
216
- throw new RangeError('requirements: min < max');
217
- const v = skew == 1
218
- ? clamp(normalizedValue, 0, 1)
219
- : Math.exp(Math.log(clamp(normalizedValue, 0, 1)) / skew);
220
- return min + v * (max - min);
221
- }
222
- /**
223
- *
224
- * @category Math
225
- */
226
- function stepValue(value, step) {
227
- var _a;
228
- if (step <= 0)
229
- throw new RangeError('requirements: step > 0');
230
- const quotient = Math.floor(value / step);
231
- const decimalDigits = (_a = decimalPart$1(step)) === null || _a === void 0 ? void 0 : _a.length;
232
- const v = toFixed$1(quotient * step, decimalDigits);
233
- const next = toFixed$1((quotient + 1) * step, decimalDigits);
234
- return Math.abs(value - v) < Math.abs(value - next) ? v : next;
235
- }
236
- /**
237
- *
238
- * @category Math
239
- */
240
- function toFixed$1(x, fractionDigits) {
241
- return Number(x.toFixed(fractionDigits));
242
- }
243
- /**
244
- *
245
- * @category Math
246
- */
247
- function decimalPart$1(x) {
248
- return String(x).split('.')[1];
249
- }
250
- /**
251
- *
252
- * @category Math
253
- */
254
- function radian(degree) {
255
- return (Math.PI * degree) / 180;
256
- }
257
-
258
- function styleHelper(value, op, influencer) {
259
- if (op && influencer) {
260
- if (typeof value == 'number') {
261
- if (op == '+')
262
- return `${value + influencer}px`;
263
- if (op == '-')
264
- return `${value - influencer}px`;
265
- if (op == '*')
266
- return `${value * influencer}px`;
267
- if (op == '/')
268
- return `${value / influencer}px`;
269
- }
270
- else {
271
- return `calc(${value}px ${op} ${influencer})`;
272
- }
273
- }
274
- else {
275
- if (typeof value == 'number') {
276
- return `${value}px`;
277
- }
278
- else {
279
- return value;
280
- }
281
- }
282
- }
283
- /**
284
- * @category Utility
285
- */
286
- function mod(n, m) {
287
- return ((n % m) + m) % m;
288
- }
289
- /**
290
- * @category Utility
291
- */
292
- function xor(a = false, b = false) {
293
- return (a || b) && a != b;
294
- }
295
- /**
296
- * @category MIDI
297
- */
298
- const noteKeys = [
299
- 'C',
300
- 'C#',
301
- 'D',
302
- 'D#',
303
- 'E',
304
- 'F',
305
- 'F#',
306
- 'G',
307
- 'G#',
308
- 'A',
309
- 'A#',
310
- 'B',
311
- ];
312
- /**
313
- * @category MIDI
314
- */
315
- function parseNoteName(noteName) {
316
- const m = noteName.match(/^([a-g])(#{0,2}|b{0,2})(-?\d+)$/i);
317
- if (!m)
318
- throw new Error('Invalid note name');
319
- const [, letter, accidental, octave] = m;
320
- return {
321
- letter: letter.toLocaleUpperCase(),
322
- accidental: accidental,
323
- octave: Number(octave),
324
- };
325
- }
326
- /**
327
- * Convert noteName to noteNumber
328
- * @category MIDI
329
- */
330
- function noteNumber(noteName) {
331
- const { letter, accidental, octave } = parseNoteName(noteName);
332
- const noteIndex = noteKeys.indexOf(letter.toLocaleUpperCase());
333
- const accidentalValue = (accidental[0] == 'b' ? -1 : 1) * accidental.length;
334
- return noteIndex + 12 * (Number(octave) + 1) + accidentalValue;
335
- }
336
- /**
337
- * Convert noteNumber to noteKey
338
- * @category MIDI
339
- */
340
- function noteKey(noteNumber) {
341
- return noteKeys[mod(noteNumber, 12)];
342
- }
343
- /**
344
- * @param note noteNumber: 0 ~ 127 or noteName e.g. 'C3'
345
- * @category MIDI
346
- */
347
- function isWhiteKey(note) {
348
- const n = typeof note == 'string' ? noteNumber(note) : note;
349
- return (mod(n, 12) == 0 ||
350
- mod(n, 12) == 2 ||
351
- mod(n, 12) == 4 ||
352
- mod(n, 12) == 5 ||
353
- mod(n, 12) == 7 ||
354
- mod(n, 12) == 9 ||
355
- mod(n, 12) == 11);
356
- }
357
- /**
358
- * @param note noteNumber: 0 ~ 127 or noteName e.g. 'C3'
359
- * @category MIDI
360
- */
361
- function isBlackKey(note) {
362
- return !isWhiteKey(note);
363
- }
364
-
365
- /**
366
- * This hook is user-land implementation of the experimental `useEffectEvent` hook.
367
- * React docs: https://react.dev/learn/separating-events-from-effects#declaring-an-effect-event
368
- */
369
- function useCallbackRef(callback, deps = []) {
370
- const callbackRef = React.useRef(() => {
371
- throw new Error('Cannot call an event handler while rendering.');
372
- });
373
- React.useInsertionEffect(() => {
374
- callbackRef.current = callback;
375
- });
376
- // eslint-disable-next-line react-hooks/exhaustive-deps
377
- return React.useCallback((...args) => { var _a; return (_a = callbackRef.current) === null || _a === void 0 ? void 0 : _a.call(callbackRef, ...args); }, deps);
378
- }
379
-
380
- function useEventListener(target, event, handler, options) {
381
- const listener = useCallbackRef(handler);
382
- React.useEffect(() => {
383
- const node = typeof target === 'function' ? target() : (target !== null && target !== void 0 ? target : document);
384
- if (!handler || !node)
385
- return;
386
- node.addEventListener(event, listener, options);
387
- return () => {
388
- node.removeEventListener(event, listener, options);
389
- };
390
- }, [event, target, options, listener, handler]);
391
- return () => {
392
- const node = typeof target === 'function' ? target() : (target !== null && target !== void 0 ? target : document);
393
- node === null || node === void 0 ? void 0 : node.removeEventListener(event, listener, options);
394
- };
395
- }
396
-
397
- function useRefCallbackEvent(event, handler, options, deps = []) {
398
- return React.useMemo(() => {
399
- let cleanup;
400
- return (node) => {
401
- if (!node) {
402
- cleanup === null || cleanup === void 0 ? void 0 : cleanup();
403
- return;
404
- }
405
- node.addEventListener(event, handler, options);
406
- cleanup = () => {
407
- node.removeEventListener(event, handler, options);
408
- };
409
- };
410
- // eslint-disable-next-line react-hooks/exhaustive-deps
411
- }, deps);
412
- }
413
-
414
- /**
415
- * @returns [refCallback, pointerDownHandler]
416
- */
417
- function useDrag({ threshold = 1, onDrag, onDragStart, onDragEnd, }) {
418
- const dragOffsetX = React.useRef(undefined);
419
- const dragOffsetY = React.useRef(undefined);
420
- const dragStartX = React.useRef(0);
421
- const dragStartY = React.useRef(0);
422
- const handleDrag = React.useCallback((event, first = false) => {
423
- const isTouch = event instanceof TouchEvent;
424
- if (isTouch && event.cancelable)
425
- event.preventDefault();
426
- const screenX = isTouch ? event.touches[0].screenX : event.screenX;
427
- const screenY = isTouch ? event.touches[0].screenY : event.screenY;
428
- let deltaX = 0;
429
- let deltaY = 0;
430
- if (first) {
431
- dragStartX.current = screenX;
432
- dragStartY.current = screenY;
433
- }
434
- if (dragOffsetX.current) {
435
- deltaX = screenX - dragOffsetX.current;
436
- dragOffsetX.current = screenX;
437
- }
438
- if (dragOffsetY.current) {
439
- deltaY = screenY - dragOffsetY.current;
440
- dragOffsetY.current = screenY;
441
- }
442
- if (Math.abs(deltaX) < threshold && Math.abs(deltaY) < threshold)
443
- return;
444
- onDrag(screenX - dragStartX.current, screenY - dragStartY.current, deltaX, deltaY);
445
- }, [threshold, onDrag]);
446
- const refHandler = useRefCallbackEvent('touchmove', handleDrag, { passive: false }, [onDrag]);
447
- const pointerDownHandler = React.useCallback((event) => {
448
- dragOffsetX.current = event.screenX;
449
- dragOffsetY.current = event.screenY;
450
- handleDrag(event, true);
451
- onDragStart === null || onDragStart === void 0 ? void 0 : onDragStart();
452
- }, [handleDrag, onDragStart]);
453
- useEventListener(globalThis.window, 'mousemove', handleDrag);
454
- useEventListener(globalThis.window, 'pointerup', () => {
455
- dragOffsetX.current = undefined;
456
- dragOffsetY.current = undefined;
457
- onDragEnd === null || onDragEnd === void 0 ? void 0 : onDragEnd();
458
- });
459
- return [refHandler, pointerDownHandler];
460
- }
461
-
462
- function addNoSelect() {
463
- document.body.classList.add('tremolo-no-select');
464
- }
465
- function removeNoSelect() {
466
- document.body.classList.remove('tremolo-no-select');
467
- }
468
-
469
- /**
470
- * Animatable rotary knob.
471
- * @category AnimationKnob
472
- */
473
- const AnimationKnob = React.forwardRef((_a, ref) => {
474
- 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"]);
475
- // -- state and ref ---
476
- const valueRef = React.useRef(0);
477
- const elmRef = React.useRef(null);
478
- // --- interpret props ---
479
- const isRelativeSize = typeof (size !== null && size !== void 0 ? size : width) == 'string' || typeof height == 'string';
480
- const onDrag = React.useCallback((_x, y) => {
481
- if (!onChange)
482
- return;
483
- const v = rawValue(valueRef.current - y / 100, min, max, skew);
484
- const v2 = clamp(stepValue(v, step), min, max);
485
- onChange(v2);
486
- }, [max, min, onChange, skew, step]);
487
- const handleKeyDown = React.useCallback((event) => {
488
- if (!keyboard || !onChange)
489
- return;
490
- const key = event.key;
491
- if (['ArrowRight', 'ArrowLeft', 'ArrowUp', 'ArrowDown'].includes(key)) {
492
- event.preventDefault();
493
- const x = key == 'ArrowRight' || key == 'ArrowUp' ? keyboard[1] : -keyboard[1];
494
- let v;
495
- if (keyboard[0] == 'normalized') {
496
- const n = normalizeValue(value, min, max, skew);
497
- v = rawValue(n + x, min, max, skew);
498
- }
499
- else {
500
- v = value + x;
501
- }
502
- onChange(clamp(stepValue(v, step), min, max));
503
- }
504
- }, [value, min, max, step, skew, keyboard, onChange]);
505
- // --- hooks ---
506
- const [touchMoveRefCallback, pointerDownHandler] = useDrag({
507
- onDrag: onDrag,
508
- onDragStart: () => {
509
- valueRef.current = normalizeValue(value, min, max, skew);
510
- if (bodyNoSelect)
511
- addNoSelect();
512
- },
513
- onDragEnd: () => {
514
- if (bodyNoSelect)
515
- removeNoSelect();
516
- },
517
- });
518
- const wheelRefCallback = useRefCallbackEvent('wheel', (event) => {
519
- if (!wheel)
520
- return;
521
- event.preventDefault();
522
- const x = event.deltaY > 0 ? -wheel[1] : wheel[1];
523
- let v;
524
- if (wheel[0] == 'normalized') {
525
- const n = normalizeValue(value, min, max, skew);
526
- v = rawValue(n + x, min, max, skew);
527
- }
528
- else {
529
- v = value + x;
530
- }
531
- if (onChange)
532
- onChange(clamp(stepValue(v, step), min, max));
533
- }, { passive: false }, [wheel, value, min, max, skew, step, onChange]);
534
- React.useImperativeHandle(ref, () => {
535
- return {
536
- focus() {
537
- var _a;
538
- (_a = elmRef.current) === null || _a === void 0 ? void 0 : _a.focus();
539
- },
540
- blur() {
541
- var _a;
542
- (_a = elmRef.current) === null || _a === void 0 ? void 0 : _a.blur();
543
- },
544
- };
545
- }, []);
546
- return (jsxRuntime.jsx("div", Object.assign({ className: clsx('tremolo-animation-knob', className), ref: (div) => {
547
- elmRef.current = div;
548
- wheelRefCallback(div);
549
- touchMoveRefCallback(div);
550
- }, 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: pointerDownHandler, onDoubleClick: () => {
551
- if (enableDoubleClickDefault && onChange) {
552
- onChange(defaultValue);
553
- }
554
- }, onKeyDown: handleKeyDown }, props, { children: jsxRuntime.jsx(AnimationCanvas, Object.assign({}, (isRelativeSize
555
- ? { relativeSize: true }
556
- : {
557
- width: size !== null && size !== void 0 ? size : width,
558
- height: size !== null && size !== void 0 ? size : height,
559
- }), { draw: draw
560
- ? draw
561
- : (ctx, { width, height }) => {
562
- const p = normalizeValue(value, min, max, skew);
563
- const startP = normalizeValue(startValue, min, max, skew);
564
- const cx = width / 2;
565
- const cy = height / 2;
566
- const r = Math.min(cx, cy);
567
- if (r <= 0)
568
- return;
569
- // reset
570
- ctx.clearRect(0, 0, width, height);
571
- ctx.lineCap = 'butt';
572
- // bg
573
- ctx.beginPath();
574
- ctx.fillStyle = bg;
575
- ctx.arc(cx, cy, r - 0.5, 0, 2 * Math.PI);
576
- ctx.fill();
577
- ctx.lineWidth = lineWeight;
578
- // inactive rotary
579
- ctx.beginPath();
580
- ctx.strokeStyle = inactiveColor;
581
- ctx.arc(cx, cy, r - 0.5 - lineWeight / 2, radian(135), radian(45));
582
- ctx.stroke();
583
- // active rotary
584
- ctx.beginPath();
585
- ctx.strokeStyle = activeColor;
586
- ctx.arc(cx, cy, r - 0.5 - lineWeight / 2, radian(135 + 270 * startP), radian(135 + 270 * p), p < startP);
587
- ctx.stroke();
588
- // thumb
589
- ctx.lineCap = 'round';
590
- ctx.beginPath();
591
- ctx.moveTo(cx, cy);
592
- ctx.lineTo(cx +
593
- Math.cos(radian(135 + 270 * p)) *
594
- (r - 0.5 - thumbWeight / 2), cy +
595
- Math.sin(radian(135 + 270 * p)) *
596
- (r - 0.5 - thumbWeight / 2));
597
- ctx.strokeStyle = thumb;
598
- ctx.lineWidth = thumbWeight;
599
- ctx.stroke();
600
- } })) })));
601
- });
602
-
603
- /** @category DragObserver */
604
- function DragObserver(props) {
605
- const { as: Component = 'div', threshold = 1, children, onDrag, onDragStart, onDragEnd } = props, attributes = __rest(props, ["as", "threshold", "children", "onDrag", "onDragStart", "onDragEnd"]);
606
- const [refCallback, pointerDownHandler] = useDrag({
607
- threshold: threshold,
608
- onDrag: onDrag,
609
- onDragStart: onDragStart,
610
- onDragEnd: onDragEnd,
611
- });
612
- return (jsxRuntime.jsx(Component, Object.assign({ ref: refCallback, onPointerDown: pointerDownHandler }, attributes, { children: children })));
613
- }
614
-
615
- /**
616
- * Interactive rotary knob component implemented in SVG.
617
- *
618
- * @category Knob
619
- */
620
- const Knob = React.forwardRef((_a, ref) => {
621
- 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, onKeyDown, onPointerDown, onDoubleClick, 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", "onKeyDown", "onPointerDown", "onDoubleClick", "className", "classes"]);
622
- const valueRef = React.useRef(0);
623
- const elmRef = React.useRef(null);
624
- // --- interpret props ---
625
- const padding = 8; // %
626
- const thumbLineWeight = 6; // %
627
- const thumbLineLength = 35; // %
628
- const lineWeight = size * 0.06; // px
629
- const p = normalizeValue(value, min, max, skew);
630
- const s = normalizeValue(startValue, min, max, skew);
631
- // --- internal functions ---
632
- const onDrag = React.useCallback((_x, y) => {
633
- if (!onChange || readonly)
634
- return;
635
- const v = rawValue(valueRef.current - y / 100, min, max, skew);
636
- const v2 = clamp(stepValue(v, step), min, max);
637
- onChange(v2);
638
- }, [max, min, onChange, readonly, skew, step]);
639
- const updateValueByEvent = React.useCallback((eventType, x) => {
640
- let newValue;
641
- if (eventType == 'normalized') {
642
- const n = normalizeValue(value, min, max, skew);
643
- newValue = rawValue(n + x, min, max, skew);
644
- }
645
- else {
646
- newValue = value + x;
647
- }
648
- return clamp(stepValue(newValue, step), min, max);
649
- }, [max, min, skew, step, value]);
650
- const handleKeyDown = React.useCallback((event) => {
651
- if (!keyboard || !onChange || readonly)
652
- return;
653
- const key = event.key;
654
- if (['ArrowRight', 'ArrowLeft', 'ArrowUp', 'ArrowDown'].includes(key)) {
655
- event.preventDefault();
656
- const x = key == 'ArrowRight' || key == 'ArrowUp' ? keyboard[1] : -keyboard[1];
657
- onChange(updateValueByEvent(keyboard[0], x));
658
- }
659
- }, [keyboard, onChange, readonly, updateValueByEvent]);
660
- // --- hooks ---
661
- const [touchMoveRefCallback, pointerDownHandler] = useDrag({
662
- onDrag: onDrag,
663
- onDragStart: () => {
664
- valueRef.current = normalizeValue(value, min, max, skew);
665
- if (bodyNoSelect)
666
- addNoSelect();
667
- },
668
- onDragEnd: () => {
669
- if (bodyNoSelect)
670
- removeNoSelect();
671
- },
672
- });
673
- const wheelRefCallback = useRefCallbackEvent('wheel', (event) => {
674
- if (!wheel || readonly)
675
- return;
676
- event.preventDefault();
677
- if (!onChange || event.deltaY == 0)
678
- return;
679
- const x = Math.sign(event.deltaY) * -wheel[1];
680
- onChange(updateValueByEvent(wheel[0], x));
681
- }, { passive: false }, [wheel, onChange, readonly, updateValueByEvent]);
682
- React.useImperativeHandle(ref, () => {
683
- return {
684
- focus() {
685
- var _a;
686
- (_a = elmRef.current) === null || _a === void 0 ? void 0 : _a.focus();
687
- },
688
- blur() {
689
- var _a;
690
- (_a = elmRef.current) === null || _a === void 0 ? void 0 : _a.blur();
691
- },
692
- };
693
- }, []);
694
- const center = size / 2;
695
- const r1 = -135;
696
- const r2 = -135 + Math.min(p, s) * 270;
697
- const r3 = -135 + Math.max(p, s) * 270;
698
- const r4 = 135;
699
- const x1 = center + center * Math.cos(radian(r1 - 90));
700
- const y1 = center + center * Math.sin(radian(r1 - 90));
701
- const x2 = center + center * Math.cos(radian(r2 - 90));
702
- const y2 = center + center * Math.sin(radian(r2 - 90));
703
- const x3 = center + center * Math.cos(radian(r3 - 90));
704
- const y3 = center + center * Math.sin(radian(r3 - 90));
705
- const x4 = center + center * Math.cos(radian(r4 - 90));
706
- const y4 = center + center * Math.sin(radian(r4 - 90));
707
- return (jsxRuntime.jsxs("svg", Object.assign({ className: clsx('tremolo-knob', className), ref: (div) => {
708
- elmRef.current = div;
709
- wheelRefCallback(div);
710
- touchMoveRefCallback(div);
711
- }, width: size, height: size, tabIndex: 0, role: "slider", "aria-valuenow": value, "aria-valuemin": min, "aria-valuemax": max, "aria-disabled": disabled, "aria-readonly": readonly, onPointerDown: (event) => {
712
- pointerDownHandler(event);
713
- onPointerDown === null || onPointerDown === void 0 ? void 0 : onPointerDown(event);
714
- }, onDoubleClick: (event) => {
715
- if (enableDoubleClickDefault && onChange) {
716
- onChange(defaultValue);
717
- }
718
- onDoubleClick === null || onDoubleClick === void 0 ? void 0 : onDoubleClick(event);
719
- }, onKeyDown: (event) => {
720
- handleKeyDown(event);
721
- onKeyDown === null || onKeyDown === void 0 ? void 0 : onKeyDown(event);
722
- } }, props, { children: [startValue > min && (jsxRuntime.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 })), jsxRuntime.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 && (jsxRuntime.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 })), jsxRuntime.jsxs("svg", { className: clsx('tremolo-knob-thumb', classes === null || classes === void 0 ? void 0 : classes.thumb), children: [jsxRuntime.jsx("circle", { cx: "50%", cy: "50%", r: `${50 - padding}%`, fill: thumb || 'currentColor' }), jsxRuntime.jsx("line", { className: clsx('tremolo-knob-thumb-line', classes === null || classes === void 0 ? void 0 : classes.thumbLine), x1: "50%", y1: `${padding}%`, x2: "50%", y2: `${thumbLineLength}%`, stroke: thumbLine || 'currentColor', strokeWidth: `${thumbLineWeight}%`,
723
- // NOTE
724
- // https://bugs.webkit.org/show_bug.cgi?id=201854
725
- // https://developer.mozilla.org/en-US/docs/Web/SVG/Reference/Attribute/transform-origin#browser_compatibility
726
- style: {
727
- transform: `rotate(${ -135 + p * 270}deg)`,
728
- transformOrigin: '50% 50%',
729
- } })] })] })));
730
- });
731
-
732
- const createStoreImpl = (createState) => {
733
- let state;
734
- const listeners = /* @__PURE__ */ new Set();
735
- const setState = (partial, replace) => {
736
- const nextState = typeof partial === "function" ? partial(state) : partial;
737
- if (!Object.is(nextState, state)) {
738
- const previousState = state;
739
- state = (replace != null ? replace : typeof nextState !== "object" || nextState === null) ? nextState : Object.assign({}, state, nextState);
740
- listeners.forEach((listener) => listener(state, previousState));
741
- }
742
- };
743
- const getState = () => state;
744
- const getInitialState = () => initialState;
745
- const subscribe = (listener) => {
746
- listeners.add(listener);
747
- return () => listeners.delete(listener);
748
- };
749
- const api = { setState, getState, getInitialState, subscribe };
750
- const initialState = state = createState(setState, getState, api);
751
- return api;
752
- };
753
- const createStore = ((createState) => createState ? createStoreImpl(createState) : createStoreImpl);
754
-
755
- const identity = (arg) => arg;
756
- function useStore(api, selector = identity) {
757
- const slice = React.useSyncExternalStore(
758
- api.subscribe,
759
- React.useCallback(() => selector(api.getState()), [api, selector]),
760
- React.useCallback(() => selector(api.getInitialState()), [api, selector])
761
- );
762
- React.useDebugValue(slice);
763
- return slice;
764
- }
765
-
766
- /**
767
- * @module NumberInput
768
- */
769
- function selectUnit(units, value) {
770
- let i = 0;
771
- for (; i < units.length; i++) {
772
- if (Math.abs(units[i][1]) > Math.abs(value))
773
- break;
774
- }
775
- return units[Math.max(0, i - 1)];
776
- }
777
- function parseValue(inputString, units, digit) {
778
- var _a;
779
- const str = inputString.trim();
780
- if (!units || typeof units == 'string') {
781
- const m = str.match(/-?\d+(\.\d+)?/);
782
- let v = Number((_a = m === null || m === void 0 ? void 0 : m[0]) !== null && _a !== void 0 ? _a : '0');
783
- v = isNaN(v) ? 0 : v;
784
- return {
785
- rawValue: v,
786
- formatValue: (digit != undefined ? v.toFixed(digit) : v) + (units !== null && units !== void 0 ? units : ''),
787
- unit: units !== null && units !== void 0 ? units : '',
788
- };
789
- }
790
- const unitList = units.map(([u, _s]) => u);
791
- const scaleList = units.map(([_u, s]) => s);
792
- let rawValue = 0;
793
- let unit = unitList[0];
794
- let formatValue = (digit != undefined ? rawValue.toFixed(digit) : rawValue) + unit;
795
- const m = str.match(/^(-?\d+(\.\d+)?)\s*(\w*)$/);
796
- if (m) {
797
- rawValue = Number(m[1]) || 0;
798
- const uIndex = unitList.indexOf(m[3]);
799
- rawValue *= uIndex != -1 ? scaleList[uIndex] : 1;
800
- const [u, scale] = selectUnit(units, rawValue);
801
- const v = rawValue / scale;
802
- formatValue = (digit != undefined ? v.toFixed(digit) : v) + u;
803
- unit = u;
804
- }
805
- return {
806
- rawValue: rawValue,
807
- formatValue: formatValue,
808
- unit: unit,
809
- };
810
- }
811
-
812
- function safeClamp(value, min = Number.MIN_SAFE_INTEGER, max = Number.MAX_SAFE_INTEGER) {
813
- return clamp(value, min, max);
814
- }
815
- const createNumberInputStore = (initProps) => {
816
- const DEFAULT_PROPS = {
817
- value: '',
818
- valueAsNumber: 0,
819
- min: 0,
820
- max: 0,
821
- step: 1,
822
- readonly: false,
823
- keepWithinRange: true,
824
- onChange: (_v, _t) => { },
825
- };
826
- return createStore()((set) => (Object.assign(Object.assign(Object.assign(Object.assign({}, DEFAULT_PROPS), initProps), {
827
- value: parseValue(String((initProps === null || initProps === void 0 ? void 0 : initProps.value) || ''), initProps === null || initProps === void 0 ? void 0 : initProps.units, initProps === null || initProps === void 0 ? void 0 : initProps.digit).formatValue,
828
- valueAsNumber: parseValue(String((initProps === null || initProps === void 0 ? void 0 : initProps.value) || ''), initProps === null || initProps === void 0 ? void 0 : initProps.units, initProps === null || initProps === void 0 ? void 0 : initProps.digit).rawValue,
829
- }), { increment: () => set((state) => {
830
- var _a, _b;
831
- if (state.readonly)
832
- return {};
833
- const current = parseValue(state.value, state.units, state.digit).rawValue;
834
- let next = current + ((_a = state.step) !== null && _a !== void 0 ? _a : 1);
835
- if (state.keepWithinRange) {
836
- next = safeClamp(next, state.min, state.max);
837
- }
838
- const v = parseValue(String(next), state.units, state.digit).formatValue;
839
- (_b = state === null || state === void 0 ? void 0 : state.onChange) === null || _b === void 0 ? void 0 : _b.call(state, next, v);
840
- return {
841
- value: v,
842
- valueAsNumber: next,
843
- };
844
- }), decrement: () => set((state) => {
845
- var _a, _b;
846
- if (state.readonly)
847
- return {};
848
- const current = parseValue(state.value, state.units, state.digit).rawValue;
849
- let next = current - ((_a = state.step) !== null && _a !== void 0 ? _a : 1);
850
- if (state.keepWithinRange) {
851
- next = safeClamp(next, state.min, state.max);
852
- }
853
- const v = parseValue(String(next), state.units, state.digit).formatValue;
854
- (_b = state === null || state === void 0 ? void 0 : state.onChange) === null || _b === void 0 ? void 0 : _b.call(state, next, v);
855
- return {
856
- value: v,
857
- valueAsNumber: next,
858
- };
859
- }), change: (value) => set((state) => {
860
- if (state.readonly)
861
- return {};
862
- const v = value !== null && value !== void 0 ? value : '';
863
- return {
864
- value: v,
865
- valueAsNumber: parseValue(v, state.units, state.digit).rawValue,
866
- };
867
- }) })));
868
- };
869
- const NumberInputContext = React.createContext(null);
870
- function NumberInputProvider(_a) {
871
- var { children } = _a, props = __rest(_a, ["children"]);
872
- const storeRef = React.useRef(null);
873
- if (!storeRef.current) {
874
- storeRef.current = createNumberInputStore(props);
875
- }
876
- React.useEffect(() => {
877
- if (storeRef.current) {
878
- const parsed = parseValue(String((props === null || props === void 0 ? void 0 : props.value) || ''), props === null || props === void 0 ? void 0 : props.units, props === null || props === void 0 ? void 0 : props.digit);
879
- storeRef.current.setState(Object.assign(Object.assign({}, props), {
880
- value: parsed.formatValue,
881
- valueAsNumber: parsed.rawValue,
882
- }));
883
- }
884
- else {
885
- storeRef.current = createNumberInputStore(props);
886
- }
887
- }, [props]);
888
- return (jsxRuntime.jsx(NumberInputContext.Provider, { value: storeRef.current, children: children }));
889
- }
890
- /** @category NumberInput */
891
- function useNumberInputContext(selector) {
892
- const store = React.useContext(NumberInputContext);
893
- if (!store)
894
- throw new Error('Missing NumberInputContext.Provider in the tree');
895
- return useStore(store, selector);
896
- }
897
-
898
- const InternalInput = React.forwardRef((_a, ref) => {
899
- var { disabled, readonly, selectWithFocus, blurOnEnter, clampValueOnBlur, wheel, keyboard, className, onChange, onFocus, onBlur, onKeyDown, children: _children } = _a, props = __rest(_a, ["disabled", "readonly", "selectWithFocus", "blurOnEnter", "clampValueOnBlur", "wheel", "keyboard", "className", "onChange", "onFocus", "onBlur", "onKeyDown", "children"]);
900
- const elmRef = React.useRef(null);
901
- const [editing, setEditing] = React.useState(false);
902
- const value = useNumberInputContext((s) => s.value);
903
- const valueAsNumber = useNumberInputContext((s) => s.valueAsNumber);
904
- const min = useNumberInputContext((s) => s.min);
905
- const max = useNumberInputContext((s) => s.max);
906
- const step = useNumberInputContext((s) => s.step);
907
- const units = useNumberInputContext((s) => s.units);
908
- const digit = useNumberInputContext((s) => s.digit);
909
- const change = useNumberInputContext((s) => s.change);
910
- const error = React.useMemo(() => {
911
- if (editing)
912
- return false;
913
- const v = valueAsNumber;
914
- return (min !== null && min !== void 0 ? min : -Infinity) > v || v > (max !== null && max !== void 0 ? max : Infinity);
915
- }, [editing, max, min, valueAsNumber]);
916
- const updateValueByEvent = React.useCallback((eventType, x) => {
917
- let newValue;
918
- if (eventType == 'normalized') {
919
- if (!min || !max) {
920
- throw new Error('required parameter: min, max'); // TODO
921
- }
922
- const n = normalizeValue(valueAsNumber, min, max);
923
- newValue = rawValue(n + x, min, max);
924
- return clamp(stepValue(newValue, step), min, max);
925
- }
926
- else {
927
- newValue = valueAsNumber + x;
928
- return stepValue(newValue, step);
929
- }
930
- }, [max, min, step, valueAsNumber]);
931
- const handleKeyDown = React.useCallback((event) => {
932
- if (!keyboard || !onChange || readonly)
933
- return;
934
- const key = event.key;
935
- if (!['ArrowUp', 'ArrowDown'].includes(key))
936
- return;
937
- event.preventDefault();
938
- const x = key == 'ArrowUp' ? keyboard[1] : -keyboard[1];
939
- const parsed = parseValue(String(updateValueByEvent(keyboard[0], x)));
940
- // console.log('key control')
941
- onChange === null || onChange === void 0 ? void 0 : onChange(parsed.rawValue, parsed.formatValue);
942
- }, [keyboard, readonly, onChange, updateValueByEvent]);
943
- const wheelRefCallback = useRefCallbackEvent('wheel', (event) => {
944
- if (!wheel || readonly)
945
- return;
946
- event.preventDefault();
947
- if (!onChange || event.deltaY == 0)
948
- return;
949
- const x = Math.sign(event.deltaY) * -wheel[1];
950
- const parsed = parseValue(String(updateValueByEvent(wheel[0], x)));
951
- // console.log('wheel control')
952
- onChange === null || onChange === void 0 ? void 0 : onChange(parsed.rawValue, parsed.formatValue);
953
- }, { passive: false }, [wheel, readonly, onChange, updateValueByEvent]);
954
- React.useImperativeHandle(ref, () => {
955
- return {
956
- focus() {
957
- var _a;
958
- (_a = elmRef.current) === null || _a === void 0 ? void 0 : _a.focus();
959
- },
960
- blur() {
961
- var _a;
962
- (_a = elmRef.current) === null || _a === void 0 ? void 0 : _a.blur();
963
- },
964
- };
965
- }, []);
966
- return (jsxRuntime.jsx("input", Object.assign({ ref: (input) => {
967
- elmRef.current = input;
968
- wheelRefCallback(input);
969
- }, className: clsx('tremolo-number-input', className), value: value, min: min, max: max, step: step, type: "text", "aria-disabled": disabled, "aria-readonly": readonly, tabIndex: -1, "data-error": error, onChange: (event) => {
970
- if (readonly)
971
- return;
972
- const v = event.currentTarget.value;
973
- const cursorPos = event.target.selectionStart;
974
- change(v);
975
- const valueAsNumber = parseValue(v, units, digit).rawValue;
976
- onChange === null || onChange === void 0 ? void 0 : onChange(valueAsNumber, v);
977
- if (cursorPos) {
978
- event.target.selectionStart = cursorPos;
979
- event.target.selectionEnd = cursorPos;
980
- }
981
- }, onFocus: (event) => {
982
- setEditing(true);
983
- const v = event.currentTarget.value;
984
- const parsed = parseValue(v, units, digit);
985
- if (selectWithFocus == 'all') {
986
- event.currentTarget.setSelectionRange(0, v.length);
987
- }
988
- else if (selectWithFocus == 'number') {
989
- event.currentTarget.setSelectionRange(0, parsed.formatValue.length - parsed.unit.length);
990
- }
991
- onFocus === null || onFocus === void 0 ? void 0 : onFocus(parsed.rawValue, parsed.formatValue, event);
992
- }, onBlur: (event) => {
993
- setEditing(false);
994
- // update value
995
- let v = parseValue(event.currentTarget.value, units, digit).rawValue;
996
- if (clampValueOnBlur) {
997
- v = safeClamp(v, min, max);
998
- }
999
- const parsed = parseValue(String(v), units, digit);
1000
- change(parsed.formatValue);
1001
- if (clampValueOnBlur) {
1002
- onChange === null || onChange === void 0 ? void 0 : onChange(parsed.rawValue, parsed.formatValue);
1003
- }
1004
- onBlur === null || onBlur === void 0 ? void 0 : onBlur(parsed.rawValue, parsed.formatValue, event);
1005
- }, onKeyDown: (event) => {
1006
- if (blurOnEnter && event.key == 'Enter') {
1007
- event.currentTarget.blur();
1008
- }
1009
- handleKeyDown(event);
1010
- onKeyDown === null || onKeyDown === void 0 ? void 0 : onKeyDown(event);
1011
- } }, props)));
1012
- });
1013
-
1014
- /** @category NumberInput */
1015
- function Stepper(_a) {
1016
- var { dynamic = true, children, className } = _a, props = __rest(_a, ["dynamic", "children", "className"]);
1017
- return (jsxRuntime.jsx("div", Object.assign({ className: clsx('tremolo-number-input-stepper', className), "data-dynamic": dynamic }, props, { children: children })));
1018
- }
1019
-
1020
- function useInterval(callback, delay) {
1021
- const savedCallback = React.useRef(callback);
1022
- // Remember the latest callback if it changes.
1023
- React.useEffect(() => {
1024
- savedCallback.current = callback;
1025
- }, [callback]);
1026
- // Set up the interval.
1027
- React.useEffect(() => {
1028
- // Don't schedule if no delay is specified.
1029
- // Note: 0 is a valid value for delay.
1030
- if (delay === null) {
1031
- return;
1032
- }
1033
- const id = setInterval(() => {
1034
- savedCallback.current();
1035
- }, delay);
1036
- return () => {
1037
- clearInterval(id);
1038
- };
1039
- }, [delay]);
1040
- }
1041
-
1042
- function useLongPress(callback, initialDelay = 500, interval = 40) {
1043
- const [pressed, setPressed] = React.useState(false);
1044
- const [delay, setDelay] = React.useState(initialDelay);
1045
- useInterval(() => {
1046
- callback();
1047
- setDelay(interval);
1048
- }, pressed ? delay : null);
1049
- useEventListener(globalThis.window, 'pointerup', () => {
1050
- setPressed(false);
1051
- setDelay(initialDelay);
1052
- });
1053
- return React.useCallback(() => {
1054
- callback();
1055
- setPressed(true);
1056
- }, [callback]);
1057
- }
1058
-
1059
- /** @category NumberInput */
1060
- function IncrementStepper(_a) {
1061
- var { size = 12, children, className } = _a, props = __rest(_a, ["size", "children", "className"]);
1062
- const max = useNumberInputContext((s) => s.max);
1063
- const valueAsNumber = useNumberInputContext((s) => s.valueAsNumber);
1064
- const readonly = useNumberInputContext((s) => s.readonly);
1065
- const keepWithinRange = useNumberInputContext((s) => s.keepWithinRange);
1066
- const increment = useNumberInputContext((s) => s.increment);
1067
- const press = useLongPress(increment);
1068
- return (
1069
- // eslint-disable-next-line jsx-a11y/role-supports-aria-props
1070
- jsxRuntime.jsx("div", Object.assign({ className: clsx('tremolo-number-input-increment-stepper', className), role: "button", tabIndex: -1, "aria-disabled": keepWithinRange && valueAsNumber >= (max !== null && max !== void 0 ? max : Number.MAX_SAFE_INTEGER), "aria-readonly": readonly, onPointerDown: press }, props, { children: children || (jsxRuntime.jsx("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntime.jsx("polyline", { points: "18 15 12 9 6 15" }) })) })));
1071
- }
1072
-
1073
- /** @category NumberInput */
1074
- function DecrementStepper(_a) {
1075
- var { size = 12, children, className } = _a, props = __rest(_a, ["size", "children", "className"]);
1076
- const min = useNumberInputContext((s) => s.min);
1077
- const valueAsNumber = useNumberInputContext((s) => s.valueAsNumber);
1078
- const readonly = useNumberInputContext((s) => s.readonly);
1079
- const keepWithinRange = useNumberInputContext((s) => s.keepWithinRange);
1080
- const decrement = useNumberInputContext((s) => s.decrement);
1081
- const press = useLongPress(decrement);
1082
- return (
1083
- // eslint-disable-next-line jsx-a11y/role-supports-aria-props
1084
- jsxRuntime.jsx("div", Object.assign({ className: clsx('tremolo-number-input-decrement-stepper', className), role: "button", tabIndex: -1, "aria-disabled": keepWithinRange && valueAsNumber <= (min !== null && min !== void 0 ? min : Number.MIN_SAFE_INTEGER), "aria-readonly": readonly, onPointerDown: press }, props, { children: children || (jsxRuntime.jsx("svg", { width: size, height: size, viewBox: "0 0 24 24", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsxRuntime.jsx("polyline", { points: "6 9 12 15 18 9" }) })) })));
1085
- }
1086
-
1087
- /**
1088
- * Input with some useful functions for entering numerical values.
1089
- * @category NumberInput
1090
- */
1091
- const NumberInput = React.forwardRef((_a, ref) => {
1092
- var { value, min, max, step = 1, units, readonly = false, disabled = false, digit, variant = 'outline', selectWithFocus = 'none', blurOnEnter = true, keepWithinRange = true, clampValueOnBlur = true, wheel = ['raw', 1], keyboard = ['raw', 1], activeColor, wrapperClassName, className, onChange, onFocus, onBlur, children } = _a, props = __rest(_a, ["value", "min", "max", "step", "units", "readonly", "disabled", "digit", "variant", "selectWithFocus", "blurOnEnter", "keepWithinRange", "clampValueOnBlur", "wheel", "keyboard", "activeColor", "wrapperClassName", "className", "onChange", "onFocus", "onBlur", "children"]);
1093
- const colors = {
1094
- '--active-color': activeColor,
1095
- };
1096
- return (jsxRuntime.jsx(NumberInputProvider, { value: String(value), min: min, max: max, step: step, units: units, digit: digit, readonly: readonly, keepWithinRange: keepWithinRange, onChange: onChange, children: jsxRuntime.jsxs("div", { className: clsx('tremolo-number-input-wrapper', wrapperClassName),
1097
- // eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex
1098
- tabIndex: 0, style: Object.assign({}, colors), "data-stepper": !!children, "data-variant": variant, children: [jsxRuntime.jsx(InternalInput, Object.assign({ ref: ref, readonly: readonly, disabled: disabled, selectWithFocus: selectWithFocus, blurOnEnter: blurOnEnter, clampValueOnBlur: clampValueOnBlur, wheel: wheel, keyboard: keyboard, className: className, onChange: onChange, onFocus: onFocus, onBlur: onBlur }, props)), children] }) }));
1099
- });
1100
-
1101
- /**
1102
- * @returns [refCallback, pointerDownHandler]
1103
- */
1104
- function useDragWithElement({ baseElementRef, onDrag, onDragStart, onDragEnd, }) {
1105
- const dragged = React.useRef(false);
1106
- const normalizedX = React.useRef(0);
1107
- const normalizedY = React.useRef(0);
1108
- const handleDrag = React.useCallback((event) => {
1109
- if (!baseElementRef.current || !dragged.current) {
1110
- return;
1111
- }
1112
- const isTouch = event instanceof TouchEvent;
1113
- if (isTouch && event.cancelable)
1114
- event.preventDefault();
1115
- const { left, top, right, bottom } = baseElementRef.current.getBoundingClientRect();
1116
- const mouseX = isTouch ? event.touches[0].clientX : event.clientX;
1117
- const mouseY = isTouch ? event.touches[0].clientY : event.clientY;
1118
- const nx = normalizeValue(mouseX, left, right);
1119
- const ny = normalizeValue(mouseY, top, bottom);
1120
- normalizedX.current = nx;
1121
- normalizedY.current = ny;
1122
- onDrag(nx, ny);
1123
- }, [onDrag, baseElementRef]);
1124
- const refHandler = useRefCallbackEvent('touchmove', handleDrag, { passive: false }, [onDrag]);
1125
- const pointerDownHandler = React.useCallback((event) => {
1126
- dragged.current = true;
1127
- handleDrag(event);
1128
- onDragStart === null || onDragStart === void 0 ? void 0 : onDragStart(normalizedX.current, normalizedY.current);
1129
- }, [handleDrag, onDragStart]);
1130
- useEventListener(globalThis.window, 'pointermove', handleDrag);
1131
- useEventListener(globalThis.window, 'pointerup', () => {
1132
- if (!dragged.current)
1133
- return;
1134
- dragged.current = false;
1135
- onDragEnd === null || onDragEnd === void 0 ? void 0 : onDragEnd(normalizedX.current, normalizedY.current);
1136
- });
1137
- return [refHandler, pointerDownHandler];
1138
- }
1139
-
1140
- const createPianoStore = (initProps) => {
1141
- // const noteRange = initProps.noteRange || { first: 0, last: 127 }
1142
- const DEFAULT_PROPS = {
1143
- noteRange: { first: 0, last: 127 },
1144
- glissando: true,
1145
- midiMax: 127,
1146
- fill: false,
1147
- label: () => undefined,
1148
- onPlayNote: () => { },
1149
- onStopNote: () => { },
1150
- };
1151
- return createStore()(() => (Object.assign(Object.assign(Object.assign({}, DEFAULT_PROPS), initProps), { notePosition: initProps.notePosition })));
1152
- };
1153
- const PianoContext = React.createContext(null);
1154
- function PianoProvider(_a) {
1155
- var { children } = _a, props = __rest(_a, ["children"]);
1156
- const storeRef = React.useRef(null);
1157
- if (!storeRef.current) {
1158
- storeRef.current = createPianoStore(props);
1159
- }
1160
- React.useEffect(() => {
1161
- if (storeRef.current) {
1162
- storeRef.current.setState(props);
1163
- }
1164
- else {
1165
- storeRef.current = createPianoStore(props);
1166
- }
1167
- }, [props]);
1168
- return (jsxRuntime.jsx(PianoContext.Provider, { value: storeRef.current, children: children }));
1169
- }
1170
- /** @category Piano */
1171
- function usePianoContext(selector) {
1172
- const store = React.useContext(PianoContext);
1173
- if (!store)
1174
- throw new Error('Missing PianoContext.Provider in the tree');
1175
- return useStore(store, selector);
1176
- }
1177
-
1178
- /** @category Piano */
1179
- function KeyLabel(_a) {
1180
- var { label, className, wrapperClassName, wrapperStyle, __note, __label } = _a, props = __rest(_a, ["label", "className", "wrapperClassName", "wrapperStyle", "__note", "__label"]);
1181
- const noteRange = usePianoContext((s) => s.noteRange);
1182
- const noteRangeArray = getNoteRangeArray(noteRange);
1183
- const index = noteRangeArray.indexOf(__note);
1184
- const content = label
1185
- ? label(__note, index)
1186
- : __label && __label(__note, index);
1187
- return ((content != undefined || content != null) && (jsxRuntime.jsx("div", { className: clsx('tremolo-piano-key-label-wrapper', wrapperClassName), style: wrapperStyle, children: jsxRuntime.jsx("div", Object.assign({ className: clsx('tremolo-piano-key-label', className) }, props, { children: content })) })));
1188
- }
1189
-
1190
- /** @category Piano */
1191
- const defaultWhiteKeyWidth = 40;
1192
- /** @category Piano */
1193
- const defaultBlackKeyWidth = 26;
1194
- const KeyImpl = React.forwardRef((_a, ref) => {
1195
- var { keyType, noteNumber, width, height, bg, color, activeBg, activeColor, className, style, children, __width } = _a, props = __rest(_a, ["keyType", "noteNumber", "width", "height", "bg", "color", "activeBg", "activeColor", "className", "style", "children", "__width"]);
1196
- const [played, setPlayed] = React.useState(false);
1197
- const midiMax = usePianoContext((s) => s.midiMax);
1198
- const fill = usePianoContext((s) => s.fill);
1199
- // const glissando = usePianoContext(s => s.glissando)
1200
- const onPlayNote = usePianoContext((s) => s.onPlayNote);
1201
- const onStopNote = usePianoContext((s) => s.onStopNote);
1202
- const label = usePianoContext((s) => s.label);
1203
- const notePosition = usePianoContext((s) => s.notePosition);
1204
- const position = notePosition(noteNumber);
1205
- const disabled = noteNumber > midiMax;
1206
- const colors = {
1207
- '--bg': bg,
1208
- '--color': color,
1209
- '--active-bg': activeBg,
1210
- '--active-color': activeColor,
1211
- };
1212
- React.useImperativeHandle(ref, () => {
1213
- return {
1214
- play() {
1215
- if (disabled)
1216
- return;
1217
- setPlayed(true);
1218
- if (onPlayNote)
1219
- onPlayNote(noteNumber);
1220
- },
1221
- stop() {
1222
- setPlayed(false);
1223
- if (onStopNote)
1224
- onStopNote(noteNumber);
1225
- },
1226
- played() {
1227
- return played;
1228
- },
1229
- };
1230
- }, [disabled, noteNumber, onPlayNote, onStopNote, played]);
1231
- let keyLabelProps = {};
1232
- if (children != undefined) {
1233
- React.Children.forEach(children, (child) => {
1234
- if (React.isValidElement(child)) {
1235
- if (child.type == KeyLabel) {
1236
- keyLabelProps = child.props;
1237
- }
1238
- else {
1239
- throw new Error('only <KeyLabel>');
1240
- }
1241
- }
1242
- else {
1243
- throw new Error('children is an invalid element.');
1244
- }
1245
- });
1246
- }
1247
- return (jsxRuntime.jsx("div", Object.assign({ className: clsx(`tremolo-piano-${keyType}-key`, className), "aria-disabled": disabled, "data-active": played, style: Object.assign(Object.assign(Object.assign({}, colors), { left: position, width: fill ? __width : width, height: height }), style) }, props, { children: jsxRuntime.jsx(KeyLabel, Object.assign({ label: label, __note: noteNumber }, keyLabelProps)) })));
1248
- });
1249
- /** @category Piano */
1250
- const WhiteKey = React.forwardRef((_a, ref) => {
1251
- var { width = defaultWhiteKeyWidth, height = '100%', onContextMenu = (e) => e.preventDefault() } = _a, props = __rest(_a, ["width", "height", "onContextMenu"]);
1252
- return (jsxRuntime.jsx(KeyImpl, Object.assign({ ref: ref, keyType: "white", width: width, height: height, onContextMenu: onContextMenu }, props)));
1253
- });
1254
- /** @category Piano */
1255
- const BlackKey = React.forwardRef((_a, ref) => {
1256
- var { width = defaultBlackKeyWidth, height = '60%', onContextMenu = (e) => e.preventDefault() } = _a, props = __rest(_a, ["width", "height", "onContextMenu"]);
1257
- return (jsxRuntime.jsx(KeyImpl, Object.assign({ ref: ref, keyType: "black", width: width, height: height, onContextMenu: onContextMenu }, props)));
1258
- });
1259
-
1260
- /** @category Piano */
1261
- const SHORTCUTS = {
1262
- HOME_ROW: {
1263
- keys: [
1264
- 'a',
1265
- 'w',
1266
- 's',
1267
- 'e',
1268
- 'd',
1269
- 'f',
1270
- 't',
1271
- 'g',
1272
- 'y',
1273
- 'h',
1274
- 'u',
1275
- 'j',
1276
- 'k',
1277
- 'o',
1278
- 'l',
1279
- 'p',
1280
- ';',
1281
- ],
1282
- },
1283
- };
1284
-
1285
- /**
1286
- * Piano component
1287
- *
1288
- * TODO:
1289
- * - add scale highlight
1290
- */
1291
- /** @category Piano */
1292
- function getNoteRangeArray(noteRange) {
1293
- return Array.from({ length: noteRange.last - noteRange.first + 1 }, (_, i) => i + noteRange.first);
1294
- }
1295
- const blackPerWhiteWidth = defaultBlackKeyWidth / defaultWhiteKeyWidth; // 0.65
1296
- /**
1297
- * Customizable piano component.
1298
- * @category Piano
1299
- */
1300
- function Piano(_a) {
1301
- var { noteRange, glissando = true, midiMax = 127, keyboardShortcuts, fill = false, height = fill ? '100%' : 160, whiteNoteWidth: _whiteNoteWidth = defaultWhiteKeyWidth, style, className, onPlayNote, onStopNote, label, children, onPointerDown } = _a, props = __rest(_a, ["noteRange", "glissando", "midiMax", "keyboardShortcuts", "fill", "height", "whiteNoteWidth", "style", "className", "onPlayNote", "onStopNote", "label", "children", "onPointerDown"]);
1302
- // -- state and ref ---
1303
- const [whiteNoteWidth, setWhiteNoteWidth] = React.useState(_whiteNoteWidth);
1304
- const keyRefs = React.useRef([]);
1305
- for (let i = 0; i < noteRange.last - noteRange.first + 1; i++) {
1306
- keyRefs.current[i] = React.createRef();
1307
- }
1308
- const pianoRef = React.useRef(null);
1309
- const hitKeyIndex = React.useRef(-1);
1310
- // --- interpret props ---
1311
- const noteRangeArray = getNoteRangeArray(noteRange);
1312
- const whiteNotes = noteRangeArray.filter((v) => isWhiteKey(v));
1313
- const blackNotes = noteRangeArray.filter((v) => isBlackKey(v));
1314
- const whiteNoteCount = whiteNotes.length;
1315
- const padding = 1;
1316
- const staticWidth = (whiteNoteWidth + padding) * whiteNoteCount;
1317
- // const blackNoteShiftPercent = 0.3
1318
- const childrenWithProps = React.useMemo(() => {
1319
- return (children &&
1320
- React.Children.map(children, (child, index) => {
1321
- if (React.isValidElement(child)) {
1322
- const __width = child.type == WhiteKey ? whiteNoteWidth : whiteNoteWidth * 0.65;
1323
- const props = { ref: keyRefs.current[index], __width };
1324
- return React.cloneElement(child, props);
1325
- }
1326
- return child;
1327
- }));
1328
- }, [children, whiteNoteWidth]);
1329
- // --- internal functions ---
1330
- const notePosition = React.useCallback((note) => {
1331
- const pitchPositions = {
1332
- C: 0,
1333
- 'C#': 1,
1334
- D: 1,
1335
- 'D#': 2,
1336
- E: 2,
1337
- F: 3,
1338
- 'F#': 4,
1339
- G: 4,
1340
- 'G#': 5,
1341
- A: 5,
1342
- 'A#': 6,
1343
- B: 6,
1344
- };
1345
- const blackNoteWidth = whiteNoteWidth * blackPerWhiteWidth;
1346
- const padding = 1;
1347
- const targetNoteKey = noteKey(note);
1348
- const firstNoteKey = noteKey(noteRange.first);
1349
- const octave = Math.floor((note - noteRange.first) / 12);
1350
- const octaveOffset = noteKeys.indexOf(firstNoteKey) > noteKeys.indexOf(targetNoteKey) ? 1 : 0;
1351
- const w = whiteNoteWidth + padding;
1352
- const pos = pitchPositions[targetNoteKey] - pitchPositions[firstNoteKey];
1353
- const blackKeyOffset = isBlackKey(note) ? blackNoteWidth / 2 : 0;
1354
- return pos * w + (octave + octaveOffset) * 7 * w - blackKeyOffset;
1355
- }, [noteRange.first, whiteNoteWidth]);
1356
- const getHitKeyIndex = React.useCallback((x, y) => {
1357
- if (!pianoRef.current)
1358
- return -1;
1359
- const containerHeight = pianoRef.current.clientHeight;
1360
- const notes = [...blackNotes, ...whiteNotes];
1361
- for (let i = 0; i < notes.length; i++) {
1362
- const note = notes[i];
1363
- const pos = notePosition(note);
1364
- const w = isWhiteKey(note)
1365
- ? whiteNoteWidth
1366
- : whiteNoteWidth * blackPerWhiteWidth;
1367
- const h = isWhiteKey(note) ? containerHeight : containerHeight * 0.6;
1368
- if (pos <= x && x < pos + w && 0 <= y && y < h) {
1369
- return note;
1370
- }
1371
- }
1372
- return -1;
1373
- }, [blackNotes, notePosition, whiteNoteWidth, whiteNotes]);
1374
- // TODO: 単一のポインターに対しては、useDragで対応可能だが、
1375
- // マルチタッチに対しては、TouchEventを使う必要がありそう
1376
- // 取り敢えず、シングルタッチだけ対応
1377
- const onDrag = React.useCallback((perX, perY) => {
1378
- var _a, _b, _c, _d;
1379
- if (!pianoRef.current)
1380
- return;
1381
- const x = perX * staticWidth;
1382
- const y = perY * pianoRef.current.clientHeight;
1383
- const note = getHitKeyIndex(x, y);
1384
- const index = noteRangeArray.indexOf(note);
1385
- if (index == -1)
1386
- return;
1387
- if (hitKeyIndex.current != index) {
1388
- (_b = (_a = keyRefs.current[hitKeyIndex.current]) === null || _a === void 0 ? void 0 : _a.current) === null || _b === void 0 ? void 0 : _b.stop();
1389
- (_d = (_c = keyRefs.current[index]) === null || _c === void 0 ? void 0 : _c.current) === null || _d === void 0 ? void 0 : _d.play();
1390
- hitKeyIndex.current = index;
1391
- }
1392
- }, [getHitKeyIndex, noteRangeArray, staticWidth]);
1393
- const onDragEnd = React.useCallback(() => {
1394
- var _a, _b, _c, _d;
1395
- if ((_b = (_a = keyRefs.current[hitKeyIndex.current]) === null || _a === void 0 ? void 0 : _a.current) === null || _b === void 0 ? void 0 : _b.played()) {
1396
- (_d = (_c = keyRefs.current[hitKeyIndex.current]) === null || _c === void 0 ? void 0 : _c.current) === null || _d === void 0 ? void 0 : _d.stop();
1397
- }
1398
- hitKeyIndex.current = -1;
1399
- }, [keyRefs]);
1400
- // --- hooks ---
1401
- React.useEffect(() => {
1402
- if (fill && pianoRef.current) {
1403
- const parent = pianoRef.current.parentElement;
1404
- if (!parent)
1405
- throw new Error("doesn't have a parent element.");
1406
- const resizeObserver = new ResizeObserver(() => {
1407
- const w = pianoRef.current.clientWidth;
1408
- setWhiteNoteWidth(w / whiteNoteCount - padding);
1409
- });
1410
- resizeObserver.observe(parent);
1411
- return () => {
1412
- resizeObserver.unobserve(parent);
1413
- };
1414
- }
1415
- else {
1416
- setWhiteNoteWidth(_whiteNoteWidth);
1417
- }
1418
- }, [fill, _whiteNoteWidth, whiteNoteCount]);
1419
- const [touchMoveRefCallback, pointerDownHandler] = useDragWithElement({
1420
- baseElementRef: pianoRef,
1421
- onDrag: onDrag,
1422
- onDragEnd: onDragEnd,
1423
- });
1424
- useEventListener(globalThis.window, 'keydown', (e) => {
1425
- var _a, _b, _c, _d;
1426
- if (e.repeat)
1427
- return;
1428
- if (!keyboardShortcuts)
1429
- return;
1430
- const index = keyboardShortcuts.keys.indexOf(e.key);
1431
- if (index != -1) {
1432
- if (!((_b = (_a = keyRefs.current[index]) === null || _a === void 0 ? void 0 : _a.current) === null || _b === void 0 ? void 0 : _b.played())) {
1433
- (_d = (_c = keyRefs.current[index]) === null || _c === void 0 ? void 0 : _c.current) === null || _d === void 0 ? void 0 : _d.play();
1434
- }
1435
- }
1436
- });
1437
- useEventListener(globalThis.window, 'keyup', (e) => {
1438
- var _a, _b;
1439
- if (e.repeat)
1440
- return;
1441
- if (!keyboardShortcuts)
1442
- return;
1443
- const index = keyboardShortcuts.keys.indexOf(e.key);
1444
- if (index != -1) {
1445
- (_b = (_a = keyRefs.current[index]) === null || _a === void 0 ? void 0 : _a.current) === null || _b === void 0 ? void 0 : _b.stop();
1446
- }
1447
- });
1448
- return (jsxRuntime.jsx(PianoProvider, { notePosition: notePosition, noteRange: noteRange, glissando: glissando, midiMax: midiMax, fill: fill, onPlayNote: onPlayNote, onStopNote: onStopNote, label: label, children: jsxRuntime.jsx("div", Object.assign({ ref: (div) => {
1449
- pianoRef.current = div;
1450
- touchMoveRefCallback(div);
1451
- }, className: clsx('tremolo-piano', className), style: Object.assign({ width: fill ? '100%' : staticWidth, height: height }, style), onPointerDown: (event) => {
1452
- pointerDownHandler(event);
1453
- onPointerDown === null || onPointerDown === void 0 ? void 0 : onPointerDown(event);
1454
- } }, props, { children: childrenWithProps ||
1455
- noteRangeArray.map((note, index) => isWhiteKey(note) ? (jsxRuntime.jsx(WhiteKey, { ref: keyRefs.current[index], noteNumber: note, __width: whiteNoteWidth }, note)) : (jsxRuntime.jsx(BlackKey, { ref: keyRefs.current[index], noteNumber: note, __width: whiteNoteWidth * blackPerWhiteWidth }, note))) })) }));
1456
- }
1457
-
1458
- const createSliderStore = (initProps) => {
1459
- const DEFAULT_PROPS = {
1460
- min: 0,
1461
- max: 0,
1462
- step: 0,
1463
- skew: 0,
1464
- vertical: false,
1465
- reverse: false,
1466
- disabled: false,
1467
- readonly: false,
1468
- };
1469
- return createStore()(() => (Object.assign(Object.assign({}, DEFAULT_PROPS), initProps)));
1470
- };
1471
- const SliderContext = React.createContext(null);
1472
- function SliderProvider(_a) {
1473
- var { children } = _a, props = __rest(_a, ["children"]);
1474
- const storeRef = React.useRef(null);
1475
- if (!storeRef.current) {
1476
- storeRef.current = createSliderStore(props);
1477
- }
1478
- React.useEffect(() => {
1479
- if (storeRef.current) {
1480
- storeRef.current.setState(props);
1481
- }
1482
- else {
1483
- storeRef.current = createSliderStore(props);
1484
- }
1485
- }, [props]);
1486
- return (jsxRuntime.jsx(SliderContext.Provider, { value: storeRef.current, children: children }));
1487
- }
1488
- /** @category Slider */
1489
- function useSliderContext(selector) {
1490
- const store = React.useContext(SliderContext);
1491
- if (!store)
1492
- throw new Error('Missing SliderContext.Provider in the tree');
1493
- return useStore(store, selector);
1494
- }
1495
-
1496
- /**
1497
- * clamp value between min and max
1498
- * @category Math
1499
- */
1500
- /**
1501
- *
1502
- * @category Math
1503
- */
1504
- function toFixed(x, fractionDigits) {
1505
- return Number(x.toFixed(fractionDigits));
1506
- }
1507
- /**
1508
- *
1509
- * @category Math
1510
- */
1511
- function decimalPart(x) {
1512
- return String(x).split('.')[1];
1513
- }
1514
-
1515
- /**
1516
- * @module Slider
1517
- */
1518
- function generateOptionsList(options, min, max, step) {
1519
- var _a;
1520
- const optionsList = [];
1521
- const per = options[0] == 'step' ? step : options[0];
1522
- const count = Math.floor(max / per) - Math.ceil(min / per) + 1;
1523
- for (let i = 0; i < count; i++) {
1524
- const value = toFixed(per * (Math.ceil(min / per) + i), (_a = decimalPart(per)) === null || _a === void 0 ? void 0 : _a.length);
1525
- optionsList.push({ value: value, type: options[1] });
1526
- }
1527
- return optionsList;
1528
- }
1529
-
1530
- /** @category Slider */
1531
- function ScaleOption(_a) {
1532
- 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"]);
1533
- const min = useSliderContext((s) => s.min);
1534
- const max = useSliderContext((s) => s.max);
1535
- const skew = useSliderContext((s) => s.skew);
1536
- const vertical = useSliderContext((s) => s.vertical);
1537
- const reverse = useSliderContext((s) => s.reverse);
1538
- const calcPercent = React.useCallback((rawValue) => {
1539
- return toFixed$1(xor(vertical, reverse)
1540
- ? 100 - normalizeValue(rawValue, min, max, skew) * 100
1541
- : normalizeValue(rawValue, min, max, skew) * 100);
1542
- }, [vertical, reverse, max, min, skew]);
1543
- return (jsxRuntime.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' && (jsxRuntime.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' && (jsxRuntime.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 }))] })));
1544
- }
1545
-
1546
- /** @category Slider */
1547
- function Scale(_a) {
1548
- var { gap = 6, options, children, className, style } = _a, props = __rest(_a, ["gap", "options", "children", "className", "style"]);
1549
- const min = useSliderContext((s) => s.min);
1550
- const max = useSliderContext((s) => s.max);
1551
- const step = useSliderContext((s) => s.step);
1552
- const vertical = useSliderContext((s) => s.vertical);
1553
- const reverse = useSliderContext((s) => s.reverse);
1554
- const optionsList = options
1555
- ? generateOptionsList(options, min, max, step)
1556
- : [];
1557
- if (xor(vertical, reverse))
1558
- optionsList.reverse();
1559
- return (jsxRuntime.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
1560
- ? optionsList.map(({ value, type }, index) => {
1561
- return jsxRuntime.jsx(ScaleOption, { value: value, type: type }, index);
1562
- })
1563
- : children })));
1564
- }
1565
-
1566
- /** @category Slider */
1567
- const defaultThumbSize = 22;
1568
- /** @category Slider */
1569
- const SliderThumb = React.forwardRef(({ size, width = defaultThumbSize, height = defaultThumbSize, color, children, className, style, __percent, }, ref) => {
1570
- const wrapperRef = React.useRef(null);
1571
- const vertical = useSliderContext((s) => s.vertical);
1572
- const disabled = useSliderContext((s) => s.disabled);
1573
- const readonly = useSliderContext((s) => s.readonly);
1574
- React.useImperativeHandle(ref, () => {
1575
- return {
1576
- focus() {
1577
- var _a;
1578
- (_a = wrapperRef.current) === null || _a === void 0 ? void 0 : _a.focus();
1579
- },
1580
- blur() {
1581
- var _a;
1582
- (_a = wrapperRef.current) === null || _a === void 0 ? void 0 : _a.blur();
1583
- },
1584
- };
1585
- }, []);
1586
- return (jsxRuntime.jsx("div", { className: "tremolo-slider-thumb-wrapper", style: {
1587
- top: vertical ? `${__percent}%` : '50%',
1588
- left: !vertical ? `${__percent}%` : '50%',
1589
- }, children: children ? (children) : (
1590
- // default slider thumb
1591
- jsxRuntime.jsx("div", { ref: wrapperRef, className: clsx('tremolo-slider-thumb', className),
1592
- // eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex
1593
- tabIndex: 0, "aria-disabled": disabled, "aria-readonly": readonly, style: Object.assign(Object.assign({ '--color': color }, { width: size !== null && size !== void 0 ? size : width, height: size !== null && size !== void 0 ? size : height }), style) })) }));
1594
- });
1595
-
1596
- const defaultLength = 140;
1597
- const defaultThickness = 10;
1598
- /** @category Slider */
1599
- function SliderTrack(_a) {
1600
- var { length = defaultLength, thickness = defaultThickness, active, inactive, children, className, style, defaultStyle = true, __thumb, __percent = 0 } = _a, props = __rest(_a, ["length", "thickness", "active", "inactive", "children", "className", "style", "defaultStyle", "__thumb", "__percent"]);
1601
- const vertical = useSliderContext((s) => s.vertical);
1602
- const reverse = useSliderContext((s) => s.reverse);
1603
- const disabled = useSliderContext((s) => s.disabled);
1604
- const direction = vertical ? 'bottom' : 'right';
1605
- const colors = {
1606
- '--active': active,
1607
- '--inactive': inactive,
1608
- };
1609
- return (jsxRuntime.jsxs("div", Object.assign({ className: clsx('tremolo-slider-track', className), "aria-disabled": disabled, "data-vertical": vertical, style: !defaultStyle
1610
- ? style
1611
- : Object.assign(Object.assign(Object.assign({}, colors), { background: xor(vertical, reverse)
1612
- ? `linear-gradient(to ${direction}, var(--inactive, #eee) ${__percent}%, var(--active, #7998ec) ${__percent}%)`
1613
- : `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) }, props, { children: [children, __thumb] })));
1614
- }
1615
-
1616
- /**
1617
- * Customizable slider
1618
- * @category Slider
1619
- */
1620
- const Slider = React.forwardRef((_a, ref) => {
1621
- var _b;
1622
- var { value, min, max, step = 1, skew = 1, vertical = false, reverse = false, bodyNoSelect = true, wheel = ['raw', 1], keyboard = ['raw', 1], disabled = false, readonly = false, onChange, onDragStart, onDragEnd, className, style, children, onFocus, onBlur, onPointerDown, onKeyDown } = _a, props = __rest(_a, ["value", "min", "max", "step", "skew", "vertical", "reverse", "bodyNoSelect", "wheel", "keyboard", "disabled", "readonly", "onChange", "onDragStart", "onDragEnd", "className", "style", "children", "onFocus", "onBlur", "onPointerDown", "onKeyDown"]);
1623
- // -- state and ref ---
1624
- const trackElementRef = React.useRef(null);
1625
- const thumbRef = React.useRef(null);
1626
- // --- interpret props ---
1627
- const p = toFixed$1(normalizeValue(value, min, max, skew) * 100);
1628
- const rev = toFixed$1(100 - p);
1629
- // NOTE
1630
- // normal -> normal (right)
1631
- // vertical -> rev (up)
1632
- // reverse -> rev (left)
1633
- // vertical & reverse -> normal (down)
1634
- const displayReversed = React.useMemo(() => xor(vertical, reverse), [vertical, reverse]);
1635
- const percent = displayReversed ? rev : p;
1636
- let trackProps = {};
1637
- let thumbProps = {};
1638
- let scaleComponent = undefined;
1639
- if (children != undefined) {
1640
- React.Children.forEach(children, (child) => {
1641
- if (React.isValidElement(child)) {
1642
- if (child.type == SliderThumb) {
1643
- thumbProps = child.props;
1644
- }
1645
- else if (child.type == SliderTrack) {
1646
- trackProps = child.props;
1647
- }
1648
- else if (child.type == Scale) {
1649
- scaleComponent = child;
1650
- }
1651
- else {
1652
- throw new Error('only <SliderThumb> or <SliderTrack>');
1653
- }
1654
- }
1655
- else {
1656
- throw new Error('children is an invalid element.');
1657
- }
1658
- });
1659
- }
1660
- // --- internal functions ---
1661
- const onDrag = React.useCallback((nx, ny) => {
1662
- if (!onChange || readonly)
1663
- return;
1664
- const n = vertical ? ny : nx;
1665
- const v = rawValue(displayReversed ? 1 - n : n, min, max, skew);
1666
- const v2 = clamp(stepValue(v, step), min, max);
1667
- onChange(v2);
1668
- }, [displayReversed, max, min, onChange, readonly, skew, step, vertical]);
1669
- const updateValueByEvent = React.useCallback((eventType, x) => {
1670
- let newValue;
1671
- if (eventType == 'normalized') {
1672
- const n = normalizeValue(value, min, max, skew);
1673
- newValue = rawValue(n + x, min, max, skew);
1674
- }
1675
- else {
1676
- newValue = value + x;
1677
- }
1678
- return clamp(stepValue(newValue, step), min, max);
1679
- }, [max, min, skew, step, value]);
1680
- const handleKeyDown = React.useCallback((event) => {
1681
- if (!keyboard || !onChange || readonly)
1682
- return;
1683
- const key = event.key;
1684
- if (['ArrowRight', 'ArrowLeft', 'ArrowUp', 'ArrowDown'].includes(key)) {
1685
- event.preventDefault();
1686
- let x = key == 'ArrowRight' || key == 'ArrowUp' ? keyboard[1] : -keyboard[1];
1687
- if (reverse)
1688
- x *= -1;
1689
- onChange(updateValueByEvent(keyboard[0], x));
1690
- }
1691
- }, [keyboard, onChange, readonly, reverse, updateValueByEvent]);
1692
- // --- hooks ---
1693
- const [touchMoveRefCallback, pointerDownHandler] = useDragWithElement({
1694
- baseElementRef: trackElementRef,
1695
- onDrag: onDrag,
1696
- onDragStart: (nx, ny) => {
1697
- var _a;
1698
- if (readonly)
1699
- return;
1700
- if (bodyNoSelect)
1701
- addNoSelect();
1702
- (_a = thumbRef.current) === null || _a === void 0 ? void 0 : _a.focus();
1703
- onDragStart === null || onDragStart === void 0 ? void 0 : onDragStart(clamp(stepValue(rawValue(vertical ? ny : nx, min, max, skew), step), min, max));
1704
- },
1705
- onDragEnd: (nx, ny) => {
1706
- if (readonly)
1707
- return;
1708
- if (bodyNoSelect)
1709
- removeNoSelect();
1710
- onDragEnd === null || onDragEnd === void 0 ? void 0 : onDragEnd(clamp(stepValue(rawValue(vertical ? ny : nx, min, max, skew), step), min, max));
1711
- },
1712
- });
1713
- const wheelRefCallback = useRefCallbackEvent('wheel', (event) => {
1714
- if (!wheel || !onChange || readonly)
1715
- return;
1716
- event.preventDefault();
1717
- let x;
1718
- if (!vertical && event.deltaX != 0) {
1719
- x = event.deltaX > 0 ? wheel[1] : -wheel[1];
1720
- }
1721
- else {
1722
- if (event.deltaY == 0)
1723
- return;
1724
- x = event.deltaY > 0 ? -wheel[1] : wheel[1];
1725
- }
1726
- if (vertical && reverse)
1727
- x *= -1;
1728
- onChange(updateValueByEvent(wheel[0], x));
1729
- }, {
1730
- passive: false,
1731
- }, [wheel, vertical, readonly, onChange, updateValueByEvent]);
1732
- React.useImperativeHandle(ref, () => {
1733
- return {
1734
- focus() {
1735
- var _a;
1736
- (_a = thumbRef.current) === null || _a === void 0 ? void 0 : _a.focus();
1737
- },
1738
- blur() {
1739
- var _a;
1740
- (_a = thumbRef.current) === null || _a === void 0 ? void 0 : _a.blur();
1741
- },
1742
- };
1743
- }, []);
1744
- return (jsxRuntime.jsx(SliderProvider, { min: min, max: max, step: step, skew: skew, vertical: vertical, reverse: reverse, disabled: disabled, readonly: readonly, children: jsxRuntime.jsx("div", Object.assign({ className: clsx('tremolo-slider', className), ref: (div) => {
1745
- wheelRefCallback(div);
1746
- touchMoveRefCallback(div);
1747
- }, 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) => {
1748
- pointerDownHandler(event);
1749
- onPointerDown === null || onPointerDown === void 0 ? void 0 : onPointerDown(event);
1750
- }, onKeyDown: (event) => {
1751
- handleKeyDown(event);
1752
- onKeyDown === null || onKeyDown === void 0 ? void 0 : onKeyDown(event);
1753
- }, onFocus: (event) => {
1754
- var _a;
1755
- (_a = thumbRef.current) === null || _a === void 0 ? void 0 : _a.focus();
1756
- onFocus === null || onFocus === void 0 ? void 0 : onFocus(event);
1757
- }, onBlur: (event) => {
1758
- var _a;
1759
- (_a = thumbRef.current) === null || _a === void 0 ? void 0 : _a.blur();
1760
- onBlur === null || onBlur === void 0 ? void 0 : onBlur(event);
1761
- } }, props, { children: jsxRuntime.jsxs("div", { style: {
1762
- display: 'flex',
1763
- flexDirection: vertical ? 'row' : 'column',
1764
- width: !vertical ? '100%' : undefined,
1765
- height: vertical ? '100%' : undefined,
1766
- }, children: [jsxRuntime.jsx("div", { className: "tremolo-slider-track-wrapper", ref: trackElementRef, children: jsxRuntime.jsx(SliderTrack, Object.assign({ __percent: percent, __thumb: jsxRuntime.jsx(SliderThumb, Object.assign({ ref: thumbRef, __percent: percent }, thumbProps)) }, trackProps)) }), scaleComponent] }) })) }));
1767
- });
1768
-
1769
- /** @category WheelObserver */
1770
- function WheelObserver(props) {
1771
- const { children, onWheel, as: Component = 'div' } = props, attributes = __rest(props, ["children", "onWheel", "as"]);
1772
- const wheelRefCallback = useRefCallbackEvent('wheel', (event) => {
1773
- if (onWheel)
1774
- onWheel(event);
1775
- }, { passive: false }, [onWheel]);
1776
- return (jsxRuntime.jsx(Component, Object.assign({ ref: wheelRefCallback }, attributes, { children: children })));
1777
- }
1778
-
1779
- /** @category XYPad */
1780
- function XYPadArea(_a) {
1781
- var { width = 120, height = 120, color, children, className, style, __thumb } = _a, props = __rest(_a, ["width", "height", "color", "children", "className", "style", "__thumb"]);
1782
- return (jsxRuntime.jsxs("div", Object.assign({ className: clsx('tremolo-xy-pad-area', className), style: Object.assign(Object.assign({ '--color': color }, { width: width, height: height }), style) }, props, { children: [children, __thumb] })));
1783
- }
1784
-
1785
- /** @category XYPad */
1786
- const XYPadThumb = React.forwardRef((_a, ref) => {
1787
- var { size, width = 22, height = 22, color, children, wrapperClassName, wrapperStyle, className, style, __disabled, __css } = _a, props = __rest(_a, ["size", "width", "height", "color", "children", "wrapperClassName", "wrapperStyle", "className", "style", "__disabled", "__css"]);
1788
- const wrapperRef = React.useRef(null);
1789
- React.useImperativeHandle(ref, () => {
1790
- return {
1791
- focus() {
1792
- var _a;
1793
- (_a = wrapperRef.current) === null || _a === void 0 ? void 0 : _a.focus();
1794
- },
1795
- blur() {
1796
- var _a;
1797
- (_a = wrapperRef.current) === null || _a === void 0 ? void 0 : _a.blur();
1798
- },
1799
- };
1800
- }, []);
1801
- return (jsxRuntime.jsx("div", Object.assign({ className: clsx('tremolo-xy-pad-thumb-wrapper', wrapperClassName), style: Object.assign(Object.assign({}, __css), wrapperStyle) }, props, { children: children ? (children) : (
1802
- // default thumb
1803
- jsxRuntime.jsx("div", { ref: wrapperRef, className: clsx('tremolo-xy-pad-thumb', className),
1804
- // eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex
1805
- tabIndex: 0, "aria-disabled": __disabled, style: Object.assign(Object.assign({ '--color': color }, { width: size !== null && size !== void 0 ? size : width, height: size !== null && size !== void 0 ? size : height }), style) })) })));
1806
- });
1807
-
1808
- const defaultValueOptions = {
1809
- skew: 1,
1810
- step: 1,
1811
- reverse: false,
1812
- wheel: ['raw', 1],
1813
- keyboard: ['raw', 1],
1814
- };
1815
- /**
1816
- * Simple XYPad
1817
- * @category XYPad
1818
- */
1819
- const XYPad = React.forwardRef((_a, ref) => {
1820
- var _b;
1821
- var { x: _x, y: _y, className, style, bodyNoSelect = true, disabled = false, readonly = false, onChange, onDragStart, onDragEnd, onPointerDown, onKeyDown, onFocus, onBlur, children } = _a, props = __rest(_a, ["x", "y", "className", "style", "bodyNoSelect", "disabled", "readonly", "onChange", "onDragStart", "onDragEnd", "onPointerDown", "onKeyDown", "onFocus", "onBlur", "children"]);
1822
- const x = React.useMemo(() => {
1823
- return Object.assign(Object.assign({}, defaultValueOptions), _x);
1824
- }, [_x]);
1825
- const y = React.useMemo(() => {
1826
- return Object.assign(Object.assign({}, defaultValueOptions), _y);
1827
- }, [_y]);
1828
- // -- state and ref ---
1829
- const areaElementRef = React.useRef(null);
1830
- const thumbRef = React.useRef(null);
1831
- // --- interpret props ---
1832
- const nx = normalizeValue(x.value, x.min, x.max, x.skew);
1833
- const ny = normalizeValue(y.value, y.min, y.max, y.skew);
1834
- const percentX = toFixed$1((x.reverse ? 1 - nx : nx) * 100);
1835
- const percentY = toFixed$1((y.reverse ? 1 - ny : ny) * 100);
1836
- let areaProps = {};
1837
- let thumbProps = {};
1838
- if (children != undefined) {
1839
- React.Children.forEach(children, (child) => {
1840
- if (React.isValidElement(child)) {
1841
- if (child.type == XYPadThumb) {
1842
- thumbProps = child.props;
1843
- }
1844
- else if (child.type == XYPadArea) {
1845
- areaProps = child.props;
1846
- }
1847
- else {
1848
- throw new Error('only <XYPadThumb> or <XYPadArea>');
1849
- }
1850
- }
1851
- else {
1852
- throw new Error('children is an invalid element.');
1853
- }
1854
- });
1855
- }
1856
- // --- internal functions ---
1857
- const onDrag = React.useCallback((nx, ny) => {
1858
- if (!onChange || readonly)
1859
- return;
1860
- const vx = rawValue(x.reverse ? 1 - nx : nx, x.min, x.max, x.skew);
1861
- const vy = rawValue(y.reverse ? 1 - ny : ny, y.min, y.max, y.skew);
1862
- const newX = clamp(stepValue(vx, x.step), x.min, x.max);
1863
- const newY = clamp(stepValue(vy, y.step), y.min, y.max);
1864
- onChange(newX, newY);
1865
- }, [
1866
- onChange,
1867
- readonly,
1868
- x.max,
1869
- x.min,
1870
- x.reverse,
1871
- x.skew,
1872
- x.step,
1873
- y.max,
1874
- y.min,
1875
- y.reverse,
1876
- y.skew,
1877
- y.step,
1878
- ]);
1879
- const updateValueByEvent = React.useCallback((eventType, target, x) => {
1880
- let v;
1881
- if (eventType == 'normalized') {
1882
- const n = normalizeValue(target.value, target.min, target.max, target.skew);
1883
- v = rawValue(n + x, target.min, target.max, target.skew);
1884
- }
1885
- else {
1886
- v = target.value + x;
1887
- }
1888
- return clamp(stepValue(v, target.step), target.min, target.max);
1889
- }, []);
1890
- const handleKeyDown = React.useCallback((event) => {
1891
- if (!onChange || readonly)
1892
- return;
1893
- const key = event.key;
1894
- if (['ArrowRight', 'ArrowLeft', 'ArrowUp', 'ArrowDown'].includes(key)) {
1895
- const isHorizontal = key == 'ArrowRight' || key == 'ArrowLeft';
1896
- const target = isHorizontal ? x : y;
1897
- if (!target.keyboard)
1898
- return;
1899
- event.preventDefault();
1900
- let delta = target.keyboard[1];
1901
- if (key == 'ArrowLeft' || key == 'ArrowUp')
1902
- delta *= -1;
1903
- if (target.reverse)
1904
- delta *= -1;
1905
- const newValue = updateValueByEvent(target.keyboard[0], target, delta);
1906
- if (isHorizontal) {
1907
- onChange(newValue, y.value);
1908
- }
1909
- else {
1910
- onChange(x.value, newValue);
1911
- }
1912
- }
1913
- }, [onChange, readonly, x, y, updateValueByEvent]);
1914
- // --- hooks ---
1915
- const [touchMoveRefCallback, pointerDownHandler] = useDragWithElement({
1916
- baseElementRef: areaElementRef,
1917
- onDrag: onDrag,
1918
- onDragStart: (nx, ny) => {
1919
- var _a;
1920
- if (readonly)
1921
- return;
1922
- if (bodyNoSelect)
1923
- addNoSelect();
1924
- (_a = thumbRef.current) === null || _a === void 0 ? void 0 : _a.focus();
1925
- const valueX = clamp(stepValue(rawValue(nx, x.min, x.max, x.skew), x.step), x.min, x.max);
1926
- const valueY = clamp(stepValue(rawValue(ny, y.min, y.max, y.skew), y.step), y.min, y.max);
1927
- onDragStart === null || onDragStart === void 0 ? void 0 : onDragStart(valueX, valueY);
1928
- },
1929
- onDragEnd: (nx, ny) => {
1930
- if (readonly)
1931
- return;
1932
- if (bodyNoSelect)
1933
- removeNoSelect();
1934
- const valueX = clamp(stepValue(rawValue(nx, x.min, x.max, x.skew), x.step), x.min, x.max);
1935
- const valueY = clamp(stepValue(rawValue(ny, y.min, y.max, y.skew), y.step), y.min, y.max);
1936
- onDragEnd === null || onDragEnd === void 0 ? void 0 : onDragEnd(valueX, valueY);
1937
- },
1938
- });
1939
- const wheelRefCallback = useRefCallbackEvent('wheel', (event) => {
1940
- if (!onChange || readonly)
1941
- return;
1942
- const target = event.shiftKey ? x : y;
1943
- if (!target.wheel)
1944
- return;
1945
- event.preventDefault();
1946
- let delta = target.wheel[1];
1947
- if (event.deltaY < 0)
1948
- delta *= -1;
1949
- if (target.reverse)
1950
- delta *= -1;
1951
- const newValue = updateValueByEvent(target.wheel[0], target, delta);
1952
- if (event.shiftKey) {
1953
- onChange(newValue, y.value);
1954
- }
1955
- else {
1956
- onChange(x.value, newValue);
1957
- }
1958
- }, {
1959
- passive: false,
1960
- }, [x, y, onChange, readonly, updateValueByEvent]);
1961
- React.useImperativeHandle(ref, () => {
1962
- return {
1963
- focus() {
1964
- var _a;
1965
- (_a = thumbRef.current) === null || _a === void 0 ? void 0 : _a.focus();
1966
- },
1967
- blur() {
1968
- var _a;
1969
- (_a = thumbRef.current) === null || _a === void 0 ? void 0 : _a.blur();
1970
- },
1971
- };
1972
- }, []);
1973
- return (
1974
- // eslint-disable-next-line jsx-a11y/no-static-element-interactions
1975
- jsxRuntime.jsx("div", Object.assign({ className: clsx('tremolo-xy-pad', className), ref: (div) => {
1976
- wheelRefCallback(div);
1977
- touchMoveRefCallback(div);
1978
- }, 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) => {
1979
- pointerDownHandler(event);
1980
- onPointerDown === null || onPointerDown === void 0 ? void 0 : onPointerDown(event);
1981
- }, onKeyDown: (event) => {
1982
- handleKeyDown(event);
1983
- onKeyDown === null || onKeyDown === void 0 ? void 0 : onKeyDown(event);
1984
- }, onFocus: (event) => {
1985
- var _a;
1986
- (_a = thumbRef.current) === null || _a === void 0 ? void 0 : _a.focus();
1987
- onFocus === null || onFocus === void 0 ? void 0 : onFocus(event);
1988
- }, onBlur: (event) => {
1989
- var _a;
1990
- (_a = thumbRef.current) === null || _a === void 0 ? void 0 : _a.blur();
1991
- onBlur === null || onBlur === void 0 ? void 0 : onBlur(event);
1992
- } }, props, { children: jsxRuntime.jsx("div", { className: "tremolo-xy-pad-area-wrapper", ref: areaElementRef, children: jsxRuntime.jsx(XYPadArea, Object.assign({ __thumb: jsxRuntime.jsx(XYPadThumb, Object.assign({ ref: thumbRef, __disabled: disabled, __css: {
1993
- top: `${percentY}%`,
1994
- left: `${percentX}%`,
1995
- } }, thumbProps)) }, areaProps)) }) })));
1996
- });
1997
-
1998
- const useAnimationFrame = (callback = () => { }, deps = []) => {
1999
- const reqIdRef = React.useRef(-1);
2000
- const loop = React.useCallback(() => {
2001
- reqIdRef.current = requestAnimationFrame(loop);
2002
- callback();
2003
- // eslint-disable-next-line react-hooks/exhaustive-deps
2004
- }, [callback, ...deps]);
2005
- React.useEffect(() => {
2006
- reqIdRef.current = requestAnimationFrame(loop);
2007
- return () => cancelAnimationFrame(reqIdRef.current);
2008
- }, [loop]);
2009
- };
2010
-
2011
- exports.AnimationCanvas = AnimationCanvas;
2012
- exports.AnimationKnob = AnimationKnob;
2013
- exports.BlackKey = BlackKey;
2014
- exports.DecrementStepper = DecrementStepper;
2015
- exports.DragObserver = DragObserver;
2016
- exports.IncrementStepper = IncrementStepper;
2017
- exports.KeyLabel = KeyLabel;
2018
- exports.Knob = Knob;
2019
- exports.NumberInput = NumberInput;
2020
- exports.Piano = Piano;
2021
- exports.SHORTCUTS = SHORTCUTS;
2022
- exports.Scale = Scale;
2023
- exports.ScaleOption = ScaleOption;
2024
- exports.Slider = Slider;
2025
- exports.SliderThumb = SliderThumb;
2026
- exports.SliderTrack = SliderTrack;
2027
- exports.Stepper = Stepper;
2028
- exports.WheelObserver = WheelObserver;
2029
- exports.WhiteKey = WhiteKey;
2030
- exports.XYPad = XYPad;
2031
- exports.XYPadArea = XYPadArea;
2032
- exports.XYPadThumb = XYPadThumb;
2033
- exports.getNoteRangeArray = getNoteRangeArray;
2034
- exports.useAnimationFrame = useAnimationFrame;
2035
- exports.useDrag = useDrag;
2036
- exports.useDragWithElement = useDragWithElement;
2037
- exports.useEventListener = useEventListener;
2038
- exports.useInterval = useInterval;
2039
- exports.useLongPress = useLongPress;
2040
- exports.useSliderContext = useSliderContext;
2041
- //# sourceMappingURL=index.js.map