@tremolo-ui/vue 0.7.0 → 0.9.0
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/index.cjs +865 -611
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +934 -169
- package/dist/index.d.cts.map +1 -1
- package/dist/index.d.ts +934 -169
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +339 -128
- package/dist/index.js.map +1 -1
- package/package.json +8 -8
- package/src/components/AnimationCanvas/AnimationCanvas.ts +27 -30
- package/src/components/AnimationCanvas/index.ts +1 -5
- package/src/components/DropZone/DropZone.ts +19 -9
- package/src/components/DropZone/index.ts +1 -1
- package/src/components/FileInput/FileInput.ts +28 -14
- package/src/components/FileInput/index.ts +1 -1
- package/src/components/Knob/Knob.ts +107 -57
- package/src/components/Knob/KnobThumb.ts +32 -22
- package/src/components/Knob/index.ts +2 -2
- package/src/components/NumberInput/NumberInput.ts +136 -53
- package/src/components/NumberInput/NumberInputField.ts +5 -2
- package/src/components/NumberInput/NumberInputStepper.ts +25 -4
- package/src/components/NumberInput/context.ts +12 -0
- package/src/components/NumberInput/index.ts +1 -1
- package/src/components/NumberInput/stepper-button.ts +8 -1
- package/src/components/Piano/Piano.ts +51 -43
- package/src/components/Piano/index.ts +6 -1
- package/src/components/PointsEditor/PointsEditor.ts +43 -35
- package/src/components/PointsEditor/PointsEditorContainer.ts +2 -6
- package/src/components/PointsEditor/PointsEditorPoint.ts +82 -42
- package/src/components/PointsEditor/context.ts +1 -1
- package/src/components/PointsEditor/index.ts +5 -2
- package/src/components/Slider/Slider.ts +92 -49
- package/src/components/Slider/SliderMarks.ts +28 -14
- package/src/components/Slider/SliderMarksOption.ts +54 -33
- package/src/components/Slider/SliderThumb.ts +26 -8
- package/src/components/Slider/SliderTrack.ts +31 -16
- package/src/components/Slider/context.ts +1 -1
- package/src/components/Slider/index.ts +8 -5
- package/src/components/XYPad/XYPad.ts +94 -56
- package/src/components/XYPad/XYPadThumb.ts +21 -14
- package/src/components/XYPad/index.ts +2 -2
- package/src/components/_util/change-gesture.ts +44 -0
- package/src/components/_util/useCheckSteps.ts +1 -1
- package/src/components/_util/visually-hidden-range-input.ts +1 -1
- package/src/composables/useInstance.ts +1 -1
- package/src/composables/useWheel.ts +5 -2
- package/src/index.ts +21 -4
package/dist/index.cjs
CHANGED
|
@@ -1,45 +1,47 @@
|
|
|
1
1
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
2
2
|
let vue = require("vue");
|
|
3
3
|
let _tremolo_ui_dom = require("@tremolo-ui/dom");
|
|
4
|
+
let _tremolo_ui_dom_internal = require("@tremolo-ui/dom/internal");
|
|
4
5
|
let _tremolo_ui_functions = require("@tremolo-ui/functions");
|
|
5
6
|
//#region src/components/AnimationCanvas/AnimationCanvas.ts
|
|
7
|
+
const animationCanvasProps = {
|
|
8
|
+
/** Draws a frame. */
|
|
9
|
+
draw: {
|
|
10
|
+
type: Function,
|
|
11
|
+
required: true
|
|
12
|
+
},
|
|
13
|
+
/** Sets the canvas up, once, before the first frame. */
|
|
14
|
+
init: Function,
|
|
15
|
+
/** Draw on every animation frame. @default true */
|
|
16
|
+
animate: {
|
|
17
|
+
type: Boolean,
|
|
18
|
+
default: true
|
|
19
|
+
},
|
|
20
|
+
/** Settings for the 2D context. Read once, when the canvas is created. */
|
|
21
|
+
options: Object,
|
|
22
|
+
/** Keep the drawing while the canvas is resized. @default true */
|
|
23
|
+
reduceFlickering: {
|
|
24
|
+
type: Boolean,
|
|
25
|
+
default: true
|
|
26
|
+
},
|
|
27
|
+
/** Follow the size of the parent element; `width` and `height` are ignored. */
|
|
28
|
+
resizable: Boolean,
|
|
29
|
+
/** Width in CSS pixels, while not `resizable`. @default 100 */
|
|
30
|
+
width: {
|
|
31
|
+
type: Number,
|
|
32
|
+
default: 100
|
|
33
|
+
},
|
|
34
|
+
/** Height in CSS pixels, while not `resizable`. @default 100 */
|
|
35
|
+
height: {
|
|
36
|
+
type: Number,
|
|
37
|
+
default: 100
|
|
38
|
+
}
|
|
39
|
+
};
|
|
6
40
|
/** A `<canvas>` drawn by `draw` on every animation frame. */
|
|
7
41
|
const AnimationCanvas = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
8
42
|
name: "AnimationCanvas",
|
|
9
43
|
inheritAttrs: false,
|
|
10
|
-
props:
|
|
11
|
-
/** Draws a frame. */
|
|
12
|
-
draw: {
|
|
13
|
-
type: Function,
|
|
14
|
-
required: true
|
|
15
|
-
},
|
|
16
|
-
/** Sets the canvas up before the first frame and after a resize. */
|
|
17
|
-
init: Function,
|
|
18
|
-
/** Draw on every animation frame. @default true */
|
|
19
|
-
animate: {
|
|
20
|
-
type: Boolean,
|
|
21
|
-
default: true
|
|
22
|
-
},
|
|
23
|
-
/** Settings for the 2D context. Read once, when the canvas is created. */
|
|
24
|
-
options: Object,
|
|
25
|
-
/** Keep the drawing while the canvas is resized. @default true */
|
|
26
|
-
reduceFlickering: {
|
|
27
|
-
type: Boolean,
|
|
28
|
-
default: true
|
|
29
|
-
},
|
|
30
|
-
/** Follow the size of the parent element; `width` and `height` are ignored. */
|
|
31
|
-
resizable: Boolean,
|
|
32
|
-
/** Width in CSS pixels, while not `resizable`. @default 100 */
|
|
33
|
-
width: {
|
|
34
|
-
type: Number,
|
|
35
|
-
default: 100
|
|
36
|
-
},
|
|
37
|
-
/** Height in CSS pixels, while not `resizable`. @default 100 */
|
|
38
|
-
height: {
|
|
39
|
-
type: Number,
|
|
40
|
-
default: 100
|
|
41
|
-
}
|
|
42
|
-
},
|
|
44
|
+
props: animationCanvasProps,
|
|
43
45
|
setup(props, { attrs }) {
|
|
44
46
|
const canvas = (0, vue.ref)(null);
|
|
45
47
|
const instance = (0, vue.shallowRef)(null);
|
|
@@ -110,7 +112,7 @@ function useInstance(target, options, create, update) {
|
|
|
110
112
|
flush: "post"
|
|
111
113
|
});
|
|
112
114
|
(0, vue.watch)(() => ({ ...(0, vue.toValue)(options) }), (next, previous) => {
|
|
113
|
-
if (instance) update(instance, (0,
|
|
115
|
+
if (instance) update(instance, (0, _tremolo_ui_dom_internal.replaceOptions)(previous, next));
|
|
114
116
|
}, { flush: "post" });
|
|
115
117
|
return { current: () => instance };
|
|
116
118
|
}
|
|
@@ -138,17 +140,18 @@ function useDropZone(target, options = {}) {
|
|
|
138
140
|
}
|
|
139
141
|
//#endregion
|
|
140
142
|
//#region src/components/DropZone/DropZone.ts
|
|
143
|
+
const dropZoneProps = {
|
|
144
|
+
/** Which files to take, as the `accept` attribute of a file input. */
|
|
145
|
+
accept: String,
|
|
146
|
+
/** Take every file dropped, rather than the first. */
|
|
147
|
+
multiple: Boolean,
|
|
148
|
+
/** Ignore drops. The zone carries `data-disabled`. */
|
|
149
|
+
disabled: Boolean
|
|
150
|
+
};
|
|
141
151
|
/** A region that takes dropped files. */
|
|
142
152
|
const DropZone = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
143
153
|
name: "DropZone",
|
|
144
|
-
props:
|
|
145
|
-
/** Which files to take, as the `accept` attribute of a file input. */
|
|
146
|
-
accept: String,
|
|
147
|
-
/** Take every file dropped, rather than the first. */
|
|
148
|
-
multiple: Boolean,
|
|
149
|
-
/** Ignore drops. The zone carries `data-disabled`. */
|
|
150
|
-
disabled: Boolean
|
|
151
|
-
},
|
|
154
|
+
props: dropZoneProps,
|
|
152
155
|
emits: {
|
|
153
156
|
/** The dropped files that satisfy `accept`. */
|
|
154
157
|
drop: (files, _event) => Array.isArray(files),
|
|
@@ -189,6 +192,18 @@ function useFileInputContext() {
|
|
|
189
192
|
}
|
|
190
193
|
//#endregion
|
|
191
194
|
//#region src/components/FileInput/FileInput.ts
|
|
195
|
+
const fileInputProps = {
|
|
196
|
+
/**
|
|
197
|
+
* Which files to take: extensions, MIME types and type groups. It is
|
|
198
|
+
* checked again when the files arrive, since the picker only takes it as
|
|
199
|
+
* a hint.
|
|
200
|
+
*/
|
|
201
|
+
accept: String,
|
|
202
|
+
/** Let several files be picked at once. */
|
|
203
|
+
multiple: Boolean,
|
|
204
|
+
/** Make the input unusable. The parts carry `data-disabled`. */
|
|
205
|
+
disabled: Boolean
|
|
206
|
+
};
|
|
192
207
|
/**
|
|
193
208
|
* Picks files. The control is the native file input, out of sight but in the
|
|
194
209
|
* tab order, with `FileInputTrigger` as its label.
|
|
@@ -196,18 +211,7 @@ function useFileInputContext() {
|
|
|
196
211
|
const FileInput = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
197
212
|
name: "FileInput",
|
|
198
213
|
inheritAttrs: false,
|
|
199
|
-
props:
|
|
200
|
-
/**
|
|
201
|
-
* Which files to take: extensions, MIME types and type groups. It is
|
|
202
|
-
* checked again when the files arrive, since the picker only takes it as
|
|
203
|
-
* a hint.
|
|
204
|
-
*/
|
|
205
|
-
accept: String,
|
|
206
|
-
/** Let several files be picked at once. */
|
|
207
|
-
multiple: Boolean,
|
|
208
|
-
/** Make the input unusable. The parts carry `data-disabled`. */
|
|
209
|
-
disabled: Boolean
|
|
210
|
-
},
|
|
214
|
+
props: fileInputProps,
|
|
211
215
|
emits: {
|
|
212
216
|
/** The picked files that satisfy `accept`. */
|
|
213
217
|
change: (files) => Array.isArray(files),
|
|
@@ -224,7 +228,7 @@ const FileInput = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
224
228
|
});
|
|
225
229
|
function onChange(event) {
|
|
226
230
|
const input = event.target;
|
|
227
|
-
const { accepted, rejected } = (0,
|
|
231
|
+
const { accepted, rejected } = (0, _tremolo_ui_dom_internal.partitionByAccept)(Array.from(input.files ?? []), props.accept);
|
|
228
232
|
input.value = "";
|
|
229
233
|
if (accepted.length > 0) emit("change", accepted);
|
|
230
234
|
if (rejected.length > 0) emit("reject", rejected);
|
|
@@ -240,7 +244,7 @@ const FileInput = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
240
244
|
accept: props.accept,
|
|
241
245
|
multiple: props.multiple,
|
|
242
246
|
disabled: props.disabled,
|
|
243
|
-
style:
|
|
247
|
+
style: _tremolo_ui_dom_internal.visuallyHiddenStyle,
|
|
244
248
|
"aria-label": ariaLabel,
|
|
245
249
|
"aria-labelledby": ariaLabelledby,
|
|
246
250
|
"aria-describedby": ariaDescribedby,
|
|
@@ -292,7 +296,37 @@ function useDragValue(target, options) {
|
|
|
292
296
|
* `@tremolo-ui/dom`.
|
|
293
297
|
*/
|
|
294
298
|
function useWheel(target, onWheel, options = {}) {
|
|
295
|
-
useInstance(target, options, (element, opts) => (0, _tremolo_ui_dom.createWheel)(element,
|
|
299
|
+
useInstance(target, options, (element, opts) => (0, _tremolo_ui_dom.createWheel)(element, {
|
|
300
|
+
...opts,
|
|
301
|
+
onWheel: (event) => onWheel(event)
|
|
302
|
+
}), (instance, next) => instance.update(next));
|
|
303
|
+
}
|
|
304
|
+
//#endregion
|
|
305
|
+
//#region src/components/_util/change-gesture.ts
|
|
306
|
+
/**
|
|
307
|
+
* The core's change gesture, reporting the control's value: the start gets
|
|
308
|
+
* the value before the change, the end the last one the control emitted.
|
|
309
|
+
* `modelValue` lags behind until the parent renders, and a drag ends in the
|
|
310
|
+
* same event as its last change, so the component reports each value it
|
|
311
|
+
* emits through `changed`.
|
|
312
|
+
*/
|
|
313
|
+
function useChangeGesture(options) {
|
|
314
|
+
let last = options.value();
|
|
315
|
+
const gesture = (0, _tremolo_ui_dom.createChangeGesture)({
|
|
316
|
+
onStart: (source) => {
|
|
317
|
+
last = options.value();
|
|
318
|
+
options.onStart(last, source);
|
|
319
|
+
},
|
|
320
|
+
onEnd: (source) => options.onEnd(last, source)
|
|
321
|
+
});
|
|
322
|
+
(0, vue.watchEffect)(() => gesture.update({ endDelay: options.endDelay() }));
|
|
323
|
+
(0, vue.watch)(options.inactive, (inactive) => {
|
|
324
|
+
if (inactive) gesture.end();
|
|
325
|
+
});
|
|
326
|
+
(0, vue.onScopeDispose)(() => gesture.end());
|
|
327
|
+
return Object.assign(gesture, { changed: (value) => {
|
|
328
|
+
last = value;
|
|
329
|
+
} });
|
|
296
330
|
}
|
|
297
331
|
//#endregion
|
|
298
332
|
//#region src/components/_util/useCheckSteps.ts
|
|
@@ -306,85 +340,108 @@ function useCheckSteps(options) {
|
|
|
306
340
|
try {
|
|
307
341
|
if (process.env.NODE_ENV === "production") return;
|
|
308
342
|
(0, vue.watchEffect)(() => {
|
|
309
|
-
for (const warning of (0,
|
|
343
|
+
for (const warning of (0, _tremolo_ui_dom_internal.checkSteps)(options())) console.warn(warning);
|
|
310
344
|
});
|
|
311
345
|
} catch {}
|
|
312
346
|
}
|
|
313
347
|
//#endregion
|
|
314
348
|
//#region src/components/Knob/Knob.ts
|
|
349
|
+
const knobProps = {
|
|
350
|
+
/** The current value. Bind it with `v-model`. */
|
|
351
|
+
modelValue: {
|
|
352
|
+
type: Number,
|
|
353
|
+
required: true
|
|
354
|
+
},
|
|
355
|
+
/** The value with the knob turned all the way down. */
|
|
356
|
+
min: {
|
|
357
|
+
type: Number,
|
|
358
|
+
required: true
|
|
359
|
+
},
|
|
360
|
+
/** The value with the knob turned all the way up. */
|
|
361
|
+
max: {
|
|
362
|
+
type: Number,
|
|
363
|
+
required: true
|
|
364
|
+
},
|
|
365
|
+
/** Granularity of the value. @default 1 */
|
|
366
|
+
step: {
|
|
367
|
+
type: Number,
|
|
368
|
+
default: 1
|
|
369
|
+
},
|
|
370
|
+
/** How the value is distributed across the travel. @default linearScale */
|
|
371
|
+
scale: {
|
|
372
|
+
type: Object,
|
|
373
|
+
default: () => _tremolo_ui_functions.linearScale
|
|
374
|
+
},
|
|
375
|
+
/**
|
|
376
|
+
* The value a double click restores. `null` turns the double click off.
|
|
377
|
+
* @default startValue
|
|
378
|
+
*/
|
|
379
|
+
resetValue: {
|
|
380
|
+
type: Number,
|
|
381
|
+
default: void 0
|
|
382
|
+
},
|
|
383
|
+
/** Where the active arc starts. @default min */
|
|
384
|
+
startValue: Number,
|
|
385
|
+
/** Width and height of the knob. Sets `--knob-size`. */
|
|
386
|
+
size: [Number, String],
|
|
387
|
+
/** The cursor to show while dragging. @default 'grabbing' */
|
|
388
|
+
dragCursor: {
|
|
389
|
+
type: String,
|
|
390
|
+
default: "grabbing"
|
|
391
|
+
},
|
|
392
|
+
/** How much one notch of the wheel moves the value. `null` turns it off. */
|
|
393
|
+
wheel: {
|
|
394
|
+
type: [Array, Object],
|
|
395
|
+
default: () => _tremolo_ui_dom.DEFAULT_WHEEL_OPTIONS
|
|
396
|
+
},
|
|
397
|
+
/** How much one arrow key press moves the value. `null` turns it off. */
|
|
398
|
+
keyboard: {
|
|
399
|
+
type: [Array, Object],
|
|
400
|
+
default: () => _tremolo_ui_dom.DEFAULT_KEYBOARD_OPTIONS
|
|
401
|
+
},
|
|
402
|
+
/** How much a drag moves the value, per modifier key. */
|
|
403
|
+
dragSensitivity: {
|
|
404
|
+
type: [Number, Object],
|
|
405
|
+
default: () => _tremolo_ui_dom.DEFAULT_DRAG_SENSITIVITY
|
|
406
|
+
},
|
|
407
|
+
/** Hide the cursor while dragging and read the movement directly. */
|
|
408
|
+
pointerLock: Boolean,
|
|
409
|
+
/** Make the knob unchangeable and remove it from the tab order. */
|
|
410
|
+
disabled: Boolean,
|
|
411
|
+
/** Make the knob unchangeable while leaving it focusable. */
|
|
412
|
+
readonly: Boolean,
|
|
413
|
+
/**
|
|
414
|
+
* How long after the last wheel notch or arrow key a change counts as over,
|
|
415
|
+
* in milliseconds, for `change-end`.
|
|
416
|
+
* @default 500
|
|
417
|
+
*/
|
|
418
|
+
changeEndDelay: {
|
|
419
|
+
type: Number,
|
|
420
|
+
default: 500
|
|
421
|
+
},
|
|
422
|
+
/** How far the knob turns from `min` to `max`, in degrees. @default 270 */
|
|
423
|
+
angleRange: {
|
|
424
|
+
type: Number,
|
|
425
|
+
default: 270
|
|
426
|
+
}
|
|
427
|
+
};
|
|
315
428
|
/**
|
|
316
429
|
* Interactive rotary knob, drawn in SVG by `KnobSVGRoot` and the parts inside
|
|
317
430
|
* it. Bind the value with `v-model`.
|
|
318
431
|
*/
|
|
319
432
|
const Knob = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
320
433
|
name: "Knob",
|
|
321
|
-
props:
|
|
322
|
-
|
|
323
|
-
modelValue:
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
},
|
|
332
|
-
/** The value with the knob turned all the way up. */
|
|
333
|
-
max: {
|
|
334
|
-
type: Number,
|
|
335
|
-
required: true
|
|
336
|
-
},
|
|
337
|
-
/** Granularity of the value. @default 1 */
|
|
338
|
-
step: {
|
|
339
|
-
type: Number,
|
|
340
|
-
default: 1
|
|
341
|
-
},
|
|
342
|
-
/** How the value is distributed across the travel. @default linearScale */
|
|
343
|
-
scale: {
|
|
344
|
-
type: Object,
|
|
345
|
-
default: () => _tremolo_ui_functions.linearScale
|
|
346
|
-
},
|
|
347
|
-
/** The value a double click restores. @default min */
|
|
348
|
-
defaultValue: Number,
|
|
349
|
-
/** Where the active arc starts. @default min */
|
|
350
|
-
startValue: Number,
|
|
351
|
-
/** Width and height of the knob. Sets `--knob-size`. */
|
|
352
|
-
size: [Number, String],
|
|
353
|
-
/** The cursor to show while dragging. @default { cursor: 'grabbing' } */
|
|
354
|
-
externalStyles: Object,
|
|
355
|
-
/** How much one notch of the wheel moves the value. `null` turns it off. */
|
|
356
|
-
wheel: {
|
|
357
|
-
type: [Array, Object],
|
|
358
|
-
default: () => _tremolo_ui_dom.DEFAULT_WHEEL_OPTIONS
|
|
359
|
-
},
|
|
360
|
-
/** How much one arrow key press moves the value. `null` turns it off. */
|
|
361
|
-
keyboard: {
|
|
362
|
-
type: [Array, Object],
|
|
363
|
-
default: () => _tremolo_ui_dom.DEFAULT_KEYBOARD_OPTIONS
|
|
364
|
-
},
|
|
365
|
-
/** How much a drag moves the value, per modifier key. */
|
|
366
|
-
dragSensitivity: {
|
|
367
|
-
type: [Number, Object],
|
|
368
|
-
default: () => _tremolo_ui_dom.DEFAULT_DRAG_SENSITIVITY
|
|
369
|
-
},
|
|
370
|
-
/** Hide the cursor while dragging and read the movement directly. */
|
|
371
|
-
pointerLock: Boolean,
|
|
372
|
-
/** Restore `defaultValue` on a double click. @default true */
|
|
373
|
-
enableDoubleClickDefault: {
|
|
374
|
-
type: Boolean,
|
|
375
|
-
default: true
|
|
376
|
-
},
|
|
377
|
-
/** Make the knob unchangeable and remove it from the tab order. */
|
|
378
|
-
disabled: Boolean,
|
|
379
|
-
/** Make the knob unchangeable while leaving it focusable. */
|
|
380
|
-
readonly: Boolean,
|
|
381
|
-
/** How far the knob turns from `min` to `max`, in degrees. @default 270 */
|
|
382
|
-
angleRange: {
|
|
383
|
-
type: Number,
|
|
384
|
-
default: 270
|
|
385
|
-
}
|
|
434
|
+
props: knobProps,
|
|
435
|
+
emits: {
|
|
436
|
+
"update:modelValue": (value) => typeof value === "number",
|
|
437
|
+
/**
|
|
438
|
+
* A change of the value started, with the value before it and what it is
|
|
439
|
+
* made with.
|
|
440
|
+
*/
|
|
441
|
+
changeStart: (value, _source) => typeof value === "number",
|
|
442
|
+
/** The change ended, with the value it ended on. */
|
|
443
|
+
changeEnd: (value, _source) => typeof value === "number"
|
|
386
444
|
},
|
|
387
|
-
emits: { "update:modelValue": (value) => typeof value === "number" },
|
|
388
445
|
setup(props, { slots, emit, expose }) {
|
|
389
446
|
const root = (0, vue.ref)(null);
|
|
390
447
|
const dragging = (0, vue.ref)(false);
|
|
@@ -435,7 +492,17 @@ const Knob = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
435
492
|
return angles.value;
|
|
436
493
|
}
|
|
437
494
|
});
|
|
438
|
-
const
|
|
495
|
+
const gesture = useChangeGesture({
|
|
496
|
+
value: () => props.modelValue,
|
|
497
|
+
inactive: () => inactive.value,
|
|
498
|
+
endDelay: () => props.changeEndDelay,
|
|
499
|
+
onStart: (value, source) => emit("changeStart", value, source),
|
|
500
|
+
onEnd: (value, source) => emit("changeEnd", value, source)
|
|
501
|
+
});
|
|
502
|
+
const change = (next) => {
|
|
503
|
+
gesture.changed(next);
|
|
504
|
+
emit("update:modelValue", next);
|
|
505
|
+
};
|
|
439
506
|
useDragValue(root, () => ({
|
|
440
507
|
axis: [range.value, {
|
|
441
508
|
...range.value,
|
|
@@ -443,11 +510,11 @@ const Knob = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
443
510
|
}],
|
|
444
511
|
mapping: (0, _tremolo_ui_dom.relativeMapping)({
|
|
445
512
|
pixelRange: 100,
|
|
446
|
-
sensitivity: (state) => (0,
|
|
513
|
+
sensitivity: (state) => (0, _tremolo_ui_dom_internal.selectModifier)(props.dragSensitivity, state.event).value
|
|
447
514
|
}),
|
|
448
515
|
getValue: () => [props.modelValue, props.modelValue],
|
|
449
516
|
threshold: 1,
|
|
450
|
-
cursor: inactive.value ? void 0 : props.
|
|
517
|
+
cursor: inactive.value ? void 0 : props.dragCursor,
|
|
451
518
|
pointerLock: inactive.value ? false : props.pointerLock,
|
|
452
519
|
shouldStart: () => !inactive.value,
|
|
453
520
|
onChange: (v) => {
|
|
@@ -455,17 +522,20 @@ const Knob = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
455
522
|
},
|
|
456
523
|
onDragStart: () => {
|
|
457
524
|
dragging.value = true;
|
|
525
|
+
if (!inactive.value) gesture.hold("pointer");
|
|
458
526
|
},
|
|
459
527
|
onDragEnd: () => {
|
|
460
528
|
dragging.value = false;
|
|
529
|
+
gesture.end();
|
|
461
530
|
}
|
|
462
531
|
}));
|
|
463
532
|
useWheel(root, (event) => {
|
|
464
533
|
if (!props.wheel || inactive.value) return;
|
|
465
|
-
const direction = (0,
|
|
534
|
+
const direction = (0, _tremolo_ui_dom_internal.wheelDirection)(event);
|
|
466
535
|
if (direction === null) return;
|
|
467
536
|
event.preventDefault();
|
|
468
|
-
|
|
537
|
+
gesture.pulse("wheel");
|
|
538
|
+
change((0, _tremolo_ui_dom_internal.applyDelta)(props.modelValue, direction, props.wheel, range.value, event));
|
|
469
539
|
}, { requireFocus: true });
|
|
470
540
|
expose({
|
|
471
541
|
/** Move the focus to the knob. */
|
|
@@ -487,16 +557,17 @@ const Knob = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
487
557
|
"data-disabled": props.disabled ? "" : void 0,
|
|
488
558
|
"data-readonly": props.readonly ? "" : void 0,
|
|
489
559
|
"data-dragging": dragging.value ? "" : void 0,
|
|
490
|
-
style: { "--knob-size": (0,
|
|
560
|
+
style: { "--knob-size": (0, _tremolo_ui_dom_internal.cssLength)(props.size) },
|
|
491
561
|
onKeydown: (event) => {
|
|
492
562
|
if (!props.keyboard || inactive.value) return;
|
|
493
|
-
const direction = (0,
|
|
563
|
+
const direction = (0, _tremolo_ui_dom_internal.arrowKeyDirection)(event.key);
|
|
494
564
|
if (direction === null) return;
|
|
495
565
|
event.preventDefault();
|
|
496
|
-
|
|
566
|
+
gesture.pulse("keyboard");
|
|
567
|
+
change((0, _tremolo_ui_dom_internal.applyDelta)(props.modelValue, direction, props.keyboard, range.value, event));
|
|
497
568
|
},
|
|
498
569
|
onDblclick: () => {
|
|
499
|
-
if (!inactive.value && props.
|
|
570
|
+
if (!inactive.value && props.resetValue !== null) gesture.instant("doubleClick", () => change(props.resetValue ?? props.startValue ?? props.min));
|
|
500
571
|
}
|
|
501
572
|
}, slots.default?.());
|
|
502
573
|
}
|
|
@@ -602,54 +673,55 @@ const KnobSVGRoot = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
602
673
|
});
|
|
603
674
|
//#endregion
|
|
604
675
|
//#region src/components/Knob/KnobThumb.ts
|
|
676
|
+
const knobThumbProps = {
|
|
677
|
+
/** Fill colour of the circle. @default 'currentColor' */
|
|
678
|
+
color: {
|
|
679
|
+
type: String,
|
|
680
|
+
default: "currentColor"
|
|
681
|
+
},
|
|
682
|
+
/** Colour of the line that points at the value. @default 'currentColor' */
|
|
683
|
+
lineColor: {
|
|
684
|
+
type: String,
|
|
685
|
+
default: "currentColor"
|
|
686
|
+
},
|
|
687
|
+
/** Diameter of the circle, as a percentage of the knob. @default 84 */
|
|
688
|
+
size: {
|
|
689
|
+
type: Number,
|
|
690
|
+
default: 84
|
|
691
|
+
},
|
|
692
|
+
/** Thickness of the line, as a percentage of the knob. @default 6 */
|
|
693
|
+
lineWeight: {
|
|
694
|
+
type: Number,
|
|
695
|
+
default: 6
|
|
696
|
+
},
|
|
697
|
+
/** How far down the line reaches, as a percentage. @default 35 */
|
|
698
|
+
lineLength: {
|
|
699
|
+
type: Number,
|
|
700
|
+
default: 35
|
|
701
|
+
},
|
|
702
|
+
/** Classes for the line that points at the value. */
|
|
703
|
+
classes: Object
|
|
704
|
+
};
|
|
605
705
|
/** The circle that turns with the value, and the line on it that points at it. */
|
|
606
706
|
const KnobThumb = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
607
707
|
name: "KnobThumb",
|
|
608
|
-
props:
|
|
609
|
-
/** Fill colour of the circle. @default 'currentColor' */
|
|
610
|
-
thumb: {
|
|
611
|
-
type: String,
|
|
612
|
-
default: "currentColor"
|
|
613
|
-
},
|
|
614
|
-
/** Colour of the line that points at the value. @default 'currentColor' */
|
|
615
|
-
thumbLine: {
|
|
616
|
-
type: String,
|
|
617
|
-
default: "currentColor"
|
|
618
|
-
},
|
|
619
|
-
/** Diameter of the circle, as a percentage of the knob. @default 84 */
|
|
620
|
-
thumbSize: {
|
|
621
|
-
type: Number,
|
|
622
|
-
default: 84
|
|
623
|
-
},
|
|
624
|
-
/** Thickness of the line, as a percentage of the knob. @default 6 */
|
|
625
|
-
thumbLineWeight: {
|
|
626
|
-
type: Number,
|
|
627
|
-
default: 6
|
|
628
|
-
},
|
|
629
|
-
/** How far down the line reaches, as a percentage. @default 35 */
|
|
630
|
-
thumbLineLength: {
|
|
631
|
-
type: Number,
|
|
632
|
-
default: 35
|
|
633
|
-
},
|
|
634
|
-
/** Classes for the line that points at the value. */
|
|
635
|
-
classes: Object
|
|
636
|
-
},
|
|
708
|
+
props: knobThumbProps,
|
|
637
709
|
setup(props) {
|
|
638
710
|
checkPlacement("KnobThumb", "KnobSVGRoot");
|
|
639
711
|
const knob = useKnobContext();
|
|
640
712
|
return () => (0, vue.h)("svg", null, [(0, vue.h)("circle", {
|
|
641
713
|
cx: "50%",
|
|
642
714
|
cy: "50%",
|
|
643
|
-
r: `${props.
|
|
644
|
-
fill: props.
|
|
715
|
+
r: `${props.size / 2}%`,
|
|
716
|
+
fill: props.color
|
|
645
717
|
}), (0, vue.h)("line", {
|
|
646
|
-
class: props.classes?.
|
|
718
|
+
class: props.classes?.line,
|
|
647
719
|
x1: "50%",
|
|
648
|
-
y1: `${(_tremolo_ui_dom.KNOB_VIEWBOX_SIZE - (0, _tremolo_ui_functions.clamp)(props.
|
|
720
|
+
y1: `${(_tremolo_ui_dom.KNOB_VIEWBOX_SIZE - (0, _tremolo_ui_functions.clamp)(props.size, 0, 100)) / 2}%`,
|
|
649
721
|
x2: "50%",
|
|
650
|
-
y2: `${props.
|
|
651
|
-
stroke: props.
|
|
652
|
-
"stroke-width": `${props.
|
|
722
|
+
y2: `${props.lineLength}%`,
|
|
723
|
+
stroke: props.lineColor,
|
|
724
|
+
"stroke-width": `${props.lineWeight}%`,
|
|
653
725
|
style: {
|
|
654
726
|
transform: `rotate(${knob.angles.r1 + knob.angles.p * knob.angleRange}deg)`,
|
|
655
727
|
transformOrigin: "50% 50%"
|
|
@@ -664,6 +736,7 @@ const NumberInputKey = Symbol("NumberInput");
|
|
|
664
736
|
function useNumberInputContext() {
|
|
665
737
|
return injectContext(NumberInputKey, "NumberInput");
|
|
666
738
|
}
|
|
739
|
+
const NumberInputGestureKey = Symbol("NumberInputGesture");
|
|
667
740
|
/** @internal Whether the drag on `NumberInputStepper` has moved the value. */
|
|
668
741
|
const StepperKey = Symbol("NumberInputStepper");
|
|
669
742
|
//#endregion
|
|
@@ -685,74 +758,99 @@ const dragSensitivityProp = {
|
|
|
685
758
|
};
|
|
686
759
|
//#endregion
|
|
687
760
|
//#region src/components/NumberInput/NumberInput.ts
|
|
761
|
+
const numberInputProps = {
|
|
762
|
+
/** The current value. Bind it with `v-model`. */
|
|
763
|
+
modelValue: {
|
|
764
|
+
type: Number,
|
|
765
|
+
required: true
|
|
766
|
+
},
|
|
767
|
+
/** The lowest value. Leave it out for no lower end. */
|
|
768
|
+
min: Number,
|
|
769
|
+
/** The highest value. Leave it out for no upper end. */
|
|
770
|
+
max: Number,
|
|
771
|
+
/** Granularity of the value. @default 1 */
|
|
772
|
+
step: {
|
|
773
|
+
type: Number,
|
|
774
|
+
default: 1
|
|
775
|
+
},
|
|
776
|
+
/** How the value is distributed, for a `normalized` amount. */
|
|
777
|
+
scale: {
|
|
778
|
+
type: Object,
|
|
779
|
+
default: () => _tremolo_ui_functions.linearScale
|
|
780
|
+
},
|
|
781
|
+
/** The text shown for a value. @default String */
|
|
782
|
+
format: {
|
|
783
|
+
type: Function,
|
|
784
|
+
default: String
|
|
785
|
+
},
|
|
786
|
+
/** Read a value back out of the text. Has to undo `format`. */
|
|
787
|
+
parse: {
|
|
788
|
+
type: Function,
|
|
789
|
+
default: _tremolo_ui_dom_internal.parseNumberText
|
|
790
|
+
},
|
|
791
|
+
/** Keep the value within `min` and `max` when committed or stepped. */
|
|
792
|
+
clampValue: {
|
|
793
|
+
type: Boolean,
|
|
794
|
+
default: true
|
|
795
|
+
},
|
|
796
|
+
wheel: wheelProp,
|
|
797
|
+
keyboard: keyboardProp,
|
|
798
|
+
dragSensitivity: dragSensitivityProp,
|
|
799
|
+
/** Pixels of vertical drag on the stepper per `step`. `null` turns it off. */
|
|
800
|
+
drag: {
|
|
801
|
+
type: Number,
|
|
802
|
+
default: 1
|
|
803
|
+
},
|
|
804
|
+
/** Hide the cursor while dragging the stepper. */
|
|
805
|
+
pointerLock: Boolean,
|
|
806
|
+
/** The cursor to show while dragging the stepper. @default 'ns-resize' */
|
|
807
|
+
dragCursor: {
|
|
808
|
+
type: String,
|
|
809
|
+
default: "ns-resize"
|
|
810
|
+
},
|
|
811
|
+
/** Select the text when the field takes focus. @default 'none' */
|
|
812
|
+
selectOnFocus: {
|
|
813
|
+
type: String,
|
|
814
|
+
default: "none"
|
|
815
|
+
},
|
|
816
|
+
/** Show the plain value while the field has focus. */
|
|
817
|
+
unformatOnFocus: Boolean,
|
|
818
|
+
/** Put the caret back at the same digit after an arrow key step. */
|
|
819
|
+
keepCaretOnStep: Boolean,
|
|
820
|
+
/** Commit and leave the field on Enter. @default true */
|
|
821
|
+
blurOnEnter: {
|
|
822
|
+
type: Boolean,
|
|
823
|
+
default: true
|
|
824
|
+
},
|
|
825
|
+
/** Make the input unchangeable and remove it from the tab order. */
|
|
826
|
+
disabled: Boolean,
|
|
827
|
+
/** Make the value unchangeable while leaving the field focusable. */
|
|
828
|
+
readonly: Boolean,
|
|
829
|
+
/**
|
|
830
|
+
* How long after the last wheel notch, arrow key or typed character a change
|
|
831
|
+
* counts as over, in milliseconds, for `change-end`.
|
|
832
|
+
* @default 500
|
|
833
|
+
*/
|
|
834
|
+
changeEndDelay: {
|
|
835
|
+
type: Number,
|
|
836
|
+
default: 500
|
|
837
|
+
}
|
|
838
|
+
};
|
|
688
839
|
/** Input with some useful functions for entering numbers. Bind it with `v-model`. */
|
|
689
840
|
const NumberInput = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
690
841
|
name: "NumberInput",
|
|
691
|
-
props:
|
|
692
|
-
|
|
693
|
-
modelValue:
|
|
694
|
-
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
step: {
|
|
703
|
-
type: Number,
|
|
704
|
-
default: 1
|
|
705
|
-
},
|
|
706
|
-
/** How the value is distributed, for a `normalized` amount. */
|
|
707
|
-
scale: {
|
|
708
|
-
type: Object,
|
|
709
|
-
default: () => _tremolo_ui_functions.linearScale
|
|
710
|
-
},
|
|
711
|
-
/** The text shown for a value. @default String */
|
|
712
|
-
format: {
|
|
713
|
-
type: Function,
|
|
714
|
-
default: String
|
|
715
|
-
},
|
|
716
|
-
/** Read a value back out of the text. Has to undo `format`. */
|
|
717
|
-
parse: {
|
|
718
|
-
type: Function,
|
|
719
|
-
default: _tremolo_ui_dom.parseNumberText
|
|
720
|
-
},
|
|
721
|
-
/** Keep the value within `min` and `max` when committed or stepped. */
|
|
722
|
-
clampValue: {
|
|
723
|
-
type: Boolean,
|
|
724
|
-
default: true
|
|
725
|
-
},
|
|
726
|
-
wheel: wheelProp,
|
|
727
|
-
keyboard: keyboardProp,
|
|
728
|
-
dragSensitivity: dragSensitivityProp,
|
|
729
|
-
/** Pixels of vertical drag on the stepper per `step`. `null` turns it off. */
|
|
730
|
-
drag: {
|
|
731
|
-
type: Number,
|
|
732
|
-
default: 1
|
|
733
|
-
},
|
|
734
|
-
/** Hide the cursor while dragging the stepper. */
|
|
735
|
-
pointerLock: Boolean,
|
|
736
|
-
/** Select the text when the field takes focus. @default 'none' */
|
|
737
|
-
selectOnFocus: {
|
|
738
|
-
type: String,
|
|
739
|
-
default: "none"
|
|
740
|
-
},
|
|
741
|
-
/** Show the plain value while the field has focus. */
|
|
742
|
-
unformatOnFocus: Boolean,
|
|
743
|
-
/** Put the caret back at the same digit after an arrow key step. */
|
|
744
|
-
keepCaretOnStep: Boolean,
|
|
745
|
-
/** Commit and leave the field on Enter. @default true */
|
|
746
|
-
blurOnEnter: {
|
|
747
|
-
type: Boolean,
|
|
748
|
-
default: true
|
|
749
|
-
},
|
|
750
|
-
/** Make the input unchangeable and remove it from the tab order. */
|
|
751
|
-
disabled: Boolean,
|
|
752
|
-
/** Make the value unchangeable while leaving the field focusable. */
|
|
753
|
-
readonly: Boolean
|
|
842
|
+
props: numberInputProps,
|
|
843
|
+
emits: {
|
|
844
|
+
"update:modelValue": (value) => typeof value === "number",
|
|
845
|
+
/**
|
|
846
|
+
* A change of the value started — a press on a stepper, the first wheel
|
|
847
|
+
* notch, arrow key or typed character — with the value before it and what
|
|
848
|
+
* it is made with.
|
|
849
|
+
*/
|
|
850
|
+
changeStart: (value, _source) => typeof value === "number",
|
|
851
|
+
/** The change ended, with the value it ended on. */
|
|
852
|
+
changeEnd: (value, _source) => typeof value === "number"
|
|
754
853
|
},
|
|
755
|
-
emits: { "update:modelValue": (value) => typeof value === "number" },
|
|
756
854
|
setup(props, { slots, emit, expose }) {
|
|
757
855
|
const root = (0, vue.ref)(null);
|
|
758
856
|
/**
|
|
@@ -762,14 +860,14 @@ const NumberInput = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
762
860
|
const draft = (0, vue.ref)(null);
|
|
763
861
|
let input = null;
|
|
764
862
|
const inactive = (0, vue.computed)(() => props.disabled || props.readonly);
|
|
765
|
-
const ranges = (0, vue.computed)(() => (0,
|
|
863
|
+
const ranges = (0, vue.computed)(() => (0, _tremolo_ui_dom_internal.numberInputRanges)({
|
|
766
864
|
min: props.min,
|
|
767
865
|
max: props.max,
|
|
768
866
|
step: props.step,
|
|
769
867
|
scale: props.scale,
|
|
770
868
|
clampValue: props.clampValue
|
|
771
869
|
}));
|
|
772
|
-
const bounds = (0, vue.computed)(() => (0,
|
|
870
|
+
const bounds = (0, vue.computed)(() => (0, _tremolo_ui_dom_internal.numberInputBounds)(props.modelValue, {
|
|
773
871
|
min: props.min,
|
|
774
872
|
max: props.max,
|
|
775
873
|
clampValue: props.clampValue
|
|
@@ -787,11 +885,40 @@ const NumberInput = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
787
885
|
wheel: props.wheel,
|
|
788
886
|
format: props.format
|
|
789
887
|
}));
|
|
888
|
+
const gesture = useChangeGesture({
|
|
889
|
+
value: () => props.modelValue,
|
|
890
|
+
inactive: () => inactive.value,
|
|
891
|
+
endDelay: () => props.changeEndDelay,
|
|
892
|
+
onStart: (value, source) => emit("changeStart", value, source),
|
|
893
|
+
onEnd: (value, source) => emit("changeEnd", value, source)
|
|
894
|
+
});
|
|
790
895
|
function changeValue(next) {
|
|
791
896
|
if (inactive.value) return;
|
|
792
897
|
draft.value = null;
|
|
793
|
-
if (next
|
|
898
|
+
if (next === props.modelValue) return;
|
|
899
|
+
gesture.changed(next);
|
|
900
|
+
emit("update:modelValue", next);
|
|
794
901
|
}
|
|
902
|
+
let pressed = false;
|
|
903
|
+
(0, vue.provide)(NumberInputGestureKey, {
|
|
904
|
+
press: () => {
|
|
905
|
+
if (inactive.value) return;
|
|
906
|
+
gesture.hold("pointer");
|
|
907
|
+
if (pressed) return;
|
|
908
|
+
pressed = true;
|
|
909
|
+
const release = () => {
|
|
910
|
+
pressed = false;
|
|
911
|
+
gesture.end();
|
|
912
|
+
window.removeEventListener("pointerup", release);
|
|
913
|
+
window.removeEventListener("pointercancel", release);
|
|
914
|
+
};
|
|
915
|
+
window.addEventListener("pointerup", release);
|
|
916
|
+
window.addEventListener("pointercancel", release);
|
|
917
|
+
},
|
|
918
|
+
key: () => {
|
|
919
|
+
if (!inactive.value) gesture.pulse("keyboard");
|
|
920
|
+
}
|
|
921
|
+
});
|
|
795
922
|
(0, vue.provide)(NumberInputKey, {
|
|
796
923
|
get value() {
|
|
797
924
|
return props.modelValue;
|
|
@@ -823,6 +950,9 @@ const NumberInput = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
823
950
|
get pointerLock() {
|
|
824
951
|
return props.pointerLock;
|
|
825
952
|
},
|
|
953
|
+
get dragCursor() {
|
|
954
|
+
return props.dragCursor;
|
|
955
|
+
},
|
|
826
956
|
get selectOnFocus() {
|
|
827
957
|
return props.selectOnFocus;
|
|
828
958
|
},
|
|
@@ -857,29 +987,40 @@ const NumberInput = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
857
987
|
if (inactive.value) return;
|
|
858
988
|
draft.value = next;
|
|
859
989
|
const parsed = props.parse(next);
|
|
860
|
-
if (Number.isFinite(parsed))
|
|
990
|
+
if (!Number.isFinite(parsed)) return;
|
|
991
|
+
if (parsed !== props.modelValue) {
|
|
992
|
+
gesture.pulse("keyboard");
|
|
993
|
+
gesture.changed(parsed);
|
|
994
|
+
}
|
|
995
|
+
emit("update:modelValue", parsed);
|
|
861
996
|
},
|
|
862
997
|
commitDraft: () => {
|
|
863
998
|
if (draft.value === null || inactive.value) return;
|
|
864
|
-
const committed = (0,
|
|
999
|
+
const committed = (0, _tremolo_ui_dom_internal.commitNumberInputText)(draft.value, props.parse, {
|
|
865
1000
|
min: props.min,
|
|
866
1001
|
max: props.max,
|
|
867
1002
|
clampValue: props.clampValue
|
|
868
1003
|
});
|
|
869
|
-
if (committed === null)
|
|
870
|
-
|
|
1004
|
+
if (committed === null) {
|
|
1005
|
+
draft.value = null;
|
|
1006
|
+
return;
|
|
1007
|
+
}
|
|
1008
|
+
if (committed !== props.modelValue) gesture.pulse("keyboard");
|
|
1009
|
+
changeValue(committed);
|
|
1010
|
+
gesture.end();
|
|
871
1011
|
},
|
|
872
1012
|
changeValue,
|
|
873
|
-
nudge: (direction, option, modifiers) => changeValue((0,
|
|
1013
|
+
nudge: (direction, option, modifiers) => changeValue((0, _tremolo_ui_dom_internal.nudgeNumberInput)(props.modelValue, direction, option, ranges.value, modifiers)),
|
|
874
1014
|
setInput: (element) => {
|
|
875
1015
|
input = element;
|
|
876
1016
|
}
|
|
877
1017
|
});
|
|
878
1018
|
useWheel(root, (event) => {
|
|
879
|
-
const direction = (0,
|
|
1019
|
+
const direction = (0, _tremolo_ui_dom_internal.wheelDirection)(event);
|
|
880
1020
|
if (!props.wheel || inactive.value || direction === null) return;
|
|
881
1021
|
event.preventDefault();
|
|
882
|
-
|
|
1022
|
+
gesture.pulse("wheel");
|
|
1023
|
+
changeValue((0, _tremolo_ui_dom_internal.nudgeNumberInput)(props.modelValue, direction, props.wheel, ranges.value, event));
|
|
883
1024
|
}, { requireFocus: true });
|
|
884
1025
|
expose({
|
|
885
1026
|
focus: () => {
|
|
@@ -917,9 +1058,11 @@ function stepperButton(name, direction) {
|
|
|
917
1058
|
setup(_, { slots }) {
|
|
918
1059
|
const field = useNumberInputContext();
|
|
919
1060
|
const stepper = (0, vue.inject)(StepperKey, null);
|
|
1061
|
+
const gesture = (0, vue.inject)(NumberInputGestureKey, null);
|
|
920
1062
|
const blocked = (0, vue.computed)(() => field.disabled || (direction > 0 ? field.atMax : field.atMin));
|
|
921
1063
|
const press = useLongPress({ onPress: () => {
|
|
922
1064
|
if (field.disabled || field.readonly) return;
|
|
1065
|
+
gesture?.press();
|
|
923
1066
|
if (stepper?.moved()) return;
|
|
924
1067
|
field.nudge(direction, ["raw", field.step]);
|
|
925
1068
|
} });
|
|
@@ -960,6 +1103,7 @@ const NumberInputField = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
960
1103
|
name: "NumberInputField",
|
|
961
1104
|
setup(_, { expose }) {
|
|
962
1105
|
const field = useNumberInputContext();
|
|
1106
|
+
const gesture = (0, vue.inject)(NumberInputGestureKey, null);
|
|
963
1107
|
const input = (0, vue.ref)(null);
|
|
964
1108
|
const focused = (0, vue.ref)(false);
|
|
965
1109
|
(0, vue.watchEffect)(() => field.setInput(input.value));
|
|
@@ -973,18 +1117,19 @@ const NumberInputField = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
973
1117
|
const span = field.selectOnFocus === "all" ? {
|
|
974
1118
|
start: 0,
|
|
975
1119
|
end: element.value.length
|
|
976
|
-
} : (0,
|
|
1120
|
+
} : (0, _tremolo_ui_dom_internal.numberSpan)(element.value);
|
|
977
1121
|
if (span) element.setSelectionRange(span.start, span.end);
|
|
978
1122
|
}
|
|
979
1123
|
async function step(direction, event) {
|
|
980
1124
|
const element = event.currentTarget;
|
|
981
1125
|
const from = element.value;
|
|
982
|
-
const offset = field.keepCaretOnStep && element.selectionStart !== null ? (0,
|
|
1126
|
+
const offset = field.keepCaretOnStep && element.selectionStart !== null ? (0, _tremolo_ui_dom_internal.caretDecimalOffset)(from, element.selectionStart) : null;
|
|
1127
|
+
gesture?.key();
|
|
983
1128
|
field.nudge(direction, field.keyboard, event);
|
|
984
1129
|
if (offset === null) return;
|
|
985
1130
|
await (0, vue.nextTick)();
|
|
986
1131
|
if (element.value === from) return;
|
|
987
|
-
const caret = (0,
|
|
1132
|
+
const caret = (0, _tremolo_ui_dom_internal.caretAtDecimalOffset)(element.value, offset);
|
|
988
1133
|
element.setSelectionRange(caret, caret);
|
|
989
1134
|
}
|
|
990
1135
|
expose({
|
|
@@ -1045,6 +1190,7 @@ const NumberInputStepper = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
1045
1190
|
name: "NumberInputStepper",
|
|
1046
1191
|
setup(_, { slots }) {
|
|
1047
1192
|
const field = useNumberInputContext();
|
|
1193
|
+
const gesture = (0, vue.inject)(NumberInputGestureKey, null);
|
|
1048
1194
|
const el = (0, vue.ref)(null);
|
|
1049
1195
|
let instance = null;
|
|
1050
1196
|
const enabled = (0, vue.computed)(() => field.drag !== null && !field.disabled && !field.readonly);
|
|
@@ -1052,11 +1198,12 @@ const NumberInputStepper = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
1052
1198
|
range: field.rawRange,
|
|
1053
1199
|
pixels: field.drag ?? 1,
|
|
1054
1200
|
sensitivity: field.dragSensitivity,
|
|
1055
|
-
pointerLock: field.pointerLock
|
|
1201
|
+
pointerLock: field.pointerLock,
|
|
1202
|
+
cursor: field.dragCursor
|
|
1056
1203
|
});
|
|
1057
1204
|
(0, vue.watch)([el, enabled], ([element, on], _, onCleanup) => {
|
|
1058
1205
|
if (!element || !on) return;
|
|
1059
|
-
const current = (0,
|
|
1206
|
+
const current = (0, _tremolo_ui_dom_internal.createStepperDrag)(element, {
|
|
1060
1207
|
...options(),
|
|
1061
1208
|
getValue: () => field.value,
|
|
1062
1209
|
onChange: (next) => field.changeValue(next)
|
|
@@ -1072,70 +1219,76 @@ const NumberInputStepper = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
1072
1219
|
});
|
|
1073
1220
|
(0, vue.watch)(options, (next) => instance?.update(next));
|
|
1074
1221
|
(0, vue.provide)(StepperKey, { moved: () => instance?.moved() ?? false });
|
|
1075
|
-
return () => (0, vue.h)("div", {
|
|
1222
|
+
return () => (0, vue.h)("div", {
|
|
1223
|
+
ref: el,
|
|
1224
|
+
onPointerdown: () => {
|
|
1225
|
+
if (enabled.value) gesture?.press();
|
|
1226
|
+
}
|
|
1227
|
+
}, slots.default?.());
|
|
1076
1228
|
}
|
|
1077
1229
|
});
|
|
1078
1230
|
//#endregion
|
|
1079
1231
|
//#region src/components/Piano/Piano.ts
|
|
1232
|
+
const pianoProps = {
|
|
1233
|
+
/** The notes drawn, from `first` to `last`. */
|
|
1234
|
+
noteRange: {
|
|
1235
|
+
type: Object,
|
|
1236
|
+
required: true
|
|
1237
|
+
},
|
|
1238
|
+
/** Let a pointer slide from one key to the next. @default true */
|
|
1239
|
+
glissando: {
|
|
1240
|
+
type: Boolean,
|
|
1241
|
+
default: true
|
|
1242
|
+
},
|
|
1243
|
+
/** Highest note that can sound. @default 127 */
|
|
1244
|
+
midiMax: {
|
|
1245
|
+
type: Number,
|
|
1246
|
+
default: 127
|
|
1247
|
+
},
|
|
1248
|
+
/** Play notes from the computer keyboard. See `SHORTCUTS` in `@tremolo-ui/dom`. */
|
|
1249
|
+
keyboardShortcuts: Object,
|
|
1250
|
+
/** Where keyboard shortcuts listen. @default 'root' */
|
|
1251
|
+
keyboardShortcutsScope: {
|
|
1252
|
+
type: String,
|
|
1253
|
+
default: "root"
|
|
1254
|
+
},
|
|
1255
|
+
/** Follow the width of the parent element. */
|
|
1256
|
+
resizable: Boolean,
|
|
1257
|
+
/** Width of a white key in pixels. @default 40 */
|
|
1258
|
+
whiteKeyWidth: {
|
|
1259
|
+
type: Number,
|
|
1260
|
+
default: 40
|
|
1261
|
+
},
|
|
1262
|
+
/** Space between two white keys, in pixels. @default 1 */
|
|
1263
|
+
keyGap: {
|
|
1264
|
+
type: Number,
|
|
1265
|
+
default: 1
|
|
1266
|
+
},
|
|
1267
|
+
/** Width of a black key, as a fraction of a white one. @default 0.65 */
|
|
1268
|
+
blackKeyWidthRatio: {
|
|
1269
|
+
type: Number,
|
|
1270
|
+
default: .65
|
|
1271
|
+
},
|
|
1272
|
+
/** Height of a black key, as a fraction of the keyboard. @default 0.6 */
|
|
1273
|
+
blackKeyHeightRatio: {
|
|
1274
|
+
type: Number,
|
|
1275
|
+
default: .6
|
|
1276
|
+
},
|
|
1277
|
+
/** Classes for the label inside each key. */
|
|
1278
|
+
classes: Object,
|
|
1279
|
+
/**
|
|
1280
|
+
* Extra attributes for one key, by note. The geometry of the key is
|
|
1281
|
+
* applied after the returned style and cannot be overridden.
|
|
1282
|
+
*/
|
|
1283
|
+
keyProps: Function
|
|
1284
|
+
};
|
|
1080
1285
|
/**
|
|
1081
1286
|
* Customizable piano. The keys are drawn by the component; what goes inside
|
|
1082
1287
|
* one is the `label` slot, which receives the note and its state.
|
|
1083
1288
|
*/
|
|
1084
1289
|
const Piano = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
1085
1290
|
name: "Piano",
|
|
1086
|
-
props:
|
|
1087
|
-
/** The notes drawn, from `first` to `last`. */
|
|
1088
|
-
noteRange: {
|
|
1089
|
-
type: Object,
|
|
1090
|
-
required: true
|
|
1091
|
-
},
|
|
1092
|
-
/** Let a pointer slide from one key to the next. @default true */
|
|
1093
|
-
glissando: {
|
|
1094
|
-
type: Boolean,
|
|
1095
|
-
default: true
|
|
1096
|
-
},
|
|
1097
|
-
/** Highest note that can sound. @default 127 */
|
|
1098
|
-
midiMax: {
|
|
1099
|
-
type: Number,
|
|
1100
|
-
default: 127
|
|
1101
|
-
},
|
|
1102
|
-
/** Play notes from the computer keyboard. See `SHORTCUTS` in `@tremolo-ui/dom`. */
|
|
1103
|
-
keyboardShortcuts: Object,
|
|
1104
|
-
/** Where keyboard shortcuts listen. @default 'root' */
|
|
1105
|
-
keyboardShortcutsScope: {
|
|
1106
|
-
type: String,
|
|
1107
|
-
default: "root"
|
|
1108
|
-
},
|
|
1109
|
-
/** Follow the width of the parent element. */
|
|
1110
|
-
resizable: Boolean,
|
|
1111
|
-
/** Width of a white key in pixels. @default 40 */
|
|
1112
|
-
whiteKeyWidth: {
|
|
1113
|
-
type: Number,
|
|
1114
|
-
default: 40
|
|
1115
|
-
},
|
|
1116
|
-
/** Space between two white keys, in pixels. @default 1 */
|
|
1117
|
-
keyGap: {
|
|
1118
|
-
type: Number,
|
|
1119
|
-
default: 1
|
|
1120
|
-
},
|
|
1121
|
-
/** Width of a black key, as a fraction of a white one. @default 0.65 */
|
|
1122
|
-
blackKeyWidthRatio: {
|
|
1123
|
-
type: Number,
|
|
1124
|
-
default: .65
|
|
1125
|
-
},
|
|
1126
|
-
/** Height of a black key, as a fraction of the keyboard. @default 0.6 */
|
|
1127
|
-
blackKeyHeightRatio: {
|
|
1128
|
-
type: Number,
|
|
1129
|
-
default: .6
|
|
1130
|
-
},
|
|
1131
|
-
/** Classes for the label inside each key. */
|
|
1132
|
-
classes: Object,
|
|
1133
|
-
/**
|
|
1134
|
-
* Extra attributes for one key, by note. The geometry of the key is
|
|
1135
|
-
* applied after the returned style and cannot be overridden.
|
|
1136
|
-
*/
|
|
1137
|
-
keyProps: Function
|
|
1138
|
-
},
|
|
1291
|
+
props: pianoProps,
|
|
1139
1292
|
emits: {
|
|
1140
1293
|
/** A note started sounding. */
|
|
1141
1294
|
playNote: (note, _velocity) => typeof note === "number",
|
|
@@ -1148,7 +1301,7 @@ const Piano = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
1148
1301
|
const activeNotes = (0, vue.ref)([]);
|
|
1149
1302
|
/** Set while `resizable` is on, measured from the parent. */
|
|
1150
1303
|
const resizedKeyWidth = (0, vue.ref)(null);
|
|
1151
|
-
const notes = (0, vue.computed)(() => (0,
|
|
1304
|
+
const notes = (0, vue.computed)(() => (0, _tremolo_ui_dom_internal.getNoteRangeArray)(props.noteRange));
|
|
1152
1305
|
const layout = (0, vue.computed)(() => ({
|
|
1153
1306
|
noteRange: props.noteRange,
|
|
1154
1307
|
whiteKeyWidth: props.resizable ? resizedKeyWidth.value ?? props.whiteKeyWidth : props.whiteKeyWidth,
|
|
@@ -1196,7 +1349,7 @@ const Piano = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
1196
1349
|
const parent = element.parentElement;
|
|
1197
1350
|
if (!parent) throw new Error("doesn't have a parent element.");
|
|
1198
1351
|
const observer = new ResizeObserver(() => {
|
|
1199
|
-
resizedKeyWidth.value = (0,
|
|
1352
|
+
resizedKeyWidth.value = (0, _tremolo_ui_dom_internal.fitWhiteKeyWidth)(element.clientWidth, {
|
|
1200
1353
|
noteRange: {
|
|
1201
1354
|
first,
|
|
1202
1355
|
last
|
|
@@ -1227,7 +1380,7 @@ const Piano = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
1227
1380
|
"data-resizable": props.resizable ? "" : void 0,
|
|
1228
1381
|
style: {
|
|
1229
1382
|
position: "relative",
|
|
1230
|
-
width: props.resizable ? "100%" : `${(0,
|
|
1383
|
+
width: props.resizable ? "100%" : `${(0, _tremolo_ui_dom_internal.pianoWidth)(layout.value)}px`
|
|
1231
1384
|
}
|
|
1232
1385
|
}, notes.value.map((note, index) => {
|
|
1233
1386
|
const state = {
|
|
@@ -1257,7 +1410,7 @@ const Piano = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
1257
1410
|
keyStyle,
|
|
1258
1411
|
{
|
|
1259
1412
|
left: `${(0, _tremolo_ui_dom.notePosition)(note, layout.value)}px`,
|
|
1260
|
-
width: `${white ? layout.value.whiteKeyWidth : (0,
|
|
1413
|
+
width: `${white ? layout.value.whiteKeyWidth : (0, _tremolo_ui_dom_internal.blackKeyWidth)(layout.value)}px`,
|
|
1261
1414
|
height: white ? "100%" : `${props.blackKeyHeightRatio * 100}%`
|
|
1262
1415
|
}
|
|
1263
1416
|
]
|
|
@@ -1275,42 +1428,46 @@ function usePointsEditorContext() {
|
|
|
1275
1428
|
//#endregion
|
|
1276
1429
|
//#region src/components/PointsEditor/PointsEditor.ts
|
|
1277
1430
|
const EMPTY = [];
|
|
1431
|
+
const pointsEditorProps = {
|
|
1432
|
+
/** Make the points unchangeable and remove them from the tab order. */
|
|
1433
|
+
disabled: Boolean,
|
|
1434
|
+
/** Make the points unmovable. */
|
|
1435
|
+
readonly: Boolean,
|
|
1436
|
+
/** The cursor to show while dragging a point. @default 'grabbing' */
|
|
1437
|
+
dragCursor: {
|
|
1438
|
+
type: String,
|
|
1439
|
+
default: "grabbing"
|
|
1440
|
+
},
|
|
1441
|
+
/** How much one wheel notch moves the focused point. */
|
|
1442
|
+
wheel: {
|
|
1443
|
+
type: [Array, Object],
|
|
1444
|
+
default: () => _tremolo_ui_dom_internal.POINTS_EDITOR_DEFAULT_WHEEL
|
|
1445
|
+
},
|
|
1446
|
+
/** How much one arrow key press moves a point. */
|
|
1447
|
+
keyboard: {
|
|
1448
|
+
type: [Array, Object],
|
|
1449
|
+
default: () => _tremolo_ui_dom_internal.POINTS_EDITOR_DEFAULT_KEYBOARD
|
|
1450
|
+
},
|
|
1451
|
+
/** How much a drag moves a point, per modifier key. */
|
|
1452
|
+
dragSensitivity: {
|
|
1453
|
+
type: [Number, Object],
|
|
1454
|
+
default: () => _tremolo_ui_dom.DEFAULT_DRAG_SENSITIVITY
|
|
1455
|
+
},
|
|
1456
|
+
/**
|
|
1457
|
+
* Let points be selected, and a selection be moved as one. A selection
|
|
1458
|
+
* updates several points in the same tick.
|
|
1459
|
+
*/
|
|
1460
|
+
selectable: Boolean,
|
|
1461
|
+
/** Ids of the selected points. Bind it with `v-model:selection`. */
|
|
1462
|
+
selection: Array
|
|
1463
|
+
};
|
|
1278
1464
|
/**
|
|
1279
1465
|
* Multiple point controller. Bind the selection with `v-model:selection` to
|
|
1280
1466
|
* hold it yourself; the editor keeps its own otherwise.
|
|
1281
1467
|
*/
|
|
1282
1468
|
const PointsEditor = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
1283
1469
|
name: "PointsEditor",
|
|
1284
|
-
props:
|
|
1285
|
-
/** Make the points unchangeable and remove them from the tab order. */
|
|
1286
|
-
disabled: Boolean,
|
|
1287
|
-
/** Make the points unmovable. */
|
|
1288
|
-
readonly: Boolean,
|
|
1289
|
-
/** The cursor to show while dragging a point. @default { cursor: 'grabbing' } */
|
|
1290
|
-
externalStyles: Object,
|
|
1291
|
-
/** How much one wheel notch moves the focused point. */
|
|
1292
|
-
wheel: {
|
|
1293
|
-
type: [Array, Object],
|
|
1294
|
-
default: () => _tremolo_ui_dom.POINTS_EDITOR_DEFAULT_WHEEL
|
|
1295
|
-
},
|
|
1296
|
-
/** How much one arrow key press moves a point. */
|
|
1297
|
-
keyboard: {
|
|
1298
|
-
type: [Array, Object],
|
|
1299
|
-
default: () => _tremolo_ui_dom.POINTS_EDITOR_DEFAULT_KEYBOARD
|
|
1300
|
-
},
|
|
1301
|
-
/** How much a drag moves a point, per modifier key. */
|
|
1302
|
-
dragSensitivity: {
|
|
1303
|
-
type: [Number, Object],
|
|
1304
|
-
default: () => _tremolo_ui_dom.DEFAULT_DRAG_SENSITIVITY
|
|
1305
|
-
},
|
|
1306
|
-
/**
|
|
1307
|
-
* Let points be selected, and a selection be moved as one. A selection
|
|
1308
|
-
* updates several points in the same tick.
|
|
1309
|
-
*/
|
|
1310
|
-
selectable: Boolean,
|
|
1311
|
-
/** Ids of the selected points. Bind it with `v-model:selection`. */
|
|
1312
|
-
selection: Array
|
|
1313
|
-
},
|
|
1470
|
+
props: pointsEditorProps,
|
|
1314
1471
|
emits: { "update:selection": (selection) => Array.isArray(selection) },
|
|
1315
1472
|
setup(props, { slots, emit }) {
|
|
1316
1473
|
const ownSelection = (0, vue.shallowRef)(props.selection ?? []);
|
|
@@ -1347,8 +1504,8 @@ const PointsEditor = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
1347
1504
|
get dragSensitivity() {
|
|
1348
1505
|
return props.dragSensitivity;
|
|
1349
1506
|
},
|
|
1350
|
-
get
|
|
1351
|
-
return props.
|
|
1507
|
+
get dragCursor() {
|
|
1508
|
+
return props.dragCursor;
|
|
1352
1509
|
},
|
|
1353
1510
|
get selectable() {
|
|
1354
1511
|
return props.selectable;
|
|
@@ -1404,7 +1561,7 @@ const PointsEditorContainer = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
1404
1561
|
(0, vue.watch)([el, selecting], ([element, on], _, onCleanup) => {
|
|
1405
1562
|
if (!element || !on) return;
|
|
1406
1563
|
const drag = (0, _tremolo_ui_dom.createDragValue)(element, {
|
|
1407
|
-
axis:
|
|
1564
|
+
axis: _tremolo_ui_dom_internal.POINT_AXIS,
|
|
1408
1565
|
mapping: (0, _tremolo_ui_dom.elementMapping)(() => element),
|
|
1409
1566
|
shouldStart: (event) => !points.editor.isPointElement(event.target),
|
|
1410
1567
|
onDragStart: ([x, y], state) => points.editor.beginSelectionBox({
|
|
@@ -1423,7 +1580,7 @@ const PointsEditorContainer = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
1423
1580
|
flush: "post"
|
|
1424
1581
|
});
|
|
1425
1582
|
useWheel(el, (event) => {
|
|
1426
|
-
const move = (0,
|
|
1583
|
+
const move = (0, _tremolo_ui_dom_internal.wheelMove)(event);
|
|
1427
1584
|
if (!move) return;
|
|
1428
1585
|
const axis = move.axis === 0 ? "x" : "y";
|
|
1429
1586
|
if (points.editor.nudgeFocusedPoint(axis, move.direction, event)) event.preventDefault();
|
|
@@ -1451,59 +1608,76 @@ function visuallyHiddenRangeInput(props) {
|
|
|
1451
1608
|
return (0, vue.h)("input", {
|
|
1452
1609
|
...props,
|
|
1453
1610
|
type: "range",
|
|
1454
|
-
style:
|
|
1611
|
+
style: _tremolo_ui_dom_internal.visuallyHiddenStyle
|
|
1455
1612
|
});
|
|
1456
1613
|
}
|
|
1457
1614
|
//#endregion
|
|
1458
1615
|
//#region src/components/PointsEditor/PointsEditorPoint.ts
|
|
1459
1616
|
const perAxis = (setting, axis) => typeof setting === "string" ? setting : setting?.[axis];
|
|
1617
|
+
const pointsEditorPointProps = {
|
|
1618
|
+
/** Where the point is, with `y` growing downwards. Bind it with `v-model`. */
|
|
1619
|
+
modelValue: {
|
|
1620
|
+
type: Object,
|
|
1621
|
+
required: true
|
|
1622
|
+
},
|
|
1623
|
+
/** How the selection refers to this point. One is generated when left out. */
|
|
1624
|
+
id: String,
|
|
1625
|
+
/** The lowest position the point can take, per axis. */
|
|
1626
|
+
min: Object,
|
|
1627
|
+
/** The highest position the point can take, per axis. */
|
|
1628
|
+
max: Object,
|
|
1629
|
+
/** Sets `--color`, for the theme to colour the point with. */
|
|
1630
|
+
color: String,
|
|
1631
|
+
/** Overrides the `disabled` of `PointsEditor`. */
|
|
1632
|
+
disabled: {
|
|
1633
|
+
type: Boolean,
|
|
1634
|
+
default: void 0
|
|
1635
|
+
},
|
|
1636
|
+
/** Overrides the `readonly` of `PointsEditor`. */
|
|
1637
|
+
readonly: {
|
|
1638
|
+
type: Boolean,
|
|
1639
|
+
default: void 0
|
|
1640
|
+
},
|
|
1641
|
+
/**
|
|
1642
|
+
* How long after the last wheel notch or arrow key a change counts as over,
|
|
1643
|
+
* in milliseconds, for `change-end`.
|
|
1644
|
+
* @default 500
|
|
1645
|
+
*/
|
|
1646
|
+
changeEndDelay: {
|
|
1647
|
+
type: Number,
|
|
1648
|
+
default: 500
|
|
1649
|
+
},
|
|
1650
|
+
/** Overrides the `wheel` of `PointsEditor`; `null` turns it off. */
|
|
1651
|
+
wheel: {
|
|
1652
|
+
type: [Array, Object],
|
|
1653
|
+
default: void 0
|
|
1654
|
+
},
|
|
1655
|
+
/** Overrides the `keyboard` of `PointsEditor`; `null` turns it off. */
|
|
1656
|
+
keyboard: {
|
|
1657
|
+
type: [Array, Object],
|
|
1658
|
+
default: void 0
|
|
1659
|
+
},
|
|
1660
|
+
/** The accessible name of each axis, or one for both. */
|
|
1661
|
+
ariaLabel: [String, Object],
|
|
1662
|
+
/** What the value of each axis means, or one for both. */
|
|
1663
|
+
ariaValuetext: [String, Object]
|
|
1664
|
+
};
|
|
1460
1665
|
/** One point, bound with `v-model` as `{ x, y }` from 0 to 1. */
|
|
1461
1666
|
const PointsEditorPoint = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
1462
1667
|
name: "PointsEditorPoint",
|
|
1463
1668
|
inheritAttrs: false,
|
|
1464
|
-
props:
|
|
1465
|
-
/** Where the point is, with `y` growing downwards. Bind it with `v-model`. */
|
|
1466
|
-
modelValue: {
|
|
1467
|
-
type: Object,
|
|
1468
|
-
required: true
|
|
1469
|
-
},
|
|
1470
|
-
/** How the selection refers to this point. One is generated when left out. */
|
|
1471
|
-
id: String,
|
|
1472
|
-
/** The lowest position the point can take, per axis. */
|
|
1473
|
-
min: Object,
|
|
1474
|
-
/** The highest position the point can take, per axis. */
|
|
1475
|
-
max: Object,
|
|
1476
|
-
/** Sets `--color`, for the theme to colour the point with. */
|
|
1477
|
-
color: String,
|
|
1478
|
-
/** Overrides the `disabled` of `PointsEditor`. */
|
|
1479
|
-
disabled: {
|
|
1480
|
-
type: Boolean,
|
|
1481
|
-
default: void 0
|
|
1482
|
-
},
|
|
1483
|
-
/** Overrides the `readonly` of `PointsEditor`. */
|
|
1484
|
-
readonly: {
|
|
1485
|
-
type: Boolean,
|
|
1486
|
-
default: void 0
|
|
1487
|
-
},
|
|
1488
|
-
/** Overrides the `wheel` of `PointsEditor`; `null` turns it off. */
|
|
1489
|
-
wheel: {
|
|
1490
|
-
type: [Array, Object],
|
|
1491
|
-
default: void 0
|
|
1492
|
-
},
|
|
1493
|
-
/** Overrides the `keyboard` of `PointsEditor`; `null` turns it off. */
|
|
1494
|
-
keyboard: {
|
|
1495
|
-
type: [Array, Object],
|
|
1496
|
-
default: void 0
|
|
1497
|
-
},
|
|
1498
|
-
/** The accessible name of each axis, or one for both. */
|
|
1499
|
-
ariaLabel: [String, Object],
|
|
1500
|
-
/** What the value of each axis means, or one for both. */
|
|
1501
|
-
ariaValuetext: [String, Object]
|
|
1502
|
-
},
|
|
1669
|
+
props: pointsEditorPointProps,
|
|
1503
1670
|
emits: {
|
|
1504
1671
|
"update:modelValue": (value) => typeof value === "object",
|
|
1505
|
-
|
|
1506
|
-
|
|
1672
|
+
/**
|
|
1673
|
+
* A change of this point started — a drag on it, the first wheel notch or
|
|
1674
|
+
* arrow key while it has the focus — with where it is and what the change
|
|
1675
|
+
* is made with. The points that move along with a selection report
|
|
1676
|
+
* through `update:modelValue` only.
|
|
1677
|
+
*/
|
|
1678
|
+
changeStart: (value, _source) => typeof value === "object",
|
|
1679
|
+
/** The change ended, with where the point is. */
|
|
1680
|
+
changeEnd: (value, _source) => typeof value === "object"
|
|
1507
1681
|
},
|
|
1508
1682
|
setup(props, { slots, attrs, emit }) {
|
|
1509
1683
|
const points = usePointsEditorContext();
|
|
@@ -1515,7 +1689,14 @@ const PointsEditorPoint = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
1515
1689
|
const inactive = (0, vue.computed)(() => disabled.value || readonly.value);
|
|
1516
1690
|
const wheel = (0, vue.computed)(() => props.wheel === void 0 ? points.wheel : props.wheel);
|
|
1517
1691
|
const keyboard = (0, vue.computed)(() => props.keyboard === void 0 ? points.keyboard : props.keyboard);
|
|
1518
|
-
const current = (0, vue.computed)(() => (0,
|
|
1692
|
+
const current = (0, vue.computed)(() => (0, _tremolo_ui_dom_internal.clampPoint)(props.modelValue, props.min, props.max));
|
|
1693
|
+
const gesture = useChangeGesture({
|
|
1694
|
+
value: () => current.value,
|
|
1695
|
+
inactive: () => inactive.value,
|
|
1696
|
+
endDelay: () => props.changeEndDelay,
|
|
1697
|
+
onStart: (value, source) => emit("changeStart", value, source),
|
|
1698
|
+
onEnd: (value, source) => emit("changeEnd", value, source)
|
|
1699
|
+
});
|
|
1519
1700
|
const el = (0, vue.ref)(null);
|
|
1520
1701
|
const x = (0, vue.ref)(null);
|
|
1521
1702
|
const dragging = (0, vue.ref)(false);
|
|
@@ -1524,9 +1705,13 @@ const PointsEditorPoint = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
1524
1705
|
min: props.min,
|
|
1525
1706
|
max: props.max,
|
|
1526
1707
|
readonly: inactive.value,
|
|
1527
|
-
onChange: (next) =>
|
|
1708
|
+
onChange: (next) => {
|
|
1709
|
+
gesture.changed(next);
|
|
1710
|
+
emit("update:modelValue", next);
|
|
1711
|
+
},
|
|
1528
1712
|
element: el.value,
|
|
1529
|
-
wheel: wheel.value
|
|
1713
|
+
wheel: wheel.value,
|
|
1714
|
+
beforeWheel: () => gesture.pulse("wheel")
|
|
1530
1715
|
});
|
|
1531
1716
|
(0, vue.watch)(id, (key, _, onCleanup) => onCleanup(points.editor.registerPoint(key, read)), { immediate: true });
|
|
1532
1717
|
/** Where the pointer was when the drag started. */
|
|
@@ -1534,9 +1719,9 @@ const PointsEditorPoint = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
1534
1719
|
(0, vue.watch)(el, (element, _, onCleanup) => {
|
|
1535
1720
|
if (!element) return;
|
|
1536
1721
|
const drag = (0, _tremolo_ui_dom.createDragValue)(element, {
|
|
1537
|
-
axis:
|
|
1538
|
-
mapping: (0, _tremolo_ui_dom.elementMapping)(() => points.container, { sensitivity: (state) => (0,
|
|
1539
|
-
cursor: inactive.value ? void 0 : points.
|
|
1722
|
+
axis: _tremolo_ui_dom_internal.POINT_AXIS,
|
|
1723
|
+
mapping: (0, _tremolo_ui_dom.elementMapping)(() => points.container, { sensitivity: (state) => (0, _tremolo_ui_dom_internal.selectModifier)(points.dragSensitivity, state.event).value }),
|
|
1724
|
+
cursor: inactive.value ? void 0 : points.dragCursor,
|
|
1540
1725
|
shouldStart: () => !disabled.value,
|
|
1541
1726
|
onChange: ([px, py]) => {
|
|
1542
1727
|
if (origin) points.editor.movePointDrag({
|
|
@@ -1552,15 +1737,15 @@ const PointsEditorPoint = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
1552
1737
|
};
|
|
1553
1738
|
dragging.value = true;
|
|
1554
1739
|
x.value?.focus();
|
|
1555
|
-
if (!inactive.value)
|
|
1740
|
+
if (!inactive.value) gesture.hold("pointer");
|
|
1556
1741
|
},
|
|
1557
1742
|
onDragEnd: () => {
|
|
1558
1743
|
origin = null;
|
|
1559
1744
|
dragging.value = false;
|
|
1560
|
-
|
|
1745
|
+
gesture.end();
|
|
1561
1746
|
}
|
|
1562
1747
|
});
|
|
1563
|
-
const stop = (0, vue.watch)(() => inactive.value ? void 0 : points.
|
|
1748
|
+
const stop = (0, vue.watch)(() => inactive.value ? void 0 : points.dragCursor, (cursor) => drag.update({ cursor }));
|
|
1564
1749
|
onCleanup(() => {
|
|
1565
1750
|
stop();
|
|
1566
1751
|
drag.destroy();
|
|
@@ -1621,10 +1806,11 @@ const PointsEditorPoint = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
1621
1806
|
if (!disabled.value && event.target === event.currentTarget) x.value?.focus();
|
|
1622
1807
|
},
|
|
1623
1808
|
onKeydown: (event) => {
|
|
1624
|
-
const move = (0,
|
|
1809
|
+
const move = (0, _tremolo_ui_dom_internal.arrowKeyMove)(event.key);
|
|
1625
1810
|
if (!move) return;
|
|
1626
1811
|
event.preventDefault();
|
|
1627
1812
|
if (inactive.value || !keyboard.value) return;
|
|
1813
|
+
gesture.pulse("keyboard");
|
|
1628
1814
|
points.editor.nudgePoint(id.value, move.axis === 0 ? "x" : "y", move.direction, keyboard.value, event);
|
|
1629
1815
|
}
|
|
1630
1816
|
}, {
|
|
@@ -1674,62 +1860,85 @@ function useSliderContext() {
|
|
|
1674
1860
|
}
|
|
1675
1861
|
//#endregion
|
|
1676
1862
|
//#region src/components/Slider/Slider.ts
|
|
1863
|
+
const sliderProps = {
|
|
1864
|
+
/** The current value. Bind it with `v-model`. */
|
|
1865
|
+
modelValue: {
|
|
1866
|
+
type: Number,
|
|
1867
|
+
required: true
|
|
1868
|
+
},
|
|
1869
|
+
/** The value at the start of the travel. */
|
|
1870
|
+
min: {
|
|
1871
|
+
type: Number,
|
|
1872
|
+
required: true
|
|
1873
|
+
},
|
|
1874
|
+
/** The value at the end of the travel. */
|
|
1875
|
+
max: {
|
|
1876
|
+
type: Number,
|
|
1877
|
+
required: true
|
|
1878
|
+
},
|
|
1879
|
+
/** Granularity of the value. @default 1 */
|
|
1880
|
+
step: {
|
|
1881
|
+
type: Number,
|
|
1882
|
+
default: 1
|
|
1883
|
+
},
|
|
1884
|
+
/** How the value is distributed across the travel. @default linearScale */
|
|
1885
|
+
scale: {
|
|
1886
|
+
type: Object,
|
|
1887
|
+
default: () => _tremolo_ui_functions.linearScale
|
|
1888
|
+
},
|
|
1889
|
+
/**
|
|
1890
|
+
* Which way the slider runs. A vertical slider grows upwards.
|
|
1891
|
+
* @default 'horizontal'
|
|
1892
|
+
*/
|
|
1893
|
+
orientation: {
|
|
1894
|
+
type: String,
|
|
1895
|
+
default: "horizontal"
|
|
1896
|
+
},
|
|
1897
|
+
/** Grow the value the other way. */
|
|
1898
|
+
reverse: Boolean,
|
|
1899
|
+
/** The cursor to show while dragging. @default 'pointer' */
|
|
1900
|
+
dragCursor: {
|
|
1901
|
+
type: String,
|
|
1902
|
+
default: "pointer"
|
|
1903
|
+
},
|
|
1904
|
+
wheel: wheelProp,
|
|
1905
|
+
keyboard: keyboardProp,
|
|
1906
|
+
dragSensitivity: dragSensitivityProp,
|
|
1907
|
+
/** Make the slider unchangeable and remove it from the tab order. */
|
|
1908
|
+
disabled: Boolean,
|
|
1909
|
+
/** Make the value unchangeable. */
|
|
1910
|
+
readonly: Boolean,
|
|
1911
|
+
/**
|
|
1912
|
+
* How long after the last wheel notch or arrow key a change counts as over,
|
|
1913
|
+
* in milliseconds, for `change-end`.
|
|
1914
|
+
* @default 500
|
|
1915
|
+
*/
|
|
1916
|
+
changeEndDelay: {
|
|
1917
|
+
type: Number,
|
|
1918
|
+
default: 500
|
|
1919
|
+
}
|
|
1920
|
+
};
|
|
1677
1921
|
/** Customizable slider. Bind the value with `v-model`. */
|
|
1678
1922
|
const Slider = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
1679
1923
|
name: "Slider",
|
|
1680
|
-
props:
|
|
1681
|
-
/** The current value. Bind it with `v-model`. */
|
|
1682
|
-
modelValue: {
|
|
1683
|
-
type: Number,
|
|
1684
|
-
required: true
|
|
1685
|
-
},
|
|
1686
|
-
/** The value at the start of the travel. */
|
|
1687
|
-
min: {
|
|
1688
|
-
type: Number,
|
|
1689
|
-
required: true
|
|
1690
|
-
},
|
|
1691
|
-
/** The value at the end of the travel. */
|
|
1692
|
-
max: {
|
|
1693
|
-
type: Number,
|
|
1694
|
-
required: true
|
|
1695
|
-
},
|
|
1696
|
-
/** Granularity of the value. @default 1 */
|
|
1697
|
-
step: {
|
|
1698
|
-
type: Number,
|
|
1699
|
-
default: 1
|
|
1700
|
-
},
|
|
1701
|
-
/** How the value is distributed across the travel. @default linearScale */
|
|
1702
|
-
scale: {
|
|
1703
|
-
type: Object,
|
|
1704
|
-
default: () => _tremolo_ui_functions.linearScale
|
|
1705
|
-
},
|
|
1706
|
-
/** Run the slider vertically, with the value growing upwards. */
|
|
1707
|
-
vertical: Boolean,
|
|
1708
|
-
/** Grow the value the other way. */
|
|
1709
|
-
reverse: Boolean,
|
|
1710
|
-
/** The cursor to show while dragging. @default { cursor: 'pointer' } */
|
|
1711
|
-
externalStyles: Object,
|
|
1712
|
-
wheel: wheelProp,
|
|
1713
|
-
keyboard: keyboardProp,
|
|
1714
|
-
dragSensitivity: dragSensitivityProp,
|
|
1715
|
-
/** Make the slider unchangeable and remove it from the tab order. */
|
|
1716
|
-
disabled: Boolean,
|
|
1717
|
-
/** Make the value unchangeable. */
|
|
1718
|
-
readonly: Boolean
|
|
1719
|
-
},
|
|
1924
|
+
props: sliderProps,
|
|
1720
1925
|
emits: {
|
|
1721
1926
|
"update:modelValue": (value) => typeof value === "number",
|
|
1722
|
-
/**
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1927
|
+
/**
|
|
1928
|
+
* A change of the value started, with the value before it and what it is
|
|
1929
|
+
* made with.
|
|
1930
|
+
*/
|
|
1931
|
+
changeStart: (value, _source) => typeof value === "number",
|
|
1932
|
+
/** The change ended, with the value it ended on. */
|
|
1933
|
+
changeEnd: (value, _source) => typeof value === "number"
|
|
1726
1934
|
},
|
|
1727
1935
|
setup(props, { slots, emit, expose }) {
|
|
1728
1936
|
const root = (0, vue.ref)(null);
|
|
1729
1937
|
let track = null;
|
|
1730
1938
|
let thumb = null;
|
|
1731
1939
|
const inactive = (0, vue.computed)(() => props.disabled || props.readonly);
|
|
1732
|
-
const
|
|
1940
|
+
const vertical = (0, vue.computed)(() => props.orientation === "vertical");
|
|
1941
|
+
const displayReversed = (0, vue.computed)(() => vertical.value !== props.reverse);
|
|
1733
1942
|
const percent = (0, vue.computed)(() => (0, _tremolo_ui_dom.valuePercent)(props.modelValue, {
|
|
1734
1943
|
min: props.min,
|
|
1735
1944
|
max: props.max,
|
|
@@ -1748,7 +1957,17 @@ const Slider = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
1748
1957
|
keyboard: props.keyboard,
|
|
1749
1958
|
wheel: props.wheel
|
|
1750
1959
|
}));
|
|
1751
|
-
const
|
|
1960
|
+
const gesture = useChangeGesture({
|
|
1961
|
+
value: () => props.modelValue,
|
|
1962
|
+
inactive: () => inactive.value,
|
|
1963
|
+
endDelay: () => props.changeEndDelay,
|
|
1964
|
+
onStart: (value, source) => emit("changeStart", value, source),
|
|
1965
|
+
onEnd: (value, source) => emit("changeEnd", value, source)
|
|
1966
|
+
});
|
|
1967
|
+
const change = (next) => {
|
|
1968
|
+
gesture.changed(next);
|
|
1969
|
+
emit("update:modelValue", next);
|
|
1970
|
+
};
|
|
1752
1971
|
(0, vue.provide)(SliderKey, {
|
|
1753
1972
|
get value() {
|
|
1754
1973
|
return props.modelValue;
|
|
@@ -1765,8 +1984,8 @@ const Slider = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
1765
1984
|
get scale() {
|
|
1766
1985
|
return props.scale;
|
|
1767
1986
|
},
|
|
1768
|
-
get
|
|
1769
|
-
return props.
|
|
1987
|
+
get orientation() {
|
|
1988
|
+
return props.orientation;
|
|
1770
1989
|
},
|
|
1771
1990
|
get reverse() {
|
|
1772
1991
|
return props.reverse;
|
|
@@ -1788,31 +2007,30 @@ const Slider = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
1788
2007
|
thumb = input;
|
|
1789
2008
|
}
|
|
1790
2009
|
});
|
|
1791
|
-
const valueOf = (v) => v[
|
|
2010
|
+
const valueOf = (v) => v[vertical.value ? 1 : 0];
|
|
1792
2011
|
useDragValue(root, () => ({
|
|
1793
2012
|
axis: axis.value,
|
|
1794
|
-
mapping: (0, _tremolo_ui_dom.elementMapping)(() => track, { sensitivity: (state) => (0,
|
|
1795
|
-
cursor: inactive.value ? void 0 : props.
|
|
2013
|
+
mapping: (0, _tremolo_ui_dom.elementMapping)(() => track, { sensitivity: (state) => (0, _tremolo_ui_dom_internal.selectModifier)(props.dragSensitivity, state.event).value }),
|
|
2014
|
+
cursor: inactive.value ? void 0 : props.dragCursor,
|
|
1796
2015
|
shouldStart: () => !inactive.value,
|
|
1797
2016
|
updateOnPointerDown: true,
|
|
1798
2017
|
onChange: (v) => {
|
|
1799
2018
|
if (!inactive.value) change(valueOf(v));
|
|
1800
2019
|
},
|
|
1801
|
-
onDragStart: (
|
|
2020
|
+
onDragStart: () => {
|
|
1802
2021
|
if (inactive.value) return;
|
|
2022
|
+
gesture.hold("pointer");
|
|
1803
2023
|
thumb?.focus();
|
|
1804
|
-
emit("dragStart", valueOf(v));
|
|
1805
2024
|
},
|
|
1806
|
-
onDragEnd: (
|
|
1807
|
-
if (!inactive.value) emit("dragEnd", valueOf(v));
|
|
1808
|
-
}
|
|
2025
|
+
onDragEnd: () => gesture.end()
|
|
1809
2026
|
}));
|
|
1810
2027
|
useWheel(root, (event) => {
|
|
1811
2028
|
if (!props.wheel || inactive.value) return;
|
|
1812
|
-
const direction = (0,
|
|
2029
|
+
const direction = (0, _tremolo_ui_dom_internal.wheelDirection)(event, { horizontal: !vertical.value });
|
|
1813
2030
|
if (direction === null) return;
|
|
1814
2031
|
event.preventDefault();
|
|
1815
|
-
|
|
2032
|
+
gesture.pulse("wheel");
|
|
2033
|
+
change((0, _tremolo_ui_dom_internal.applyDelta)(props.modelValue, props.reverse ? -direction : direction, props.wheel, axis.value, event));
|
|
1816
2034
|
}, { requireFocus: true });
|
|
1817
2035
|
expose({
|
|
1818
2036
|
/** Move the focus to the thumb. */
|
|
@@ -1826,15 +2044,16 @@ const Slider = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
1826
2044
|
ref: root,
|
|
1827
2045
|
role: "group",
|
|
1828
2046
|
tabindex: -1,
|
|
1829
|
-
"data-orientation": props.
|
|
2047
|
+
"data-orientation": props.orientation,
|
|
1830
2048
|
"data-disabled": props.disabled ? "" : void 0,
|
|
1831
2049
|
"data-readonly": props.readonly ? "" : void 0,
|
|
1832
2050
|
onKeydown: (event) => {
|
|
1833
|
-
const direction = (0,
|
|
2051
|
+
const direction = (0, _tremolo_ui_dom_internal.arrowKeyDirection)(event.key);
|
|
1834
2052
|
if (direction === null) return;
|
|
1835
2053
|
event.preventDefault();
|
|
1836
2054
|
if (!props.keyboard || inactive.value) return;
|
|
1837
|
-
|
|
2055
|
+
gesture.pulse("keyboard");
|
|
2056
|
+
change((0, _tremolo_ui_dom_internal.applyDelta)(props.modelValue, props.reverse ? -direction : direction, props.keyboard, axis.value, event));
|
|
1838
2057
|
},
|
|
1839
2058
|
onFocus: () => {
|
|
1840
2059
|
if (!props.disabled) thumb?.focus();
|
|
@@ -1845,43 +2064,44 @@ const Slider = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
1845
2064
|
});
|
|
1846
2065
|
//#endregion
|
|
1847
2066
|
//#region src/components/Slider/SliderMarksOption.ts
|
|
2067
|
+
const sliderMarksOptionProps = {
|
|
2068
|
+
/** Where the mark sits, on the same scale as the thumb. */
|
|
2069
|
+
value: {
|
|
2070
|
+
type: Number,
|
|
2071
|
+
required: true
|
|
2072
|
+
},
|
|
2073
|
+
/** Draw the mark itself. @default true */
|
|
2074
|
+
mark: {
|
|
2075
|
+
type: Boolean,
|
|
2076
|
+
default: true
|
|
2077
|
+
},
|
|
2078
|
+
/**
|
|
2079
|
+
* Text shown next to the mark. Leave it out to show the value; `null`
|
|
2080
|
+
* leaves the label out.
|
|
2081
|
+
*/
|
|
2082
|
+
label: {
|
|
2083
|
+
type: [
|
|
2084
|
+
Number,
|
|
2085
|
+
String,
|
|
2086
|
+
null
|
|
2087
|
+
],
|
|
2088
|
+
default: void 0
|
|
2089
|
+
},
|
|
2090
|
+
/** Thickness of the mark. Sets `--thickness`. */
|
|
2091
|
+
thickness: [Number, String],
|
|
2092
|
+
/** Length of the mark. Sets `--length`. */
|
|
2093
|
+
length: [Number, String],
|
|
2094
|
+
/** Space between the mark and the label. Sets `--gap`. */
|
|
2095
|
+
gap: [Number, String],
|
|
2096
|
+
/** Classes for the mark and the label inside the option. */
|
|
2097
|
+
classes: Object,
|
|
2098
|
+
/** Styles for the mark and the label inside the option. */
|
|
2099
|
+
styles: Object
|
|
2100
|
+
};
|
|
1848
2101
|
/** One mark along the slider, and its label. */
|
|
1849
2102
|
const SliderMarksOption = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
1850
2103
|
name: "SliderMarksOption",
|
|
1851
|
-
props:
|
|
1852
|
-
/** Where the mark sits, on the same scale as the thumb. */
|
|
1853
|
-
value: {
|
|
1854
|
-
type: Number,
|
|
1855
|
-
required: true
|
|
1856
|
-
},
|
|
1857
|
-
/** Draw the mark itself. @default true */
|
|
1858
|
-
mark: {
|
|
1859
|
-
type: Boolean,
|
|
1860
|
-
default: true
|
|
1861
|
-
},
|
|
1862
|
-
/**
|
|
1863
|
-
* Text shown next to the mark. Leave it out to show the value; `null`
|
|
1864
|
-
* leaves the label out.
|
|
1865
|
-
*/
|
|
1866
|
-
label: {
|
|
1867
|
-
type: [
|
|
1868
|
-
Number,
|
|
1869
|
-
String,
|
|
1870
|
-
null
|
|
1871
|
-
],
|
|
1872
|
-
default: void 0
|
|
1873
|
-
},
|
|
1874
|
-
/** Thickness of the mark. Sets `--thickness`. */
|
|
1875
|
-
thickness: [Number, String],
|
|
1876
|
-
/** Length of the mark. Sets `--length`. */
|
|
1877
|
-
length: [Number, String],
|
|
1878
|
-
/** Space between the mark and the label. Sets `--gap`. */
|
|
1879
|
-
gap: [Number, String],
|
|
1880
|
-
/** Classes for the mark and the label inside the option. */
|
|
1881
|
-
classes: Object,
|
|
1882
|
-
/** Styles for the mark and the label inside the option. */
|
|
1883
|
-
styles: Object
|
|
1884
|
-
},
|
|
2104
|
+
props: sliderMarksOptionProps,
|
|
1885
2105
|
setup(props) {
|
|
1886
2106
|
const slider = useSliderContext();
|
|
1887
2107
|
checkPlacement("SliderMarksOption", "SliderMarks");
|
|
@@ -1889,20 +2109,20 @@ const SliderMarksOption = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
1889
2109
|
min: slider.min,
|
|
1890
2110
|
max: slider.max,
|
|
1891
2111
|
scale: slider.scale
|
|
1892
|
-
}, slider.vertical !== slider.reverse));
|
|
2112
|
+
}, slider.orientation === "vertical" !== slider.reverse));
|
|
1893
2113
|
return () => {
|
|
1894
|
-
const orientation = slider.
|
|
2114
|
+
const orientation = slider.orientation;
|
|
1895
2115
|
return (0, vue.h)("div", {
|
|
1896
2116
|
"data-orientation": orientation,
|
|
1897
2117
|
style: {
|
|
1898
|
-
"--thickness": (0,
|
|
1899
|
-
"--length": (0,
|
|
1900
|
-
"--gap": (0,
|
|
2118
|
+
"--thickness": (0, _tremolo_ui_dom_internal.cssLength)(props.thickness),
|
|
2119
|
+
"--length": (0, _tremolo_ui_dom_internal.cssLength)(props.length),
|
|
2120
|
+
"--gap": (0, _tremolo_ui_dom_internal.cssLength)(props.gap),
|
|
1901
2121
|
position: "absolute",
|
|
1902
|
-
translate: slider.vertical ? "var(--translate, 0 -50%)" : "var(--translate, -50% 0)",
|
|
2122
|
+
translate: slider.orientation === "vertical" ? "var(--translate, 0 -50%)" : "var(--translate, -50% 0)",
|
|
1903
2123
|
zIndex: 10,
|
|
1904
|
-
left: slider.vertical ? void 0 : `${percent.value}%`,
|
|
1905
|
-
top: slider.vertical ? `${percent.value}%` : void 0
|
|
2124
|
+
left: slider.orientation === "vertical" ? void 0 : `${percent.value}%`,
|
|
2125
|
+
top: slider.orientation === "vertical" ? `${percent.value}%` : void 0
|
|
1906
2126
|
}
|
|
1907
2127
|
}, [props.mark ? (0, vue.h)("div", {
|
|
1908
2128
|
class: props.classes?.mark,
|
|
@@ -1917,35 +2137,36 @@ const SliderMarksOption = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
1917
2137
|
});
|
|
1918
2138
|
//#endregion
|
|
1919
2139
|
//#region src/components/Slider/SliderMarks.ts
|
|
2140
|
+
const sliderMarksProps = {
|
|
2141
|
+
/** Space between the marks and the track. Sets `--gap`. */
|
|
2142
|
+
gap: [Number, String],
|
|
2143
|
+
/**
|
|
2144
|
+
* Build the marks instead of writing `SliderMarksOption` out: a number
|
|
2145
|
+
* puts one every that many, `'step'` one every `step`. The default slot
|
|
2146
|
+
* is ignored while it is set.
|
|
2147
|
+
*/
|
|
2148
|
+
options: [
|
|
2149
|
+
String,
|
|
2150
|
+
Number,
|
|
2151
|
+
Object
|
|
2152
|
+
]
|
|
2153
|
+
};
|
|
1920
2154
|
/** The marks along the slider: written out as options, or built from `options`. */
|
|
1921
2155
|
const SliderMarks = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
1922
2156
|
name: "SliderMarks",
|
|
1923
|
-
props:
|
|
1924
|
-
/** Space between the marks and the track. Sets `--gap`. */
|
|
1925
|
-
gap: [Number, String],
|
|
1926
|
-
/**
|
|
1927
|
-
* Build the marks instead of writing `SliderMarksOption` out: a number
|
|
1928
|
-
* puts one every that many, `'step'` one every `step`. The default slot
|
|
1929
|
-
* is ignored while it is set.
|
|
1930
|
-
*/
|
|
1931
|
-
options: [
|
|
1932
|
-
String,
|
|
1933
|
-
Number,
|
|
1934
|
-
Object
|
|
1935
|
-
]
|
|
1936
|
-
},
|
|
2157
|
+
props: sliderMarksProps,
|
|
1937
2158
|
setup(props, { slots }) {
|
|
1938
2159
|
const slider = useSliderContext();
|
|
1939
2160
|
providePlacement("SliderMarks");
|
|
1940
2161
|
const marks = (0, vue.computed)(() => {
|
|
1941
2162
|
if (props.options === void 0) return [];
|
|
1942
|
-
const list = (0,
|
|
1943
|
-
return slider.vertical !== slider.reverse ? list.reverse() : list;
|
|
2163
|
+
const list = (0, _tremolo_ui_dom_internal.sliderMarks)(props.options, slider.min, slider.max, slider.step);
|
|
2164
|
+
return slider.orientation === "vertical" !== slider.reverse ? list.reverse() : list;
|
|
1944
2165
|
});
|
|
1945
2166
|
return () => (0, vue.h)("div", {
|
|
1946
|
-
"data-orientation": slider.
|
|
2167
|
+
"data-orientation": slider.orientation,
|
|
1947
2168
|
style: {
|
|
1948
|
-
"--gap": (0,
|
|
2169
|
+
"--gap": (0, _tremolo_ui_dom_internal.cssLength)(props.gap),
|
|
1949
2170
|
position: "relative"
|
|
1950
2171
|
}
|
|
1951
2172
|
}, props.options !== void 0 ? marks.value.map(({ value, mark, label }) => (0, vue.h)(SliderMarksOption, {
|
|
@@ -1958,6 +2179,9 @@ const SliderMarks = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
1958
2179
|
});
|
|
1959
2180
|
//#endregion
|
|
1960
2181
|
//#region src/components/Slider/SliderThumb.ts
|
|
2182
|
+
const sliderThumbProps = {
|
|
2183
|
+
/** Sets `--color`, for the theme to colour the thumb with. */
|
|
2184
|
+
color: String };
|
|
1961
2185
|
/**
|
|
1962
2186
|
* The thumb, placed at the value. The ARIA (`aria-label` and friends) lands
|
|
1963
2187
|
* on the range input inside it, which is the control and takes the focus.
|
|
@@ -1965,9 +2189,7 @@ const SliderMarks = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
1965
2189
|
const SliderThumb = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
1966
2190
|
name: "SliderThumb",
|
|
1967
2191
|
inheritAttrs: false,
|
|
1968
|
-
props:
|
|
1969
|
-
/** Sets `--color`, for the theme to colour the thumb with. */
|
|
1970
|
-
color: String },
|
|
2192
|
+
props: sliderThumbProps,
|
|
1971
2193
|
setup(props, { slots, attrs, expose }) {
|
|
1972
2194
|
const slider = useSliderContext();
|
|
1973
2195
|
checkPlacement("SliderThumb", "SliderTrack");
|
|
@@ -1995,8 +2217,8 @@ color: String },
|
|
|
1995
2217
|
},
|
|
1996
2218
|
style,
|
|
1997
2219
|
{
|
|
1998
|
-
top: slider.vertical ? `${slider.percent}%` : "50%",
|
|
1999
|
-
left: slider.vertical ? "50%" : `${slider.percent}%`
|
|
2220
|
+
top: slider.orientation === "vertical" ? `${slider.percent}%` : "50%",
|
|
2221
|
+
left: slider.orientation === "vertical" ? "50%" : `${slider.percent}%`
|
|
2000
2222
|
}
|
|
2001
2223
|
]
|
|
2002
2224
|
}, [visuallyHiddenRangeInput({
|
|
@@ -2007,7 +2229,7 @@ color: String },
|
|
|
2007
2229
|
step: slider.step,
|
|
2008
2230
|
disabled: slider.disabled,
|
|
2009
2231
|
"aria-readonly": slider.readonly,
|
|
2010
|
-
"aria-orientation": slider.
|
|
2232
|
+
"aria-orientation": slider.orientation,
|
|
2011
2233
|
"aria-label": ariaLabel,
|
|
2012
2234
|
"aria-labelledby": ariaLabelledby,
|
|
2013
2235
|
"aria-describedby": ariaDescribedby,
|
|
@@ -2026,19 +2248,20 @@ color: String },
|
|
|
2026
2248
|
});
|
|
2027
2249
|
//#endregion
|
|
2028
2250
|
//#region src/components/Slider/SliderTrack.ts
|
|
2251
|
+
const sliderTrackProps = {
|
|
2252
|
+
/** How long the track is along the axis the slider runs. Sets `--length`. */
|
|
2253
|
+
length: [Number, String],
|
|
2254
|
+
/** How thick the track is across that axis. Sets `--thickness`. */
|
|
2255
|
+
thickness: [Number, String],
|
|
2256
|
+
/** Colour of the part from `min` to the value. Sets `--active-color`. */
|
|
2257
|
+
activeColor: String,
|
|
2258
|
+
/** Colour of the rest of the track. Sets `--inactive-color`. */
|
|
2259
|
+
inactiveColor: String
|
|
2260
|
+
};
|
|
2029
2261
|
/** The track the thumb runs along, and what the pointer is measured against. */
|
|
2030
2262
|
const SliderTrack = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
2031
2263
|
name: "SliderTrack",
|
|
2032
|
-
props:
|
|
2033
|
-
/** How long the track is along the axis the slider runs. Sets `--length`. */
|
|
2034
|
-
length: [Number, String],
|
|
2035
|
-
/** How thick the track is across that axis. Sets `--thickness`. */
|
|
2036
|
-
thickness: [Number, String],
|
|
2037
|
-
/** Colour of the part from `min` to the value. Sets `--active`. */
|
|
2038
|
-
active: String,
|
|
2039
|
-
/** Colour of the rest of the track. Sets `--inactive`. */
|
|
2040
|
-
inactive: String
|
|
2041
|
-
},
|
|
2264
|
+
props: sliderTrackProps,
|
|
2042
2265
|
setup(props, { slots }) {
|
|
2043
2266
|
const slider = useSliderContext();
|
|
2044
2267
|
providePlacement("SliderTrack");
|
|
@@ -2048,13 +2271,13 @@ const SliderTrack = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
2048
2271
|
return () => (0, vue.h)("div", {
|
|
2049
2272
|
ref: el,
|
|
2050
2273
|
"data-disabled": slider.disabled ? "" : void 0,
|
|
2051
|
-
"data-orientation": slider.
|
|
2052
|
-
"data-flipped": slider.vertical !== slider.reverse ? "" : void 0,
|
|
2274
|
+
"data-orientation": slider.orientation,
|
|
2275
|
+
"data-flipped": slider.orientation === "vertical" !== slider.reverse ? "" : void 0,
|
|
2053
2276
|
style: {
|
|
2054
|
-
"--active": props.
|
|
2055
|
-
"--inactive": props.
|
|
2056
|
-
"--length": (0,
|
|
2057
|
-
"--thickness": (0,
|
|
2277
|
+
"--active-color": props.activeColor,
|
|
2278
|
+
"--inactive-color": props.inactiveColor,
|
|
2279
|
+
"--length": (0, _tremolo_ui_dom_internal.cssLength)(props.length),
|
|
2280
|
+
"--thickness": (0, _tremolo_ui_dom_internal.cssLength)(props.thickness),
|
|
2058
2281
|
"--percent": `${slider.percent}%`,
|
|
2059
2282
|
position: "relative"
|
|
2060
2283
|
}
|
|
@@ -2070,68 +2293,86 @@ function useXYPadContext() {
|
|
|
2070
2293
|
}
|
|
2071
2294
|
//#endregion
|
|
2072
2295
|
//#region src/components/XYPad/XYPad.ts
|
|
2296
|
+
const xyPadProps = {
|
|
2297
|
+
/** The current value as `[x, y]`. Bind it with `v-model`. */
|
|
2298
|
+
modelValue: {
|
|
2299
|
+
type: Array,
|
|
2300
|
+
required: true
|
|
2301
|
+
},
|
|
2302
|
+
/** The value at the start of the travel, per axis. */
|
|
2303
|
+
min: {
|
|
2304
|
+
type: [Number, Array],
|
|
2305
|
+
required: true
|
|
2306
|
+
},
|
|
2307
|
+
/** The value at the end of the travel, per axis. */
|
|
2308
|
+
max: {
|
|
2309
|
+
type: [Number, Array],
|
|
2310
|
+
required: true
|
|
2311
|
+
},
|
|
2312
|
+
/** Granularity of the value, per axis. @default 1 */
|
|
2313
|
+
step: {
|
|
2314
|
+
type: [Number, Array],
|
|
2315
|
+
default: 1
|
|
2316
|
+
},
|
|
2317
|
+
/** How the value is distributed, per axis. @default linearScale */
|
|
2318
|
+
scale: {
|
|
2319
|
+
type: [Object, Array],
|
|
2320
|
+
default: () => _tremolo_ui_functions.linearScale
|
|
2321
|
+
},
|
|
2322
|
+
/** Grow the value the other way, per axis. `y` grows downwards unless reversed. */
|
|
2323
|
+
reverse: {
|
|
2324
|
+
type: [Boolean, Array],
|
|
2325
|
+
default: false
|
|
2326
|
+
},
|
|
2327
|
+
/** The cursor to show while dragging. @default 'pointer' */
|
|
2328
|
+
dragCursor: {
|
|
2329
|
+
type: String,
|
|
2330
|
+
default: "pointer"
|
|
2331
|
+
},
|
|
2332
|
+
wheel: wheelProp,
|
|
2333
|
+
keyboard: keyboardProp,
|
|
2334
|
+
dragSensitivity: dragSensitivityProp,
|
|
2335
|
+
/** Make the pad unchangeable and remove it from the tab order. */
|
|
2336
|
+
disabled: Boolean,
|
|
2337
|
+
/** Make the value unchangeable. */
|
|
2338
|
+
readonly: Boolean,
|
|
2339
|
+
/**
|
|
2340
|
+
* How long after the last wheel notch or arrow key a change counts as over,
|
|
2341
|
+
* in milliseconds, for `change-end`.
|
|
2342
|
+
* @default 500
|
|
2343
|
+
*/
|
|
2344
|
+
changeEndDelay: {
|
|
2345
|
+
type: Number,
|
|
2346
|
+
default: 500
|
|
2347
|
+
}
|
|
2348
|
+
};
|
|
2073
2349
|
/**
|
|
2074
2350
|
* Two-dimensional slider. The per-axis settings are `[x, y]` tuples, and a
|
|
2075
2351
|
* plain value applies to both axes. Bind the value with `v-model`.
|
|
2076
2352
|
*/
|
|
2077
2353
|
const XYPad = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
2078
2354
|
name: "XYPad",
|
|
2079
|
-
props:
|
|
2080
|
-
/** The current value as `[x, y]`. Bind it with `v-model`. */
|
|
2081
|
-
modelValue: {
|
|
2082
|
-
type: Array,
|
|
2083
|
-
required: true
|
|
2084
|
-
},
|
|
2085
|
-
/** The value at the start of the travel, per axis. */
|
|
2086
|
-
min: {
|
|
2087
|
-
type: [Number, Array],
|
|
2088
|
-
required: true
|
|
2089
|
-
},
|
|
2090
|
-
/** The value at the end of the travel, per axis. */
|
|
2091
|
-
max: {
|
|
2092
|
-
type: [Number, Array],
|
|
2093
|
-
required: true
|
|
2094
|
-
},
|
|
2095
|
-
/** Granularity of the value, per axis. @default 1 */
|
|
2096
|
-
step: {
|
|
2097
|
-
type: [Number, Array],
|
|
2098
|
-
default: 1
|
|
2099
|
-
},
|
|
2100
|
-
/** How the value is distributed, per axis. @default linearScale */
|
|
2101
|
-
scale: {
|
|
2102
|
-
type: [Object, Array],
|
|
2103
|
-
default: () => _tremolo_ui_functions.linearScale
|
|
2104
|
-
},
|
|
2105
|
-
/** Grow the value the other way, per axis. `y` grows downwards unless reversed. */
|
|
2106
|
-
reverse: {
|
|
2107
|
-
type: [Boolean, Array],
|
|
2108
|
-
default: false
|
|
2109
|
-
},
|
|
2110
|
-
/** The cursor to show while dragging. @default { cursor: 'pointer' } */
|
|
2111
|
-
externalStyles: Object,
|
|
2112
|
-
wheel: wheelProp,
|
|
2113
|
-
keyboard: keyboardProp,
|
|
2114
|
-
dragSensitivity: dragSensitivityProp,
|
|
2115
|
-
/** Make the pad unchangeable and remove it from the tab order. */
|
|
2116
|
-
disabled: Boolean,
|
|
2117
|
-
/** Make the value unchangeable. */
|
|
2118
|
-
readonly: Boolean
|
|
2119
|
-
},
|
|
2355
|
+
props: xyPadProps,
|
|
2120
2356
|
emits: {
|
|
2121
2357
|
"update:modelValue": (value) => Array.isArray(value),
|
|
2122
|
-
|
|
2123
|
-
|
|
2358
|
+
/**
|
|
2359
|
+
* A change of the value started, with the value before it and what it is
|
|
2360
|
+
* made with.
|
|
2361
|
+
*/
|
|
2362
|
+
changeStart: (value, _source) => Array.isArray(value),
|
|
2363
|
+
/** The change ended, with the value it ended on. */
|
|
2364
|
+
changeEnd: (value, _source) => Array.isArray(value)
|
|
2124
2365
|
},
|
|
2125
2366
|
setup(props, { slots, emit, expose }) {
|
|
2126
2367
|
const root = (0, vue.ref)(null);
|
|
2127
2368
|
let area = null;
|
|
2128
2369
|
let thumb = null;
|
|
2129
2370
|
const inactive = (0, vue.computed)(() => props.disabled || props.readonly);
|
|
2130
|
-
const min = (0, vue.computed)(() => (0,
|
|
2131
|
-
const max = (0, vue.computed)(() => (0,
|
|
2132
|
-
const step = (0, vue.computed)(() => (0,
|
|
2133
|
-
const scale = (0, vue.computed)(() => (0,
|
|
2134
|
-
const reverse = (0, vue.computed)(() => (0,
|
|
2371
|
+
const min = (0, vue.computed)(() => (0, _tremolo_ui_dom_internal.toXY)(props.min));
|
|
2372
|
+
const max = (0, vue.computed)(() => (0, _tremolo_ui_dom_internal.toXY)(props.max));
|
|
2373
|
+
const step = (0, vue.computed)(() => (0, _tremolo_ui_dom_internal.toXY)(props.step));
|
|
2374
|
+
const scale = (0, vue.computed)(() => (0, _tremolo_ui_dom_internal.toXY)(props.scale));
|
|
2375
|
+
const reverse = (0, vue.computed)(() => (0, _tremolo_ui_dom_internal.toXY)(props.reverse));
|
|
2135
2376
|
const percent = (0, vue.computed)(() => [0, 1].map((i) => (0, _tremolo_ui_dom.valuePercent)(props.modelValue[i], {
|
|
2136
2377
|
min: min.value[i],
|
|
2137
2378
|
max: max.value[i],
|
|
@@ -2151,11 +2392,21 @@ const XYPad = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
2151
2392
|
keyboard: props.keyboard,
|
|
2152
2393
|
wheel: props.wheel
|
|
2153
2394
|
}));
|
|
2154
|
-
const
|
|
2395
|
+
const gesture = useChangeGesture({
|
|
2396
|
+
value: () => props.modelValue,
|
|
2397
|
+
inactive: () => inactive.value,
|
|
2398
|
+
endDelay: () => props.changeEndDelay,
|
|
2399
|
+
onStart: (value, source) => emit("changeStart", value, source),
|
|
2400
|
+
onEnd: (value, source) => emit("changeEnd", value, source)
|
|
2401
|
+
});
|
|
2402
|
+
const change = (next) => {
|
|
2403
|
+
gesture.changed(next);
|
|
2404
|
+
emit("update:modelValue", next);
|
|
2405
|
+
};
|
|
2155
2406
|
/** Move one axis by one press of `option`, in screen coordinates. */
|
|
2156
2407
|
function nudge({ axis: i, direction }, option, modifiers) {
|
|
2157
2408
|
const value = props.modelValue;
|
|
2158
|
-
const next = (0,
|
|
2409
|
+
const next = (0, _tremolo_ui_dom_internal.applyDelta)(value[i], reverse.value[i] ? -direction : direction, option, axis.value[i], modifiers);
|
|
2159
2410
|
change(i === 0 ? [next, value[1]] : [value[0], next]);
|
|
2160
2411
|
}
|
|
2161
2412
|
(0, vue.provide)(XYPadKey, {
|
|
@@ -2196,27 +2447,26 @@ const XYPad = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
2196
2447
|
});
|
|
2197
2448
|
useDragValue(root, () => ({
|
|
2198
2449
|
axis: axis.value,
|
|
2199
|
-
mapping: (0, _tremolo_ui_dom.elementMapping)(() => area, { sensitivity: (state) => (0,
|
|
2450
|
+
mapping: (0, _tremolo_ui_dom.elementMapping)(() => area, { sensitivity: (state) => (0, _tremolo_ui_dom_internal.selectModifier)(props.dragSensitivity, state.event).value }),
|
|
2200
2451
|
updateOnPointerDown: true,
|
|
2201
|
-
cursor: inactive.value ? void 0 : props.
|
|
2452
|
+
cursor: inactive.value ? void 0 : props.dragCursor,
|
|
2202
2453
|
shouldStart: () => !inactive.value,
|
|
2203
2454
|
onChange: (v) => {
|
|
2204
2455
|
if (!inactive.value) change(v);
|
|
2205
2456
|
},
|
|
2206
|
-
onDragStart: (
|
|
2457
|
+
onDragStart: () => {
|
|
2207
2458
|
if (inactive.value) return;
|
|
2459
|
+
gesture.hold("pointer");
|
|
2208
2460
|
thumb?.focus();
|
|
2209
|
-
emit("dragStart", v);
|
|
2210
2461
|
},
|
|
2211
|
-
onDragEnd: (
|
|
2212
|
-
if (!inactive.value) emit("dragEnd", v);
|
|
2213
|
-
}
|
|
2462
|
+
onDragEnd: () => gesture.end()
|
|
2214
2463
|
}));
|
|
2215
2464
|
useWheel(root, (event) => {
|
|
2216
2465
|
if (!props.wheel || inactive.value) return;
|
|
2217
|
-
const move = (0,
|
|
2466
|
+
const move = (0, _tremolo_ui_dom_internal.wheelMove)(event);
|
|
2218
2467
|
if (!move) return;
|
|
2219
2468
|
event.preventDefault();
|
|
2469
|
+
gesture.pulse("wheel");
|
|
2220
2470
|
nudge(move, props.wheel, event);
|
|
2221
2471
|
}, { requireFocus: true });
|
|
2222
2472
|
expose({
|
|
@@ -2232,10 +2482,13 @@ const XYPad = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
2232
2482
|
"data-disabled": props.disabled ? "" : void 0,
|
|
2233
2483
|
"data-readonly": props.readonly ? "" : void 0,
|
|
2234
2484
|
onKeydown: (event) => {
|
|
2235
|
-
const move = (0,
|
|
2485
|
+
const move = (0, _tremolo_ui_dom_internal.arrowKeyMove)(event.key);
|
|
2236
2486
|
if (!move) return;
|
|
2237
2487
|
event.preventDefault();
|
|
2238
|
-
if (props.keyboard && !inactive.value)
|
|
2488
|
+
if (props.keyboard && !inactive.value) {
|
|
2489
|
+
gesture.pulse("keyboard");
|
|
2490
|
+
nudge(move, props.keyboard, event);
|
|
2491
|
+
}
|
|
2239
2492
|
},
|
|
2240
2493
|
onFocus: () => {
|
|
2241
2494
|
if (!props.disabled) thumb?.focus();
|
|
@@ -2263,22 +2516,23 @@ const XYPadArea = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
2263
2516
|
});
|
|
2264
2517
|
//#endregion
|
|
2265
2518
|
//#region src/components/XYPad/XYPadThumb.ts
|
|
2519
|
+
const xyPadThumbProps = {
|
|
2520
|
+
/** Sets `--color`, for the theme to colour the thumb with. */
|
|
2521
|
+
color: String,
|
|
2522
|
+
/** The accessible name of each axis, as `[x, y]`. */
|
|
2523
|
+
ariaLabel: [String, Array],
|
|
2524
|
+
/** The ids of what labels each axis, as `[x, y]` or one for both. */
|
|
2525
|
+
ariaLabelledby: [String, Array],
|
|
2526
|
+
/** The ids of what describes each axis, as `[x, y]` or one for both. */
|
|
2527
|
+
ariaDescribedby: [String, Array],
|
|
2528
|
+
/** What the value of each axis means, as `[x, y]` or one for both. */
|
|
2529
|
+
ariaValuetext: [String, Array]
|
|
2530
|
+
};
|
|
2266
2531
|
/** The thumb, placed at the value, with one range input per axis inside. */
|
|
2267
2532
|
const XYPadThumb = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
2268
2533
|
name: "XYPadThumb",
|
|
2269
2534
|
inheritAttrs: false,
|
|
2270
|
-
props:
|
|
2271
|
-
/** Sets `--color`, for the theme to colour the thumb with. */
|
|
2272
|
-
color: String,
|
|
2273
|
-
/** The accessible name of each axis, as `[x, y]`. */
|
|
2274
|
-
ariaLabel: [String, Array],
|
|
2275
|
-
/** The ids of what labels each axis, as `[x, y]` or one for both. */
|
|
2276
|
-
ariaLabelledby: [String, Array],
|
|
2277
|
-
/** The ids of what describes each axis, as `[x, y]` or one for both. */
|
|
2278
|
-
ariaDescribedby: [String, Array],
|
|
2279
|
-
/** What the value of each axis means, as `[x, y]` or one for both. */
|
|
2280
|
-
ariaValuetext: [String, Array]
|
|
2281
|
-
},
|
|
2535
|
+
props: xyPadThumbProps,
|
|
2282
2536
|
setup(props, { slots, attrs, expose }) {
|
|
2283
2537
|
const pad = useXYPadContext();
|
|
2284
2538
|
checkPlacement("XYPadThumb", "XYPadArea");
|
|
@@ -2296,7 +2550,7 @@ const XYPadThumb = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
2296
2550
|
}
|
|
2297
2551
|
});
|
|
2298
2552
|
function input(axis) {
|
|
2299
|
-
const labels = (0,
|
|
2553
|
+
const labels = (0, _tremolo_ui_dom_internal.toXY)(props.ariaLabel);
|
|
2300
2554
|
return visuallyHiddenRangeInput({
|
|
2301
2555
|
ref: axis === 0 ? x : y,
|
|
2302
2556
|
"data-axis": axis === 0 ? "x" : "y",
|
|
@@ -2308,9 +2562,9 @@ const XYPadThumb = /* @__PURE__ */ (0, vue.defineComponent)({
|
|
|
2308
2562
|
"aria-readonly": pad.readonly,
|
|
2309
2563
|
"aria-orientation": axis === 0 ? "horizontal" : "vertical",
|
|
2310
2564
|
"aria-label": labels[axis] ?? (axis === 0 ? "x" : "y"),
|
|
2311
|
-
"aria-labelledby": (0,
|
|
2312
|
-
"aria-describedby": (0,
|
|
2313
|
-
"aria-valuetext": (0,
|
|
2565
|
+
"aria-labelledby": (0, _tremolo_ui_dom_internal.toXY)(props.ariaLabelledby)[axis],
|
|
2566
|
+
"aria-describedby": (0, _tremolo_ui_dom_internal.toXY)(props.ariaDescribedby)[axis],
|
|
2567
|
+
"aria-valuetext": (0, _tremolo_ui_dom_internal.toXY)(props.ariaValuetext)[axis],
|
|
2314
2568
|
onInput: (event) => {
|
|
2315
2569
|
const target = event.target;
|
|
2316
2570
|
if (pad.readonly) {
|