@tremolo-ui/react 0.3.0 → 0.5.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.
Files changed (64) hide show
  1. package/dist/index.cjs +1162 -1554
  2. package/dist/index.cjs.map +1 -1
  3. package/dist/index.css +58 -93
  4. package/dist/index.d.cts +592 -278
  5. package/dist/index.d.cts.map +1 -1
  6. package/dist/index.d.ts +592 -278
  7. package/dist/index.d.ts.map +1 -1
  8. package/dist/index.js +1163 -1555
  9. package/dist/index.js.map +1 -1
  10. package/package.json +12 -13
  11. package/src/components/AnimationCanvas/index.tsx +84 -155
  12. package/src/components/Knob/ActiveLine.tsx +6 -6
  13. package/src/components/Knob/InactiveLine.tsx +9 -11
  14. package/src/components/Knob/SVGRoot.tsx +9 -18
  15. package/src/components/Knob/context.tsx +57 -89
  16. package/src/components/Knob/index.css +6 -2
  17. package/src/components/Knob/index.tsx +95 -83
  18. package/src/components/NumberInput/DecrementStepper.tsx +17 -50
  19. package/src/components/NumberInput/IncrementStepper.tsx +17 -50
  20. package/src/components/NumberInput/InputField.tsx +123 -0
  21. package/src/components/NumberInput/Stepper.tsx +90 -12
  22. package/src/components/NumberInput/context.tsx +74 -146
  23. package/src/components/NumberInput/index.css +38 -102
  24. package/src/components/NumberInput/index.tsx +252 -98
  25. package/src/components/NumberInput/stepperButton.tsx +90 -0
  26. package/src/components/Piano/index.tsx +272 -288
  27. package/src/components/Piano/keyboardShortcuts.ts +34 -4
  28. package/src/components/PointsEditor/Background.tsx +8 -2
  29. package/src/components/PointsEditor/Container.tsx +19 -9
  30. package/src/components/PointsEditor/Point.tsx +117 -52
  31. package/src/components/PointsEditor/context.tsx +28 -74
  32. package/src/components/PointsEditor/index.css +5 -0
  33. package/src/components/PointsEditor/index.tsx +77 -43
  34. package/src/components/Slider/{Scale.tsx → Marks.tsx} +8 -8
  35. package/src/components/Slider/{ScaleOption.tsx → MarksOption.tsx} +16 -18
  36. package/src/components/Slider/Thumb.tsx +55 -68
  37. package/src/components/Slider/Track.tsx +15 -15
  38. package/src/components/Slider/context.tsx +36 -51
  39. package/src/components/Slider/index.css +18 -5
  40. package/src/components/Slider/index.tsx +136 -170
  41. package/src/components/Slider/type.ts +4 -4
  42. package/src/components/XYPad/Area.tsx +16 -7
  43. package/src/components/XYPad/Thumb.tsx +62 -74
  44. package/src/components/XYPad/context.tsx +46 -0
  45. package/src/components/XYPad/index.css +12 -0
  46. package/src/components/XYPad/index.tsx +193 -250
  47. package/src/hooks/useDrag.ts +41 -76
  48. package/src/hooks/useDragValue.ts +149 -0
  49. package/src/hooks/useEventListener.ts +1 -1
  50. package/src/hooks/useWheel.ts +51 -0
  51. package/src/index.ts +15 -13
  52. package/src/components/AnimationCanvas/canvas.ts +0 -46
  53. package/src/components/DragObserver/index.tsx +0 -58
  54. package/src/components/NumberInput/InternalInput.tsx +0 -221
  55. package/src/components/NumberInput/type.ts +0 -58
  56. package/src/components/Piano/KeyLabel.tsx +0 -51
  57. package/src/components/Piano/context.tsx +0 -73
  58. package/src/components/Piano/key.tsx +0 -205
  59. package/src/components/WheelObserver/index.tsx +0 -48
  60. package/src/components/_util/type.ts +0 -1
  61. package/src/hooks/useDragWithElement.ts +0 -72
  62. package/src/hooks/usePianoDrag.ts +0 -75
  63. package/src/hooks/useRefCallbackEvent.ts +0 -34
  64. /package/src/hooks/{useCallbackRef.ts → _internal/useCallbackRef.ts} +0 -0
package/dist/index.d.ts CHANGED
@@ -1,27 +1,23 @@
1
1
  import * as _$react from "react";
2
- import React$1, { CSSProperties, ComponentProps, ComponentPropsWithoutRef, DependencyList, ElementType, ReactElement, ReactNode, Ref, RefObject, SVGProps } from "react";
3
- import { InputEventOption } from "@tremolo-ui/functions";
2
+ import React, { CSSProperties, ComponentPropsWithoutRef, DependencyList, ReactElement, ReactNode, Ref, RefObject, SVGProps } from "react";
4
3
  import * as _$_tremolo_ui_dom0 from "@tremolo-ui/dom";
5
- import { MIDIAccessError, NOT_SUPPORTED, PERMISSION_DENIED } from "@tremolo-ui/dom";
4
+ import { AnimationFrame, AxisOptions, MIDIAccessError, NOT_SUPPORTED, PERMISSION_DENIED, WheelOptions, XY, XY as XY$1, XYInput, XYInput as XYInput$1 } from "@tremolo-ui/dom";
5
+ import { InputEventOption, NoteRange, Scale, Units, ValueRange } from "@tremolo-ui/functions";
6
6
 
7
7
  //#region src/components/AnimationCanvas/index.d.ts
8
8
  type InitFunction = (context: CanvasRenderingContext2D, option: {
9
9
  /** current canvas width */width: number; /** current canvas height */
10
10
  height: number;
11
11
  }) => void;
12
- type DrawFunction = (context: CanvasRenderingContext2D, option: {
13
- /** current canvas width */width: number; /** current canvas height */
14
- height: number; /** frame count */
15
- count: number; /** delta time (ms) */
16
- deltaTime: number; /** elapsed time (ms) */
17
- elapsedTime: number; /** frame per second */
18
- fps: number;
19
- }) => void;
12
+ type DrawFunction = (context: CanvasRenderingContext2D, option: AnimationFrame) => void;
20
13
  interface CommonProps {
21
14
  draw: DrawFunction;
22
15
  init?: InitFunction;
23
16
  animate?: boolean;
24
17
  /**
18
+ * Read once, when the 2D context is created, so changing it later has no
19
+ * effect. Passing a fresh object on every render is therefore harmless.
20
+ *
25
21
  * @see https://developer.mozilla.org/docs/Web/API/HTMLCanvasElement/getContext#contextattributes
26
22
  */
27
23
  options?: CanvasRenderingContext2DSettings;
@@ -41,28 +37,6 @@ type AnimationCanvasProps = CommonProps & AbsoluteSizingProps & RelativeSizingPr
41
37
  declare function AnimationCanvas(props: CommonProps & AbsoluteSizingProps & Omit<ComponentPropsWithoutRef<'canvas'>, keyof AnimationCanvasProps>): ReactElement;
42
38
  declare function AnimationCanvas(pros: CommonProps & RelativeSizingProps & Omit<ComponentPropsWithoutRef<'canvas'>, keyof AnimationCanvasProps>): ReactElement;
43
39
  //#endregion
44
- //#region src/components/_util/type.d.ts
45
- type Override<T, U> = T & Omit<U, keyof T>;
46
- //#endregion
47
- //#region src/components/DragObserver/index.d.ts
48
- interface DragObserverProps<T extends ElementType> {
49
- /**
50
- * React.ElementType
51
- * @default div
52
- */
53
- as?: T;
54
- /**
55
- * Threshold at which the onDrag event fires.
56
- * Prevents onDrag events from firing, for example, when double-clicking.
57
- */
58
- threshold?: number;
59
- children?: ReactNode;
60
- onDrag?: (x: number, y: number, deltaX: number, deltaY: number) => void;
61
- onDragStart?: () => void;
62
- onDragEnd?: () => void;
63
- }
64
- declare function DragObserver<T extends ElementType = 'div'>(props: Override<DragObserverProps<T>, ComponentPropsWithoutRef<T>>): _$react.JSX.Element;
65
- //#endregion
66
40
  //#region src/components/_util/index.d.ts
67
41
  declare const cursorStyles: {
68
42
  grabbing: string;
@@ -90,18 +64,21 @@ declare function InactiveLine({
90
64
  }: Omit<SVGProps<SVGPathElement>, 'd'>): _$react.JSX.Element;
91
65
  //#endregion
92
66
  //#region src/components/Knob/SVGRoot.d.ts
93
- interface SVGRoot {
94
- block?: boolean;
95
- overflowVisible?: boolean;
67
+ interface SVGRootProps {
68
+ /**
69
+ * `<Knob.InactiveLine />`, `<Knob.ActiveLine />` and `<Knob.Thumb />` go
70
+ * here, in the order you want them painted.
71
+ */
72
+ children: ReactNode;
96
73
  }
97
74
  declare function SVGRoot({
98
75
  children,
99
76
  style,
100
77
  ...props
101
- }: Override<SVGRoot, SVGProps<SVGSVGElement>>): _$react.JSX.Element;
78
+ }: SVGRootProps & Omit<SVGProps<SVGSVGElement>, keyof SVGRootProps>): _$react.JSX.Element;
102
79
  //#endregion
103
80
  //#region src/components/Knob/Thumb.d.ts
104
- interface Props {
81
+ interface Props$1 {
105
82
  /** color */
106
83
  thumb?: string;
107
84
  /** color */
@@ -117,7 +94,7 @@ interface Props {
117
94
  thumbLine?: string;
118
95
  };
119
96
  }
120
- declare function Thumb({
97
+ declare function Thumb$2({
121
98
  className,
122
99
  thumb,
123
100
  thumbLine,
@@ -126,7 +103,7 @@ declare function Thumb({
126
103
  thumbLineLength,
127
104
  classes,
128
105
  ...props
129
- }: Props & Omit<SVGProps<SVGSVGElement>, 'd' | keyof Props>): _$react.JSX.Element;
106
+ }: Props$1 & Omit<SVGProps<SVGSVGElement>, 'd' | keyof Props$1>): _$react.JSX.Element;
130
107
  //#endregion
131
108
  //#region src/components/Knob/index.d.ts
132
109
  interface KnobProps {
@@ -134,7 +111,16 @@ interface KnobProps {
134
111
  min: number;
135
112
  max: number;
136
113
  step?: number;
137
- skew?: number;
114
+ /**
115
+ * How the value is distributed across the travel.
116
+ *
117
+ * Pick one of the scales from `@tremolo-ui/functions`: `linearScale`,
118
+ * `exponentialScale`, `curveScale(n)`, `symmetricSkewScale(n)`, or
119
+ * `skewScale(n)` for a value that has to match a JUCE parameter.
120
+ *
121
+ * @default linearScale
122
+ */
123
+ scale?: Scale;
138
124
  /**
139
125
  * value set when double-clicking
140
126
  * restriction: enableDoubleClickDefault = true
@@ -148,6 +134,10 @@ interface KnobProps {
148
134
  */
149
135
  startValue?: number;
150
136
  /** width and height */
137
+ /**
138
+ * Width and height of the knob.
139
+ * Defaults to the `--knob-size` CSS variable (50px).
140
+ */
151
141
  size?: number | string;
152
142
  /**
153
143
  * Global style to apply when dragged
@@ -173,6 +163,20 @@ interface KnobProps {
173
163
  /** angle range [degree] */
174
164
  angleRange?: number;
175
165
  onChange?: (value: number) => void;
166
+ /**
167
+ * The knob renders exactly what you compose here; there is no default
168
+ * markup to fall back to.
169
+ *
170
+ * @example
171
+ * <Knob.Root value={value} min={0} max={100} onChange={setValue}>
172
+ * <Knob.SVGRoot>
173
+ * <Knob.InactiveLine />
174
+ * <Knob.ActiveLine />
175
+ * <Knob.Thumb />
176
+ * </Knob.SVGRoot>
177
+ * </Knob.Root>
178
+ */
179
+ children: ReactNode;
176
180
  }
177
181
  interface KnobMethods {
178
182
  focus: () => void;
@@ -186,67 +190,148 @@ declare const Knob: {
186
190
  SVGRoot: typeof SVGRoot;
187
191
  InactiveLine: typeof InactiveLine;
188
192
  ActiveLine: typeof ActiveLine;
189
- Thumb: typeof Thumb;
193
+ Thumb: typeof Thumb$2;
190
194
  };
191
195
  //#endregion
192
- //#region src/components/NumberInput/DecrementStepper.d.ts
193
- interface DecrementStepperProps {
194
- size?: number;
196
+ //#region src/components/NumberInput/stepperButton.d.ts
197
+ interface StepperButtonProps {
198
+ className?: string;
199
+ style?: CSSProperties;
200
+ /** Replaces the default arrow. Size it with the `--stepper-icon-size` variable. */
195
201
  children?: ReactNode;
196
202
  }
197
- declare function DecrementStepper({
198
- size,
199
- children,
200
- className,
201
- ...props
202
- }: DecrementStepperProps & Omit<ComponentPropsWithoutRef<'div'>, keyof DecrementStepperProps>): _$react.JSX.Element;
203
+ //#endregion
204
+ //#region src/components/NumberInput/DecrementStepper.d.ts
205
+ type DecrementStepperProps = StepperButtonProps;
206
+ /** Lowers the value by one `step`, repeating while held. */
207
+ declare function DecrementStepper(props: DecrementStepperProps & Omit<ComponentPropsWithoutRef<'div'>, keyof DecrementStepperProps>): _$react.JSX.Element;
203
208
  //#endregion
204
209
  //#region src/components/NumberInput/IncrementStepper.d.ts
205
- interface IncrementStepperProps {
206
- size?: number;
207
- children?: ReactNode;
210
+ type IncrementStepperProps = StepperButtonProps;
211
+ /** Raises the value by one `step`, repeating while held. */
212
+ declare function IncrementStepper(props: IncrementStepperProps & Omit<ComponentPropsWithoutRef<'div'>, keyof IncrementStepperProps>): _$react.JSX.Element;
213
+ //#endregion
214
+ //#region src/components/NumberInput/InputField.d.ts
215
+ interface NumberInputFieldProps {
216
+ /**
217
+ * Select the text when the input takes focus. `'number'` selects the leading
218
+ * number, leaving whatever the format appended to it.
219
+ * @default 'none'
220
+ */
221
+ selectOnFocus?: 'all' | 'number' | 'none';
222
+ /**
223
+ * Commit and leave the input when Enter is pressed. Enter commits either way.
224
+ * @default true
225
+ */
226
+ blurOnEnter?: boolean;
227
+ className?: string;
228
+ style?: CSSProperties;
229
+ ref?: Ref<HTMLInputElement>;
208
230
  }
209
- declare function IncrementStepper({
210
- size,
211
- children,
231
+ /**
232
+ * The text field of a `NumberInput`, and the only place the value can be typed.
233
+ *
234
+ * While the user types, their own text stands rather than `format(value)`, so
235
+ * that a half-finished entry is not rewritten under the caret.
236
+ */
237
+ declare function InputField({
238
+ selectOnFocus,
239
+ blurOnEnter,
212
240
  className,
241
+ style,
242
+ ref,
243
+ onFocus,
244
+ onBlur,
245
+ onKeyDown,
213
246
  ...props
214
- }: IncrementStepperProps & Omit<ComponentPropsWithoutRef<'div'>, keyof IncrementStepperProps>): _$react.JSX.Element;
247
+ }: NumberInputFieldProps & Omit<ComponentPropsWithoutRef<'input'>, keyof NumberInputFieldProps | 'type' | 'value' | 'defaultValue'>): _$react.JSX.Element;
215
248
  //#endregion
216
249
  //#region src/components/NumberInput/Stepper.d.ts
217
250
  interface StepperProps {
218
- /** Display only when hovering. */
219
- dynamic?: boolean;
251
+ className?: string;
252
+ style?: CSSProperties;
253
+ /** `<NumberInput.IncrementStepper />` and `<NumberInput.DecrementStepper />` go here. */
220
254
  children?: ReactNode;
255
+ ref?: Ref<HTMLDivElement>;
221
256
  }
257
+ /**
258
+ * The area the steppers sit in, and a drag handle in its own right: dragging it
259
+ * up and down moves the value one `step` every `drag` pixels.
260
+ *
261
+ * The drag lives here rather than on `InputField` because `createDrag` turns
262
+ * off text selection on whatever element it is attached to.
263
+ */
222
264
  declare function Stepper({
223
- dynamic,
224
- children,
225
265
  className,
266
+ style,
267
+ children,
268
+ ref,
226
269
  ...props
227
270
  }: StepperProps & Omit<ComponentPropsWithoutRef<'div'>, keyof StepperProps>): _$react.JSX.Element;
228
271
  //#endregion
229
- //#region src/components/NumberInput/type.d.ts
272
+ //#region src/components/NumberInput/context.d.ts
273
+ type NumberInputContextValue = {
274
+ value: number;
275
+ /**
276
+ * The range the caller asked for. Left undefined when unbounded, which is
277
+ * what `aria-valuemin` / `aria-valuemax` and the steppers need to tell apart
278
+ * from a range that happens to sit at the edge of the safe integers.
279
+ */
280
+ min?: number;
281
+ max?: number;
282
+ step: number; /** How the value is distributed across the travel. */
283
+ scale: Scale;
284
+ disabled: boolean;
285
+ readonly: boolean;
286
+ clampValue: boolean;
287
+ /**
288
+ * The effective scaling for `applyDelta` and for clamping on commit, with the
289
+ * unbounded ends filled in. Ignores `min` / `max` when `clampValue` is off.
290
+ */
291
+ range: ValueRange;
292
+ keyboard: InputEventOption | null; /** Pixels of vertical drag on `Stepper` that move the value by one `step`. */
293
+ drag: number | null; /** What the input shows: the draft while editing, the formatted value otherwise. */
294
+ text: string;
295
+ editing: boolean; /** Whether the value sits outside `min` / `max`. Not judged while editing. */
296
+ outOfRange: boolean; /** Whether a stepper would have no effect, for `aria-disabled`. */
297
+ atMin: boolean;
298
+ atMax: boolean;
299
+ format: (value: number) => string;
300
+ parse: (text: string) => number; /** Typing. Replaces the draft and reports the parsed value, unclamped. */
301
+ setDraft: (text: string) => void; /** Blur or Enter. Clamps the draft, reports it, and drops the draft. */
302
+ commitDraft: () => void; /** Drops the draft and replaces the value: steppers, wheel, keyboard, drag. */
303
+ changeValue: (next: number) => void; /** Moves the value by one `option` in `direction`, normally +1 or -1. */
304
+ nudge: (direction: number, option: InputEventOption) => void; /** `InputField` registers itself here; `Root` focuses it through its methods. */
305
+ inputRef: RefObject<HTMLInputElement | null>;
306
+ };
230
307
  /**
231
- * [unit, scale][]
232
- * @example
233
- * [['Hz', 1], ['kHz', 1000]]
308
+ * The only state behind this is the editing draft; `value` comes from the props
309
+ * of `Root` and everything else is derived during render.
234
310
  */
235
- type Units = [string, number][];
311
+ declare function useNumberInputContext(): NumberInputContextValue;
312
+ declare function useNumberInputContext<T>(selector: (state: NumberInputContextValue) => T): T;
236
313
  //#endregion
237
314
  //#region src/components/NumberInput/index.d.ts
238
315
  interface NumberInputProps {
239
- value: number | string;
240
316
  /**
241
- * Number.MIN_SAFE_INTEGER
317
+ * The value. What the input shows is `format(value)`, except while the user
318
+ * is typing, when their own text stands until it is committed.
242
319
  */
320
+ value: number;
243
321
  min?: number;
244
- /**
245
- * Number.MAX_SAFE_INTEGER
246
- */
247
322
  max?: number;
248
323
  step?: number;
249
324
  /**
325
+ * How the value is distributed across the travel of a drag or a
326
+ * `'normalized'` wheel / keyboard nudge.
327
+ *
328
+ * @default linearScale
329
+ */
330
+ scale?: Scale;
331
+ /**
332
+ * Unit to display the value in, or a list to pick from by magnitude.
333
+ * Builds the default `format` and `parse`.
334
+ *
250
335
  * @example
251
336
  * units='Hz'
252
337
  * units={[['Hz', 1], ['kHz', 1000]]}
@@ -254,23 +339,26 @@ interface NumberInputProps {
254
339
  */
255
340
  units?: string | Units;
256
341
  /**
257
- * Digits for rounding numbers.
342
+ * Digits after the decimal point, for the default `format`.
343
+ *
258
344
  * @example
259
- * with:
260
- * units={[['Hz', 1], ['kHz', 1000]]}
261
- * digit={3}
262
- * results:
263
- * value=100 -> 100Hz, value=1600 -> 1.60Hz
345
+ * // units={[['Hz', 1], ['kHz', 1000]]} digit={2}
346
+ * // 100 -> 100.00Hz, 1600 -> 1.60kHz
264
347
  */
265
348
  digit?: number;
266
- readonly?: boolean;
267
- variant?: 'outline' | 'filled' | 'flushed' | 'unstyled';
268
- selectWithFocus?: 'all' | 'number' | 'none';
269
- blurOnEnter?: boolean;
270
- keepWithinRange?: boolean;
271
- clampValueOnBlur?: boolean;
349
+ /** Render the value as text. Takes precedence over `units` / `digit`. */
350
+ format?: (value: number) => string;
351
+ /** Read a value back out of the text. Takes precedence over `units`. */
352
+ parse?: (text: string) => number;
272
353
  /**
273
- * wheel control option
354
+ * Keep the value within `min` and `max` when it is committed or stepped.
355
+ * Typing is never clamped, so that a value can be entered digit by digit.
356
+ * @default true
357
+ */
358
+ clampValue?: boolean;
359
+ /**
360
+ * Wheel control option. Only applies while the focus is inside, so that
361
+ * scrolling past the input does not change it.
274
362
  * If null, no event will be triggered
275
363
  */
276
364
  wheel?: InputEventOption | null;
@@ -279,12 +367,40 @@ interface NumberInputProps {
279
367
  * If null, no event will be triggered
280
368
  */
281
369
  keyboard?: InputEventOption | null;
282
- activeColor?: string;
283
- wrapperClassName?: string;
284
- onChange?: (value: number, text: string) => void;
285
- onFocus?: (value: number, text: string, event: React.FocusEvent<HTMLInputElement, Element>) => void;
286
- onBlur?: (value: number, text: string, event: React.FocusEvent<HTMLInputElement, Element>) => void;
287
- children?: ReactNode;
370
+ /**
371
+ * Pixels of vertical drag on `Stepper` that move the value by one `step`.
372
+ * If null, no event will be triggered
373
+ * @default 1
374
+ */
375
+ drag?: number | null;
376
+ /**
377
+ * Only the appearance will change.
378
+ * Please consider using with readonly.
379
+ * aria-disabled property is also applied.
380
+ */
381
+ disabled?: boolean;
382
+ /**
383
+ * Make the value unchangeable.
384
+ * aria-readonly property is also applied.
385
+ */
386
+ readonly?: boolean;
387
+ className?: string;
388
+ style?: CSSProperties;
389
+ onChange?: (value: number) => void;
390
+ /**
391
+ * The input renders exactly what you compose here; there is no default
392
+ * markup to fall back to.
393
+ *
394
+ * @example
395
+ * <NumberInput.Root value={value} min={0} max={100} onChange={setValue}>
396
+ * <NumberInput.InputField />
397
+ * <NumberInput.Stepper>
398
+ * <NumberInput.IncrementStepper />
399
+ * <NumberInput.DecrementStepper />
400
+ * </NumberInput.Stepper>
401
+ * </NumberInput.Root>
402
+ */
403
+ children: ReactNode;
288
404
  }
289
405
  interface NumberInputMethods {
290
406
  focus: () => void;
@@ -294,99 +410,127 @@ interface NumberInputMethods {
294
410
  * Input with some useful functions for entering numerical values.
295
411
  */
296
412
  declare const NumberInput: {
297
- Root: _$react.ForwardRefExoticComponent<NumberInputProps & Omit<Omit<_$react.DetailedHTMLProps<_$react.InputHTMLAttributes<HTMLInputElement>, HTMLInputElement>, "ref">, "type" | keyof NumberInputProps> & _$react.RefAttributes<NumberInputMethods>>;
413
+ Root: _$react.ForwardRefExoticComponent<NumberInputProps & Omit<Omit<_$react.DetailedHTMLProps<_$react.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref">, keyof NumberInputProps> & _$react.RefAttributes<NumberInputMethods>>;
414
+ InputField: typeof InputField;
298
415
  Stepper: typeof Stepper;
299
416
  IncrementStepper: typeof IncrementStepper;
300
417
  DecrementStepper: typeof DecrementStepper;
301
418
  };
302
419
  //#endregion
303
- //#region src/components/Piano/key.d.ts
304
- interface KeyProps {
305
- noteNumber: number;
306
- width?: number;
307
- height?: number | `${number}%`;
308
- bg?: string;
309
- color?: string;
310
- activeBg?: string;
311
- activeColor?: string;
312
- style?: CSSProperties;
313
- /**
314
- * \<KeyLabel />
315
- */
316
- children?: ReactElement;
317
- /** @internal */
318
- __width?: number;
319
- }
320
- interface KeyMethods {
321
- play: (velocity?: number) => void;
322
- stop: () => void;
323
- played: () => boolean;
324
- }
325
- //#endregion
326
- //#region src/components/Piano/context.d.ts
327
- type NoteRange = {
328
- first: number;
329
- last: number;
330
- };
331
- //#endregion
332
420
  //#region src/components/Piano/keyboardShortcuts.d.ts
333
421
  type KeyboardShortcuts = {
422
+ /**
423
+ * Keys laid out from `noteRange.first`, one entry per semitone.
424
+ *
425
+ * An empty string leaves that note without a shortcut: `KeyboardEvent.key` is
426
+ * never empty, so the entry can never match. Use it to skip the black keys
427
+ * (see {@link SHORTCUTS.HOME_ROW_NATURAL}) and keep the remaining entries
428
+ * lined up with the notes.
429
+ */
334
430
  keys: string[];
335
- flags?: {
336
- naturalOnly?: boolean;
337
- };
338
431
  };
432
+ /**
433
+ * Ready-made keyboard layouts. Both assume `noteRange.first` is a C.
434
+ */
339
435
  declare const SHORTCUTS: {
340
- HOME_ROW: {
436
+ /** Every semitone from C, over the two rows of a QWERTY keyboard. */HOME_ROW: {
437
+ keys: string[];
438
+ }; /** The white keys only, on the home row. Black keys have no shortcut. */
439
+ HOME_ROW_NATURAL: {
341
440
  keys: string[];
342
441
  };
343
442
  };
344
443
  //#endregion
345
- //#region src/components/Piano/KeyLabel.d.ts
346
- interface KeyLabelProps {
347
- /**
348
- * override Piano.label
349
- */
350
- label?: (note: number, index: number) => ReactNode;
351
- wrapperClassName?: string;
352
- wrapperStyle?: CSSProperties;
353
- /** @internal */
354
- __note?: number;
355
- /** @internal */
356
- __label?: (note: number, index: number) => ReactNode;
357
- }
358
- declare function KeyLabel({
359
- label,
360
- className,
361
- wrapperClassName,
362
- wrapperStyle,
363
- __note,
364
- __label,
365
- ...props
366
- }: KeyLabelProps & Omit<ComponentPropsWithoutRef<'div'>, keyof KeyLabelProps>): false | _$react.JSX.Element;
367
- //#endregion
368
444
  //#region src/components/Piano/index.d.ts
369
445
  /**
370
- * [noteRange.first, noteRange.first + 1 ..., noteRange.last]
446
+ * `style` that also takes CSS custom properties, which is how a key's colours
447
+ * are set: see `index.css` for the ones each key type reads.
371
448
  */
372
- declare function getNoteRangeArray(noteRange: NoteRange): number[];
449
+ type CSSVariables = Record<`--${string}`, string | number | undefined>;
450
+ /**
451
+ * What {@link PianoProps.keyProps} may return for one key.
452
+ *
453
+ * `data-*` attributes are spelled out because TypeScript only allows them on
454
+ * JSX syntax, not on an object type, and selecting on one is the usual way to
455
+ * mark a key out.
456
+ */
457
+ type KeyAttributes = Omit<ComponentPropsWithoutRef<'div'>, 'style'> & {
458
+ style?: CSSProperties & CSSVariables;
459
+ } & Record<`data-${string}`, string | number | boolean | undefined>;
460
+ /** What a key is, when {@link PianoProps.label} or `keyProps` is asked about it. */
461
+ interface KeyState {
462
+ /** Position in the note range, counting from `noteRange.first`. */
463
+ index: number;
464
+ keyType: 'white' | 'black';
465
+ /** Whether the note is currently sounding. */
466
+ active: boolean;
467
+ /** Whether the note is above {@link PianoProps.midiMax} and cannot sound. */
468
+ disabled: boolean;
469
+ }
373
470
  interface PianoProps {
374
471
  noteRange: NoteRange;
472
+ /**
473
+ * Let a pointer slide from one key to the next while it is down.
474
+ *
475
+ * @default true
476
+ */
375
477
  glissando?: boolean;
478
+ /**
479
+ * Highest note that can sound. Keys above it are drawn `aria-disabled`.
480
+ *
481
+ * @default 127
482
+ */
376
483
  midiMax?: number;
377
484
  keyboardShortcuts?: KeyboardShortcuts;
485
+ /**
486
+ * Fill the parent element, deriving the width of a white key from it.
487
+ * {@link PianoProps.whiteKeyWidth} is ignored.
488
+ *
489
+ * @default false
490
+ */
378
491
  fill?: boolean;
379
- whiteNoteWidth?: number;
380
- blackNoteWidth?: number;
492
+ /** @default 40 */
493
+ whiteKeyWidth?: number;
494
+ /**
495
+ * Space between two white keys.
496
+ * @default 1
497
+ */
498
+ keyGap?: number;
499
+ /**
500
+ * Width of a black key, as a fraction of {@link PianoProps.whiteKeyWidth}.
501
+ * @default 0.65
502
+ */
503
+ blackKeyWidthRatio?: number;
504
+ /**
505
+ * Height of a black key, as a fraction of the height of the keyboard.
506
+ * @default 0.6
507
+ */
508
+ blackKeyHeightRatio?: number;
509
+ /** @default `fill ? '100%' : 160` */
381
510
  height?: number | string;
382
- style?: CSSProperties;
383
- onPlayNote?: (note: number, velocity?: number) => void;
384
- onStopNote?: (note: number) => void;
385
- label?: (note: number, index: number) => ReactNode;
511
+ style?: CSSProperties & CSSVariables;
512
+ /**
513
+ * What to draw inside a key. `''`, `null` and `undefined` leave it bare, so
514
+ * a layout with gaps — {@link SHORTCUTS.HOME_ROW_NATURAL}, say — needs no
515
+ * special casing.
516
+ */
517
+ label?: (note: number, state: KeyState) => ReactNode;
386
518
  /**
387
- * \<WhiteKey /> | \<BlackKey />
519
+ * Extra props for one key, by note: a class, a style, a `data-*` attribute
520
+ * to select on.
521
+ *
522
+ * The geometry of the key (`left`, `width`, `height`) is applied after the
523
+ * returned `style` and cannot be overridden, so a key cannot be drawn
524
+ * somewhere other than where it responds.
525
+ *
526
+ * @example highlight the notes of a scale
527
+ * ```tsx
528
+ * keyProps={(note) => ({ 'data-in-scale': inScale(note, root, 'major') })}
529
+ * ```
388
530
  */
389
- children?: ReactElement | ReactElement[];
531
+ keyProps?: (note: number, state: KeyState) => KeyAttributes;
532
+ onPlayNote?: (note: number, velocity?: number) => void;
533
+ onStopNote?: (note: number) => void;
390
534
  }
391
535
  interface PianoMethods {
392
536
  playNote: (note: number, velocity?: number) => void;
@@ -396,25 +540,32 @@ interface PianoMethods {
396
540
  * Customizable piano component.
397
541
  */
398
542
  declare const Piano: {
399
- Root: React$1.ForwardRefExoticComponent<PianoProps & Omit<Omit<React$1.DetailedHTMLProps<React$1.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref">, keyof PianoProps> & React$1.RefAttributes<PianoMethods>>;
400
- WhiteKey: React$1.ForwardRefExoticComponent<KeyProps & Omit<Omit<React$1.DetailedHTMLProps<React$1.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref">, keyof KeyProps> & React$1.RefAttributes<KeyMethods>>;
401
- BlackKey: React$1.ForwardRefExoticComponent<KeyProps & Omit<Omit<React$1.DetailedHTMLProps<React$1.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref">, keyof KeyProps> & React$1.RefAttributes<KeyMethods>>;
402
- KeyLabel: typeof KeyLabel;
543
+ Root: _$react.ForwardRefExoticComponent<PianoProps & Omit<Omit<_$react.DetailedHTMLProps<_$react.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref">, keyof PianoProps> & _$react.RefAttributes<PianoMethods>>;
403
544
  };
404
545
  //#endregion
405
546
  //#region src/components/PointsEditor/Background.d.ts
547
+ interface PointsEditorBackgroundProps {
548
+ /** Whatever the points are placed over: a graph, a canvas, an image. */
549
+ children?: ReactNode;
550
+ }
406
551
  declare function Background({
407
552
  className,
408
553
  children,
409
554
  ...props
410
- }: ComponentPropsWithoutRef<'div'>): _$react.JSX.Element;
555
+ }: PointsEditorBackgroundProps & Omit<ComponentPropsWithoutRef<'div'>, keyof PointsEditorBackgroundProps>): _$react.JSX.Element;
411
556
  //#endregion
412
557
  //#region src/components/PointsEditor/Container.d.ts
558
+ interface PointsEditorContainerProps {
559
+ /** `<PointsEditor.Point />` goes here. */
560
+ children?: ReactNode;
561
+ ref?: Ref<HTMLDivElement>;
562
+ }
413
563
  declare function Container({
414
- className,
415
564
  children,
565
+ className,
566
+ ref,
416
567
  ...props
417
- }: ComponentPropsWithoutRef<'div'>): _$react.JSX.Element;
568
+ }: PointsEditorContainerProps & Omit<ComponentPropsWithoutRef<'div'>, keyof PointsEditorContainerProps>): _$react.JSX.Element;
418
569
  //#endregion
419
570
  //#region src/components/PointsEditor/Point.d.ts
420
571
  type PointBaseType = {
@@ -433,8 +584,14 @@ interface PointProps<T extends PointBaseType> {
433
584
  width?: number | string;
434
585
  height?: number | string;
435
586
  color?: string;
587
+ /** Overrides the `disabled` of `PointsEditor.Root`. */
436
588
  disabled?: boolean;
589
+ /** Overrides the `readonly` of `PointsEditor.Root`. */
437
590
  readonly?: boolean;
591
+ /** Overrides the `wheel` of `PointsEditor.Root`. */
592
+ wheel?: InputEventOption | null;
593
+ /** Overrides the `keyboard` of `PointsEditor.Root`. */
594
+ keyboard?: InputEventOption | null;
438
595
  onChange?: (value: PointBaseType) => void;
439
596
  onDragStart?: (value: PointBaseType) => void;
440
597
  onDragEnd?: (value: PointBaseType) => void;
@@ -447,38 +604,93 @@ declare function Point<T extends PointBaseType>({
447
604
  width,
448
605
  height,
449
606
  color,
450
- disabled,
451
- readonly,
607
+ disabled: _disabled,
608
+ readonly: _readonly,
609
+ wheel: _wheel,
610
+ keyboard: _keyboard,
452
611
  onChange,
453
612
  onDragStart,
454
613
  onDragEnd,
455
614
  className,
456
615
  style,
457
616
  onPointerDown,
617
+ onKeyDown,
458
618
  ...props
459
619
  }: PointProps<T> & Omit<ComponentPropsWithoutRef<'div'>, keyof PointProps<T>>): _$react.JSX.Element;
460
620
  //#endregion
621
+ //#region src/components/PointsEditor/context.d.ts
622
+ type PointsEditorContextValue = {
623
+ disabled: boolean;
624
+ readonly: boolean; /** Inherited by every `Point`; `null` turns the wheel off. */
625
+ wheel: InputEventOption | null; /** Inherited by every `Point`; `null` turns the keyboard off. */
626
+ keyboard: InputEventOption | null;
627
+ externalStyles: {
628
+ userSelectNone?: boolean;
629
+ cursor?: Cursor;
630
+ };
631
+ /**
632
+ * `Container` registers its element here; `Point` normalizes the pointer
633
+ * against it, so a point is placed by its position within the container.
634
+ */
635
+ containerRef: RefObject<HTMLDivElement | null>;
636
+ };
637
+ /**
638
+ * The settings `Root` was given, for the subcomponents to read. There is no
639
+ * state to keep in sync: a point's value belongs to the `Point` that draws it.
640
+ */
641
+ declare function usePointsEditorContext(): PointsEditorContextValue;
642
+ declare function usePointsEditorContext<T>(selector: (state: PointsEditorContextValue) => T): T;
643
+ //#endregion
461
644
  //#region src/components/PointsEditor/index.d.ts
462
645
  interface PointsEditorProps {
463
646
  width?: number | string;
464
647
  height?: number | string;
465
- grid?: number | PointBaseType;
648
+ /**
649
+ * Only the appearance will change.
650
+ * Please consider using with readonly.
651
+ * aria-disabled property is also applied.
652
+ */
466
653
  disabled?: boolean;
654
+ /**
655
+ * Make the points unmovable.
656
+ * aria-readonly property is also applied.
657
+ */
467
658
  readonly?: boolean;
468
659
  externalStyles?: {
469
660
  userSelectNone?: boolean;
470
661
  cursor?: Cursor;
471
662
  };
472
663
  /**
473
- * wheel control option
664
+ * wheel control option for every `Point`. Shift selects the x axis.
474
665
  * If null, no event will be triggered
666
+ *
667
+ * A `Point` can override it with a `wheel` of its own.
475
668
  */
476
669
  wheel?: InputEventOption | null;
477
670
  /**
478
- * keyboard control option
671
+ * keyboard control option for every `Point`, on the arrow keys.
479
672
  * If null, no event will be triggered
673
+ *
674
+ * A `Point` can override it with a `keyboard` of its own.
480
675
  */
481
676
  keyboard?: InputEventOption | null;
677
+ /**
678
+ * The editor renders exactly what you compose here; there is no default
679
+ * markup to fall back to.
680
+ *
681
+ * @example
682
+ * <PointsEditor.Root>
683
+ * <PointsEditor.Background>
684
+ * <svg viewBox="0 0 200 100">...</svg>
685
+ * </PointsEditor.Background>
686
+ * <PointsEditor.Container>
687
+ * {points.map((point, i) => (
688
+ * <PointsEditor.Point key={i} value={point} onChange={...} />
689
+ * ))}
690
+ * </PointsEditor.Container>
691
+ * </PointsEditor.Root>
692
+ */
693
+ children: ReactNode;
482
694
  }
483
695
  /**
484
696
  * Multiple Point Controller
@@ -491,28 +703,28 @@ declare const PointsEditor: {
491
703
  };
492
704
  //#endregion
493
705
  //#region src/components/Slider/type.d.ts
494
- type ScaleType = 'mark' | 'mark-number' | 'number';
495
- type ScaleOptions = ['step', ScaleType] | [number, ScaleType];
706
+ type MarksType = 'mark' | 'mark-number' | 'number';
707
+ type MarksOptions = ['step', MarksType] | [number, MarksType];
496
708
  //#endregion
497
- //#region src/components/Slider/Scale.d.ts
498
- interface ScaleProps {
709
+ //#region src/components/Slider/Marks.d.ts
710
+ interface MarksProps {
499
711
  gap?: number | string;
500
- options?: ScaleOptions;
712
+ options?: MarksOptions;
501
713
  children?: ReactNode;
502
714
  }
503
- declare function Scale({
715
+ declare function Marks({
504
716
  gap,
505
717
  options,
506
718
  children,
507
719
  className,
508
720
  style,
509
721
  ...props
510
- }: ScaleProps & Omit<ComponentPropsWithoutRef<'div'>, keyof ScaleProps>): _$react.JSX.Element;
722
+ }: MarksProps & Omit<ComponentPropsWithoutRef<'div'>, keyof MarksProps>): _$react.JSX.Element;
511
723
  //#endregion
512
- //#region src/components/Slider/ScaleOption.d.ts
513
- interface ScaleOptionProps {
724
+ //#region src/components/Slider/MarksOption.d.ts
725
+ interface MarksOptionProps {
514
726
  value: number;
515
- type?: ScaleType;
727
+ type?: MarksType;
516
728
  /** Display text instead of value. */
517
729
  label?: string;
518
730
  /** mark thickness */
@@ -531,7 +743,7 @@ interface ScaleOptionProps {
531
743
  label?: CSSProperties;
532
744
  };
533
745
  }
534
- declare function ScaleOption({
746
+ declare function MarksOption({
535
747
  value,
536
748
  type,
537
749
  label,
@@ -544,24 +756,31 @@ declare function ScaleOption({
544
756
  className,
545
757
  style,
546
758
  ...props
547
- }: ScaleOptionProps & Omit<ComponentPropsWithoutRef<'div'>, keyof ScaleOptionProps>): _$react.JSX.Element;
759
+ }: MarksOptionProps & Omit<ComponentPropsWithoutRef<'div'>, keyof MarksOptionProps>): _$react.JSX.Element;
548
760
  //#endregion
549
761
  //#region src/components/Slider/Thumb.d.ts
550
762
  interface SliderThumbProps {
551
- size?: number | string;
552
- width?: number | string;
553
- height?: number | string;
763
+ /**
764
+ * Size comes from the `--thumb-size` CSS variable on `Slider.Root`, so that
765
+ * the root can reserve the matching amount of space around the track.
766
+ */
554
767
  color?: string;
555
768
  className?: string;
556
769
  style?: CSSProperties;
557
770
  children?: ReactNode;
558
- /** @internal */
559
- __percent?: number;
771
+ ref?: Ref<SliderThumbMethods>;
560
772
  }
561
773
  interface SliderThumbMethods {
562
774
  focus: () => void;
563
775
  blur: () => void;
564
776
  }
777
+ declare function Thumb$1({
778
+ color,
779
+ children,
780
+ className,
781
+ style,
782
+ ref
783
+ }: SliderThumbProps): _$react.JSX.Element;
565
784
  //#endregion
566
785
  //#region src/components/Slider/Track.d.ts
567
786
  interface SliderTrackProps {
@@ -572,11 +791,9 @@ interface SliderTrackProps {
572
791
  defaultStyle?: boolean;
573
792
  className?: string;
574
793
  style?: CSSProperties;
575
- children?: ReactElement;
576
- /** @internal */
577
- __thumb?: ReactElement;
578
- /** @internal */
579
- __percent?: number;
794
+ /** `<Slider.Thumb />` goes here. */
795
+ children?: ReactNode;
796
+ ref?: Ref<HTMLDivElement>;
580
797
  }
581
798
  declare function Track({
582
799
  length,
@@ -587,23 +804,35 @@ declare function Track({
587
804
  className,
588
805
  style,
589
806
  defaultStyle,
590
- __thumb,
591
- __percent,
807
+ ref,
592
808
  ...props
593
809
  }: SliderTrackProps & Omit<ComponentPropsWithoutRef<'div'>, keyof SliderTrackProps>): _$react.JSX.Element;
594
810
  //#endregion
595
811
  //#region src/components/Slider/context.d.ts
596
- type State = {
812
+ type SliderContextValue = {
813
+ value: number;
597
814
  min: number;
598
815
  max: number;
599
- step: number;
600
- skew: number;
816
+ step: number; /** How the value is distributed across the travel. */
817
+ scale: Scale;
601
818
  vertical: boolean;
602
819
  reverse: boolean;
603
820
  disabled: boolean;
604
821
  readonly: boolean;
822
+ /**
823
+ * Position of the thumb, 0-100, already accounting for the display direction
824
+ * implied by `vertical` and `reverse`.
825
+ */
826
+ percent: number; /** `Track` registers its element here; `Root` normalizes the pointer against it. */
827
+ trackRef: RefObject<HTMLDivElement | null>; /** `Thumb` registers itself here; `Root` focuses it when a drag starts. */
828
+ thumbRef: RefObject<SliderThumbMethods | null>;
605
829
  };
606
- declare function useSliderContext<T>(selector: (state: State) => T): T;
830
+ /**
831
+ * Everything here is derived during render, so there is no state to keep in
832
+ * sync: `value` comes from the props of `Root` and the rest follows from it.
833
+ */
834
+ declare function useSliderContext(): SliderContextValue;
835
+ declare function useSliderContext<T>(selector: (state: SliderContextValue) => T): T;
607
836
  //#endregion
608
837
  //#region src/components/Slider/index.d.ts
609
838
  interface SliderProps {
@@ -611,7 +840,16 @@ interface SliderProps {
611
840
  min: number;
612
841
  max: number;
613
842
  step?: number;
614
- skew?: number;
843
+ /**
844
+ * How the value is distributed across the travel.
845
+ *
846
+ * Pick one of the scales from `@tremolo-ui/functions`: `linearScale`,
847
+ * `exponentialScale`, `curveScale(n)`, `symmetricSkewScale(n)`, or
848
+ * `skewScale(n)` for a value that has to match a JUCE parameter.
849
+ *
850
+ * @default linearScale
851
+ */
852
+ scale?: Scale;
615
853
  /**
616
854
  * slider orientation
617
855
  * aria-orientation property is also applied.
@@ -649,8 +887,18 @@ interface SliderProps {
649
887
  onChange?: (value: number) => void;
650
888
  onDragStart?: (value: number) => void;
651
889
  onDragEnd?: (value: number) => void;
652
- /** \<SliderThumb /> | \<SliderTrack /> */
653
- children?: ReactElement | ReactElement[];
890
+ /**
891
+ * The slider renders exactly what you compose here; there is no default
892
+ * markup to fall back to.
893
+ *
894
+ * @example
895
+ * <Slider.Root value={value} min={0} max={100} onChange={setValue}>
896
+ * <Slider.Track>
897
+ * <Slider.Thumb />
898
+ * </Slider.Track>
899
+ * </Slider.Root>
900
+ */
901
+ children: ReactNode;
654
902
  }
655
903
  interface SliderMethods {
656
904
  focus: () => void;
@@ -660,36 +908,13 @@ interface SliderMethods {
660
908
  * Customizable slider
661
909
  */
662
910
  declare const Slider: {
663
- Root: React$1.ForwardRefExoticComponent<SliderProps & Omit<Omit<React$1.DetailedHTMLProps<React$1.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref">, keyof SliderProps> & React$1.RefAttributes<SliderMethods>>;
664
- Thumb: React$1.ForwardRefExoticComponent<SliderThumbProps & React$1.RefAttributes<SliderThumbMethods>>;
911
+ Root: React.ForwardRefExoticComponent<SliderProps & Omit<Omit<React.DetailedHTMLProps<React.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref">, keyof SliderProps> & React.RefAttributes<SliderMethods>>;
912
+ Thumb: typeof Thumb$1;
665
913
  Track: typeof Track;
666
- Scale: typeof Scale;
667
- ScaleOption: typeof ScaleOption;
914
+ Marks: typeof Marks;
915
+ MarksOption: typeof MarksOption;
668
916
  };
669
917
  //#endregion
670
- //#region src/components/WheelObserver/index.d.ts
671
- interface WheelObserverProps<T extends ElementType> {
672
- /**
673
- * React.ElementType
674
- * @default div
675
- */
676
- as?: T;
677
- children?: ReactNode;
678
- onWheel?: (event: WheelEvent) => void;
679
- }
680
- /**
681
- * @example
682
- * <WheelObserver
683
- * onWheel={(event) => {
684
- * event.preventDefault()
685
- * console.log(event.deltaY)
686
- * }
687
- * >
688
- * <div>Wheel here</div>
689
- * </WheelObserver>
690
- */
691
- declare function WheelObserver<T extends ElementType = 'div'>(props: Override<WheelObserverProps<T>, ComponentProps<T>>): _$react.JSX.Element;
692
- //#endregion
693
918
  //#region src/components/XYPad/Area.d.ts
694
919
  interface XYPadAreaProps {
695
920
  width?: number | string;
@@ -697,9 +922,9 @@ interface XYPadAreaProps {
697
922
  color?: string;
698
923
  className?: string;
699
924
  style?: CSSProperties;
700
- children?: ReactElement;
701
- /** inherit */
702
- __thumb?: ReactElement;
925
+ /** `<XYPad.Thumb />` goes here. */
926
+ children?: ReactNode;
927
+ ref?: Ref<HTMLDivElement>;
703
928
  }
704
929
  declare function Area({
705
930
  width,
@@ -708,65 +933,92 @@ declare function Area({
708
933
  children,
709
934
  className,
710
935
  style,
711
- __thumb,
936
+ ref,
712
937
  ...props
713
938
  }: XYPadAreaProps & Omit<ComponentPropsWithoutRef<'div'>, keyof XYPadAreaProps>): _$react.JSX.Element;
714
939
  //#endregion
715
940
  //#region src/components/XYPad/Thumb.d.ts
716
941
  interface XYPadThumbProps {
717
- size?: number | string;
718
- width?: number | string;
719
- height?: number | string;
942
+ /**
943
+ * Size comes from the `--thumb-size` CSS variable on `XYPad.Root`, so that
944
+ * the root can reserve the matching amount of space around the area.
945
+ */
720
946
  color?: string;
721
947
  wrapperClassName?: string;
722
948
  wrapperStyle?: CSSProperties;
723
949
  children?: ReactNode;
724
- /** @internal */
725
- __disabled?: boolean;
726
- /** @internal */
727
- __readonly?: boolean;
728
- /** @internal */
729
- __css?: CSSProperties;
950
+ ref?: Ref<XYPadThumbMethods>;
730
951
  }
731
952
  interface XYPadThumbMethods {
732
953
  focus: () => void;
733
954
  blur: () => void;
734
955
  }
956
+ type Props = XYPadThumbProps & Omit<ComponentPropsWithoutRef<'div'>, keyof XYPadThumbProps>;
957
+ declare function Thumb({
958
+ color,
959
+ children,
960
+ wrapperClassName,
961
+ wrapperStyle,
962
+ className,
963
+ style,
964
+ ref,
965
+ ...props
966
+ }: Props): _$react.JSX.Element;
735
967
  //#endregion
736
968
  //#region src/components/XYPad/index.d.ts
737
969
  /**
738
970
  * Two-dimensional slider component.
971
+ *
972
+ * The per-axis settings mirror `Slider`, given as `[x, y]` tuples. A plain
973
+ * value applies to both axes.
739
974
  */
740
- interface ValueOptions {
741
- value: number;
742
- min: number;
743
- max: number;
744
- step?: number;
745
- skew?: number;
746
- reverse?: boolean;
975
+ interface XYPadProps {
976
+ value: XY<number>;
977
+ min: XYInput<number>;
978
+ max: XYInput<number>;
979
+ step?: XYInput<number>;
747
980
  /**
748
- * wheel control option
981
+ * How the value of each axis is distributed across the travel.
982
+ *
983
+ * Pick one of the scales from `@tremolo-ui/functions`: `linearScale`,
984
+ * `exponentialScale`, `curveScale(n)`, `symmetricSkewScale(n)`, or
985
+ * `skewScale(n)` for a value that has to match a JUCE parameter.
986
+ *
987
+ * @default linearScale
988
+ */
989
+ scale?: XYInput<Scale>;
990
+ reverse?: XYInput<boolean>;
991
+ /**
992
+ * wheel control option. Shift selects the x axis.
993
+ * If null, no event will be triggered
749
994
  */
750
995
  wheel?: InputEventOption | null;
751
996
  /**
752
997
  * keyboard control option
998
+ * If null, no event will be triggered
753
999
  */
754
1000
  keyboard?: InputEventOption | null;
755
- }
756
- interface XYPadProps {
757
- x: ValueOptions;
758
- y: ValueOptions;
759
1001
  externalStyles?: {
760
1002
  userSelectNone?: boolean;
761
1003
  cursor?: Cursor;
762
1004
  };
763
1005
  disabled?: boolean;
764
1006
  readonly?: boolean;
765
- onChange?: (valueX: number, valueY: number) => void;
766
- onDragStart?: (valueX: number, valueY: number) => void;
767
- onDragEnd?: (valueX: number, valueY: number) => void;
768
- /** \<XYPadThumb /> | \<XYPadArea /> */
769
- children?: ReactElement | ReactElement[];
1007
+ onChange?: (value: XY<number>) => void;
1008
+ onDragStart?: (value: XY<number>) => void;
1009
+ onDragEnd?: (value: XY<number>) => void;
1010
+ /**
1011
+ * The pad renders exactly what you compose here; there is no default
1012
+ * markup to fall back to.
1013
+ *
1014
+ * @example
1015
+ * <XYPad.Root value={[x, y]} min={0} max={100} onChange={setValue}>
1016
+ * <XYPad.Area>
1017
+ * <XYPad.Thumb />
1018
+ * </XYPad.Area>
1019
+ * </XYPad.Root>
1020
+ */
1021
+ children: ReactNode;
770
1022
  }
771
1023
  interface XYPadMethods {
772
1024
  focus: () => void;
@@ -777,8 +1029,8 @@ interface XYPadMethods {
777
1029
  * Simple XYPad
778
1030
  */
779
1031
  declare const XYPad: {
780
- Root: React$1.ForwardRefExoticComponent<XYPadProps & Omit<Omit<React$1.DetailedHTMLProps<React$1.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref">, keyof XYPadProps> & React$1.RefAttributes<XYPadMethods>>;
781
- Thumb: React$1.ForwardRefExoticComponent<XYPadThumbProps & Omit<Omit<React$1.DetailedHTMLProps<React$1.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref">, keyof XYPadThumbProps> & React$1.RefAttributes<XYPadThumbMethods>>;
1032
+ Root: _$react.ForwardRefExoticComponent<XYPadProps & Omit<Omit<_$react.DetailedHTMLProps<_$react.HTMLAttributes<HTMLDivElement>, HTMLDivElement>, "ref">, keyof XYPadProps> & _$react.RefAttributes<XYPadMethods>>;
1033
+ Thumb: typeof Thumb;
782
1034
  Area: typeof Area;
783
1035
  };
784
1036
  //#endregion
@@ -787,36 +1039,70 @@ declare function useAnimationFrame(callback?: () => void, deps?: DependencyList)
787
1039
  //#endregion
788
1040
  //#region src/hooks/useDrag.d.ts
789
1041
  interface UseDragProps {
1042
+ /**
1043
+ * Threshold at which the onDrag event fires.
1044
+ * Prevents onDrag events from firing, for example, when double-clicking.
1045
+ */
790
1046
  threshold?: number;
1047
+ /** CSS cursor to show while dragging. Applied to the element itself. */
1048
+ cursor?: string;
791
1049
  onDrag?: (x: number, y: number, deltaX: number, deltaY: number) => void;
792
1050
  onDragStart?: () => void;
793
1051
  onDragEnd?: () => void;
794
1052
  }
795
1053
  /**
796
- * @returns [refCallback, pointerDownHandler]
1054
+ * Track a pointer drag on an element.
1055
+ *
1056
+ * @returns a ref callback to attach to the element being dragged
797
1057
  */
798
1058
  declare function useDrag<T extends Element>({
799
- threshold: _threshold,
1059
+ threshold,
1060
+ cursor,
800
1061
  onDrag,
801
1062
  onDragStart,
802
1063
  onDragEnd
803
- }: UseDragProps): [(div: EventTarget | null) => void, (event: React.PointerEvent<T>) => void];
1064
+ }: UseDragProps): (node: T | null) => void;
804
1065
  //#endregion
805
- //#region src/hooks/useDragWithElement.d.ts
806
- interface UseDragWithElement<T extends Element> {
807
- baseElementRef: RefObject<T | null>;
808
- onDrag: (normalizedX: number, normalizedY: number) => void;
809
- onDragStart?: (normalizedX: number, normalizedY: number) => void;
810
- onDragEnd?: (normalizedX: number, normalizedY: number) => void;
1066
+ //#region src/hooks/useDragValue.d.ts
1067
+ interface UseDragValueOptions {
1068
+ /** Scaling of each axis; a single value applies to both. */
1069
+ axis: XYInput$1<AxisOptions>;
1070
+ /**
1071
+ * Normalize the pointer against the bounding rect of this element, so that
1072
+ * the value *is* the position pointed at.
1073
+ *
1074
+ * Give either this or `getValue`.
1075
+ */
1076
+ baseElementRef?: RefObject<Element | null>;
1077
+ /**
1078
+ * Move the value away from where it stood when the drag started, by the
1079
+ * distance dragged. The pointer position itself carries no meaning.
1080
+ *
1081
+ * Give either this or `baseElementRef`.
1082
+ */
1083
+ getValue?: () => XY$1<number>;
1084
+ /**
1085
+ * Pixels of movement that span the whole range, with `getValue`.
1086
+ * @default 100
1087
+ */
1088
+ pixelRange?: XYInput$1<number>;
1089
+ /** @see DragValueOptions.updateOnPointerDown */
1090
+ updateOnPointerDown?: boolean;
1091
+ /** @default 0 */
1092
+ threshold?: number;
1093
+ /** CSS cursor to show while dragging. Applied to the element itself. */
1094
+ cursor?: string;
1095
+ onChange?: (value: XY$1<number>) => void;
1096
+ onDragStart?: (value: XY$1<number>) => void;
1097
+ onDragEnd?: (value: XY$1<number>) => void;
811
1098
  }
812
- declare function useDragWithElement<T extends Element>({
813
- baseElementRef,
814
- onDrag,
815
- onDragStart,
816
- onDragEnd
817
- }: UseDragWithElement<T>): {
818
- refHandler: (div: EventTarget | null) => void;
819
- pointerDownHandler: (event: React.PointerEvent<T>) => void;
1099
+ /**
1100
+ * Drive a value with a pointer drag.
1101
+ *
1102
+ * @returns a ref callback for the element that starts the drag, and whether a drag is in progress
1103
+ */
1104
+ declare function useDragValue<T extends Element>(options: UseDragValueOptions): {
1105
+ refCallback: (node: T | null) => void;
820
1106
  dragging: boolean;
821
1107
  };
822
1108
  //#endregion
@@ -855,5 +1141,33 @@ declare function useMIDIInput(midiAccess: MIDIAccess | null, onNoteOnEvent?: (no
855
1141
  */
856
1142
  declare function useMIDIMessage(midiAccess: MIDIAccess | null, onMIDIMessage: (event: MIDIMessageEvent) => void): void;
857
1143
  //#endregion
858
- export { type AbsoluteSizingProps, AnimationCanvas, type AnimationCanvasProps, type CommonProps, type DecrementStepperProps, DragObserver, type DragObserverProps, type DrawFunction, type IncrementStepperProps, type InitFunction, type KeyLabelProps, type KeyMethods, type KeyProps, type KeyboardShortcuts, Knob, type KnobMethods, type KnobProps, type MIDIAccessError, NOT_SUPPORTED, NumberInput, type NumberInputMethods, type NumberInputProps, PERMISSION_DENIED, Piano, type PianoMethods, type PianoProps, type PointBaseType, type PointProps, PointsEditor, type PointsEditorProps, type RelativeSizingProps, SHORTCUTS, type ScaleOptionProps, type ScaleProps, Slider, type SliderMethods, type SliderProps, type SliderThumbMethods, type SliderThumbProps, type SliderTrackProps, type StepperProps, type ValueOptions, WheelObserver, type WheelObserverProps, XYPad, type XYPadAreaProps, type XYPadMethods, type XYPadProps, type XYPadThumbMethods, type XYPadThumbProps, clampPoint, getNoteRangeArray, useAnimationFrame, useDrag, useDragWithElement, useEventListener, useInterval, useLongPress, useMIDIAccess, useMIDIInput, useMIDIMessage, useSliderContext };
1144
+ //#region src/hooks/useWheel.d.ts
1145
+ interface UseWheelOptions extends WheelOptions {
1146
+ /**
1147
+ * Listen on this element rather than on the one the returned ref callback is
1148
+ * attached to, and ignore that callback.
1149
+ *
1150
+ * For a control made of several movable parts: a wheel event only reaches
1151
+ * what the cursor is over, so a listener per part responds only while the
1152
+ * cursor is over that same part. Listening on the element they share lets
1153
+ * every part see the event, and each one decide whether it is the one to act.
1154
+ *
1155
+ * The element is read when the listener is attached, so a ref filled in by a
1156
+ * parent is fine as long as the parent is above in the tree.
1157
+ */
1158
+ target?: RefObject<Element | null>;
1159
+ }
1160
+ /**
1161
+ * Listen to wheel events on an element.
1162
+ *
1163
+ * The listener is not passive, so the handler may call `preventDefault()`.
1164
+ *
1165
+ * @returns a ref callback to attach to the element, unused when `target` is given
1166
+ */
1167
+ declare function useWheel<T extends Element>(onWheel: (event: WheelEvent) => void, {
1168
+ requireFocus,
1169
+ target
1170
+ }?: UseWheelOptions): (node: T | null) => void;
1171
+ //#endregion
1172
+ export { type AbsoluteSizingProps, AnimationCanvas, type AnimationCanvasProps, type CSSVariables, type CommonProps, type DecrementStepperProps, type DrawFunction, type IncrementStepperProps, type InitFunction, type KeyAttributes, type KeyState, type KeyboardShortcuts, Knob, type KnobMethods, type KnobProps, type MIDIAccessError, type MarksOptionProps, type MarksProps, NOT_SUPPORTED, NumberInput, type NumberInputFieldProps, type NumberInputMethods, type NumberInputProps, PERMISSION_DENIED, Piano, type PianoMethods, type PianoProps, type PointBaseType, type PointProps, PointsEditor, type PointsEditorBackgroundProps, type PointsEditorContainerProps, type PointsEditorContextValue, type PointsEditorProps, type RelativeSizingProps, SHORTCUTS, Slider, type SliderMethods, type SliderProps, type SliderThumbMethods, type SliderThumbProps, type SliderTrackProps, type StepperProps, type UseDragValueOptions, type UseWheelOptions, type XY, type XYInput, XYPad, type XYPadAreaProps, type XYPadMethods, type XYPadProps, type XYPadThumbMethods, type XYPadThumbProps, clampPoint, useAnimationFrame, useDrag, useDragValue, useEventListener, useInterval, useLongPress, useMIDIAccess, useMIDIInput, useMIDIMessage, useNumberInputContext, usePointsEditorContext, useSliderContext, useWheel };
859
1173
  //# sourceMappingURL=index.d.ts.map