@tremolo-ui/dom 0.8.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.d.cts CHANGED
@@ -1,3 +1,4 @@
1
+ import { D as ModifierState, E as ModifierMap, O as ModifierValue, S as notePosition, T as Modifier, _ as NoteRange, c as PointsEditorInstance, f as createPointsEditor, h as XYInput, l as PointsEditorOptions, m as XY, p as SelectionBoxRect, s as PointPosition, t as MarksOptions, u as PointsEditorPoint, v as PianoLayout, w as InputEventOption } from "./marks-DK7xJmGM.cjs";
1
2
  import { Scale, ValueRange } from "@tremolo-ui/functions";
2
3
  //#region src/canvas/animation.d.ts
3
4
  /** What the canvas looked like when a frame was drawn. */
@@ -15,7 +16,15 @@ interface AnimationFrame {
15
16
  /** Frames per second implied by `deltaTime`, or 0 when no time elapsed. */
16
17
  fps: number;
17
18
  }
19
+ /**
20
+ * Draws one frame, given the 2D context and the frame: the size in CSS pixels,
21
+ * `count`, `deltaTime`, `elapsedTime` and `fps`.
22
+ */
18
23
  type CanvasDrawFunction = (context: CanvasRenderingContext2D, frame: AnimationFrame) => void;
24
+ /**
25
+ * Sets up what every frame shares. Called once, with the context and the size
26
+ * in CSS pixels, before the first frame; not again on a resize.
27
+ */
19
28
  type CanvasInitFunction = (context: CanvasRenderingContext2D, size: {
20
29
  width: number;
21
30
  height: number;
@@ -91,67 +100,6 @@ interface AnimationCanvasInstance {
91
100
  */
92
101
  export declare function createAnimationCanvas(canvas: HTMLCanvasElement, options: AnimationCanvasOptions): AnimationCanvasInstance;
93
102
  //#endregion
94
- //#region src/canvas/context.d.ts
95
- /**
96
- * The assignable parts of a 2D context's drawing state. They have to be
97
- * carried across a resize by hand because setting `canvas.width` resets the
98
- * context to its defaults. The transform and line dash are handled separately
99
- * by {@link DrawingContext} because they are exposed through methods.
100
- *
101
- * @see https://developer.mozilla.org/en-US/docs/Web/API/CanvasRenderingContext2D/save
102
- */
103
- export declare const drawingState: readonly ["strokeStyle", "fillStyle", "globalAlpha", "lineWidth", "lineCap", "lineJoin", "miterLimit", "lineDashOffset", "shadowOffsetX", "shadowOffsetY", "shadowBlur", "shadowColor", "globalCompositeOperation", "filter", "font", "fontKerning", "fontStretch", "fontVariantCaps", "textAlign", "textBaseline", "direction", "letterSpacing", "textRendering", "wordSpacing", "imageSmoothingEnabled", "imageSmoothingQuality"];
104
- type DrawingState = (typeof drawingState)[number];
105
- type DrawingStateValue = CanvasRenderingContext2D[DrawingState];
106
- type DrawingContext = Pick<CanvasRenderingContext2D, DrawingState> & {
107
- /** The current line dash sequence. */
108
- lineDash: number[];
109
- /** The current transformation matrix. */
110
- transform: DOMMatrix;
111
- };
112
- export declare function isDrawingState(value: unknown): value is DrawingState;
113
- //#endregion
114
- //#region src/file/accept.d.ts
115
- /**
116
- * What an `accept` rule is matched against.
117
- *
118
- * `File` satisfies it, and so does `DataTransferItem` — which matters while a
119
- * drag is still in the air, since the browser reports the type of what is
120
- * being dragged but withholds the name.
121
- */
122
- interface AcceptCandidate {
123
- /** The file name, when it is known. */
124
- name?: string;
125
- /** The MIME type, or `''` when the browser has no type for it. */
126
- type: string;
127
- }
128
- /**
129
- * Does a file satisfy an `accept` attribute?
130
- *
131
- * `accept` is written the way the HTML attribute is: a comma separated list of
132
- * extensions (`.wav`), MIME types (`audio/wav`) and type groups (`audio/*`).
133
- * Anything that matches one entry is accepted, and an empty or missing
134
- * `accept` takes everything.
135
- *
136
- * **The browser's own `accept` is only a hint to the file picker.** A person
137
- * can switch it to "All Files", drag a file in, or pick one the picker was
138
- * never asked about, so what arrives still has to be checked.
139
- *
140
- * A rule that cannot be decided is not treated as a rejection: with no `name`,
141
- * an extension rule says nothing either way, and `accept=".wav"` reports a
142
- * match rather than refusing a file it has not seen the name of. The name is
143
- * there by the time the file is dropped, which is when the answer counts.
144
- */
145
- export declare function matchesAccept(candidate: AcceptCandidate, accept?: string): boolean;
146
- /**
147
- * Split files into those that satisfy `accept` and those that do not, keeping
148
- * their order. See {@link matchesAccept}.
149
- */
150
- export declare function partitionByAccept(files: Iterable<File>, accept?: string): {
151
- accepted: File[];
152
- rejected: File[];
153
- };
154
- //#endregion
155
103
  //#region src/file/drop-zone.d.ts
156
104
  /** What is in the air over the element. */
157
105
  interface DropZoneState {
@@ -221,130 +169,55 @@ interface DropZoneInstance {
221
169
  */
222
170
  export declare function createDropZone(element: Element, options?: DropZoneOptions): DropZoneInstance;
223
171
  //#endregion
224
- //#region src/input/modifiers.d.ts
225
- /**
226
- * Options for setting the amount of keyboard and mouse wheel changes.
227
- */
228
- type InputEventOption = readonly ['normalized' | 'raw', number];
229
- /**
230
- * A modifier key that can carry an amount of its own.
231
- *
232
- * `ctrl` and `meta` are kept apart rather than folded into one "command" key:
233
- * a plugin UI that mirrors a desktop host usually wants the same physical key
234
- * on every platform, not the platform's own convention.
235
- */
236
- type Modifier = 'shift' | 'alt' | 'ctrl' | 'meta';
237
- /** The modifier flags of a `WheelEvent` or a `KeyboardEvent`. */
238
- interface ModifierState {
239
- shiftKey: boolean;
240
- altKey: boolean;
241
- ctrlKey: boolean;
242
- metaKey: boolean;
172
+ //#region src/input/change-gesture.d.ts
173
+ /** What a change of value was made with. */
174
+ type ChangeSource = 'pointer' | 'wheel' | 'keyboard' | 'doubleClick';
175
+ interface ChangeGestureOptions {
176
+ /** Called before the first change of a gesture. */
177
+ onStart?: (source: ChangeSource) => void;
178
+ /** Called after the last change of a gesture. */
179
+ onEnd?: (source: ChangeSource) => void;
180
+ /**
181
+ * How long after the last wheel notch or key press a gesture counts as
182
+ * over, in milliseconds. Neither has an event that says it is done, so the
183
+ * gesture ends when nothing more arrives for this long.
184
+ *
185
+ * @default 500
186
+ */
187
+ endDelay?: number;
243
188
  }
244
- /** One setting per modifier key, with `default` for none of them. */
245
- type ModifierSetting = number | InputEventOption;
246
- type ModifierMap<T extends ModifierSetting> = {
247
- default: T;
248
- } & Partial<Record<Modifier, T>>;
249
- /**
250
- * A single setting, or one per modifier key.
251
- *
252
- * @example
253
- * ['raw', 1]
254
- * { default: ['raw', 1], shift: ['raw', 0.1] }
255
- */
256
- type ModifierValue<T extends ModifierSetting> = T | ModifierMap<T>;
257
- /**
258
- * Pick the setting that applies, given the modifier keys being held.
259
- *
260
- * @example
261
- * selectModifier({ default: 1, shift: 0.1 }, event)
262
- */
263
- export declare function selectModifier<T extends ModifierSetting>(options: ModifierValue<T>, modifiers?: ModifierState): {
264
- value: T;
265
- modifier: Modifier | null;
266
- };
267
- /**
268
- * Turn every entry of a setting into another kind of setting, keeping which
269
- * modifier each belongs to.
270
- *
271
- * A drag sensitivity is a number and a keyboard amount is a tuple, but the two
272
- * describe the same thing from the caller's side. This carries one over to the
273
- * other so that a component can hand a sensitivity to {@link applyDelta}
274
- * without unpicking the modifier map itself — which matters, since naming a
275
- * modifier is also what takes `step` out of the pipeline.
276
- *
277
- * @example
278
- * mapModifier({ default: 1, shift: 0.1 }, (f) => ['raw', step * f])
279
- * // { default: ['raw', 1], shift: ['raw', 0.1] }
280
- */
281
- export declare function mapModifier<T extends ModifierSetting, U extends ModifierSetting>(options: ModifierValue<T>, fn: (value: T) => U): ModifierValue<U>;
282
- //#endregion
283
- //#region src/input/apply-delta.d.ts
284
- /**
285
- * Move a value by an amount of input, as reported by a wheel or an arrow key.
286
- *
287
- * The pipeline matches {@link createDragValue}: scale, then step, then clamp.
288
- * Which key or which sign of `deltaY` counts as which direction is left to the
289
- * caller, since it differs per component.
290
- *
291
- * @param direction which way, and how many times, to apply the option. The
292
- * size of one step is `option[1]`, so this is normally `1` or `-1`.
293
- *
294
- * @param modifiers the event, for `options` that name a modifier key. See
295
- * {@link selectModifier}.
296
- *
297
- * @example
298
- * // ArrowDown on a slider whose keyboard option is ['raw', 1]
299
- * applyDelta(value, -1, keyboard, { min, max, step, scale })
300
- *
301
- * @example
302
- * // Shift+ArrowDown, where `keyboard` is { default: …, shift: ['raw', 0.1] }
303
- * applyDelta(value, -1, keyboard, range, event)
304
- */
305
- export declare function applyDelta(value: number, direction: number, options: ModifierValue<InputEventOption>, { min, max, step, scale }: ValueRange, modifiers?: ModifierState): number;
306
- //#endregion
307
- //#region src/input/check-steps.d.ts
308
- interface CheckStepsOptions {
309
- /** The component, for the message. */
310
- component: string;
311
- /** The axis, for a component that has more than one. */
312
- axis?: string;
189
+ interface ChangeGestureInstance {
190
+ /**
191
+ * Start a gesture that lasts until {@link end}, such as a drag. A gesture of
192
+ * another kind in progress ends first.
193
+ */
194
+ hold: (source: ChangeSource) => void;
313
195
  /**
314
- * The range to probe, or `null` to check nothing. An unbounded input has no
315
- * travel to sample, so `NumberInput` passes `null` when `min` and `max` are
316
- * not both there.
196
+ * One step of a gesture with no end of its own, such as a wheel notch:
197
+ * starts one if none is in progress, and ends it `endDelay` after the last
198
+ * step. While a held gesture is in progress the step belongs to it.
317
199
  */
318
- range: ValueRange | null;
319
- keyboard?: ModifierValue<InputEventOption> | null;
320
- wheel?: ModifierValue<InputEventOption> | null;
200
+ pulse: (source: ChangeSource) => void;
321
201
  /**
322
- * How the value is displayed, where the component shows one. Called with
323
- * probe values only.
202
+ * A gesture that starts and ends around a single change, such as a reset:
203
+ * `change` runs between the two.
324
204
  */
325
- format?: (value: number) => string;
205
+ instant: (source: ChangeSource, change: () => void) => void;
206
+ /** End the gesture in progress, if any. */
207
+ end: () => void;
208
+ /** Whether a gesture is in progress. */
209
+ active: () => boolean;
210
+ /** Replace the given options. A gesture in progress picks them up. */
211
+ update: (options: Partial<ChangeGestureOptions>) => void;
212
+ /** End a gesture in progress, so that nothing is left touched. */
213
+ destroy: () => void;
326
214
  }
327
215
  /**
328
- * The warnings to show when a key press or a wheel notch cannot produce a
329
- * change the user can see. Empty when there is nothing to say.
330
- *
331
- * Two settings that are each fine on their own can cancel out, and nothing
332
- * fails when they do — the control simply sits there:
333
- *
334
- * - **`step` coarser than the amount.** `keyboard={['raw', 0.1]}` with
335
- * `step={1}` rounds every press straight back to where it started
336
- * - **the display coarser than the amount.** A `format` showing two decimals
337
- * of a kHz value cannot show a press worth 1 Hz
338
- *
339
- * The second is only reported when the press is invisible at *every* point
340
- * along the travel. A display that rounds is a deliberate choice and is
341
- * normally right — it is being too coarse everywhere that makes it a mistake.
342
- *
343
- * **Meant for development builds only.** It probes the whole travel, so call
344
- * it behind an inline `process.env.NODE_ENV` check: the bundler then drops
345
- * the call, and this function and its messages with it.
216
+ * Track when a change of value starts and ends, whatever made it: a drag, the
217
+ * wheel, the keys or a reset. A host that records automation needs both ends
218
+ * to know when the control is touched.
346
219
  */
347
- export declare function checkSteps({ component, axis, range, keyboard, wheel, format }: CheckStepsOptions): string[];
220
+ export declare function createChangeGesture(options?: ChangeGestureOptions): ChangeGestureInstance;
348
221
  //#endregion
349
222
  //#region src/input/defaults.d.ts
350
223
  /**
@@ -370,74 +243,6 @@ export declare const DEFAULT_WHEEL_OPTIONS: ModifierValue<InputEventOption>;
370
243
  */
371
244
  export declare const DEFAULT_DRAG_SENSITIVITY: ModifierValue<number>;
372
245
  //#endregion
373
- //#region src/input/direction.d.ts
374
- /**
375
- * Which way an input moves a value, before any amount is applied.
376
- *
377
- * `applyDelta` takes the direction as given, since which key or which sign of
378
- * `deltaY` counts as "up" differs per control. The answers are collected here
379
- * so that every wrapper gives the same one: a knob that turns the other way
380
- * in one framework would be a bug nobody could see from the code.
381
- *
382
- * Two families, by what the control looks like:
383
- *
384
- * - **one value** (`Knob`, `Slider`, `NumberInput`): right and up raise it
385
- * - **a position on screen** (`XYPad`, `PointsEditor`): in screen coordinates,
386
- * x growing rightwards and y growing downwards, plus which axis moves
387
- *
388
- * A control that runs the other way (`reverse`) flips the result itself.
389
- */
390
- /** One of the four arrow keys, as `KeyboardEvent.key` names it. */
391
- type ArrowKey = 'ArrowRight' | 'ArrowLeft' | 'ArrowUp' | 'ArrowDown';
392
- /** Is `key` one of the four arrow keys? */
393
- export declare function isArrowKey(key: string): key is ArrowKey;
394
- /** A move along one of the two axes of a position on screen. */
395
- interface AxisMove {
396
- /** 0 = x, 1 = y. */
397
- axis: 0 | 1;
398
- /** `1` towards the right or the bottom, `-1` towards the left or the top. */
399
- direction: 1 | -1;
400
- }
401
- /**
402
- * The direction an arrow key moves a single value: right and up raise it.
403
- * `null` for any other key.
404
- */
405
- export declare function arrowKeyDirection(key: string): 1 | -1 | null;
406
- /**
407
- * The axis and direction an arrow key moves a position on screen. `null` for
408
- * any other key.
409
- *
410
- * The key picks the axis, whichever element inside the control holds the
411
- * focus: a two-dimensional control is one control to the person moving it.
412
- */
413
- export declare function arrowKeyMove(key: string): AxisMove | null;
414
- interface WheelDirectionOptions {
415
- /**
416
- * Read horizontal scrolling as well, for a control laid out horizontally:
417
- * scrolling right raises the value. Vertical scrolling still counts when
418
- * there is no horizontal movement.
419
- *
420
- * @default false
421
- */
422
- horizontal?: boolean;
423
- }
424
- /**
425
- * The direction one wheel event moves a single value: scrolling up raises it.
426
- * `null` when the event carries no movement the control reads.
427
- */
428
- export declare function wheelDirection(event: Pick<WheelEvent, 'deltaX' | 'deltaY'>, { horizontal }?: WheelDirectionOptions): 1 | -1 | null;
429
- /**
430
- * The axis and direction one wheel event moves a position on screen. `null`
431
- * when the event carries no movement.
432
- *
433
- * Scrolling moves y, and shift switches to x. Browsers turn shift+wheel into
434
- * horizontal scrolling: `deltaY` comes out empty and `deltaX` carries the
435
- * movement. Reading whichever axis moved keeps shift working as the x-axis
436
- * modifier — and picks up a trackpad's own horizontal gesture, which never
437
- * had a modifier.
438
- */
439
- export declare function wheelMove(event: Pick<WheelEvent, 'deltaX' | 'deltaY' | 'shiftKey'>): AxisMove | null;
440
- //#endregion
441
246
  //#region src/knob/geometry.d.ts
442
247
  /**
443
248
  * Width and height of the viewBox a knob is drawn in. The arcs and the thumb
@@ -473,17 +278,6 @@ interface KnobAngles {
473
278
  r4: number;
474
279
  }
475
280
  export declare function knobAngles({ value, min, max, scale, startValue, angleRange }: KnobAngleOptions): KnobAngles;
476
- /**
477
- * The point at `angle` on a circle of `radius` around the centre of the
478
- * viewBox.
479
- *
480
- * The radius depends on the stroke of the line being drawn, which each arc
481
- * has its own of, so the point is found per arc rather than once for the knob.
482
- */
483
- export declare function knobArcPoint(angle: number, radius: number): {
484
- x: number;
485
- y: number;
486
- };
487
281
  /**
488
282
  * The radius that keeps a stroke of `strokeWidth` inside the viewBox: half of
489
283
  * the stroke falls outside the path it is drawn along.
@@ -493,14 +287,16 @@ export declare function knobArcRadius(strokeWidth: number | string | undefined):
493
287
  export declare function knobArcPath(startAngle: number, endAngle: number, radius: number): string;
494
288
  //#endregion
495
289
  //#region src/midi/access.d.ts
496
- /** @private */
497
- export declare const PERMISSION_DENIED = "PERMISSION_DENIED";
498
- /** @private */
499
- export declare const NOT_SUPPORTED = "NOT_SUPPORTED";
500
- /** @private */
501
- export declare const UNAVAILABLE = "UNAVAILABLE";
502
- /** @private */
503
- type MIDIAccessError = typeof PERMISSION_DENIED | typeof NOT_SUPPORTED | typeof UNAVAILABLE;
290
+ /**
291
+ * Why MIDI access could not be had.
292
+ *
293
+ * - `'NOT_SUPPORTED'`: the browser has no Web MIDI API, and asking again will
294
+ * not change that
295
+ * - `'PERMISSION_DENIED'`: the user or the browser said no. Asking again is
296
+ * worthwhile
297
+ * - `'UNAVAILABLE'`: anything else
298
+ */
299
+ type MIDIAccessError = 'NOT_SUPPORTED' | 'PERMISSION_DENIED' | 'UNAVAILABLE';
504
300
  type MIDIAccessOptions = {
505
301
  /**
506
302
  * Ask for system exclusive messages as well.
@@ -542,13 +338,6 @@ interface MIDIAccessInstance {
542
338
  export declare function createMIDIAccess(): MIDIAccessInstance;
543
339
  //#endregion
544
340
  //#region src/midi/input.d.ts
545
- /**
546
- * Centre of the 14-bit pitch bend range: no bend.
547
- *
548
- * The range is not symmetric — 0 is 8192 below centre and 16383 is 8191 above
549
- * — so a wheel at rest reports exactly this rather than half of the maximum.
550
- */
551
- export declare const PITCH_BEND_CENTER = 8192;
552
341
  /**
553
342
  * Every handler is given the channel last, as 0-15. MIDI channels are written
554
343
  * 1-16 on hardware, so add one before showing it to anyone.
@@ -557,7 +346,8 @@ type MIDIInputHandlers = {
557
346
  onNoteOnEvent?: (note: number, velocity: number, channel: number) => void;
558
347
  onNoteOffEvent?: (note: number, channel: number) => void;
559
348
  /**
560
- * The 14-bit bend, 0-16383, centred at {@link PITCH_BEND_CENTER}.
349
+ * The 14-bit bend, 0-16383, centred at 8192. `normalizePitchBend` in
350
+ * `@tremolo-ui/functions` turns it into -1 to 1.
561
351
  *
562
352
  * The two data bytes are little-endian — the first carries the low 7 bits —
563
353
  * which is the other way round from every other message.
@@ -604,259 +394,6 @@ interface MIDIMessageInstance {
604
394
  */
605
395
  export declare function createMIDIMessage(midiAccess: MIDIAccess | null, onMIDIMessage: (event: MIDIMessageEvent) => void): MIDIMessageInstance;
606
396
  //#endregion
607
- //#region src/number-input/stepper-drag.d.ts
608
- interface StepperDragOptions {
609
- /** The value now, read when the drag starts moving it. */
610
- getValue: () => number;
611
- /**
612
- * The range the value moves across. Its `step` is what one step of the drag
613
- * is worth; see `numberInputRanges` for the one a number input uses.
614
- */
615
- range: ValueRange;
616
- /**
617
- * How many pixels of vertical movement make one step.
618
- *
619
- * @default 1
620
- */
621
- pixels?: number;
622
- /**
623
- * How much a step is worth, per modifier key: `0.1` makes the same movement
624
- * count a tenth as much. Pressing or releasing the key mid-drag does not
625
- * move the value.
626
- *
627
- * @default { default: 1, shift: 0.1 }
628
- */
629
- sensitivity?: ModifierValue<number>;
630
- /** Hide the pointer and keep it from hitting the edge of the screen. */
631
- pointerLock?: boolean;
632
- /** Called with the new value whenever the drag moves it. */
633
- onChange: (value: number) => void;
634
- }
635
- interface StepperDragInstance {
636
- /** Replace the given options. `pointerLock` reaches the next drag. */
637
- update: (options: Partial<StepperDragOptions>) => void;
638
- /**
639
- * Whether the drag in progress has moved the value. A stepper button's
640
- * press-and-hold repeat stands down once it has, so the value is not moved
641
- * twice.
642
- */
643
- moved: () => boolean;
644
- destroy: () => void;
645
- }
646
- /**
647
- * Drag up and down on the steppers of a number input to move its value, one
648
- * `step` every `pixels` — up raises it, as on a knob.
649
- *
650
- * Counted from where the drag started moving rather than added up per
651
- * event, so rounding cannot accumulate. The start is taken on the first
652
- * move, not on pointerdown: a stepper button acts on pointerdown, so by then
653
- * the value may already have been nudged once, and the drag carries on from
654
- * there.
655
- */
656
- export declare function createStepperDrag(element: Element, options: StepperDragOptions): StepperDragInstance;
657
- //#endregion
658
- //#region src/number-input/value.d.ts
659
- /**
660
- * The value a number input edits, and how far it may go.
661
- *
662
- * Unlike a slider, either end may be left open, and `clampValue: false` lets
663
- * the value past the ends that are set.
664
- */
665
- interface NumberInputValueOptions {
666
- min?: number;
667
- max?: number;
668
- step?: number;
669
- scale?: Scale;
670
- /**
671
- * Keep the value between `min` and `max`.
672
- *
673
- * @default true
674
- */
675
- clampValue?: boolean;
676
- }
677
- /** The ranges {@link nudgeNumberInput} moves a value across. */
678
- interface NumberInputRanges {
679
- /** For a `normalized` amount, which needs a finite span to take a share of. */
680
- normalized: ValueRange;
681
- /** For a `raw` amount, which does not. */
682
- raw: ValueRange;
683
- }
684
- /**
685
- * The ranges a number input moves its value across, with the open ends
686
- * filled in.
687
- *
688
- * A normalized amount needs a finite span even when an end is unbounded or
689
- * clamping is off. Safe integers provide one without overflowing the span a
690
- * scale calculates. A raw amount needs no span, so its open ends can cover
691
- * every finite number instead of stopping at the safe-integer range.
692
- */
693
- export declare function numberInputRanges({ min, max, step, scale, clampValue }: NumberInputValueOptions): NumberInputRanges;
694
- /**
695
- * Move a number input's value by one press of a key, a wheel notch or a
696
- * stepper, picking the range that suits the kind of amount. See `applyDelta`.
697
- */
698
- export declare function nudgeNumberInput(value: number, direction: number, options: ModifierValue<InputEventOption>, ranges: NumberInputRanges, modifiers?: ModifierState): number;
699
- /**
700
- * Where the value stands against the ends: whether it can go no further
701
- * down or up, and whether it lies outside them — which only an unclamped
702
- * input, or a value set from outside, can do.
703
- */
704
- export declare function numberInputBounds(value: number, { min, max, clampValue }: NumberInputValueOptions): {
705
- atMin: boolean;
706
- atMax: boolean;
707
- outOfRange: boolean;
708
- };
709
- /**
710
- * The value typed text commits to, or `null` when there is no number in it.
711
- *
712
- * Text with no number is not a value: the input should go back to what it
713
- * was showing rather than commit a zero the user never typed. What is read
714
- * is clamped here and not while typing, since clamping as the user types
715
- * would make "1500" impossible to enter into an input whose max is 100.
716
- */
717
- export declare function commitNumberInputText(text: string, parse: (text: string) => number, { min, max, clampValue }: NumberInputValueOptions): number | null;
718
- //#endregion
719
- //#region src/number-input/text.d.ts
720
- /**
721
- * Reading a number out of the text of a number input, and keeping the caret
722
- * in place while the number under it changes.
723
- *
724
- * The text is whatever `format` made of the value — `"440 Hz"`, `"-6.0 dB"` —
725
- * or a half-typed entry, so none of this assumes the text is a number alone.
726
- */
727
- /** Where the number is in the text; the rest, on either side, is the unit. */
728
- interface NumberSpan {
729
- start: number;
730
- end: number;
731
- }
732
- /**
733
- * Where the number is in the text: from its first digit to its last, with the
734
- * sign and the decimal point in front of it. Whatever is left on either side
735
- * is taken for the unit, so it does not matter whether a space separates them,
736
- * or what the number looks like — `+6.0`, `1e+21`, `1,000` and `1:30` are each
737
- * one number. `null` when the text has no digit at all.
738
- */
739
- export declare function numberSpan(text: string): NumberSpan | null;
740
- /**
741
- * The number in the text, with the unit after it ignored: the default `parse`
742
- * of a number input.
743
- *
744
- * `NaN`, which leaves the value alone, whenever the number cannot be read
745
- * safely, rather than a part of it: text with no number, a number that is not
746
- * a plain one (`1,000` would otherwise read as 1, and `1:30` as 1), and text
747
- * with something in front of the number, which can change what it means (the
748
- * `L` of a pan reading `L 30`). A `format` that writes any of those needs its
749
- * own `parse`.
750
- */
751
- export declare function parseNumberText(text: string): number;
752
- /**
753
- * Where the caret is, relative to the decimal point, so that it can be put
754
- * back at the same digit once the value has changed. See
755
- * {@link caretAtDecimalOffset}.
756
- */
757
- export declare function caretDecimalOffset(text: string, caret: number): number;
758
- /**
759
- * The caret position `offset` characters from the decimal point of the new
760
- * text, kept within the number.
761
- *
762
- * @example
763
- * // The caret sits in front of the point of "9.9" when ArrowUp turns it
764
- * // into "10.0"
765
- * const offset = caretDecimalOffset('9.9', 1) // 0
766
- * caretAtDecimalOffset('10.0', offset) // 2: still in front of the point
767
- */
768
- export declare function caretAtDecimalOffset(text: string, offset: number): number;
769
- //#endregion
770
- //#region src/options/replace.d.ts
771
- /**
772
- * The `update()` argument that leaves an instance with exactly `next` as its
773
- * options.
774
- *
775
- * `update()` merges into what the instance has, which suits a wrapper that
776
- * pushes one setting at a time. A wrapper handed the whole new set instead —
777
- * a Svelte action, a Vue composable — has to clear what the new set no longer
778
- * carries, or a handler taken away, or an option left to its default, keeps
779
- * working.
780
- *
781
- * @example
782
- * instance.update(replaceOptions(previous, next))
783
- */
784
- export declare function replaceOptions<T extends object>(previous: T | undefined, next: T | undefined): Partial<T>;
785
- //#endregion
786
- //#region src/piano/layout.d.ts
787
- type NoteRange = {
788
- first: number;
789
- last: number;
790
- };
791
- /**
792
- * `[noteRange.first, noteRange.first + 1, ..., noteRange.last]`
793
- */
794
- export declare function getNoteRangeArray(noteRange: NoteRange): number[];
795
- /**
796
- * The geometry of a drawn keyboard.
797
- *
798
- * One description is shared by the drawing and the hit testing, so a key cannot
799
- * be drawn somewhere other than where it responds.
800
- */
801
- interface PianoLayout {
802
- noteRange: NoteRange;
803
- /** Width of a white key, excluding {@link PianoLayout.keyGap}. */
804
- whiteKeyWidth: number;
805
- /**
806
- * Space between two white keys. Part of the slot a white key occupies, so it
807
- * still belongs to one of the keys for the purpose of hit testing.
808
- *
809
- * @default 1
810
- */
811
- keyGap?: number;
812
- /**
813
- * Width of a black key, as a fraction of {@link PianoLayout.whiteKeyWidth}.
814
- *
815
- * @default 0.65
816
- */
817
- blackKeyWidthRatio?: number;
818
- /**
819
- * Height of a black key, as a fraction of the height of the keyboard.
820
- *
821
- * @default 0.6
822
- */
823
- blackKeyHeightRatio?: number;
824
- }
825
- /** Width of a black key in pixels. */
826
- export declare function blackKeyWidth(layout: PianoLayout): number;
827
- /** Width of the whole keyboard in pixels. */
828
- export declare function pianoWidth(layout: PianoLayout): number;
829
- /**
830
- * Offset of the left edge of a key from the left edge of the keyboard, in
831
- * pixels.
832
- *
833
- * Notes outside `noteRange` are placed too, so the value is negative below
834
- * `noteRange.first`.
835
- */
836
- export declare function notePosition(note: number, layout: PianoLayout): number;
837
- /**
838
- * The note drawn at a point, or null where there is none.
839
- *
840
- * Black keys are tested first, so they win where they overlap a white one. A
841
- * white key covers its gap as well as its width, so the whole width of the
842
- * keyboard belongs to some key and a click cannot fall between two.
843
- *
844
- * @param x offset from the left edge of the keyboard, in pixels
845
- * @param y offset from its top edge, in pixels
846
- * @param height height of the keyboard, in pixels
847
- */
848
- export declare function noteAt(x: number, y: number, height: number, layout: PianoLayout): number | null;
849
- /**
850
- * The white key width that makes the keyboard exactly `width` wide, for a
851
- * keyboard that follows the size of its container.
852
- *
853
- * Solved from {@link pianoWidth} rather than by dividing among the white
854
- * keys, so that a range that starts or ends on a black key — which sticks out
855
- * by a fraction of a white key — still fills the container. The width grows
856
- * linearly with the white key width, so two samples pin it down.
857
- */
858
- export declare function fitWhiteKeyWidth(width: number, layout: Omit<PianoLayout, 'whiteKeyWidth'>): number;
859
- //#endregion
860
397
  //#region src/piano/shortcuts.d.ts
861
398
  type KeyboardShortcuts = {
862
399
  /**
@@ -976,219 +513,6 @@ interface PianoInputInstance {
976
513
  */
977
514
  export declare function createPianoInput(element: Element, options: PianoInputOptions): PianoInputInstance;
978
515
  //#endregion
979
- //#region src/xy.d.ts
980
- /**
981
- * A pair of per-axis values. The tuple elements are labelled, so editors show
982
- * `[x: number, y: number]` rather than a bare pair.
983
- */
984
- type XY<T> = [x: T, y: T];
985
- /**
986
- * A setting that may be given once for both axes, or per axis.
987
- *
988
- * A single value is told from a pair with `Array.isArray`, so the single form
989
- * is only offered while `T` cannot itself be an array. Where it can, the pair
990
- * is the only way to write it, since a lone array would be read as a pair.
991
- */
992
- type XYInput<T> = [T] extends [readonly unknown[]] ? readonly [x: T, y: T] : T | readonly [x: T, y: T];
993
- /**
994
- * Spread a setting that may have been given as a single value.
995
- *
996
- * The parameter is written out rather than taken as `XYInput<T>`: a
997
- * conditional type cannot be narrowed, so the constraint stays where it is
998
- * declared and this takes both forms.
999
- *
1000
- * The pair is copied rather than passed along, so that the result is a tuple
1001
- * the caller owns even when a readonly one was given.
1002
- */
1003
- export declare function toXY<T>(value: T | readonly [x: T, y: T]): XY<T>;
1004
- //#endregion
1005
- //#region src/selection/box.d.ts
1006
- /**
1007
- * A rectangle in the 0..1 space of whatever the box is drawn over, with `y`
1008
- * growing downwards — the same space the items are given in.
1009
- */
1010
- interface SelectionBoxRect {
1011
- x: number;
1012
- y: number;
1013
- width: number;
1014
- height: number;
1015
- }
1016
- interface SelectionBoxOptions<Id> {
1017
- /**
1018
- * Everything the box can pick up, read on every move rather than taken as a
1019
- * snapshot: what is under the box changes while it is dragged, and an item
1020
- * may have moved since the last one.
1021
- */
1022
- items: () => Iterable<readonly [Id, XY<number>]>;
1023
- /** The box as it is dragged, and `null` once it is gone. */
1024
- onBoxChange?: (box: SelectionBoxRect | null) => void;
1025
- /** What the box covers, added to whatever it started from. */
1026
- onSelectionChange?: (ids: Id[]) => void;
1027
- }
1028
- interface SelectionBoxBeginOptions<Id> {
1029
- /**
1030
- * Add to `selection` rather than replacing it. Ctrl / meta rather than
1031
- * shift, for the controls where shift is the fine-adjustment key.
1032
- */
1033
- additive?: boolean;
1034
- /** What was selected before the box started. Only read when `additive`. */
1035
- selection?: readonly Id[];
1036
- }
1037
- interface SelectionBoxInstance<Id> {
1038
- /** Replace the given options, without interrupting a box in progress. */
1039
- update: (options: Partial<SelectionBoxOptions<Id>>) => void;
1040
- /** Start a box at `at`, which is one of its corners. */
1041
- begin: (at: XY<number>, options?: SelectionBoxBeginOptions<Id>) => void;
1042
- /** Drag the opposite corner to `to`. */
1043
- move: (to: XY<number>) => void;
1044
- /**
1045
- * Finish the box. The selection stays as it is.
1046
- *
1047
- * @returns whether a box was running, so that a caller can tell a drag from
1048
- * a press that selected nothing.
1049
- */
1050
- end: () => boolean;
1051
- /** The box being dragged, or `null` when there is none. */
1052
- box: () => SelectionBoxRect | null;
1053
- destroy: () => void;
1054
- }
1055
- /** Whether the box covers the point, edges included. */
1056
- export declare function selectionBoxCovers(box: SelectionBoxRect, [x, y]: XY<number>): boolean;
1057
- /**
1058
- * Selecting by dragging a box over a set of items.
1059
- *
1060
- * The drag itself is not here: the caller owns the pointer, and reports where
1061
- * it went in the same 0..1 space the items are given in.
1062
- */
1063
- export declare function createSelectionBox<Id>(options: SelectionBoxOptions<Id>): SelectionBoxInstance<Id>;
1064
- //#endregion
1065
- //#region src/points-editor/index.d.ts
1066
- /** Where a point is: 0..1 on each axis, with y growing downwards. */
1067
- interface PointPosition {
1068
- x: number;
1069
- y: number;
1070
- }
1071
- /**
1072
- * A point's value is its position in the editor, so its range is the editor:
1073
- * no scaling, and no rounding to a step.
1074
- */
1075
- export declare const POINT_AXIS: {
1076
- min: number;
1077
- max: number;
1078
- };
1079
- /**
1080
- * How much one wheel notch moves a point by default: a hundredth of the
1081
- * editor, whatever its pixel size.
1082
- */
1083
- export declare const POINTS_EDITOR_DEFAULT_WHEEL: ModifierValue<InputEventOption>;
1084
- /**
1085
- * How much one arrow key press moves a point by default. Shift is the
1086
- * fine-adjustment key everywhere else, so it is bound here too — but only on
1087
- * the keyboard. On the wheel it already means the x axis, and browsers hand
1088
- * shift+wheel over as horizontal scrolling anyway.
1089
- */
1090
- export declare const POINTS_EDITOR_DEFAULT_KEYBOARD: ModifierValue<InputEventOption>;
1091
- /** Keep a point within its range. An axis left out runs from 0 to 1. */
1092
- export declare function clampPoint(point: PointPosition, min?: Partial<PointPosition>, max?: Partial<PointPosition>): PointPosition;
1093
- /**
1094
- * What a point tells the editor about itself, so that a selection can be
1095
- * moved without the editor knowing how the points are stored.
1096
- */
1097
- interface PointsEditorPoint {
1098
- value: PointPosition;
1099
- min?: Partial<PointPosition>;
1100
- max?: Partial<PointPosition>;
1101
- /** A point that cannot move stays put while the rest of a selection moves. */
1102
- readonly?: boolean;
1103
- onChange?: (value: PointPosition) => void;
1104
- /** The point's own element, to match the focus and a press against. */
1105
- element?: Element | null;
1106
- /** The wheel option the point resolved, `null` for no wheel. */
1107
- wheel?: ModifierValue<InputEventOption> | null;
1108
- }
1109
- interface PointsEditorOptions {
1110
- /**
1111
- * Let points be selected, and a selection be moved as one. While it is off
1112
- * nothing is selected, and a drag moves only the point it started on.
1113
- *
1114
- * @default false
1115
- */
1116
- selectable?: boolean;
1117
- /**
1118
- * The ids of the selected points. Whoever holds the selection pushes it
1119
- * back with `update()` after {@link PointsEditorOptions.onSelectionChange}.
1120
- */
1121
- selection?: readonly string[];
1122
- /** Called whenever a press or a selection box changes the selection. */
1123
- onSelectionChange?: (selection: string[]) => void;
1124
- /** Called whenever the selection box changes, with `null` once it is gone. */
1125
- onSelectionBoxChange?: (rect: SelectionBoxRect | null) => void;
1126
- }
1127
- interface PointsEditorInstance {
1128
- /** Replace the given options. */
1129
- update: (options: Partial<PointsEditorOptions>) => void;
1130
- /**
1131
- * Register a point under `id`. `read` is called whenever the editor needs
1132
- * the point, so it can return what the point is now rather than what it
1133
- * was when it registered. Returns the function that unregisters it.
1134
- */
1135
- registerPoint: (id: string, read: () => PointsEditorPoint) => () => void;
1136
- /** Whether the element is a point, or inside one. */
1137
- isPointElement: (element: Element | null | undefined) => boolean;
1138
- /**
1139
- * A pointer went down on a point: work out the new selection and remember
1140
- * where everything the drag picked up started.
1141
- *
1142
- * Ctrl / meta add the point to the selection or take it out: shift is the
1143
- * fine-adjustment key on every control here, and it cannot be both. A
1144
- * press on a point already selected keeps the selection, so the group can
1145
- * be dragged.
1146
- */
1147
- beginPointDrag: (id: string, modifiers: ModifierState) => void;
1148
- /**
1149
- * Move everything the drag picked up by `delta` from where it started,
1150
- * stopping the whole group together at the edge.
1151
- */
1152
- movePointDrag: (delta: PointPosition) => void;
1153
- /**
1154
- * Move `id` — and the selection, when it is part of one — by `delta` from
1155
- * where the points are now: an input that is not a drag has no earlier
1156
- * position to measure against.
1157
- */
1158
- nudgeSelection: (id: string, delta: PointPosition) => void;
1159
- /**
1160
- * Move `id` by one press of `option` along one axis, taking the selection
1161
- * along as {@link PointsEditorInstance.nudgeSelection} does.
1162
- */
1163
- nudgePoint: (id: string, axis: 'x' | 'y', direction: number, option: ModifierValue<InputEventOption>, modifiers?: ModifierState) => void;
1164
- /**
1165
- * Move the point holding the focus by one wheel notch, with its own wheel
1166
- * option. The wheel is listened to once for the whole editor, since a wheel
1167
- * event only reaches what the cursor is over. Returns whether a point took
1168
- * it, so the caller knows whether to consume the event.
1169
- */
1170
- nudgeFocusedPoint: (axis: 'x' | 'y', direction: number, modifiers: ModifierState) => boolean;
1171
- /** A drag on empty space started at `at`: start a selection box there. */
1172
- beginSelectionBox: (at: PointPosition, modifiers: ModifierState) => void;
1173
- moveSelectionBox: (to: PointPosition) => void;
1174
- /**
1175
- * End the selection box. The press that started it left the focus on
1176
- * nothing, and the arrow keys and the wheel reach a point only through the
1177
- * focus, so it is handed to one of the points the box selected.
1178
- */
1179
- endSelectionBox: () => void;
1180
- destroy: () => void;
1181
- }
1182
- /**
1183
- * The selection and the moves of a points editor: which points a press or a
1184
- * box selects, and how a selection moves as one.
1185
- *
1186
- * The points stay with the wrapper, which registers each one; the editor only
1187
- * reads them when it needs to, so a point's value can change on every frame
1188
- * of a drag without anything being re-registered.
1189
- */
1190
- export declare function createPointsEditor(options?: PointsEditorOptions): PointsEditorInstance;
1191
- //#endregion
1192
516
  //#region src/pointer/drag.d.ts
1193
517
  type DragState = {
1194
518
  /** Total movement from the drag start, in screen coordinates. */
@@ -1490,8 +814,12 @@ export declare function createLongPress(options: LongPressOptions): LongPressIns
1490
814
  //#endregion
1491
815
  //#region src/pointer/wheel.d.ts
1492
816
  interface WheelOptions {
1493
- /** Replace the callback through {@link WheelInstance.update}. */
1494
- onWheel?: (event: WheelEvent) => void;
817
+ /**
818
+ * Called for every wheel event that `requireFocus` lets through. The
819
+ * listener is not passive, so this may call `preventDefault()` to keep the
820
+ * page from scrolling.
821
+ */
822
+ onWheel: (event: WheelEvent) => void;
1495
823
  /**
1496
824
  * Only report events while the focus is inside the element.
1497
825
  *
@@ -1509,7 +837,7 @@ interface WheelOptions {
1509
837
  }
1510
838
  interface WheelInstance {
1511
839
  /** Replace the given options, keeping the listener in place. */
1512
- update: (options: WheelOptions) => void;
840
+ update: (options: Partial<WheelOptions>) => void;
1513
841
  destroy: () => void;
1514
842
  }
1515
843
  /**
@@ -1518,7 +846,7 @@ interface WheelInstance {
1518
846
  * The listener is registered with `passive: false` so that the handler can call
1519
847
  * `preventDefault()` to stop the page from scrolling.
1520
848
  */
1521
- export declare function createWheel(element: Element, onWheel: (event: WheelEvent) => void, options?: WheelOptions): WheelInstance;
849
+ export declare function createWheel(element: Element, options: WheelOptions): WheelInstance;
1522
850
  //#endregion
1523
851
  //#region src/position.d.ts
1524
852
  /**
@@ -1531,70 +859,5 @@ export declare function createWheel(element: Element, onWheel: (event: WheelEven
1531
859
  */
1532
860
  export declare function valuePercent(value: number, { min, max, scale }: Pick<ValueRange, 'min' | 'max' | 'scale'>, reversed?: boolean): number;
1533
861
  //#endregion
1534
- //#region src/slider/marks.d.ts
1535
- /**
1536
- * How `Slider.Marks` fills itself in when it is given no children: one option
1537
- * every `per`, or every `step` of the slider. The object form turns off the
1538
- * mark or the label for the whole set; a single option is customized by
1539
- * writing `Slider.MarksOption` out instead.
1540
- */
1541
- type MarksOptions = 'step' | number | {
1542
- per: 'step' | number;
1543
- mark?: boolean;
1544
- label?: boolean;
1545
- };
1546
- /** One mark along a slider, as {@link sliderMarks} lays them out. */
1547
- interface SliderMark {
1548
- value: number;
1549
- mark: boolean;
1550
- label: boolean;
1551
- }
1552
- /**
1553
- * The marks `options` asks for between `min` and `max`, in ascending order.
1554
- *
1555
- * Each value is a whole multiple of the interval, rounded to the digits the
1556
- * interval has: stepping by 0.1 would otherwise put binary debris in the
1557
- * labels (`0.1 * 3` is `0.30000000000000004`).
1558
- */
1559
- export declare function sliderMarks(options: MarksOptions, min: number, max: number, step: number): SliderMark[];
1560
- //#endregion
1561
- //#region src/style.d.ts
1562
- /**
1563
- * A number as a CSS length, for a custom property.
1564
- *
1565
- * A custom property takes whatever text it is given, so `--size: 50` comes out
1566
- * as the invalid `50` rather than `50px`. React appends `px` to a bare number
1567
- * only for the properties it knows take a length, and a custom property is
1568
- * never one of them; Vue and Svelte append nothing at all. Anything already a
1569
- * string is passed through, so `'3rem'` and `'100%'` still work.
1570
- */
1571
- export declare function cssLength(value: number | string | undefined): string | undefined;
1572
- /**
1573
- * Take an element out of sight while leaving it in the accessibility tree and
1574
- * in the tab order.
1575
- *
1576
- * `display: none` and `visibility: hidden` would remove it from both, and the
1577
- * native control underneath a headless component is what carries the ARIA and
1578
- * the keyboard behaviour. `pointer-events: none` is safe because nothing is
1579
- * ever clicked here directly: a `<label>` forwards its click, and a drag is
1580
- * handled by the part that is visible.
1581
- *
1582
- * Every value is a string with its unit, so the object can be handed to any
1583
- * framework's `style` binding as it is.
1584
- */
1585
- export declare const visuallyHiddenStyle: {
1586
- readonly position: "absolute";
1587
- readonly width: "1px";
1588
- readonly height: "1px";
1589
- readonly padding: "0";
1590
- readonly margin: "-1px";
1591
- readonly overflow: "hidden";
1592
- readonly clip: "rect(0, 0, 0, 0)";
1593
- readonly clipPath: "inset(50%)";
1594
- readonly whiteSpace: "nowrap";
1595
- readonly border: "0";
1596
- readonly pointerEvents: "none";
1597
- };
1598
- //#endregion
1599
- export type { AcceptCandidate, AnimationCanvasInstance, AnimationCanvasOptions, AnimationFrame, ArrowKey, AxisMove, AxisOptions, CanvasDrawFunction, CanvasInitFunction, CheckStepsOptions, DragInstance, DragOptions, DragState, DragValueInstance, DragValueMapping, DragValueOptions, DrawingContext, DrawingState, DrawingStateValue, DropZoneInstance, DropZoneOptions, DropZoneState, InputEventOption, KeyboardShortcuts, KeyboardShortcutsScope, KnobAngleOptions, KnobAngles, LongPressInstance, LongPressOptions, MIDIAccessError, MIDIAccessInstance, MIDIAccessOptions, MIDIAccessState, MIDIInputHandlers, MIDIInputInstance, MIDIMessageInstance, MappingContext, MarksOptions, Modifier, ModifierMap, ModifierState, ModifierValue, NoteRange, NoteSource, NumberInputRanges, NumberInputValueOptions, NumberSpan, PianoInputInstance, PianoInputOptions, PianoLayout, PointPosition, PointsEditorInstance, PointsEditorOptions, PointsEditorPoint, SelectionBoxBeginOptions, SelectionBoxInstance, SelectionBoxOptions, SelectionBoxRect, SliderMark, StepperDragInstance, StepperDragOptions, WheelDirectionOptions, WheelInstance, WheelOptions, XY, XYInput };
862
+ export { type AnimationCanvasInstance, type AnimationCanvasOptions, type AnimationFrame, type AxisOptions, type CanvasDrawFunction, type CanvasInitFunction, type ChangeGestureInstance, type ChangeGestureOptions, type ChangeSource, type DragInstance, type DragOptions, type DragState, type DragValueInstance, type DragValueMapping, type DragValueOptions, type DropZoneInstance, type DropZoneOptions, type DropZoneState, type InputEventOption, type KeyboardShortcuts, type KeyboardShortcutsScope, type KnobAngleOptions, type KnobAngles, type LongPressInstance, type LongPressOptions, type MIDIAccessError, type MIDIAccessInstance, type MIDIAccessOptions, type MIDIAccessState, type MIDIInputHandlers, type MIDIInputInstance, type MIDIMessageInstance, type MappingContext, type MarksOptions, type Modifier, type ModifierMap, type ModifierState, type ModifierValue, type NoteRange, type NoteSource, type PianoInputInstance, type PianoInputOptions, type PianoLayout, type PointPosition, type PointsEditorInstance, type PointsEditorOptions, type PointsEditorPoint, type SelectionBoxRect, type WheelInstance, type WheelOptions, type XY, type XYInput, createPointsEditor, notePosition };
1600
863
  //# sourceMappingURL=index.d.cts.map