@tremolo-ui/react 0.0.5 → 0.0.7
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.
- package/dist/cjs/index.js +512 -93
- package/dist/cjs/index.js.map +1 -1
- package/dist/cjs/types/components/AnimationCanvas/index.d.ts +3 -4
- package/dist/cjs/types/components/AnimationCanvas/index.d.ts.map +1 -1
- package/dist/cjs/types/components/Knob/index.d.ts +6 -7
- package/dist/cjs/types/components/Knob/index.d.ts.map +1 -1
- package/dist/cjs/types/components/NumberInput/index.d.ts +10 -7
- package/dist/cjs/types/components/NumberInput/index.d.ts.map +1 -1
- package/dist/cjs/types/components/Piano/BlackKey.d.ts +4 -0
- package/dist/cjs/types/components/Piano/BlackKey.d.ts.map +1 -0
- package/dist/cjs/types/components/Piano/KeyLabel.d.ts +20 -0
- package/dist/cjs/types/components/Piano/KeyLabel.d.ts.map +1 -0
- package/dist/cjs/types/components/Piano/WhiteKey.d.ts +4 -0
- package/dist/cjs/types/components/Piano/WhiteKey.d.ts.map +1 -0
- package/dist/cjs/types/components/Piano/index.d.ts +35 -0
- package/dist/cjs/types/components/Piano/index.d.ts.map +1 -0
- package/dist/cjs/types/components/Piano/key.d.ts +39 -0
- package/dist/cjs/types/components/Piano/key.d.ts.map +1 -0
- package/dist/cjs/types/components/Piano/keyboardShortcuts.d.ts +12 -0
- package/dist/cjs/types/components/Piano/keyboardShortcuts.d.ts.map +1 -0
- package/dist/cjs/types/components/Slider/Thumb.d.ts +17 -2
- package/dist/cjs/types/components/Slider/Thumb.d.ts.map +1 -1
- package/dist/cjs/types/components/Slider/Track.d.ts +21 -2
- package/dist/cjs/types/components/Slider/Track.d.ts.map +1 -1
- package/dist/cjs/types/components/Slider/index.d.ts +18 -10
- package/dist/cjs/types/components/Slider/index.d.ts.map +1 -1
- package/dist/cjs/types/components/_util/index.d.ts +4 -0
- package/dist/cjs/types/components/_util/index.d.ts.map +1 -0
- package/dist/cjs/types/index.d.ts +1 -0
- package/dist/cjs/types/index.d.ts.map +1 -1
- package/dist/esm/index.js +509 -95
- package/dist/esm/index.js.map +1 -1
- package/dist/esm/types/components/AnimationCanvas/index.d.ts +3 -4
- package/dist/esm/types/components/AnimationCanvas/index.d.ts.map +1 -1
- package/dist/esm/types/components/Knob/index.d.ts +6 -7
- package/dist/esm/types/components/Knob/index.d.ts.map +1 -1
- package/dist/esm/types/components/NumberInput/index.d.ts +10 -7
- package/dist/esm/types/components/NumberInput/index.d.ts.map +1 -1
- package/dist/esm/types/components/Piano/BlackKey.d.ts +4 -0
- package/dist/esm/types/components/Piano/BlackKey.d.ts.map +1 -0
- package/dist/esm/types/components/Piano/KeyLabel.d.ts +20 -0
- package/dist/esm/types/components/Piano/KeyLabel.d.ts.map +1 -0
- package/dist/esm/types/components/Piano/WhiteKey.d.ts +4 -0
- package/dist/esm/types/components/Piano/WhiteKey.d.ts.map +1 -0
- package/dist/esm/types/components/Piano/index.d.ts +35 -0
- package/dist/esm/types/components/Piano/index.d.ts.map +1 -0
- package/dist/esm/types/components/Piano/key.d.ts +39 -0
- package/dist/esm/types/components/Piano/key.d.ts.map +1 -0
- package/dist/esm/types/components/Piano/keyboardShortcuts.d.ts +12 -0
- package/dist/esm/types/components/Piano/keyboardShortcuts.d.ts.map +1 -0
- package/dist/esm/types/components/Slider/Thumb.d.ts +17 -2
- package/dist/esm/types/components/Slider/Thumb.d.ts.map +1 -1
- package/dist/esm/types/components/Slider/Track.d.ts +21 -2
- package/dist/esm/types/components/Slider/Track.d.ts.map +1 -1
- package/dist/esm/types/components/Slider/index.d.ts +18 -10
- package/dist/esm/types/components/Slider/index.d.ts.map +1 -1
- package/dist/esm/types/components/_util/index.d.ts +4 -0
- package/dist/esm/types/components/_util/index.d.ts.map +1 -0
- package/dist/esm/types/index.d.ts +1 -0
- package/dist/esm/types/index.d.ts.map +1 -1
- package/dist/styles/{variables.css → index.css} +4 -0
- package/package.json +7 -7
- package/src/components/AnimationCanvas/index.tsx +3 -7
- package/src/components/Knob/index.tsx +15 -19
- package/src/components/NumberInput/index.tsx +18 -11
- package/src/components/Piano/BlackKey.tsx +108 -0
- package/src/components/Piano/KeyLabel.tsx +69 -0
- package/src/components/Piano/WhiteKey.tsx +109 -0
- package/src/components/Piano/index.tsx +222 -0
- package/src/components/Piano/key.ts +43 -0
- package/src/components/Piano/keyboardShortcuts.ts +12 -0
- package/src/components/Slider/Thumb.tsx +56 -15
- package/src/components/Slider/Track.tsx +62 -3
- package/src/components/Slider/index.tsx +125 -89
- package/src/components/_util/index.ts +11 -0
- package/src/index.ts +1 -0
- package/src/styles/{variables.css → index.css} +4 -0
package/dist/cjs/index.js
CHANGED
|
@@ -96,7 +96,7 @@ function AnimationCanvas(_a) {
|
|
|
96
96
|
if (!parent)
|
|
97
97
|
throw new Error("Canvas doesn't have a parent element.");
|
|
98
98
|
const memoCanvas = memoCanvasRef.current;
|
|
99
|
-
const memoContext = memoCanvas === null || memoCanvas ===
|
|
99
|
+
const memoContext = memoCanvas === null || memoCanvas === undefined ? undefined : memoCanvas.getContext('2d', options);
|
|
100
100
|
const resizeObserver = new ResizeObserver(() => {
|
|
101
101
|
// console.log('resize')
|
|
102
102
|
// Prevents loss of some context when the canvas is resized
|
|
@@ -152,15 +152,27 @@ function AnimationCanvas(_a) {
|
|
|
152
152
|
return (jsxRuntime.jsxs(jsxRuntime.Fragment, { children: [jsxRuntime.jsx("canvas", Object.assign({ className: clsx('tremolo-animation-canvas', className), width: relativeSize ? 0 : width, height: relativeSize ? 0 : height, css: react.css(style), ref: canvasRef }, props)), relativeSize && reduceFlickering && (jsxRuntime.jsx("canvas", { style: { display: 'none' }, width: relativeSize ? 0 : width, height: relativeSize ? 0 : height, ref: memoCanvasRef }))] }));
|
|
153
153
|
}
|
|
154
154
|
|
|
155
|
+
/**
|
|
156
|
+
* clamp value between min and max
|
|
157
|
+
* @category Math
|
|
158
|
+
*/
|
|
155
159
|
function clamp(value, min, max) {
|
|
156
160
|
return Math.max(min, Math.min(value, max));
|
|
157
161
|
}
|
|
162
|
+
/**
|
|
163
|
+
* Normalize the value from 0 to 1
|
|
164
|
+
* @category Math
|
|
165
|
+
*/
|
|
158
166
|
function normalizeValue(rawValue, min, max, skew = 1) {
|
|
159
167
|
if (min >= max)
|
|
160
168
|
throw new RangeError('requirements: min < max');
|
|
161
169
|
const v = clamp((rawValue - min) / (max - min), 0, 1);
|
|
162
170
|
return Math.pow(v, skew);
|
|
163
171
|
}
|
|
172
|
+
/**
|
|
173
|
+
* Convert normalized values back to raw values.
|
|
174
|
+
* @category Math
|
|
175
|
+
*/
|
|
164
176
|
function rawValue(normalizedValue, min, max, skew = 1) {
|
|
165
177
|
if (min >= max)
|
|
166
178
|
throw new RangeError('requirements: min < max');
|
|
@@ -169,22 +181,38 @@ function rawValue(normalizedValue, min, max, skew = 1) {
|
|
|
169
181
|
: Math.exp(Math.log(clamp(normalizedValue, 0, 1)) / skew);
|
|
170
182
|
return min + v * (max - min);
|
|
171
183
|
}
|
|
184
|
+
/**
|
|
185
|
+
*
|
|
186
|
+
* @category Math
|
|
187
|
+
*/
|
|
172
188
|
function stepValue(value, step) {
|
|
173
189
|
var _a;
|
|
174
190
|
if (step <= 0)
|
|
175
191
|
throw new RangeError('requirements: step > 0');
|
|
176
192
|
const quotient = Math.floor(value / step);
|
|
177
|
-
const decimalDigits = (_a = decimalPart$1(step)) === null || _a ===
|
|
193
|
+
const decimalDigits = (_a = decimalPart$1(step)) === null || _a === undefined ? undefined : _a.length;
|
|
178
194
|
const v = toFixed$2(quotient * step, decimalDigits);
|
|
179
195
|
const next = toFixed$2((quotient + 1) * step, decimalDigits);
|
|
180
196
|
return Math.abs(value - v) < Math.abs(value - next) ? v : next;
|
|
181
197
|
}
|
|
198
|
+
/**
|
|
199
|
+
*
|
|
200
|
+
* @category Math
|
|
201
|
+
*/
|
|
182
202
|
function toFixed$2(x, fractionDigits) {
|
|
183
203
|
return Number(x.toFixed(fractionDigits));
|
|
184
204
|
}
|
|
205
|
+
/**
|
|
206
|
+
*
|
|
207
|
+
* @category Math
|
|
208
|
+
*/
|
|
185
209
|
function decimalPart$1(x) {
|
|
186
210
|
return String(x).split('.')[1];
|
|
187
211
|
}
|
|
212
|
+
/**
|
|
213
|
+
*
|
|
214
|
+
* @category Math
|
|
215
|
+
*/
|
|
188
216
|
function radian(degree) {
|
|
189
217
|
return (Math.PI * degree) / 180;
|
|
190
218
|
}
|
|
@@ -214,6 +242,62 @@ function styleHelper(value, op, influencer) {
|
|
|
214
242
|
}
|
|
215
243
|
}
|
|
216
244
|
}
|
|
245
|
+
/**
|
|
246
|
+
* @category Utility
|
|
247
|
+
*/
|
|
248
|
+
function mod(n, m) {
|
|
249
|
+
return (((n % m) + m) % m);
|
|
250
|
+
}
|
|
251
|
+
/**
|
|
252
|
+
* @category MIDI
|
|
253
|
+
*/
|
|
254
|
+
const noteNames = ['C', 'C#', 'D', 'D#', 'E', 'F', 'F#', 'G', 'G#', 'A', 'A#', 'B'];
|
|
255
|
+
/**
|
|
256
|
+
* @category MIDI
|
|
257
|
+
*/
|
|
258
|
+
function parseNoteName(noteName) {
|
|
259
|
+
const m = noteName.match(/^([a-g])(#{0,2}|b{0,2})(-?\d+)$/i);
|
|
260
|
+
if (!m)
|
|
261
|
+
throw new Error('Invalid note name');
|
|
262
|
+
const [, letter, accidental, octave] = m;
|
|
263
|
+
return {
|
|
264
|
+
letter: letter.toLocaleUpperCase(),
|
|
265
|
+
accidental: accidental,
|
|
266
|
+
octave: Number(octave),
|
|
267
|
+
};
|
|
268
|
+
}
|
|
269
|
+
/**
|
|
270
|
+
*
|
|
271
|
+
* @category MIDI
|
|
272
|
+
*/
|
|
273
|
+
function noteNumber(noteName) {
|
|
274
|
+
const { letter, accidental, octave, } = parseNoteName(noteName);
|
|
275
|
+
const noteIndex = noteNames.indexOf(letter.toLocaleUpperCase());
|
|
276
|
+
const accidentalValue = (accidental[0] == 'b' ? -1 : 1) * accidental.length;
|
|
277
|
+
return noteIndex + 12 * (Number(octave) + 1) + accidentalValue;
|
|
278
|
+
}
|
|
279
|
+
/**
|
|
280
|
+
*
|
|
281
|
+
* @category MIDI
|
|
282
|
+
*/
|
|
283
|
+
function noteName(noteNumber) {
|
|
284
|
+
const noteIndex = mod(noteNumber, 12);
|
|
285
|
+
const octave = Math.floor(noteNumber / 12) - 1;
|
|
286
|
+
return noteNames[noteIndex] + octave;
|
|
287
|
+
}
|
|
288
|
+
/**
|
|
289
|
+
* @category MIDI
|
|
290
|
+
*/
|
|
291
|
+
function isWhiteKey(note) {
|
|
292
|
+
const n = typeof note == 'string' ? noteNumber(note) : note;
|
|
293
|
+
return (mod(n, 12) == 0 ||
|
|
294
|
+
mod(n, 12) == 2 ||
|
|
295
|
+
mod(n, 12) == 4 ||
|
|
296
|
+
mod(n, 12) == 5 ||
|
|
297
|
+
mod(n, 12) == 7 ||
|
|
298
|
+
mod(n, 12) == 9 ||
|
|
299
|
+
mod(n, 12) == 11);
|
|
300
|
+
}
|
|
217
301
|
|
|
218
302
|
/**
|
|
219
303
|
* This hook is user-land implementation of the experimental `useEffectEvent` hook.
|
|
@@ -226,13 +310,13 @@ function useCallbackRef(callback, deps = []) {
|
|
|
226
310
|
React.useInsertionEffect(() => {
|
|
227
311
|
callbackRef.current = callback;
|
|
228
312
|
});
|
|
229
|
-
return React.useCallback((...args) => { var _a; return (_a = callbackRef.current) === null || _a ===
|
|
313
|
+
return React.useCallback((...args) => { var _a; return (_a = callbackRef.current) === null || _a === undefined ? undefined : _a.call(callbackRef, ...args); }, deps);
|
|
230
314
|
}
|
|
231
315
|
|
|
232
316
|
function useEventListener(target, event, handler, options) {
|
|
233
317
|
const listener = useCallbackRef(handler);
|
|
234
318
|
React.useEffect(() => {
|
|
235
|
-
const node = typeof target === 'function' ? target() : (target !== null && target !==
|
|
319
|
+
const node = typeof target === 'function' ? target() : (target !== null && target !== undefined ? target : document);
|
|
236
320
|
if (!handler || !node)
|
|
237
321
|
return;
|
|
238
322
|
node.addEventListener(event, listener, options);
|
|
@@ -241,8 +325,8 @@ function useEventListener(target, event, handler, options) {
|
|
|
241
325
|
};
|
|
242
326
|
}, [event, target, options, listener, handler]);
|
|
243
327
|
return () => {
|
|
244
|
-
const node = typeof target === 'function' ? target() : (target !== null && target !==
|
|
245
|
-
node === null || node ===
|
|
328
|
+
const node = typeof target === 'function' ? target() : (target !== null && target !== undefined ? target : document);
|
|
329
|
+
node === null || node === undefined ? undefined : node.removeEventListener(event, listener, options);
|
|
246
330
|
};
|
|
247
331
|
}
|
|
248
332
|
|
|
@@ -251,7 +335,7 @@ function useRefCallbackEvent(event, handler, options, deps = []) {
|
|
|
251
335
|
let cleanup;
|
|
252
336
|
return (node) => {
|
|
253
337
|
if (!node) {
|
|
254
|
-
cleanup === null || cleanup ===
|
|
338
|
+
cleanup === null || cleanup === undefined ? undefined : cleanup();
|
|
255
339
|
return;
|
|
256
340
|
}
|
|
257
341
|
node.addEventListener(event, handler, options);
|
|
@@ -262,6 +346,13 @@ function useRefCallbackEvent(event, handler, options, deps = []) {
|
|
|
262
346
|
}, deps);
|
|
263
347
|
}
|
|
264
348
|
|
|
349
|
+
function addNoSelect() {
|
|
350
|
+
document.body.classList.add('tremolo-no-select');
|
|
351
|
+
}
|
|
352
|
+
function removeNoSelect() {
|
|
353
|
+
document.body.classList.remove('tremolo-no-select');
|
|
354
|
+
}
|
|
355
|
+
|
|
265
356
|
const defaultOptions = {
|
|
266
357
|
active: '#7998ec',
|
|
267
358
|
inactive: '#eee',
|
|
@@ -274,14 +365,14 @@ const defaultOptions = {
|
|
|
274
365
|
* simple rotary Knob.
|
|
275
366
|
*/
|
|
276
367
|
function Knob(_a) {
|
|
277
|
-
var { value, min, max, defaultValue = min, startValue = min, step = 1, skew = 1, size, width = 50, height = 50, options = defaultOptions, draw, bodyNoSelect = true,
|
|
368
|
+
var { value, min, max, defaultValue = min, startValue = min, step = 1, skew = 1, size, width = 50, height = 50, options = defaultOptions, draw, bodyNoSelect = true, wheel, enableDoubleClickDefault = true, style, className, onChange, _active, _focus, _hover } = _a, props = __rest(_a, ["value", "min", "max", "defaultValue", "startValue", "step", "skew", "size", "width", "height", "options", "draw", "bodyNoSelect", "wheel", "enableDoubleClickDefault", "style", "className", "onChange", "_active", "_focus", "_hover"]);
|
|
278
369
|
// -- state and ref ---
|
|
279
370
|
// const [privateValue, setPrivateValue] = useState(value);
|
|
280
371
|
const dragOffsetY = React.useRef(undefined);
|
|
281
372
|
// --- interpret props ---
|
|
282
373
|
const opts = Object.assign(Object.assign({}, defaultOptions), options);
|
|
283
374
|
// const percent = normalizeValue(value, min, max, skew)
|
|
284
|
-
const isRelativeSize = typeof (size !== null && size !==
|
|
375
|
+
const isRelativeSize = typeof (size !== null && size !== undefined ? size : width) == 'string';
|
|
285
376
|
const adaptSize = (size) => {
|
|
286
377
|
if (typeof size == 'string') {
|
|
287
378
|
return Number(size.slice(0, -1));
|
|
@@ -296,7 +387,7 @@ function Knob(_a) {
|
|
|
296
387
|
event.preventDefault();
|
|
297
388
|
if (dragOffsetY.current) {
|
|
298
389
|
if (bodyNoSelect)
|
|
299
|
-
|
|
390
|
+
addNoSelect();
|
|
300
391
|
const screenY = isTouch ? event.touches[0].screenY : event.screenY;
|
|
301
392
|
const delta = dragOffsetY.current - screenY;
|
|
302
393
|
dragOffsetY.current = screenY;
|
|
@@ -309,12 +400,12 @@ function Knob(_a) {
|
|
|
309
400
|
};
|
|
310
401
|
// --- hooks ---
|
|
311
402
|
const wheelRefCallback = useRefCallbackEvent('wheel', (event) => {
|
|
312
|
-
if (!
|
|
403
|
+
if (!wheel)
|
|
313
404
|
return;
|
|
314
405
|
event.preventDefault();
|
|
315
|
-
const x = event.deltaY > 0 ? -
|
|
406
|
+
const x = event.deltaY > 0 ? -wheel[1] : wheel[1];
|
|
316
407
|
let v;
|
|
317
|
-
if (
|
|
408
|
+
if (wheel[0] == 'normalized') {
|
|
318
409
|
const n = normalizeValue(value, min, max, skew);
|
|
319
410
|
v = rawValue(n + x, min, max, skew);
|
|
320
411
|
}
|
|
@@ -323,18 +414,18 @@ function Knob(_a) {
|
|
|
323
414
|
}
|
|
324
415
|
if (onChange)
|
|
325
416
|
onChange(clamp(stepValue(v, step), min, max));
|
|
326
|
-
}, { passive: false }, [
|
|
417
|
+
}, { passive: false }, [wheel, value, min, max, skew, step, onChange]);
|
|
327
418
|
const touchMoveRefCallback = useRefCallbackEvent('touchmove', handleEvent, { passive: false }, [value, min, max, skew, step, onChange, bodyNoSelect]);
|
|
328
419
|
useEventListener(window, 'mousemove', handleEvent);
|
|
329
420
|
useEventListener(window, 'pointerup', () => {
|
|
330
421
|
dragOffsetY.current = undefined;
|
|
331
422
|
if (bodyNoSelect)
|
|
332
|
-
|
|
423
|
+
removeNoSelect();
|
|
333
424
|
});
|
|
334
425
|
return (jsxRuntime.jsxs("div", Object.assign({ className: clsx('tremolo-knob', className), ref: (div) => {
|
|
335
426
|
wheelRefCallback(div);
|
|
336
427
|
touchMoveRefCallback(div);
|
|
337
|
-
}, role: "slider", tabIndex: 0, "aria-valuenow": value, "aria-valuemax": max, "aria-valuemin": min, css: react.css(Object.assign(Object.assign({ display: 'inline-block', width: size !== null && size !==
|
|
428
|
+
}, role: "slider", tabIndex: 0, "aria-valuenow": value, "aria-valuemax": max, "aria-valuemin": min, css: react.css(Object.assign(Object.assign({ display: 'inline-block', width: size !== null && size !== undefined ? size : width, height: size !== null && size !== undefined ? size : height, cursor: 'pointer' }, style), { ':active': Object.assign({}, _active), ':focus': Object.assign({}, _focus), ':hover': Object.assign({}, _hover) })), onPointerDown: (event) => {
|
|
338
429
|
dragOffsetY.current = event.screenY;
|
|
339
430
|
handleEvent(event);
|
|
340
431
|
}, onDoubleClick: () => {
|
|
@@ -345,7 +436,7 @@ function Knob(_a) {
|
|
|
345
436
|
'.no-select': {
|
|
346
437
|
userSelect: 'none',
|
|
347
438
|
},
|
|
348
|
-
} }), jsxRuntime.jsx(AnimationCanvas, { width: adaptSize(size !== null && size !==
|
|
439
|
+
} }), jsxRuntime.jsx(AnimationCanvas, { width: adaptSize(size !== null && size !== undefined ? size : width), height: adaptSize(size !== null && size !== undefined ? size : height), relativeSize: isRelativeSize,
|
|
349
440
|
// TODO
|
|
350
441
|
// reduceFlickering={false}
|
|
351
442
|
draw: draw ? draw : (ctx, width, height) => {
|
|
@@ -390,10 +481,21 @@ function Knob(_a) {
|
|
|
390
481
|
} })] })));
|
|
391
482
|
}
|
|
392
483
|
|
|
484
|
+
/**
|
|
485
|
+
* clamp value between min and max
|
|
486
|
+
* @category Math
|
|
487
|
+
*/
|
|
488
|
+
/**
|
|
489
|
+
*
|
|
490
|
+
* @category Math
|
|
491
|
+
*/
|
|
393
492
|
function toFixed$1(x, fractionDigits) {
|
|
394
493
|
return Number(x.toFixed(fractionDigits));
|
|
395
494
|
}
|
|
396
495
|
|
|
496
|
+
/**
|
|
497
|
+
* @module NumberInput
|
|
498
|
+
*/
|
|
397
499
|
function selectUnit(units, value) {
|
|
398
500
|
if (typeof units == 'string')
|
|
399
501
|
return [units, 1];
|
|
@@ -456,14 +558,14 @@ function parseValue(inputString, units, digit, defaultValue = 0) {
|
|
|
456
558
|
* Input with some useful functions for entering numerical values.
|
|
457
559
|
*/
|
|
458
560
|
function NumberInput(_a) {
|
|
459
|
-
var { value, min, max, step, defaultValue = min, units, disabled = false, placeholder, readOnly, tabIndex,
|
|
561
|
+
var { value, min, max, step, defaultValue = min, units, disabled = false, placeholder, readOnly, tabIndex, typeNumber = false, digit, selectWithFocus = 'none', blurWithEnter = true, className, style, onChange, onFocus, onBlur } = _a, props = __rest(_a, ["value", "min", "max", "step", "defaultValue", "units", "disabled", "placeholder", "readOnly", "tabIndex", "typeNumber", "digit", "selectWithFocus", "blurWithEnter", "className", "style", "onChange", "onFocus", "onBlur"]);
|
|
460
562
|
const [showValue, setShowValue] = React.useState(parseValue(String(value), units, digit, defaultValue).formatValue);
|
|
461
|
-
const
|
|
462
|
-
const { _active, _focus, _hover } =
|
|
463
|
-
return (jsxRuntime.jsx("input", { className: clsx('tremolo-number-input', className), value: showValue, min: min, max: max, step: step, type:
|
|
563
|
+
const calculatedTypeNumber = units ? false : typeNumber;
|
|
564
|
+
const { _active, _focus, _hover } = props, rest = __rest(props, ["_active", "_focus", "_hover"]);
|
|
565
|
+
return (jsxRuntime.jsx("input", Object.assign({ className: clsx('tremolo-number-input', className), value: showValue, min: min, max: max, step: step, type: calculatedTypeNumber ? 'number' : 'text', spellCheck: 'false', disabled: disabled, placeholder: placeholder, readOnly: readOnly, tabIndex: tabIndex, css: react.css(Object.assign(Object.assign({ display: 'inline-block', font: 'inherit', margin: 0, paddingTop: 6, paddingBottom: 6, paddingLeft: 10, paddingRight: 10, borderStyle: 'solid', borderWidth: 1, borderColor: '#bbb', borderRadius: 4, outline: 0, transition: 'all 0.1s linear', appearance: 'textfield', '&:hover': Object.assign({ borderColor: 'var(--tremolo-theme-color)' }, _hover), '&:focus': Object.assign({ borderColor: 'var(--tremolo-theme-color)', boxShadow: '0px 0px 0px 2px rgba(var(--tremolo-theme-color-rgb), 0.1)' }, _focus) }, (_active && { '&:active': Object.assign({}, _active) })), style)), onChange: (event) => {
|
|
464
566
|
const v = event.currentTarget.value;
|
|
465
567
|
setShowValue(v);
|
|
466
|
-
const newValue = clamp(parseValue(v, units, digit, defaultValue).rawValue, min !== null && min !==
|
|
568
|
+
const newValue = clamp(parseValue(v, units, digit, defaultValue).rawValue, min !== null && min !== undefined ? min : -Infinity, max !== null && max !== undefined ? max : Infinity);
|
|
467
569
|
if (onChange)
|
|
468
570
|
onChange(newValue, event);
|
|
469
571
|
}, onFocus: (event) => {
|
|
@@ -488,16 +590,286 @@ function NumberInput(_a) {
|
|
|
488
590
|
if (blurWithEnter && event.key == 'Enter') {
|
|
489
591
|
event.currentTarget.blur();
|
|
490
592
|
}
|
|
491
|
-
} }));
|
|
593
|
+
} }, rest)));
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
function KeyLabel({ label, className, style, wrapperStyle, __note, __index, __label, }) {
|
|
597
|
+
const content = label ? label(__note, __index) : __label && __label(__note, __index);
|
|
598
|
+
return ((content != undefined || content != null) &&
|
|
599
|
+
jsxRuntime.jsx("div", { className: 'tremolo-piano-key-label-wrapper', css: react.css(Object.assign({ display: 'flex', justifyContent: 'center', alignItems: 'end', height: '100%' }, wrapperStyle)), children: jsxRuntime.jsx("div", { className: clsx('tremolo-piano-key-label', className), css: react.css(Object.assign({ display: 'flex', justifyContent: 'center', alignItems: 'center', fontSize: '0.6rem', height: 10, marginBottom: 10, padding: 4, borderRadius: 4, borderStyle: 'solid', borderWidth: 1, borderColor: '#888', aspectRatio: 1, maxWidth: 'calc(100% - 16px)' }, style)), children: content }) }));
|
|
492
600
|
}
|
|
493
601
|
|
|
602
|
+
const WhiteKey = React.forwardRef(({ width = 40, height = '100%', bg = 'white', activeBg = '#ccc', style, children, __glissando, __position, __note, __disabled, __index, __fill, __width, __playNote, __stopNote, __label, }, ref) => {
|
|
603
|
+
const [played, setPlayed] = React.useState(false);
|
|
604
|
+
React.useImperativeHandle(ref, () => {
|
|
605
|
+
return {
|
|
606
|
+
play() {
|
|
607
|
+
if (__disabled)
|
|
608
|
+
return;
|
|
609
|
+
setPlayed(true);
|
|
610
|
+
if (__playNote)
|
|
611
|
+
__playNote(__note);
|
|
612
|
+
},
|
|
613
|
+
stop() {
|
|
614
|
+
setPlayed(false);
|
|
615
|
+
if (__stopNote)
|
|
616
|
+
__stopNote(__note);
|
|
617
|
+
},
|
|
618
|
+
played() {
|
|
619
|
+
return played;
|
|
620
|
+
}
|
|
621
|
+
};
|
|
622
|
+
}, []);
|
|
623
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
624
|
+
let keyLabelProps;
|
|
625
|
+
if (children != undefined) {
|
|
626
|
+
React.Children.forEach(children, (child) => {
|
|
627
|
+
if (React.isValidElement(child)) {
|
|
628
|
+
if (child.type == KeyLabel) {
|
|
629
|
+
keyLabelProps = child.props;
|
|
630
|
+
}
|
|
631
|
+
else {
|
|
632
|
+
throw new Error('only <KeyLabel>');
|
|
633
|
+
}
|
|
634
|
+
}
|
|
635
|
+
else {
|
|
636
|
+
throw new Error('children is an invalid element.');
|
|
637
|
+
}
|
|
638
|
+
});
|
|
639
|
+
}
|
|
640
|
+
return (jsxRuntime.jsx("div", { className: `tremolo-piano-white-key`, "aria-disabled": __disabled, css: react.css(Object.assign({ position: 'absolute', backgroundColor: played ? activeBg : bg, color: 'black', left: __position, width: __fill ? __width : (width !== null && width !== undefined ? width : __width), height: height, border: '1px solid #555', borderRadius: '0 0 8px 8px', cursor: __disabled ? 'not-allowed' : 'pointer', zIndex: 1 }, style)), onPointerDown: () => {
|
|
641
|
+
if (__disabled)
|
|
642
|
+
return;
|
|
643
|
+
setPlayed(true);
|
|
644
|
+
if (__playNote)
|
|
645
|
+
__playNote(__note);
|
|
646
|
+
}, onPointerEnter: () => {
|
|
647
|
+
if (__disabled)
|
|
648
|
+
return;
|
|
649
|
+
if (__glissando) {
|
|
650
|
+
setPlayed(true);
|
|
651
|
+
if (__playNote)
|
|
652
|
+
__playNote(__note);
|
|
653
|
+
}
|
|
654
|
+
}, onPointerUp: () => {
|
|
655
|
+
if (__disabled)
|
|
656
|
+
return;
|
|
657
|
+
setPlayed(false);
|
|
658
|
+
if (__stopNote)
|
|
659
|
+
__stopNote(__note);
|
|
660
|
+
}, onPointerLeave: () => {
|
|
661
|
+
if (__disabled)
|
|
662
|
+
return;
|
|
663
|
+
setPlayed(false);
|
|
664
|
+
if (__stopNote)
|
|
665
|
+
__stopNote(__note);
|
|
666
|
+
}, children: jsxRuntime.jsx(KeyLabel, Object.assign({ __note: __note, __label: __label, __index: __index }, keyLabelProps)) }));
|
|
667
|
+
});
|
|
668
|
+
|
|
669
|
+
const BlackKey = React.forwardRef(({ width = 40 * 0.65, height = '60%', bg = '#333', activeBg = '#666', style, children, __glissando, __position, __note, __disabled, __index, __fill, __width, __playNote, __stopNote, __label, }, ref) => {
|
|
670
|
+
const [played, setPlayed] = React.useState(false);
|
|
671
|
+
React.useImperativeHandle(ref, () => {
|
|
672
|
+
return {
|
|
673
|
+
play() {
|
|
674
|
+
if (__disabled)
|
|
675
|
+
return;
|
|
676
|
+
setPlayed(true);
|
|
677
|
+
if (__playNote)
|
|
678
|
+
__playNote(__note);
|
|
679
|
+
},
|
|
680
|
+
stop() {
|
|
681
|
+
setPlayed(false);
|
|
682
|
+
if (__stopNote)
|
|
683
|
+
__stopNote(__note);
|
|
684
|
+
},
|
|
685
|
+
played() {
|
|
686
|
+
return played;
|
|
687
|
+
}
|
|
688
|
+
};
|
|
689
|
+
}, []);
|
|
690
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
691
|
+
let keyLabelProps;
|
|
692
|
+
if (children != undefined) {
|
|
693
|
+
React.Children.forEach(children, (child) => {
|
|
694
|
+
if (React.isValidElement(child)) {
|
|
695
|
+
if (child.type == KeyLabel) {
|
|
696
|
+
keyLabelProps = child.props;
|
|
697
|
+
}
|
|
698
|
+
else {
|
|
699
|
+
throw new Error('only <KeyLabel>');
|
|
700
|
+
}
|
|
701
|
+
}
|
|
702
|
+
else {
|
|
703
|
+
throw new Error('children is an invalid element.');
|
|
704
|
+
}
|
|
705
|
+
});
|
|
706
|
+
}
|
|
707
|
+
return (jsxRuntime.jsx("div", { className: `tremolo-piano-black-key`, "aria-disabled": __disabled, css: react.css(Object.assign({ position: 'absolute', backgroundColor: played ? activeBg : bg, color: 'white', left: __position, width: __fill ? __width : (width !== null && width !== undefined ? width : __width), height: height, border: '1px solid #555', borderRadius: '0 0 8px 8px', cursor: __disabled ? 'not-allowed' : 'pointer', zIndex: 2 }, style)), onPointerDown: () => {
|
|
708
|
+
if (__disabled)
|
|
709
|
+
return;
|
|
710
|
+
setPlayed(true);
|
|
711
|
+
if (__playNote)
|
|
712
|
+
__playNote(__note);
|
|
713
|
+
}, onPointerEnter: () => {
|
|
714
|
+
if (__disabled)
|
|
715
|
+
return;
|
|
716
|
+
if (__glissando) {
|
|
717
|
+
setPlayed(true);
|
|
718
|
+
if (__playNote)
|
|
719
|
+
__playNote(__note);
|
|
720
|
+
}
|
|
721
|
+
}, onPointerUp: () => {
|
|
722
|
+
if (__disabled)
|
|
723
|
+
return;
|
|
724
|
+
setPlayed(false);
|
|
725
|
+
if (__stopNote)
|
|
726
|
+
__stopNote(__note);
|
|
727
|
+
}, onPointerLeave: () => {
|
|
728
|
+
if (__disabled)
|
|
729
|
+
return;
|
|
730
|
+
setPlayed(false);
|
|
731
|
+
if (__stopNote)
|
|
732
|
+
__stopNote(__note);
|
|
733
|
+
}, children: jsxRuntime.jsx(KeyLabel, Object.assign({ __note: __note, __label: __label, __index: __index }, keyLabelProps)) }));
|
|
734
|
+
});
|
|
735
|
+
|
|
736
|
+
const Shortcuts = {
|
|
737
|
+
HOME_ROW: {
|
|
738
|
+
keys: ['a', 'w', 's', 'e', 'd', 'f', 't', 'g', 'y', 'h', 'u', 'j', 'k', 'o', 'l', 'p', ';']
|
|
739
|
+
}
|
|
740
|
+
};
|
|
741
|
+
|
|
742
|
+
function Piano({ noteRange, glissando = true, midiMax = 127, keyboardShortcuts, fill = false, height = fill ? '100%' : 160, style, playNote, stopNote, label, children, }) {
|
|
743
|
+
// -- state and ref ---
|
|
744
|
+
const [pressed, setPressed] = React.useState(false);
|
|
745
|
+
const [whiteNoteWidth, setWhiteNoteWidth] = React.useState(-1);
|
|
746
|
+
const keyRefs = React.useRef([]);
|
|
747
|
+
for (let i = 0; i < noteRange.last - noteRange.first + 1; i++) {
|
|
748
|
+
keyRefs.current[i] = React.createRef();
|
|
749
|
+
}
|
|
750
|
+
const pianoRef = React.useRef(null);
|
|
751
|
+
// --- interpret props ---
|
|
752
|
+
const noteRangeArray = Array.from({ length: noteRange.last - noteRange.first + 1 }, (_, i) => i + noteRange.first);
|
|
753
|
+
const whiteNoteCount = noteRangeArray.filter((v) => isWhiteKey(v)).length;
|
|
754
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
755
|
+
let whiteKeyProps, blackKeyProps;
|
|
756
|
+
if (children != undefined) {
|
|
757
|
+
React.Children.forEach(children, (child) => {
|
|
758
|
+
if (React.isValidElement(child)) {
|
|
759
|
+
if (child.type == WhiteKey) {
|
|
760
|
+
whiteKeyProps = child.props;
|
|
761
|
+
}
|
|
762
|
+
else if (child.type == BlackKey) {
|
|
763
|
+
blackKeyProps = child.props;
|
|
764
|
+
}
|
|
765
|
+
else {
|
|
766
|
+
throw new Error('only <WhiteKey> or <BlackKey>');
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
else {
|
|
770
|
+
throw new Error('children is an invalid element.');
|
|
771
|
+
}
|
|
772
|
+
});
|
|
773
|
+
}
|
|
774
|
+
// --- internal functions ---
|
|
775
|
+
function notePosition(note) {
|
|
776
|
+
const pitchPositions = {
|
|
777
|
+
C: 0,
|
|
778
|
+
'C#': 0.55,
|
|
779
|
+
D: 1,
|
|
780
|
+
'D#': 1.8,
|
|
781
|
+
E: 2,
|
|
782
|
+
F: 3,
|
|
783
|
+
'F#': 3.5,
|
|
784
|
+
G: 4,
|
|
785
|
+
'G#': 4.7,
|
|
786
|
+
A: 5,
|
|
787
|
+
'A#': 5.85,
|
|
788
|
+
B: 6,
|
|
789
|
+
};
|
|
790
|
+
const toNoteName = (n) => {
|
|
791
|
+
const { letter, accidental } = parseNoteName(noteName(n));
|
|
792
|
+
return (letter + accidental);
|
|
793
|
+
};
|
|
794
|
+
const _noteName = toNoteName(note);
|
|
795
|
+
const firstNoteName = toNoteName(noteRange.first);
|
|
796
|
+
const pos = pitchPositions[_noteName] - pitchPositions[firstNoteName];
|
|
797
|
+
const octave = Math.floor((note - noteRange.first) / 12);
|
|
798
|
+
const octaveOffset = noteNames.indexOf(firstNoteName) > noteNames.indexOf(_noteName) ? 1 : 0;
|
|
799
|
+
const length = whiteNoteWidth + 3;
|
|
800
|
+
return pos * length + (octave + octaveOffset) * 7 * length;
|
|
801
|
+
}
|
|
802
|
+
// --- hooks ---
|
|
803
|
+
React.useEffect(() => {
|
|
804
|
+
if (fill && pianoRef.current) {
|
|
805
|
+
const parent = pianoRef.current.parentElement;
|
|
806
|
+
if (!parent)
|
|
807
|
+
throw new Error("doesn't have a parent element.");
|
|
808
|
+
const resizeObserver = new ResizeObserver(() => {
|
|
809
|
+
const w = pianoRef.current.clientWidth;
|
|
810
|
+
setWhiteNoteWidth(w / whiteNoteCount - 3);
|
|
811
|
+
});
|
|
812
|
+
resizeObserver.observe(parent);
|
|
813
|
+
}
|
|
814
|
+
else {
|
|
815
|
+
setWhiteNoteWidth((whiteKeyProps === null || whiteKeyProps === undefined ? undefined : whiteKeyProps.width) || 40);
|
|
816
|
+
}
|
|
817
|
+
}, []);
|
|
818
|
+
useEventListener(window, 'keydown', (e) => {
|
|
819
|
+
var _a, _b, _c, _d;
|
|
820
|
+
if (e.repeat)
|
|
821
|
+
return;
|
|
822
|
+
if (!keyboardShortcuts)
|
|
823
|
+
return;
|
|
824
|
+
const index = keyboardShortcuts.keys.indexOf(e.key);
|
|
825
|
+
if (index != -1) {
|
|
826
|
+
if (!((_b = (_a = keyRefs.current[index]) === null || _a === undefined ? undefined : _a.current) === null || _b === undefined ? undefined : _b.played())) {
|
|
827
|
+
(_d = (_c = keyRefs.current[index]) === null || _c === undefined ? undefined : _c.current) === null || _d === undefined ? undefined : _d.play();
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
});
|
|
831
|
+
useEventListener(window, 'keyup', (e) => {
|
|
832
|
+
var _a, _b;
|
|
833
|
+
if (e.repeat)
|
|
834
|
+
return;
|
|
835
|
+
if (!keyboardShortcuts)
|
|
836
|
+
return;
|
|
837
|
+
const index = keyboardShortcuts.keys.indexOf(e.key);
|
|
838
|
+
if (index != -1) {
|
|
839
|
+
(_b = (_a = keyRefs.current[index]) === null || _a === undefined ? undefined : _a.current) === null || _b === undefined ? undefined : _b.stop();
|
|
840
|
+
}
|
|
841
|
+
});
|
|
842
|
+
return (jsxRuntime.jsx("div", { ref: pianoRef, className: "tremolo-piano", css: react.css(Object.assign({ display: 'inline-block', boxSizing: 'border-box', userSelect: 'none', width: fill ? '100%' : undefined, height: height, position: 'relative' }, style)), onPointerDown: () => {
|
|
843
|
+
setPressed(true);
|
|
844
|
+
}, onPointerUp: () => {
|
|
845
|
+
setPressed(false);
|
|
846
|
+
}, children: noteRangeArray.map((note, index) => {
|
|
847
|
+
return (isWhiteKey(note) ? (jsxRuntime.jsx(WhiteKey, Object.assign({ ref: keyRefs.current[index], __glissando: glissando && pressed, __position: notePosition(note), __note: note, __disabled: note > midiMax, __index: index, __fill: fill, __width: whiteNoteWidth, __playNote: playNote, __stopNote: stopNote, __label: label }, whiteKeyProps), note)) : (jsxRuntime.jsx(BlackKey, Object.assign({ ref: keyRefs.current[index], __glissando: glissando && pressed, __position: notePosition(note), __note: note, __disabled: note > midiMax, __index: index, __fill: fill, __width: whiteNoteWidth * 0.65, __playNote: playNote, __stopNote: stopNote, __label: label }, blackKeyProps), note)));
|
|
848
|
+
}) }));
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
/**
|
|
852
|
+
* clamp value between min and max
|
|
853
|
+
* @category Math
|
|
854
|
+
*/
|
|
855
|
+
/**
|
|
856
|
+
*
|
|
857
|
+
* @category Math
|
|
858
|
+
*/
|
|
494
859
|
function toFixed(x, fractionDigits) {
|
|
495
860
|
return Number(x.toFixed(fractionDigits));
|
|
496
861
|
}
|
|
862
|
+
/**
|
|
863
|
+
*
|
|
864
|
+
* @category Math
|
|
865
|
+
*/
|
|
497
866
|
function decimalPart(x) {
|
|
498
867
|
return String(x).split('.')[1];
|
|
499
868
|
}
|
|
500
869
|
|
|
870
|
+
/**
|
|
871
|
+
* @module Slider
|
|
872
|
+
*/
|
|
501
873
|
function isHorizontal(d) {
|
|
502
874
|
return d == 'right' || d == 'left';
|
|
503
875
|
}
|
|
@@ -526,46 +898,76 @@ function parseScaleOrderList(scale, min, max, step) {
|
|
|
526
898
|
const per = scale[0] == 'step' ? step : scale[0];
|
|
527
899
|
const count = Math.floor(max / per) - Math.ceil(min / per) + 1;
|
|
528
900
|
for (let i = 0; i < count; i++) {
|
|
529
|
-
const at = toFixed(per * (Math.ceil(min / per) + i), (_a = decimalPart(per)) === null || _a ===
|
|
901
|
+
const at = toFixed(per * (Math.ceil(min / per) + i), (_a = decimalPart(per)) === null || _a === undefined ? undefined : _a.length);
|
|
530
902
|
scalesList.push({ at: at, type: scale[1] });
|
|
531
903
|
}
|
|
532
904
|
}
|
|
533
905
|
return scalesList;
|
|
534
906
|
}
|
|
535
907
|
|
|
536
|
-
|
|
537
|
-
|
|
908
|
+
const SliderThumb = React.forwardRef(({ size, width = 22, height = 22, color = '#4e76e6', hoverColor = color, disabledColor = '#5d6478', disabledHoverColor = disabledColor, zIndex = 100, children, className, style, __disabled, __css, }, ref) => {
|
|
909
|
+
const wrapperRef = React.useRef(null);
|
|
910
|
+
React.useImperativeHandle(ref, () => {
|
|
911
|
+
return {
|
|
912
|
+
focus() {
|
|
913
|
+
var _a;
|
|
914
|
+
(_a = wrapperRef.current) === null || _a === undefined ? undefined : _a.focus();
|
|
915
|
+
},
|
|
916
|
+
blur() {
|
|
917
|
+
var _a;
|
|
918
|
+
(_a = wrapperRef.current) === null || _a === undefined ? undefined : _a.blur();
|
|
919
|
+
},
|
|
920
|
+
};
|
|
921
|
+
}, []);
|
|
922
|
+
return (jsxRuntime.jsx("div", { className: "tremolo-slider-thumb-wrapper", css: react.css(Object.assign({ position: 'absolute', translate: '-50% -50%', zIndex: zIndex }, __css)), children: children ? (children) : (
|
|
538
923
|
// default slider thumb
|
|
539
|
-
jsxRuntime.jsx("div", { className:
|
|
924
|
+
jsxRuntime.jsx("div", { ref: wrapperRef, className: clsx('tremolo-slider-thumb', className),
|
|
540
925
|
// eslint-disable-next-line jsx-a11y/no-noninteractive-tabindex
|
|
541
|
-
tabIndex: 0, css: react.css(Object.assign({ background: color, width:
|
|
542
|
-
background:
|
|
543
|
-
}, '&:
|
|
926
|
+
tabIndex: 0, css: react.css(Object.assign({ background: __disabled ? disabledColor : color, width: size !== null && size !== undefined ? size : width, height: size !== null && size !== undefined ? size : height, borderRadius: '50%', outline: 'none', '&:hover': {
|
|
927
|
+
background: __disabled ? disabledHoverColor : hoverColor
|
|
928
|
+
}, '&:focus': !__disabled && {
|
|
544
929
|
boxShadow: '0px 0px 0px 3px rgba(var(--tremolo-theme-color-rgb), 0.2)',
|
|
545
930
|
} }, style)) })) }));
|
|
546
|
-
}
|
|
931
|
+
});
|
|
547
932
|
|
|
548
|
-
function SliderTrack({ children, style,
|
|
549
|
-
|
|
933
|
+
function SliderTrack({ length = 140, thickness = 10, activeBg = '#7998ec', inactiveBg = '#eee', activeHoverBg = '#6387e9', inactiveHoverBg = '#e0e0e0', disabledActiveBg = '#858890', disabledInactiveBg = '#ddd', disabledActiveHoverBg = disabledActiveBg, disabledInactiveHoverBg = disabledInactiveBg, children, className, style, __thumb, __direction, __disabled, __percent, }) {
|
|
934
|
+
const active = __disabled ? disabledActiveBg : activeBg;
|
|
935
|
+
const inactive = __disabled ? disabledInactiveBg : inactiveBg;
|
|
936
|
+
const activeHover = __disabled ? disabledActiveHoverBg : activeHoverBg;
|
|
937
|
+
const inactiveHover = __disabled ? disabledInactiveHoverBg : inactiveHoverBg;
|
|
938
|
+
return (jsxRuntime.jsxs("div", { className: clsx('tremolo-slider-track', className), css: react.css(Object.assign({ position: 'relative', background: `linear-gradient(to ${gradientDirection(__direction)}, ${active} ${__percent}%, ${inactive} ${__percent}%)`, borderRadius: styleHelper(thickness, '/', 2), width: isHorizontal(__direction) ? length : thickness, height: isHorizontal(__direction) ? thickness : length, ':hover': {
|
|
939
|
+
background: `linear-gradient(to ${gradientDirection(__direction)}, ${activeHover} ${__percent}%, ${inactiveHover} ${__percent}%)`
|
|
940
|
+
} }, style)), children: [children, __thumb] }));
|
|
550
941
|
}
|
|
551
942
|
|
|
552
943
|
/**
|
|
553
944
|
* Customizable slider
|
|
554
945
|
*/
|
|
555
|
-
|
|
556
|
-
var _b, _c;
|
|
557
|
-
var { value, min, max, step = 1, skew = 1,
|
|
946
|
+
const Slider = React.forwardRef((_a, ref) => {
|
|
947
|
+
var _b, _c, _d, _e, _f, _g, _h;
|
|
948
|
+
var { value, min, max, step = 1, skew = 1, direction = 'right', scale, scaleOption, className, style, bodyNoSelect = true, wheel = ['raw', 1], keyboard = ['raw', 1], disabled = false, readonly = false, onChange, children } = _a; __rest(_a, ["value", "min", "max", "step", "skew", "direction", "scale", "scaleOption", "className", "style", "bodyNoSelect", "wheel", "keyboard", "disabled", "readonly", "onChange", "children"]);
|
|
558
949
|
// -- state and ref ---
|
|
559
950
|
const trackElementRef = React.useRef(null);
|
|
560
|
-
const
|
|
561
|
-
const
|
|
951
|
+
const thumbRef = React.useRef(null);
|
|
952
|
+
const thumbDragged = React.useRef(false);
|
|
953
|
+
const percent = toFixed$2(normalizeValue(value, min, max, skew) * 100);
|
|
954
|
+
const percentRev = isReversed(direction) ? toFixed$2(100 - percent) : percent;
|
|
955
|
+
const calcPercent = (v) => {
|
|
956
|
+
return toFixed$2(isReversed(direction)
|
|
957
|
+
? 100 - normalizeValue(v, min, max, skew) * 100
|
|
958
|
+
: normalizeValue(v, min, max, skew) * 100);
|
|
959
|
+
};
|
|
960
|
+
if (wheel.length != 2) {
|
|
961
|
+
throw new Error(`Slider.wheel expect ['normalized' | 'raw', number]`);
|
|
962
|
+
}
|
|
963
|
+
if (keyboard.length != 2) {
|
|
964
|
+
throw new Error(`Slider.keyboard expect ['normalized' | 'raw', number]`);
|
|
965
|
+
}
|
|
562
966
|
const scalesList = parseScaleOrderList(scale, min, max, step);
|
|
563
967
|
if (isReversed(direction))
|
|
564
968
|
scalesList.reverse();
|
|
565
969
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
566
|
-
let trackProps;
|
|
567
|
-
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
568
|
-
let thumbProps;
|
|
970
|
+
let trackProps, thumbProps;
|
|
569
971
|
if (children != undefined) {
|
|
570
972
|
React.Children.forEach(children, (child) => {
|
|
571
973
|
if (React.isValidElement(child)) {
|
|
@@ -584,15 +986,15 @@ function Slider(_a) {
|
|
|
584
986
|
}
|
|
585
987
|
});
|
|
586
988
|
}
|
|
587
|
-
|
|
989
|
+
// --- internal functions ---
|
|
588
990
|
const handleValue = (event) => {
|
|
589
|
-
if (!trackElementRef.current || !thumbDragged.current)
|
|
991
|
+
if (!trackElementRef.current || !thumbDragged.current || !onChange || readonly)
|
|
590
992
|
return;
|
|
591
993
|
const isTouch = event instanceof TouchEvent;
|
|
592
994
|
if (isTouch && event.cancelable)
|
|
593
995
|
event.preventDefault();
|
|
594
996
|
if (bodyNoSelect)
|
|
595
|
-
|
|
997
|
+
addNoSelect();
|
|
596
998
|
const { left: x1, top: y1, right: x2, bottom: y2, } = trackElementRef.current.getBoundingClientRect();
|
|
597
999
|
const mouseX = isTouch ? event.touches[0].clientX : event.clientX;
|
|
598
1000
|
const mouseY = isTouch ? event.touches[0].clientY : event.clientY;
|
|
@@ -600,70 +1002,90 @@ function Slider(_a) {
|
|
|
600
1002
|
? normalizeValue(mouseX, x1, x2)
|
|
601
1003
|
: normalizeValue(mouseY, y1, y2);
|
|
602
1004
|
const v = rawValue(isReversed(direction) ? 1 - n : n, min, max, skew);
|
|
603
|
-
|
|
604
|
-
if (onChange)
|
|
605
|
-
onChange(v2);
|
|
1005
|
+
onChange(clamp(stepValue(v, step), min, max));
|
|
606
1006
|
};
|
|
1007
|
+
const handleKeyDown = React.useCallback((event) => {
|
|
1008
|
+
if (!keyboard || !onChange || readonly)
|
|
1009
|
+
return;
|
|
1010
|
+
const key = event.key;
|
|
1011
|
+
if (['ArrowRight', 'ArrowLeft', 'ArrowUp', 'ArrowDown'].includes(key)) {
|
|
1012
|
+
event.preventDefault();
|
|
1013
|
+
let x = (key == 'ArrowRight' || key == 'ArrowUp') ? keyboard[1] : -keyboard[1];
|
|
1014
|
+
if (direction == 'down' || direction == 'left')
|
|
1015
|
+
x *= -1;
|
|
1016
|
+
let v;
|
|
1017
|
+
if (keyboard[0] == 'normalized') {
|
|
1018
|
+
const n = normalizeValue(value, min, max, skew);
|
|
1019
|
+
v = rawValue(n + x, min, max, skew);
|
|
1020
|
+
}
|
|
1021
|
+
else {
|
|
1022
|
+
v = value + x;
|
|
1023
|
+
}
|
|
1024
|
+
onChange(clamp(stepValue(v, step), min, max));
|
|
1025
|
+
}
|
|
1026
|
+
}, [value, min, max, step, skew, direction, keyboard, onChange, readonly]);
|
|
607
1027
|
// --- hooks ---
|
|
608
|
-
const touchMoveRefCallback = useRefCallbackEvent('touchmove', handleValue, { passive: false }, [min, max, skew, step, direction, onChange]);
|
|
1028
|
+
const touchMoveRefCallback = useRefCallbackEvent('touchmove', handleValue, { passive: false }, [min, max, skew, step, direction, onChange, readonly]);
|
|
609
1029
|
const wheelRefCallback = useRefCallbackEvent('wheel', (event) => {
|
|
610
|
-
if (!
|
|
1030
|
+
if (!wheel || !onChange || readonly)
|
|
611
1031
|
return;
|
|
612
1032
|
event.preventDefault();
|
|
613
|
-
let x = event.deltaY > 0 ?
|
|
1033
|
+
let x = event.deltaY > 0 ? wheel[1] : -wheel[1];
|
|
614
1034
|
if (isReversed(direction) || isHorizontal(direction))
|
|
615
1035
|
x *= -1;
|
|
616
1036
|
let v;
|
|
617
|
-
if (
|
|
1037
|
+
if (wheel[0] == 'normalized') {
|
|
618
1038
|
const n = normalizeValue(value, min, max, skew);
|
|
619
1039
|
v = rawValue(n + x, min, max, skew);
|
|
620
1040
|
}
|
|
621
1041
|
else {
|
|
622
1042
|
v = value + x;
|
|
623
1043
|
}
|
|
624
|
-
|
|
625
|
-
onChange(clamp(stepValue(v, step), min, max));
|
|
1044
|
+
onChange(clamp(stepValue(v, step), min, max));
|
|
626
1045
|
}, {
|
|
627
1046
|
passive: false,
|
|
628
|
-
}, [
|
|
1047
|
+
}, [wheel, value, min, max, skew, step]);
|
|
629
1048
|
useEventListener(window, 'mousemove', (event) => {
|
|
630
1049
|
handleValue(event);
|
|
631
1050
|
});
|
|
632
1051
|
useEventListener(window, 'mouseup', () => {
|
|
633
1052
|
thumbDragged.current = false;
|
|
634
1053
|
if (bodyNoSelect)
|
|
635
|
-
|
|
1054
|
+
removeNoSelect();
|
|
636
1055
|
});
|
|
1056
|
+
React.useImperativeHandle(ref, () => {
|
|
1057
|
+
return {
|
|
1058
|
+
focus() {
|
|
1059
|
+
var _a;
|
|
1060
|
+
(_a = thumbRef.current) === null || _a === undefined ? undefined : _a.focus();
|
|
1061
|
+
},
|
|
1062
|
+
blur() {
|
|
1063
|
+
var _a;
|
|
1064
|
+
(_a = thumbRef.current) === null || _a === undefined ? undefined : _a.blur();
|
|
1065
|
+
},
|
|
1066
|
+
};
|
|
1067
|
+
}, []);
|
|
637
1068
|
return (jsxRuntime.jsxs("div", { className: clsx('tremolo-slider', className), ref: (div) => {
|
|
638
1069
|
wheelRefCallback(div);
|
|
639
1070
|
touchMoveRefCallback(div);
|
|
640
|
-
}, tabIndex: -1, role: "slider", "aria-valuenow": value, "aria-
|
|
1071
|
+
}, tabIndex: -1, role: "slider", "aria-valuenow": value, "aria-valuemin": min, "aria-valuemax": max, "aria-orientation": isHorizontal(direction) ? 'horizontal' : 'vertical', "aria-disabled": disabled, "aria-readonly": readonly, css: react.css(Object.assign({ display: 'inline-block', margin: `calc(${styleHelper((_b = thumbProps === null || thumbProps === undefined ? undefined : thumbProps.size) !== null && _b !== undefined ? _b : 22)} / 2)`, cursor: readonly ? 'not-allowed' : 'pointer', outline: 0 }, style)), onPointerDown: (event) => {
|
|
641
1072
|
thumbDragged.current = true;
|
|
642
1073
|
handleValue(event);
|
|
643
|
-
}, children: [jsxRuntime.jsx(react.Global, { styles: {
|
|
1074
|
+
}, onKeyDown: handleKeyDown, onFocus: (_c = thumbRef.current) === null || _c === undefined ? undefined : _c.focus, onBlur: (_d = thumbRef.current) === null || _d === undefined ? undefined : _d.blur, children: [jsxRuntime.jsx(react.Global, { styles: {
|
|
644
1075
|
'.no-select': {
|
|
645
1076
|
userSelect: 'none',
|
|
646
1077
|
},
|
|
647
1078
|
} }), jsxRuntime.jsxs("div", { css: react.css({
|
|
648
1079
|
display: 'flex',
|
|
649
1080
|
flexDirection: isHorizontal(direction) ? 'column' : 'row',
|
|
650
|
-
}), children: [jsxRuntime.
|
|
651
|
-
background: `linear-gradient(to ${gradientDirection(direction)}, ${color} ${percent}%, ${bg} ${percent}%)`,
|
|
652
|
-
borderRadius: styleHelper(thickness, '/', 2),
|
|
653
|
-
borderStyle: 'solid',
|
|
654
|
-
borderColor: '#ccc',
|
|
655
|
-
borderWidth: 2,
|
|
656
|
-
width: isHorizontal(direction) ? length : thickness,
|
|
657
|
-
height: isHorizontal(direction) ? thickness : length,
|
|
658
|
-
zIndex: 1,
|
|
659
|
-
} }, trackProps)), jsxRuntime.jsx(SliderThumb, Object.assign({ color: color, __css: {
|
|
1081
|
+
}), children: [jsxRuntime.jsx("div", { className: "tremolo-slider-track-wrapper", ref: trackElementRef, children: jsxRuntime.jsx(SliderTrack, Object.assign({ __direction: direction, __disabled: disabled, __percent: percent, __thumb: jsxRuntime.jsx(SliderThumb, Object.assign({ ref: thumbRef, __disabled: disabled, __css: {
|
|
660
1082
|
top: isHorizontal(direction) ? '50%' : `${percentRev}%`,
|
|
661
1083
|
left: isHorizontal(direction) ? `${percentRev}%` : '50%',
|
|
662
|
-
} }, thumbProps))
|
|
663
|
-
? 2
|
|
664
|
-
:
|
|
665
|
-
? 2
|
|
666
|
-
:
|
|
1084
|
+
} }, thumbProps)) }, trackProps)) }), scale && (jsxRuntime.jsx("div", { className: "tremolo-slider-scale-wrapper", css: react.css(Object.assign({ display: 'block', position: 'relative', marginLeft: isVertical(direction)
|
|
1085
|
+
? ((_e = scaleOption === null || scaleOption === undefined ? undefined : scaleOption.gap) !== null && _e !== undefined ? _e : `calc((22px - ${styleHelper((_f = trackProps === null || trackProps === undefined ? undefined : trackProps.thickness) !== null && _f !== undefined ? _f : 10)}) / 2)`)
|
|
1086
|
+
: undefined, marginTop: isHorizontal(direction)
|
|
1087
|
+
? ((_g = scaleOption === null || scaleOption === undefined ? undefined : scaleOption.gap) !== null && _g !== undefined ? _g : `calc((22px - ${styleHelper((_h = trackProps === null || trackProps === undefined ? undefined : trackProps.thickness) !== null && _h !== undefined ? _h : 10)}) / 2)`)
|
|
1088
|
+
: undefined }, scaleOption === null || scaleOption === undefined ? undefined : scaleOption.style)), children: scalesList.map((item, index) => {
|
|
667
1089
|
var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l, _m, _o, _p, _q, _r, _s, _t;
|
|
668
1090
|
return (jsxRuntime.jsxs("div", { css: react.css({
|
|
669
1091
|
display: 'flex',
|
|
@@ -671,43 +1093,40 @@ function Slider(_a) {
|
|
|
671
1093
|
justifyContent: 'center',
|
|
672
1094
|
alignItems: 'center',
|
|
673
1095
|
position: 'absolute',
|
|
674
|
-
left: isHorizontal(direction)
|
|
675
|
-
|
|
676
|
-
? 100 - normalizeValue(item.at, min, max, skew) * 100
|
|
677
|
-
: normalizeValue(item.at, min, max, skew) * 100}%`
|
|
678
|
-
: undefined,
|
|
679
|
-
top: isVertical(direction)
|
|
680
|
-
? `${isReversed(direction)
|
|
681
|
-
? 100 - normalizeValue(item.at, min, max, skew) * 100
|
|
682
|
-
: normalizeValue(item.at, min, max, skew) * 100}%`
|
|
683
|
-
: undefined,
|
|
1096
|
+
left: isHorizontal(direction) ? `${calcPercent(item.at)}%` : undefined,
|
|
1097
|
+
top: isVertical(direction) ? `${calcPercent(item.at)}%` : undefined,
|
|
684
1098
|
translate: isHorizontal(direction) ? '-50% 0' : '0 -50%',
|
|
685
1099
|
zIndex: 10,
|
|
686
|
-
}), children: [((_b = (_a = item.type) !== null && _a !==
|
|
1100
|
+
}), children: [((_b = (_a = item.type) !== null && _a !== undefined ? _a : scaleOption === null || scaleOption === undefined ? undefined : scaleOption.defaultType) !== null && _b !== undefined ? _b : 'mark-number') !=
|
|
687
1101
|
'number' && (jsxRuntime.jsx("div", { className: "tremolo-slider-scale-mark", css: react.css({
|
|
688
1102
|
width: isHorizontal(direction)
|
|
689
|
-
? ((_d = (_c = item.style) === null || _c ===
|
|
690
|
-
: ((_f = (_e = item.style) === null || _e ===
|
|
1103
|
+
? ((_d = (_c = item.style) === null || _c === undefined ? undefined : _c.thickness) !== null && _d !== undefined ? _d : 1)
|
|
1104
|
+
: ((_f = (_e = item.style) === null || _e === undefined ? undefined : _e.length) !== null && _f !== undefined ? _f : '0.5rem'),
|
|
691
1105
|
height: isVertical(direction)
|
|
692
|
-
? ((_h = (_g = item.style) === null || _g ===
|
|
693
|
-
: ((_k = (_j = item.style) === null || _j ===
|
|
694
|
-
backgroundColor: (_o = (_m = (_l = item.style) === null || _l ===
|
|
1106
|
+
? ((_h = (_g = item.style) === null || _g === undefined ? undefined : _g.thickness) !== null && _h !== undefined ? _h : 1)
|
|
1107
|
+
: ((_k = (_j = item.style) === null || _j === undefined ? undefined : _j.length) !== null && _k !== undefined ? _k : '0.5rem'),
|
|
1108
|
+
backgroundColor: (_o = (_m = (_l = item.style) === null || _l === undefined ? undefined : _l.markColor) !== null && _m !== undefined ? _m : scaleOption === null || scaleOption === undefined ? undefined : scaleOption.markColor) !== null && _o !== undefined ? _o : '#222',
|
|
695
1109
|
marginBottom: isHorizontal(direction) ? 2 : undefined,
|
|
696
1110
|
marginRight: isVertical(direction) ? 2 : undefined,
|
|
697
|
-
}) })), ((_q = (_p = item.type) !== null && _p !==
|
|
1111
|
+
}) })), ((_q = (_p = item.type) !== null && _p !== undefined ? _p : scaleOption === null || scaleOption === undefined ? undefined : scaleOption.defaultType) !== null && _q !== undefined ? _q : 'mark-number') !=
|
|
698
1112
|
'mark' && (jsxRuntime.jsx("div", { className: "tremolo-slider-scale-number", css: react.css({
|
|
699
|
-
color: (_s = (_r = item.style) === null || _r ===
|
|
700
|
-
width: scaleOption === null || scaleOption ===
|
|
1113
|
+
color: (_s = (_r = item.style) === null || _r === undefined ? undefined : _r.labelColor) !== null && _s !== undefined ? _s : scaleOption === null || scaleOption === undefined ? undefined : scaleOption.labelColor,
|
|
1114
|
+
width: scaleOption === null || scaleOption === undefined ? undefined : scaleOption.labelWidth,
|
|
701
1115
|
textAlign: 'right',
|
|
702
|
-
}), children: (_t = item.text) !== null && _t !==
|
|
1116
|
+
}), children: (_t = item.text) !== null && _t !== undefined ? _t : item.at }))] }, index));
|
|
703
1117
|
}) }))] })] }));
|
|
704
|
-
}
|
|
1118
|
+
});
|
|
705
1119
|
|
|
706
1120
|
exports.AnimationCanvas = AnimationCanvas;
|
|
1121
|
+
exports.BlackKey = BlackKey;
|
|
1122
|
+
exports.KeyLabel = KeyLabel;
|
|
707
1123
|
exports.Knob = Knob;
|
|
708
1124
|
exports.NumberInput = NumberInput;
|
|
1125
|
+
exports.Piano = Piano;
|
|
1126
|
+
exports.Shortcuts = Shortcuts;
|
|
709
1127
|
exports.Slider = Slider;
|
|
710
1128
|
exports.SliderThumb = SliderThumb;
|
|
711
1129
|
exports.SliderTrack = SliderTrack;
|
|
1130
|
+
exports.WhiteKey = WhiteKey;
|
|
712
1131
|
exports.gradientDirection = gradientDirection;
|
|
713
1132
|
//# sourceMappingURL=index.js.map
|