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