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