@cutoff/audio-ui-react 1.0.0-preview.20260123.1125
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/LICENSE.md +690 -0
- package/README.md +228 -0
- package/dist/components/defaults/controls/Button.d.ts +51 -0
- package/dist/components/defaults/controls/Button.d.ts.map +1 -0
- package/dist/components/defaults/controls/ButtonView.d.ts +20 -0
- package/dist/components/defaults/controls/ButtonView.d.ts.map +1 -0
- package/dist/components/defaults/controls/CycleButton.d.ts +82 -0
- package/dist/components/defaults/controls/CycleButton.d.ts.map +1 -0
- package/dist/components/defaults/controls/Knob.d.ts +82 -0
- package/dist/components/defaults/controls/Knob.d.ts.map +1 -0
- package/dist/components/defaults/controls/KnobView.d.ts +43 -0
- package/dist/components/defaults/controls/KnobView.d.ts.map +1 -0
- package/dist/components/defaults/controls/Slider.d.ts +79 -0
- package/dist/components/defaults/controls/Slider.d.ts.map +1 -0
- package/dist/components/defaults/controls/SliderView.d.ts +90 -0
- package/dist/components/defaults/controls/SliderView.d.ts.map +1 -0
- package/dist/components/defaults/devices/Keys.d.ts +104 -0
- package/dist/components/defaults/devices/Keys.d.ts.map +1 -0
- package/dist/components/generic/controls/FilmStripBooleanControl.d.ts +58 -0
- package/dist/components/generic/controls/FilmStripBooleanControl.d.ts.map +1 -0
- package/dist/components/generic/controls/FilmStripContinuousControl.d.ts +82 -0
- package/dist/components/generic/controls/FilmStripContinuousControl.d.ts.map +1 -0
- package/dist/components/generic/controls/FilmStripDiscreteControl.d.ts +55 -0
- package/dist/components/generic/controls/FilmStripDiscreteControl.d.ts.map +1 -0
- package/dist/components/generic/controls/FilmstripView.d.ts +36 -0
- package/dist/components/generic/controls/FilmstripView.d.ts.map +1 -0
- package/dist/components/generic/controls/ImageKnob.d.ts +74 -0
- package/dist/components/generic/controls/ImageKnob.d.ts.map +1 -0
- package/dist/components/generic/controls/ImageKnobView.d.ts +38 -0
- package/dist/components/generic/controls/ImageKnobView.d.ts.map +1 -0
- package/dist/components/generic/controls/ImageRotarySwitch.d.ts +54 -0
- package/dist/components/generic/controls/ImageRotarySwitch.d.ts.map +1 -0
- package/dist/components/generic/controls/ImageSwitch.d.ts +62 -0
- package/dist/components/generic/controls/ImageSwitch.d.ts.map +1 -0
- package/dist/components/generic/controls/ImageSwitchView.d.ts +26 -0
- package/dist/components/generic/controls/ImageSwitchView.d.ts.map +1 -0
- package/dist/components/primitives/AdaptiveBox.d.ts +127 -0
- package/dist/components/primitives/AdaptiveBox.d.ts.map +1 -0
- package/dist/components/primitives/controls/BooleanControl.d.ts +66 -0
- package/dist/components/primitives/controls/BooleanControl.d.ts.map +1 -0
- package/dist/components/primitives/controls/ContinuousControl.d.ts +46 -0
- package/dist/components/primitives/controls/ContinuousControl.d.ts.map +1 -0
- package/dist/components/primitives/controls/DiscreteControl.d.ts +70 -0
- package/dist/components/primitives/controls/DiscreteControl.d.ts.map +1 -0
- package/dist/components/primitives/controls/OptionView.d.ts +12 -0
- package/dist/components/primitives/controls/OptionView.d.ts.map +1 -0
- package/dist/components/primitives/svg/FilmstripImage.d.ts +60 -0
- package/dist/components/primitives/svg/FilmstripImage.d.ts.map +1 -0
- package/dist/components/primitives/svg/Image.d.ts +50 -0
- package/dist/components/primitives/svg/Image.d.ts.map +1 -0
- package/dist/components/primitives/svg/LabelRing.d.ts +42 -0
- package/dist/components/primitives/svg/LabelRing.d.ts.map +1 -0
- package/dist/components/primitives/svg/LinearCursor.d.ts +72 -0
- package/dist/components/primitives/svg/LinearCursor.d.ts.map +1 -0
- package/dist/components/primitives/svg/LinearStrip.d.ts +49 -0
- package/dist/components/primitives/svg/LinearStrip.d.ts.map +1 -0
- package/dist/components/primitives/svg/RadialHtmlOverlay.d.ts +29 -0
- package/dist/components/primitives/svg/RadialHtmlOverlay.d.ts.map +1 -0
- package/dist/components/primitives/svg/RadialImage.d.ts +36 -0
- package/dist/components/primitives/svg/RadialImage.d.ts.map +1 -0
- package/dist/components/primitives/svg/RevealingPath.d.ts +37 -0
- package/dist/components/primitives/svg/RevealingPath.d.ts.map +1 -0
- package/dist/components/primitives/svg/RingArc.d.ts +21 -0
- package/dist/components/primitives/svg/RingArc.d.ts.map +1 -0
- package/dist/components/primitives/svg/RotaryImage.d.ts +43 -0
- package/dist/components/primitives/svg/RotaryImage.d.ts.map +1 -0
- package/dist/components/primitives/svg/TickRing.d.ts +53 -0
- package/dist/components/primitives/svg/TickRing.d.ts.map +1 -0
- package/dist/components/primitives/svg/ValueRing.d.ts +38 -0
- package/dist/components/primitives/svg/ValueRing.d.ts.map +1 -0
- package/dist/components/primitives/svg/ValueStrip.d.ts +59 -0
- package/dist/components/primitives/svg/ValueStrip.d.ts.map +1 -0
- package/dist/components/types.d.ts +451 -0
- package/dist/components/types.d.ts.map +1 -0
- package/dist/hooks/useAdaptiveSize.d.ts +32 -0
- package/dist/hooks/useAdaptiveSize.d.ts.map +1 -0
- package/dist/hooks/useArcAngle.d.ts +23 -0
- package/dist/hooks/useArcAngle.d.ts.map +1 -0
- package/dist/hooks/useAudioParameter.d.ts +89 -0
- package/dist/hooks/useAudioParameter.d.ts.map +1 -0
- package/dist/hooks/useBooleanInteraction.d.ts +106 -0
- package/dist/hooks/useBooleanInteraction.d.ts.map +1 -0
- package/dist/hooks/useBooleanParameterResolution.d.ts +54 -0
- package/dist/hooks/useBooleanParameterResolution.d.ts.map +1 -0
- package/dist/hooks/useContinuousInteraction.d.ts +94 -0
- package/dist/hooks/useContinuousInteraction.d.ts.map +1 -0
- package/dist/hooks/useContinuousParameterResolution.d.ts +75 -0
- package/dist/hooks/useContinuousParameterResolution.d.ts.map +1 -0
- package/dist/hooks/useDiscreteInteraction.d.ts +70 -0
- package/dist/hooks/useDiscreteInteraction.d.ts.map +1 -0
- package/dist/hooks/useDiscreteParameterResolution.d.ts +120 -0
- package/dist/hooks/useDiscreteParameterResolution.d.ts.map +1 -0
- package/dist/hooks/useNoteInteraction.d.ts +84 -0
- package/dist/hooks/useNoteInteraction.d.ts.map +1 -0
- package/dist/hooks/useThemableProps.d.ts +68 -0
- package/dist/hooks/useThemableProps.d.ts.map +1 -0
- package/dist/index.d.ts +77 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +3197 -0
- package/dist/index.js.map +1 -0
- package/dist/stats.html +4949 -0
- package/dist/style.css +1 -0
- package/dist/utils/textUtils.d.ts +15 -0
- package/dist/utils/textUtils.d.ts.map +1 -0
- package/dist/utils/theme.d.ts +88 -0
- package/dist/utils/theme.d.ts.map +1 -0
- package/package.json +78 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
import { BooleanInteractionMode } from '@cutoff/audio-ui-core';
|
|
3
|
+
|
|
4
|
+
export interface UseBooleanInteractionProps {
|
|
5
|
+
/** Current value of the control */
|
|
6
|
+
value: boolean;
|
|
7
|
+
/** Interaction mode: toggle (latch) or momentary */
|
|
8
|
+
mode: BooleanInteractionMode;
|
|
9
|
+
/** Callback to update the value */
|
|
10
|
+
onValueChange: (value: boolean) => void;
|
|
11
|
+
/** Whether the control is disabled */
|
|
12
|
+
disabled?: boolean;
|
|
13
|
+
/** Optional user-provided mouse down handler (composed with hook handler) */
|
|
14
|
+
onMouseDown?: React.MouseEventHandler;
|
|
15
|
+
/** Optional user-provided mouse up handler (composed with hook handler) */
|
|
16
|
+
onMouseUp?: React.MouseEventHandler;
|
|
17
|
+
/** Optional user-provided touch start handler (composed with hook handler) */
|
|
18
|
+
onTouchStart?: React.TouchEventHandler;
|
|
19
|
+
/** Optional user-provided touch end handler (composed with hook handler) */
|
|
20
|
+
onTouchEnd?: React.TouchEventHandler;
|
|
21
|
+
/** Optional user-provided keyboard key down handler (composed with hook handler) */
|
|
22
|
+
onKeyDown?: React.KeyboardEventHandler;
|
|
23
|
+
/** Optional user-provided keyboard key up handler (composed with hook handler) */
|
|
24
|
+
onKeyUp?: React.KeyboardEventHandler;
|
|
25
|
+
}
|
|
26
|
+
export interface UseBooleanInteractionResult {
|
|
27
|
+
/** Handler for mouse down events */
|
|
28
|
+
handleMouseDown: (e: React.MouseEvent) => void;
|
|
29
|
+
/** Handler for mouse up events */
|
|
30
|
+
handleMouseUp: (e: React.MouseEvent) => void;
|
|
31
|
+
/** Handler for mouse enter events (for drag-in behavior) */
|
|
32
|
+
handleMouseEnter: (e: React.MouseEvent) => void;
|
|
33
|
+
/** Handler for mouse leave events (for drag-out behavior) */
|
|
34
|
+
handleMouseLeave: (e: React.MouseEvent) => void;
|
|
35
|
+
/** Handler for touch start events */
|
|
36
|
+
handleTouchStart: (e: React.TouchEvent) => void;
|
|
37
|
+
/** Handler for touch end events */
|
|
38
|
+
handleTouchEnd: (e: React.TouchEvent) => void;
|
|
39
|
+
/** Handler for touch move events (for touch drag-in/drag-out behavior) */
|
|
40
|
+
handleTouchMove: (e: React.TouchEvent) => void;
|
|
41
|
+
/** Ref callback to attach to the button element for touch tracking */
|
|
42
|
+
setButtonElement: (element: HTMLElement | SVGSVGElement | null) => void;
|
|
43
|
+
/** Handler for keyboard key down events (Enter/Space to activate) */
|
|
44
|
+
handleKeyDown: (e: React.KeyboardEvent) => void;
|
|
45
|
+
/** Handler for keyboard key up events (Enter/Space to release momentary buttons) */
|
|
46
|
+
handleKeyUp: (e: React.KeyboardEvent) => void;
|
|
47
|
+
}
|
|
48
|
+
/**
|
|
49
|
+
* Hook to manage interactions for boolean controls (buttons, toggles).
|
|
50
|
+
*
|
|
51
|
+
* Provides standardized logic for:
|
|
52
|
+
* - Toggle mode: Click or Space/Enter to flip the value
|
|
53
|
+
* - Momentary mode: Press to activate, release to deactivate (with global pointer tracking)
|
|
54
|
+
* - Drag-in/drag-out behavior: Buttons respond to pointer entering/leaving while pressed, even when press starts outside the button
|
|
55
|
+
* - Keyboard support: Enter/Space for activation/release
|
|
56
|
+
*
|
|
57
|
+
* The hook wraps the framework-agnostic `BooleanInteractionController` and provides React
|
|
58
|
+
* event handlers that can be attached directly to DOM elements. It maintains stable callback
|
|
59
|
+
* references across renders using `useCallback` and updates the controller configuration via
|
|
60
|
+
* `useEffect` when props change.
|
|
61
|
+
*
|
|
62
|
+
* **Drag-In/Drag-Out Behavior:**
|
|
63
|
+
* - **Momentary Mode**: Press inside → turns on; drag out while pressed → turns off; drag back in while pressed → turns on again. Works even when press starts outside the button.
|
|
64
|
+
* - **Toggle Mode**: Press inside → toggles state; drag out while pressed → no change; drag back in while pressed → toggles again. Works even when press starts outside the button.
|
|
65
|
+
*
|
|
66
|
+
* The hook automatically attaches global pointer listeners (mousedown, mouseup, touchstart, touchmove, touchend)
|
|
67
|
+
* to track pointer state globally, enabling drag-in behavior from anywhere on the page. For mouse interactions,
|
|
68
|
+
* it handles mouseenter/mouseleave events to detect when the pointer crosses the button boundary while pressed.
|
|
69
|
+
* For touch interactions, it manually tracks touch position using touchmove events and elementFromPoint to detect
|
|
70
|
+
* when the touch point crosses button boundaries (since touch events don't fire mouseenter/mouseleave).
|
|
71
|
+
*
|
|
72
|
+
* @param {UseBooleanInteractionProps} props - Configuration for the boolean interaction hook
|
|
73
|
+
* @param {boolean} props.value - Current value of the control
|
|
74
|
+
* @param {BooleanInteractionMode} props.mode - Interaction mode: "toggle" or "momentary"
|
|
75
|
+
* @param {(value: boolean) => void} props.onValueChange - Callback to update the value
|
|
76
|
+
* @param {boolean} [props.disabled=false] - Whether the control is disabled
|
|
77
|
+
* @param {React.MouseEventHandler} [props.onMouseDown] - Optional user-provided mouse down handler
|
|
78
|
+
* @param {React.MouseEventHandler} [props.onMouseUp] - Optional user-provided mouse up handler
|
|
79
|
+
* @param {React.TouchEventHandler} [props.onTouchStart] - Optional user-provided touch start handler
|
|
80
|
+
* @param {React.TouchEventHandler} [props.onTouchEnd] - Optional user-provided touch end handler
|
|
81
|
+
* @param {React.KeyboardEventHandler} [props.onKeyDown] - Optional user-provided keyboard key down handler
|
|
82
|
+
* @param {React.KeyboardEventHandler} [props.onKeyUp] - Optional user-provided keyboard key up handler
|
|
83
|
+
* @returns {UseBooleanInteractionResult} Object containing event handlers including handleMouseEnter and handleMouseLeave for drag-in/drag-out behavior
|
|
84
|
+
*
|
|
85
|
+
* @example
|
|
86
|
+
* ```tsx
|
|
87
|
+
* const { handleMouseDown, handleMouseUp, handleMouseEnter, handleMouseLeave, handleTouchStart, handleTouchEnd, handleKeyDown, handleKeyUp } = useBooleanInteraction({
|
|
88
|
+
* value,
|
|
89
|
+
* mode: "momentary",
|
|
90
|
+
* onValueChange: (val) => setValue(val)
|
|
91
|
+
* });
|
|
92
|
+
*
|
|
93
|
+
* <div
|
|
94
|
+
* onMouseDown={handleMouseDown}
|
|
95
|
+
* onMouseUp={handleMouseUp}
|
|
96
|
+
* onMouseEnter={handleMouseEnter}
|
|
97
|
+
* onMouseLeave={handleMouseLeave}
|
|
98
|
+
* onTouchStart={handleTouchStart}
|
|
99
|
+
* onTouchEnd={handleTouchEnd}
|
|
100
|
+
* onKeyDown={handleKeyDown}
|
|
101
|
+
* onKeyUp={handleKeyUp}
|
|
102
|
+
* />
|
|
103
|
+
* ```
|
|
104
|
+
*/
|
|
105
|
+
export declare function useBooleanInteraction({ value, mode, onValueChange, disabled, onMouseDown: userOnMouseDown, onMouseUp: userOnMouseUp, onTouchStart: userOnTouchStart, onTouchEnd: userOnTouchEnd, onKeyDown: userOnKeyDown, onKeyUp: userOnKeyUp, }: UseBooleanInteractionProps): UseBooleanInteractionResult;
|
|
106
|
+
//# sourceMappingURL=useBooleanInteraction.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useBooleanInteraction.d.ts","sourceRoot":"","sources":["../../src/hooks/useBooleanInteraction.ts"],"names":[],"mappings":"AAMA,OAAO,KAAyC,MAAM,OAAO,CAAC;AAC9D,OAAO,EAAgC,sBAAsB,EAAE,MAAM,uBAAuB,CAAC;AAE7F,MAAM,WAAW,0BAA0B;IACvC,mCAAmC;IACnC,KAAK,EAAE,OAAO,CAAC;IACf,oDAAoD;IACpD,IAAI,EAAE,sBAAsB,CAAC;IAC7B,mCAAmC;IACnC,aAAa,EAAE,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,CAAC;IACxC,sCAAsC;IACtC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,6EAA6E;IAC7E,WAAW,CAAC,EAAE,KAAK,CAAC,iBAAiB,CAAC;IACtC,2EAA2E;IAC3E,SAAS,CAAC,EAAE,KAAK,CAAC,iBAAiB,CAAC;IACpC,8EAA8E;IAC9E,YAAY,CAAC,EAAE,KAAK,CAAC,iBAAiB,CAAC;IACvC,4EAA4E;IAC5E,UAAU,CAAC,EAAE,KAAK,CAAC,iBAAiB,CAAC;IACrC,oFAAoF;IACpF,SAAS,CAAC,EAAE,KAAK,CAAC,oBAAoB,CAAC;IACvC,kFAAkF;IAClF,OAAO,CAAC,EAAE,KAAK,CAAC,oBAAoB,CAAC;CACxC;AAED,MAAM,WAAW,2BAA2B;IACxC,oCAAoC;IACpC,eAAe,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,UAAU,KAAK,IAAI,CAAC;IAC/C,kCAAkC;IAClC,aAAa,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,UAAU,KAAK,IAAI,CAAC;IAC7C,4DAA4D;IAC5D,gBAAgB,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,UAAU,KAAK,IAAI,CAAC;IAChD,6DAA6D;IAC7D,gBAAgB,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,UAAU,KAAK,IAAI,CAAC;IAChD,qCAAqC;IACrC,gBAAgB,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,UAAU,KAAK,IAAI,CAAC;IAChD,mCAAmC;IACnC,cAAc,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,UAAU,KAAK,IAAI,CAAC;IAC9C,0EAA0E;IAC1E,eAAe,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,UAAU,KAAK,IAAI,CAAC;IAC/C,sEAAsE;IACtE,gBAAgB,EAAE,CAAC,OAAO,EAAE,WAAW,GAAG,aAAa,GAAG,IAAI,KAAK,IAAI,CAAC;IACxE,qEAAqE;IACrE,aAAa,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,aAAa,KAAK,IAAI,CAAC;IAChD,oFAAoF;IACpF,WAAW,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,aAAa,KAAK,IAAI,CAAC;CACjD;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwDG;AACH,wBAAgB,qBAAqB,CAAC,EAClC,KAAK,EACL,IAAI,EACJ,aAAa,EACb,QAAgB,EAChB,WAAW,EAAE,eAAe,EAC5B,SAAS,EAAE,aAAa,EACxB,YAAY,EAAE,gBAAgB,EAC9B,UAAU,EAAE,cAAc,EAC1B,SAAS,EAAE,aAAa,EACxB,OAAO,EAAE,WAAW,GACvB,EAAE,0BAA0B,GAAG,2BAA2B,CA4O1D"}
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
import { BooleanParameter, MidiResolution } from '@cutoff/audio-ui-core';
|
|
2
|
+
|
|
3
|
+
export interface UseBooleanParameterResolutionProps {
|
|
4
|
+
/** The parameter definition (Strict mode) */
|
|
5
|
+
parameter?: BooleanParameter;
|
|
6
|
+
/** Identifier for the parameter (used in Ad-Hoc mode) */
|
|
7
|
+
paramId?: string;
|
|
8
|
+
/** Label for the parameter (Ad-Hoc mode) */
|
|
9
|
+
label?: string;
|
|
10
|
+
/** Whether the button should latch (toggle between states) or momentary (only active while pressed) (Ad-Hoc mode) */
|
|
11
|
+
latch?: boolean;
|
|
12
|
+
/** MIDI resolution in bits (Ad-Hoc mode)
|
|
13
|
+
* @default 7
|
|
14
|
+
*/
|
|
15
|
+
midiResolution?: MidiResolution;
|
|
16
|
+
}
|
|
17
|
+
export interface UseBooleanParameterResolutionResult {
|
|
18
|
+
/** The resolved BooleanParameter (derived from props or created from ad-hoc props) */
|
|
19
|
+
derivedParameter: BooleanParameter;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Hook to resolve a BooleanParameter from props.
|
|
23
|
+
*
|
|
24
|
+
* Supports two modes:
|
|
25
|
+
* 1. Strict Mode (Parameter only): Model provided via parameter prop.
|
|
26
|
+
* 2. Ad-Hoc Mode (Props only): Model created from individual props (label, latch, etc.).
|
|
27
|
+
*
|
|
28
|
+
* When `parameter` is provided, it takes precedence over ad-hoc props.
|
|
29
|
+
*
|
|
30
|
+
* @param props - Configuration object for parameter resolution
|
|
31
|
+
* @param props.parameter - The parameter definition (Strict mode). When provided, takes precedence over ad-hoc props.
|
|
32
|
+
* @param props.paramId - Identifier for the parameter (used in Ad-Hoc mode)
|
|
33
|
+
* @param props.label - Label for the parameter (Ad-Hoc mode)
|
|
34
|
+
* @param props.latch - Whether the button should latch (toggle) or be momentary (Ad-Hoc mode)
|
|
35
|
+
* @param props.midiResolution - MIDI resolution in bits (Ad-Hoc mode, default: 7)
|
|
36
|
+
* @returns Object containing the resolved BooleanParameter
|
|
37
|
+
*
|
|
38
|
+
* @example
|
|
39
|
+
* ```tsx
|
|
40
|
+
* // Strict mode: use provided parameter
|
|
41
|
+
* const { derivedParameter } = useBooleanParameterResolution({
|
|
42
|
+
* parameter: powerParam
|
|
43
|
+
* });
|
|
44
|
+
*
|
|
45
|
+
* // Ad-Hoc mode: create from props
|
|
46
|
+
* const { derivedParameter } = useBooleanParameterResolution({
|
|
47
|
+
* paramId: "power",
|
|
48
|
+
* label: "Power",
|
|
49
|
+
* latch: true
|
|
50
|
+
* });
|
|
51
|
+
* ```
|
|
52
|
+
*/
|
|
53
|
+
export declare function useBooleanParameterResolution({ parameter, paramId, label, latch, midiResolution, }: UseBooleanParameterResolutionProps): UseBooleanParameterResolutionResult;
|
|
54
|
+
//# sourceMappingURL=useBooleanParameterResolution.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useBooleanParameterResolution.d.ts","sourceRoot":"","sources":["../../src/hooks/useBooleanParameterResolution.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,gBAAgB,EAAyB,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAEhG,MAAM,WAAW,kCAAkC;IAC/C,6CAA6C;IAC7C,SAAS,CAAC,EAAE,gBAAgB,CAAC;IAC7B,yDAAyD;IACzD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4CAA4C;IAC5C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qHAAqH;IACrH,KAAK,CAAC,EAAE,OAAO,CAAC;IAChB;;OAEG;IACH,cAAc,CAAC,EAAE,cAAc,CAAC;CACnC;AAED,MAAM,WAAW,mCAAmC;IAChD,sFAAsF;IACtF,gBAAgB,EAAE,gBAAgB,CAAC;CACtC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA+BG;AACH,wBAAgB,6BAA6B,CAAC,EAC1C,SAAS,EACT,OAAO,EACP,KAAK,EACL,KAAK,EACL,cAAkB,GACrB,EAAE,kCAAkC,GAAG,mCAAmC,CA8B1E"}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
import { ContinuousInteractionConfig } from '@cutoff/audio-ui-core';
|
|
3
|
+
|
|
4
|
+
export type UseContinuousInteractionProps = Omit<ContinuousInteractionConfig, "adjustValue"> & {
|
|
5
|
+
adjustValue: (delta: number, sensitivity?: number) => void;
|
|
6
|
+
editable?: boolean;
|
|
7
|
+
/** Minimum value (real domain). Used to calculate normalized step if step is not provided. */
|
|
8
|
+
min?: number;
|
|
9
|
+
/** Maximum value (real domain). Used to calculate normalized step if step is not provided. */
|
|
10
|
+
max?: number;
|
|
11
|
+
/** Step size (real domain). Used to calculate normalized step if step is not provided. */
|
|
12
|
+
paramStep?: number;
|
|
13
|
+
/** Function to reset the value to its default (called on double-click) */
|
|
14
|
+
resetToDefault?: () => void;
|
|
15
|
+
/** Optional user-provided mouse down handler (composed with hook handler) */
|
|
16
|
+
onMouseDown?: React.MouseEventHandler;
|
|
17
|
+
/** Optional user-provided touch start handler (composed with hook handler) */
|
|
18
|
+
onTouchStart?: React.TouchEventHandler;
|
|
19
|
+
/** Optional user-provided wheel handler (composed with hook handler) */
|
|
20
|
+
onWheel?: React.WheelEventHandler;
|
|
21
|
+
/** Optional user-provided keyboard key down handler (composed with hook handler) */
|
|
22
|
+
onKeyDown?: React.KeyboardEventHandler;
|
|
23
|
+
/** Optional user-provided double click handler (composed with hook handler) */
|
|
24
|
+
onDoubleClick?: React.MouseEventHandler;
|
|
25
|
+
};
|
|
26
|
+
export interface ContinuousInteractionHandlers {
|
|
27
|
+
onMouseDown: React.MouseEventHandler;
|
|
28
|
+
onTouchStart: React.TouchEventHandler;
|
|
29
|
+
onWheel: React.WheelEventHandler;
|
|
30
|
+
onKeyDown: React.KeyboardEventHandler;
|
|
31
|
+
onDoubleClick: React.MouseEventHandler;
|
|
32
|
+
tabIndex: number;
|
|
33
|
+
role: string;
|
|
34
|
+
"aria-disabled"?: boolean;
|
|
35
|
+
style?: React.CSSProperties;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Hook to standardize user interaction for continuous controls (Knob, Slider).
|
|
39
|
+
*
|
|
40
|
+
* This hook provides a unified interface for handling all user input methods:
|
|
41
|
+
* - Drag interactions (mouse and touch)
|
|
42
|
+
* - Wheel scrolling
|
|
43
|
+
* - Keyboard navigation (arrow keys, Home/End)
|
|
44
|
+
* - Double-click to reset to default value
|
|
45
|
+
*
|
|
46
|
+
* The hook wraps the framework-agnostic `ContinuousInteractionController` and provides React
|
|
47
|
+
* event handlers that can be attached directly to SVG elements. It handles focus
|
|
48
|
+
* management, accessibility attributes, and cursor styling automatically.
|
|
49
|
+
*
|
|
50
|
+
* Cursor types are customizable via CSS variables in themes.css (e.g., `--audioui-cursor-clickable`,
|
|
51
|
+
* `--audioui-cursor-bidirectional`). The cursor selection logic (which cursor to show when) is
|
|
52
|
+
* fixed based on interaction state, but the actual cursor values are customizable.
|
|
53
|
+
*
|
|
54
|
+
* @param adjustValue Function to adjust the value based on a delta. Receives (delta, sensitivity).
|
|
55
|
+
* @param keyboardStep Step size for keyboard interaction (normalized 0..1, default: 0.05)
|
|
56
|
+
* @param interactionMode Interaction mode: "drag", "wheel", or "both" (default: "both")
|
|
57
|
+
* @param direction Direction of drag interaction: "vertical", "horizontal", "circular", or "both" (default: "both")
|
|
58
|
+
* @param sensitivity Sensitivity of the control (default: 0.005). Higher = more sensitive.
|
|
59
|
+
* @param wheelSensitivity Optional separate sensitivity for wheel events. Defaults to DEFAULT_WHEEL_SENSITIVITY (0.005).
|
|
60
|
+
* @param step Normalized step size (0..1). Used for adaptive wheel interaction and sensitivity scaling.
|
|
61
|
+
* @param min Minimum value (real domain). Used to calculate normalized step if step is not provided.
|
|
62
|
+
* @param max Maximum value (real domain). Used to calculate normalized step if step is not provided.
|
|
63
|
+
* @param paramStep Step size (real domain). Used to calculate normalized step if step is not provided.
|
|
64
|
+
* @param disabled Whether the control is disabled (default: false)
|
|
65
|
+
* @param editable Whether the control is editable (default: true). When false, uses `--audioui-cursor-noneditable`.
|
|
66
|
+
* @param resetToDefault Function to reset the value to its default (called on double-click). Only active when editable and not disabled.
|
|
67
|
+
* @param onDragStart Callback when drag interaction starts
|
|
68
|
+
* @param onDragEnd Callback when drag interaction ends
|
|
69
|
+
* @param onMouseDown Optional user-provided mouse down handler (composed with hook handler)
|
|
70
|
+
* @param onTouchStart Optional user-provided touch start handler (composed with hook handler)
|
|
71
|
+
* @param onWheel Optional user-provided wheel handler (composed with hook handler)
|
|
72
|
+
* @param onKeyDown Optional user-provided keyboard key down handler (composed with hook handler)
|
|
73
|
+
* @param onDoubleClick Optional user-provided double click handler (composed with hook handler)
|
|
74
|
+
* @returns Object containing React event handlers (onMouseDown, onTouchStart, onWheel, onKeyDown, onDoubleClick) and accessibility props
|
|
75
|
+
*
|
|
76
|
+
* @example
|
|
77
|
+
* ```tsx
|
|
78
|
+
* const interactiveProps = useContinuousInteraction({
|
|
79
|
+
* adjustValue: (delta, sensitivity) => {
|
|
80
|
+
* setValue(v => clamp(v + delta * sensitivity, 0, 100));
|
|
81
|
+
* },
|
|
82
|
+
* resetToDefault: () => setValue(defaultValue),
|
|
83
|
+
* interactionMode: "both",
|
|
84
|
+
* direction: "vertical",
|
|
85
|
+
* sensitivity: 0.01
|
|
86
|
+
* });
|
|
87
|
+
*
|
|
88
|
+
* <svg {...interactiveProps}>
|
|
89
|
+
* <circle cx={50} cy={50} r={30} />
|
|
90
|
+
* </svg>
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
export declare function useContinuousInteraction({ adjustValue, keyboardStep, interactionMode, direction, sensitivity, wheelSensitivity, step, min, max, paramStep, disabled, editable, onDragStart, onDragEnd, resetToDefault, onMouseDown: userOnMouseDown, onTouchStart: userOnTouchStart, onWheel: userOnWheel, onKeyDown: userOnKeyDown, onDoubleClick: userOnDoubleClick, }: UseContinuousInteractionProps): ContinuousInteractionHandlers;
|
|
94
|
+
//# sourceMappingURL=useContinuousInteraction.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useContinuousInteraction.d.ts","sourceRoot":"","sources":["../../src/hooks/useContinuousInteraction.ts"],"names":[],"mappings":"AAMA,OAAO,KAAqC,MAAM,OAAO,CAAC;AAC1D,OAAO,EAAmC,2BAA2B,EAAE,MAAM,uBAAuB,CAAC;AAGrG,MAAM,MAAM,6BAA6B,GAAG,IAAI,CAAC,2BAA2B,EAAE,aAAa,CAAC,GAAG;IAC3F,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,WAAW,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;IAC3D,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,8FAA8F;IAC9F,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,8FAA8F;IAC9F,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,0FAA0F;IAC1F,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0EAA0E;IAC1E,cAAc,CAAC,EAAE,MAAM,IAAI,CAAC;IAC5B,6EAA6E;IAC7E,WAAW,CAAC,EAAE,KAAK,CAAC,iBAAiB,CAAC;IACtC,8EAA8E;IAC9E,YAAY,CAAC,EAAE,KAAK,CAAC,iBAAiB,CAAC;IACvC,wEAAwE;IACxE,OAAO,CAAC,EAAE,KAAK,CAAC,iBAAiB,CAAC;IAClC,oFAAoF;IACpF,SAAS,CAAC,EAAE,KAAK,CAAC,oBAAoB,CAAC;IACvC,+EAA+E;IAC/E,aAAa,CAAC,EAAE,KAAK,CAAC,iBAAiB,CAAC;CAC3C,CAAC;AAEF,MAAM,WAAW,6BAA6B;IAC1C,WAAW,EAAE,KAAK,CAAC,iBAAiB,CAAC;IACrC,YAAY,EAAE,KAAK,CAAC,iBAAiB,CAAC;IACtC,OAAO,EAAE,KAAK,CAAC,iBAAiB,CAAC;IACjC,SAAS,EAAE,KAAK,CAAC,oBAAoB,CAAC;IACtC,aAAa,EAAE,KAAK,CAAC,iBAAiB,CAAC;IACvC,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAC;CAC/B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAuDG;AACH,wBAAgB,wBAAwB,CAAC,EACrC,WAAW,EACX,YAAoC,EACpC,eAAwB,EACxB,SAAkB,EAClB,WAAW,EACX,gBAAgB,EAChB,IAAI,EACJ,GAAG,EACH,GAAG,EACH,SAAS,EACT,QAAgB,EAChB,QAAe,EACf,WAAW,EACX,SAAS,EACT,cAAc,EACd,WAAW,EAAE,eAAe,EAC5B,YAAY,EAAE,gBAAgB,EAC9B,OAAO,EAAE,WAAW,EACpB,SAAS,EAAE,aAAa,EACxB,aAAa,EAAE,iBAAiB,GACnC,EAAE,6BAA6B,GAAG,6BAA6B,CAiK/D"}
|
|
@@ -0,0 +1,75 @@
|
|
|
1
|
+
import { ContinuousParameter, ScaleType, MidiResolution } from '@cutoff/audio-ui-core';
|
|
2
|
+
|
|
3
|
+
export interface UseContinuousParameterResolutionProps {
|
|
4
|
+
/** The parameter definition (Strict mode) */
|
|
5
|
+
parameter?: ContinuousParameter;
|
|
6
|
+
/** Identifier for the parameter (used in Ad-Hoc mode) */
|
|
7
|
+
paramId?: string;
|
|
8
|
+
/** Label for the parameter (Ad-Hoc mode) */
|
|
9
|
+
label?: string;
|
|
10
|
+
/** Minimum value (Ad-Hoc mode) */
|
|
11
|
+
min?: number;
|
|
12
|
+
/** Maximum value (Ad-Hoc mode) */
|
|
13
|
+
max?: number;
|
|
14
|
+
/** Step size for value adjustments (Ad-Hoc mode) */
|
|
15
|
+
step?: number;
|
|
16
|
+
/** Whether the parameter operates in bipolar mode (Ad-Hoc mode) */
|
|
17
|
+
bipolar?: boolean;
|
|
18
|
+
/** Unit suffix for the value (Ad-Hoc mode, e.g. "dB", "Hz") */
|
|
19
|
+
unit?: string;
|
|
20
|
+
/** Scale function or shortcut for the parameter (Ad-Hoc mode) */
|
|
21
|
+
scale?: ScaleType;
|
|
22
|
+
/** MIDI resolution in bits (Ad-Hoc mode)
|
|
23
|
+
* @default 32
|
|
24
|
+
*/
|
|
25
|
+
midiResolution?: MidiResolution;
|
|
26
|
+
/** Default value for the parameter (Ad-Hoc mode) */
|
|
27
|
+
defaultValue?: number;
|
|
28
|
+
}
|
|
29
|
+
export interface UseContinuousParameterResolutionResult {
|
|
30
|
+
/** The resolved ContinuousParameter (derived from props or created from ad-hoc props) */
|
|
31
|
+
derivedParameter: ContinuousParameter;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Hook to resolve a ContinuousParameter from props.
|
|
35
|
+
*
|
|
36
|
+
* Supports two modes:
|
|
37
|
+
* 1. Strict Mode (Parameter only): Model provided via parameter prop.
|
|
38
|
+
* 2. Ad-Hoc Mode (Props only): Model created from individual props (min, max, step, etc.).
|
|
39
|
+
*
|
|
40
|
+
* When `parameter` is provided, it takes precedence over ad-hoc props.
|
|
41
|
+
*
|
|
42
|
+
* @param props - Configuration object for parameter resolution
|
|
43
|
+
* @param props.parameter - The parameter definition (Strict mode). When provided, takes precedence over ad-hoc props.
|
|
44
|
+
* @param props.paramId - Identifier for the parameter (used in Ad-Hoc mode)
|
|
45
|
+
* @param props.label - Label for the parameter (Ad-Hoc mode)
|
|
46
|
+
* @param props.min - Minimum value (Ad-Hoc mode)
|
|
47
|
+
* @param props.max - Maximum value (Ad-Hoc mode)
|
|
48
|
+
* @param props.step - Step size for value adjustments (Ad-Hoc mode)
|
|
49
|
+
* @param props.bipolar - Whether the parameter operates in bipolar mode (Ad-Hoc mode)
|
|
50
|
+
* @param props.unit - Unit suffix for the value (Ad-Hoc mode, e.g. "dB", "Hz")
|
|
51
|
+
* @param props.scale - Scale function or shortcut for the parameter (Ad-Hoc mode)
|
|
52
|
+
* @param props.midiResolution - MIDI resolution in bits (Ad-Hoc mode, default: 32)
|
|
53
|
+
* @param props.defaultValue - Default value for the parameter (Ad-Hoc mode)
|
|
54
|
+
* @returns Object containing the resolved ContinuousParameter
|
|
55
|
+
*
|
|
56
|
+
* @example
|
|
57
|
+
* ```tsx
|
|
58
|
+
* // Strict mode: use provided parameter
|
|
59
|
+
* const { derivedParameter } = useContinuousParameterResolution({
|
|
60
|
+
* parameter: volumeParam
|
|
61
|
+
* });
|
|
62
|
+
*
|
|
63
|
+
* // Ad-Hoc mode: create from props
|
|
64
|
+
* const { derivedParameter } = useContinuousParameterResolution({
|
|
65
|
+
* paramId: "volume",
|
|
66
|
+
* label: "Volume",
|
|
67
|
+
* min: 0,
|
|
68
|
+
* max: 100,
|
|
69
|
+
* step: 1,
|
|
70
|
+
* unit: "%"
|
|
71
|
+
* });
|
|
72
|
+
* ```
|
|
73
|
+
*/
|
|
74
|
+
export declare function useContinuousParameterResolution({ parameter, paramId, label, min, max, step, bipolar, unit, scale, midiResolution, defaultValue, }: UseContinuousParameterResolutionProps): UseContinuousParameterResolutionResult;
|
|
75
|
+
//# sourceMappingURL=useContinuousParameterResolution.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useContinuousParameterResolution.d.ts","sourceRoot":"","sources":["../../src/hooks/useContinuousParameterResolution.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,mBAAmB,EAAyB,SAAS,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAE9G,MAAM,WAAW,qCAAqC;IAClD,6CAA6C;IAC7C,SAAS,CAAC,EAAE,mBAAmB,CAAC;IAChC,yDAAyD;IACzD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,4CAA4C;IAC5C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kCAAkC;IAClC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,kCAAkC;IAClC,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,oDAAoD;IACpD,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,mEAAmE;IACnE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,+DAA+D;IAC/D,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,iEAAiE;IACjE,KAAK,CAAC,EAAE,SAAS,CAAC;IAClB;;OAEG;IACH,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC,oDAAoD;IACpD,YAAY,CAAC,EAAE,MAAM,CAAC;CACzB;AAED,MAAM,WAAW,sCAAsC;IACnD,yFAAyF;IACzF,gBAAgB,EAAE,mBAAmB,CAAC;CACzC;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,wBAAgB,gCAAgC,CAAC,EAC7C,SAAS,EACT,OAAO,EACP,KAAK,EACL,GAAG,EACH,GAAG,EACH,IAAI,EACJ,OAAO,EACP,IAAI,EACJ,KAAK,EACL,cAAmB,EACnB,YAAY,GACf,EAAE,qCAAqC,GAAG,sCAAsC,CA2BhF"}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
|
|
3
|
+
export interface UseDiscreteInteractionProps {
|
|
4
|
+
/** Current value of the control */
|
|
5
|
+
value: string | number;
|
|
6
|
+
/** List of available options */
|
|
7
|
+
options: Array<{
|
|
8
|
+
value: string | number;
|
|
9
|
+
}>;
|
|
10
|
+
/** Callback to update the value */
|
|
11
|
+
onValueChange: (value: string | number) => void;
|
|
12
|
+
/** Whether the control is disabled */
|
|
13
|
+
disabled?: boolean;
|
|
14
|
+
/** Optional user-provided click handler (composed with hook handler) */
|
|
15
|
+
onClick?: React.MouseEventHandler;
|
|
16
|
+
/** Optional user-provided mouse down handler (composed with hook handler) */
|
|
17
|
+
onMouseDown?: React.MouseEventHandler;
|
|
18
|
+
/** Optional user-provided keyboard key down handler (composed with hook handler) */
|
|
19
|
+
onKeyDown?: React.KeyboardEventHandler;
|
|
20
|
+
}
|
|
21
|
+
export interface UseDiscreteInteractionResult {
|
|
22
|
+
/** Handler for click events (cycles through options) */
|
|
23
|
+
handleClick: (e: React.MouseEvent) => void;
|
|
24
|
+
/** Handler for keyboard events (Arrows to step, Space/Enter to cycle) */
|
|
25
|
+
handleKeyDown: (e: React.KeyboardEvent) => void;
|
|
26
|
+
/** Handler for mouse down events (passes through to user handler if provided) */
|
|
27
|
+
handleMouseDown?: React.MouseEventHandler;
|
|
28
|
+
/** Manually cycle to the next value (wrapping around) */
|
|
29
|
+
cycleNext: () => void;
|
|
30
|
+
/** Manually step to the next value (clamped) */
|
|
31
|
+
stepNext: () => void;
|
|
32
|
+
/** Manually step to the previous value (clamped) */
|
|
33
|
+
stepPrev: () => void;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Hook to manage interactions for discrete controls (switches, toggles, selectors).
|
|
37
|
+
*
|
|
38
|
+
* Provides standardized logic for:
|
|
39
|
+
* - Cycling through options (wrapping) via Click or Space/Enter
|
|
40
|
+
* - Stepping through options (clamped) via Arrow keys
|
|
41
|
+
* - Finding the nearest valid option index when value doesn't match
|
|
42
|
+
*
|
|
43
|
+
* The hook wraps the framework-agnostic `DiscreteInteractionController` and provides React
|
|
44
|
+
* event handlers that can be attached directly to DOM elements. It maintains stable callback
|
|
45
|
+
* references across renders using `useCallback` and updates the controller configuration via
|
|
46
|
+
* `useEffect` when props change.
|
|
47
|
+
*
|
|
48
|
+
* @param {UseDiscreteInteractionProps} props - Configuration for the discrete interaction hook
|
|
49
|
+
* @param {string | number} props.value - Current value of the control
|
|
50
|
+
* @param {Array<{ value: string | number }>} props.options - List of available options
|
|
51
|
+
* @param {(value: string | number) => void} props.onValueChange - Callback to update the value
|
|
52
|
+
* @param {boolean} [props.disabled=false] - Whether the control is disabled
|
|
53
|
+
* @param {React.MouseEventHandler} [props.onClick] - Optional user-provided click handler
|
|
54
|
+
* @param {React.MouseEventHandler} [props.onMouseDown] - Optional user-provided mouse down handler
|
|
55
|
+
* @param {React.KeyboardEventHandler} [props.onKeyDown] - Optional user-provided keyboard key down handler
|
|
56
|
+
* @returns {UseDiscreteInteractionResult} Object containing event handlers and manual control methods
|
|
57
|
+
*
|
|
58
|
+
* @example
|
|
59
|
+
* ```tsx
|
|
60
|
+
* const { handleClick, handleKeyDown } = useDiscreteInteraction({
|
|
61
|
+
* value,
|
|
62
|
+
* options,
|
|
63
|
+
* onValueChange: (val) => setNormalizedValue(converter.normalize(val))
|
|
64
|
+
* });
|
|
65
|
+
*
|
|
66
|
+
* <div onClick={handleClick} onKeyDown={handleKeyDown} />
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
export declare function useDiscreteInteraction({ value, options, onValueChange, disabled, onClick: userOnClick, onMouseDown: userOnMouseDown, onKeyDown: userOnKeyDown, }: UseDiscreteInteractionProps): UseDiscreteInteractionResult;
|
|
70
|
+
//# sourceMappingURL=useDiscreteInteraction.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useDiscreteInteraction.d.ts","sourceRoot":"","sources":["../../src/hooks/useDiscreteInteraction.ts"],"names":[],"mappings":"AAMA,OAAO,KAAyC,MAAM,OAAO,CAAC;AAG9D,MAAM,WAAW,2BAA2B;IACxC,mCAAmC;IACnC,KAAK,EAAE,MAAM,GAAG,MAAM,CAAC;IACvB,gCAAgC;IAChC,OAAO,EAAE,KAAK,CAAC;QAAE,KAAK,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,CAAC,CAAC;IAC3C,mCAAmC;IACnC,aAAa,EAAE,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,KAAK,IAAI,CAAC;IAChD,sCAAsC;IACtC,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,wEAAwE;IACxE,OAAO,CAAC,EAAE,KAAK,CAAC,iBAAiB,CAAC;IAClC,6EAA6E;IAC7E,WAAW,CAAC,EAAE,KAAK,CAAC,iBAAiB,CAAC;IACtC,oFAAoF;IACpF,SAAS,CAAC,EAAE,KAAK,CAAC,oBAAoB,CAAC;CAC1C;AAED,MAAM,WAAW,4BAA4B;IACzC,wDAAwD;IACxD,WAAW,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,UAAU,KAAK,IAAI,CAAC;IAC3C,yEAAyE;IACzE,aAAa,EAAE,CAAC,CAAC,EAAE,KAAK,CAAC,aAAa,KAAK,IAAI,CAAC;IAChD,iFAAiF;IACjF,eAAe,CAAC,EAAE,KAAK,CAAC,iBAAiB,CAAC;IAC1C,yDAAyD;IACzD,SAAS,EAAE,MAAM,IAAI,CAAC;IACtB,gDAAgD;IAChD,QAAQ,EAAE,MAAM,IAAI,CAAC;IACrB,oDAAoD;IACpD,QAAQ,EAAE,MAAM,IAAI,CAAC;CACxB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AACH,wBAAgB,sBAAsB,CAAC,EACnC,KAAK,EACL,OAAO,EACP,aAAa,EACb,QAAgB,EAChB,OAAO,EAAE,WAAW,EACpB,WAAW,EAAE,eAAe,EAC5B,SAAS,EAAE,aAAa,GAC3B,EAAE,2BAA2B,GAAG,4BAA4B,CA+D5D"}
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
import { DiscreteParameter, DiscreteOption, MidiResolution } from '@cutoff/audio-ui-core';
|
|
3
|
+
|
|
4
|
+
export interface UseDiscreteParameterResolutionProps {
|
|
5
|
+
/** Child elements (OptionView components) for visual content mapping (Hybrid mode)
|
|
6
|
+
*
|
|
7
|
+
* **Visual Content Only**: Children provide ReactNodes for rendering (icons, text, custom components).
|
|
8
|
+
* They do NOT define the parameter model - use `options` prop or `parameter` prop for that.
|
|
9
|
+
*
|
|
10
|
+
* When both `options` and `children` are provided, children are matched to options by value
|
|
11
|
+
* to create the visual content map.
|
|
12
|
+
*/
|
|
13
|
+
children?: React.ReactNode;
|
|
14
|
+
/** Option definitions for the parameter model (Ad-Hoc mode)
|
|
15
|
+
*
|
|
16
|
+
* **Parameter Model Only**: This prop defines the parameter structure (value, label, midiValue).
|
|
17
|
+
* It does NOT provide visual content - use `children` (OptionView components) for that.
|
|
18
|
+
*
|
|
19
|
+
* When both `options` and `children` are provided:
|
|
20
|
+
* - `options` defines the parameter model
|
|
21
|
+
* - `children` provide visual content (matched by value)
|
|
22
|
+
*/
|
|
23
|
+
options?: DiscreteOption[];
|
|
24
|
+
/** Identifier for the parameter (used in Ad-Hoc mode) */
|
|
25
|
+
paramId?: string;
|
|
26
|
+
/** The parameter definition (Strict or Hybrid mode) */
|
|
27
|
+
parameter?: DiscreteParameter;
|
|
28
|
+
/** Default value (Ad-Hoc mode) or override for parameter default */
|
|
29
|
+
defaultValue?: string | number;
|
|
30
|
+
/** Label for the parameter (Ad-Hoc mode) */
|
|
31
|
+
label?: string;
|
|
32
|
+
/** MIDI resolution in bits (Ad-Hoc mode)
|
|
33
|
+
* @default 7
|
|
34
|
+
*/
|
|
35
|
+
midiResolution?: MidiResolution;
|
|
36
|
+
/** MIDI mapping strategy (Ad-Hoc mode)
|
|
37
|
+
* @default "spread"
|
|
38
|
+
*/
|
|
39
|
+
midiMapping?: "spread" | "sequential" | "custom";
|
|
40
|
+
}
|
|
41
|
+
export interface UseDiscreteParameterResolutionResult {
|
|
42
|
+
/** The resolved DiscreteParameter (derived from props or children) */
|
|
43
|
+
derivedParameter: DiscreteParameter;
|
|
44
|
+
/** Map of values to visual content (ReactNodes) from children */
|
|
45
|
+
visualContentMap: Map<string | number, React.ReactNode>;
|
|
46
|
+
/** The effective default value (resolved from parameter, prop, or first option) */
|
|
47
|
+
effectiveDefaultValue: string | number;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Hook to resolve a DiscreteParameter and visual content from props and/or children.
|
|
51
|
+
*
|
|
52
|
+
* **Important: Options vs Children**
|
|
53
|
+
*
|
|
54
|
+
* - **`options` prop**: Defines the parameter model (value, label, midiValue). Used for parameter structure.
|
|
55
|
+
* - **`children` (OptionView components)**: Provides visual content (ReactNodes) for rendering. Used for display.
|
|
56
|
+
*
|
|
57
|
+
* These serve different purposes and can be used together:
|
|
58
|
+
* - Use `options` when you have data-driven option definitions
|
|
59
|
+
* - Use `children` when you want to provide custom visual content (icons, styled text, etc.)
|
|
60
|
+
* - Use both: `options` for the model, `children` for visuals (matched by value)
|
|
61
|
+
*
|
|
62
|
+
* Supports four modes of operation:
|
|
63
|
+
* 1. **Ad-Hoc Mode (Options prop)**: Model from `options` prop, visual from `children` (if provided) or default rendering
|
|
64
|
+
* 2. **Ad-Hoc Mode (Children only)**: Model inferred from OptionView children, visual from children
|
|
65
|
+
* 3. **Strict Mode (Parameter only)**: Model from `parameter` prop, visual via `renderOption` callback
|
|
66
|
+
* 4. **Hybrid Mode (Parameter + Children)**: Model from `parameter` prop, visual from children (matched by value)
|
|
67
|
+
*
|
|
68
|
+
* @param props - Configuration object for discrete parameter resolution
|
|
69
|
+
* @param props.options - Option definitions for parameter model (Ad-Hoc mode). Takes precedence over children for model.
|
|
70
|
+
* @param props.children - Child elements (OptionView components) for visual content mapping (Hybrid/Ad-Hoc mode)
|
|
71
|
+
* @param props.paramId - Identifier for the parameter (used in Ad-Hoc mode)
|
|
72
|
+
* @param props.parameter - The parameter definition (Strict or Hybrid mode)
|
|
73
|
+
* @param props.defaultValue - Default value (Ad-Hoc mode) or override for parameter default
|
|
74
|
+
* @param props.label - Label for the parameter (Ad-Hoc mode)
|
|
75
|
+
* @param props.midiResolution - MIDI resolution in bits (Ad-Hoc mode, default: 7)
|
|
76
|
+
* @param props.midiMapping - MIDI mapping strategy (Ad-Hoc mode, default: "spread")
|
|
77
|
+
* @returns Object containing the resolved DiscreteParameter, visual content map, and effective default value
|
|
78
|
+
*
|
|
79
|
+
* @example
|
|
80
|
+
* ```tsx
|
|
81
|
+
* // Ad-Hoc Mode with options prop (data-driven)
|
|
82
|
+
* const { derivedParameter } = useDiscreteParameterResolution({
|
|
83
|
+
* options: [
|
|
84
|
+
* { value: "sine", label: "Sine Wave" },
|
|
85
|
+
* { value: "square", label: "Square Wave" }
|
|
86
|
+
* ],
|
|
87
|
+
* paramId: "waveform"
|
|
88
|
+
* });
|
|
89
|
+
*
|
|
90
|
+
* // Ad-Hoc Mode with children (visual content)
|
|
91
|
+
* const { derivedParameter, visualContentMap } = useDiscreteParameterResolution({
|
|
92
|
+
* children: [
|
|
93
|
+
* <OptionView value="sine"><SineIcon /></OptionView>,
|
|
94
|
+
* <OptionView value="square"><SquareIcon /></OptionView>
|
|
95
|
+
* ],
|
|
96
|
+
* paramId: "waveform"
|
|
97
|
+
* });
|
|
98
|
+
*
|
|
99
|
+
* // Hybrid: options for model, children for visuals
|
|
100
|
+
* const { derivedParameter, visualContentMap } = useDiscreteParameterResolution({
|
|
101
|
+
* options: [
|
|
102
|
+
* { value: "sine", label: "Sine Wave", midiValue: 0 },
|
|
103
|
+
* { value: "square", label: "Square Wave", midiValue: 1 }
|
|
104
|
+
* ],
|
|
105
|
+
* children: [
|
|
106
|
+
* <OptionView value="sine"><SineIcon /></OptionView>,
|
|
107
|
+
* <OptionView value="square"><SquareIcon /></OptionView>
|
|
108
|
+
* ],
|
|
109
|
+
* paramId: "waveform"
|
|
110
|
+
* });
|
|
111
|
+
*
|
|
112
|
+
* // Strict Mode
|
|
113
|
+
* const result = useDiscreteParameterResolution({
|
|
114
|
+
* parameter: myDiscreteParameter,
|
|
115
|
+
* defaultValue: "custom"
|
|
116
|
+
* });
|
|
117
|
+
* ```
|
|
118
|
+
*/
|
|
119
|
+
export declare function useDiscreteParameterResolution({ children, options, paramId, parameter, defaultValue, label, midiResolution, midiMapping, }: UseDiscreteParameterResolutionProps): UseDiscreteParameterResolutionResult;
|
|
120
|
+
//# sourceMappingURL=useDiscreteParameterResolution.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useDiscreteParameterResolution.d.ts","sourceRoot":"","sources":["../../src/hooks/useDiscreteParameterResolution.ts"],"names":[],"mappings":"AAMA,OAAO,KAAkB,MAAM,OAAO,CAAC;AACvC,OAAO,EAAE,iBAAiB,EAAE,cAAc,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AAG1F,MAAM,WAAW,mCAAmC;IAChD;;;;;;;OAOG;IACH,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;IAC3B;;;;;;;;OAQG;IACH,OAAO,CAAC,EAAE,cAAc,EAAE,CAAC;IAC3B,yDAAyD;IACzD,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,uDAAuD;IACvD,SAAS,CAAC,EAAE,iBAAiB,CAAC;IAC9B,oEAAoE;IACpE,YAAY,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC/B,4CAA4C;IAC5C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf;;OAEG;IACH,cAAc,CAAC,EAAE,cAAc,CAAC;IAChC;;OAEG;IACH,WAAW,CAAC,EAAE,QAAQ,GAAG,YAAY,GAAG,QAAQ,CAAC;CACpD;AAED,MAAM,WAAW,oCAAoC;IACjD,sEAAsE;IACtE,gBAAgB,EAAE,iBAAiB,CAAC;IACpC,iEAAiE;IACjE,gBAAgB,EAAE,GAAG,CAAC,MAAM,GAAG,MAAM,EAAE,KAAK,CAAC,SAAS,CAAC,CAAC;IACxD,mFAAmF;IACnF,qBAAqB,EAAE,MAAM,GAAG,MAAM,CAAC;CAC1C;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAqEG;AACH,wBAAgB,8BAA8B,CAAC,EAC3C,QAAQ,EACR,OAAO,EACP,OAAO,EACP,SAAS,EACT,YAAY,EACZ,KAAK,EACL,cAAkB,EAClB,WAAsB,GACzB,EAAE,mCAAmC,GAAG,oCAAoC,CAiF5E"}
|
|
@@ -0,0 +1,84 @@
|
|
|
1
|
+
import { default as React } from 'react';
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Props for the useNoteInteraction hook.
|
|
5
|
+
*/
|
|
6
|
+
export interface UseNoteInteractionProps {
|
|
7
|
+
/** Callback triggered when a note is pressed */
|
|
8
|
+
onNoteOn: (note: number) => void;
|
|
9
|
+
/** Callback triggered when a note is released */
|
|
10
|
+
onNoteOff: (note: number) => void;
|
|
11
|
+
/** Whether the interaction is disabled */
|
|
12
|
+
disabled?: boolean;
|
|
13
|
+
/** Optional user-provided pointer down handler */
|
|
14
|
+
onPointerDown?: React.PointerEventHandler;
|
|
15
|
+
/** Optional user-provided pointer move handler */
|
|
16
|
+
onPointerMove?: React.PointerEventHandler;
|
|
17
|
+
/** Optional user-provided pointer up handler */
|
|
18
|
+
onPointerUp?: React.PointerEventHandler;
|
|
19
|
+
/** Optional user-provided pointer cancel handler */
|
|
20
|
+
onPointerCancel?: React.PointerEventHandler;
|
|
21
|
+
}
|
|
22
|
+
/**
|
|
23
|
+
* Result object for the useNoteInteraction hook.
|
|
24
|
+
*/
|
|
25
|
+
export interface UseNoteInteractionResult {
|
|
26
|
+
/** Pointer down handler to be attached to the target element */
|
|
27
|
+
onPointerDown: React.PointerEventHandler;
|
|
28
|
+
/** Pointer move handler to be attached to the target element */
|
|
29
|
+
onPointerMove: React.PointerEventHandler;
|
|
30
|
+
/** Pointer up handler to be attached to the target element */
|
|
31
|
+
onPointerUp: React.PointerEventHandler;
|
|
32
|
+
/** Pointer cancel handler to be attached to the target element */
|
|
33
|
+
onPointerCancel: React.PointerEventHandler;
|
|
34
|
+
/** Standardized styles for the interactive element (e.g., touchAction: "none") */
|
|
35
|
+
style: React.CSSProperties;
|
|
36
|
+
}
|
|
37
|
+
/**
|
|
38
|
+
* Hook to manage note interactions for keyboard-like components.
|
|
39
|
+
*
|
|
40
|
+
* Provides standardized logic for:
|
|
41
|
+
* - Multi-touch support via PointerEvents
|
|
42
|
+
* - Glissando (sliding across keys) detection
|
|
43
|
+
* - Standardized note on/off event triggering
|
|
44
|
+
*
|
|
45
|
+
* It uses the framework-agnostic `NoteInteractionController` to handle the
|
|
46
|
+
* core interaction logic and manages pointer capture for reliable glissando.
|
|
47
|
+
*
|
|
48
|
+
* The hook returns pointer event handlers and a style object containing
|
|
49
|
+
* `touchAction: "none"` to prevent default touch behaviors. Cursor styling
|
|
50
|
+
* is handled by the consuming component based on its interactivity state.
|
|
51
|
+
*
|
|
52
|
+
* @param {UseNoteInteractionProps} props - Configuration for the note interaction hook
|
|
53
|
+
* @param {(note: number) => void} props.onNoteOn - Callback triggered when a note is pressed
|
|
54
|
+
* @param {(note: number) => void} props.onNoteOff - Callback triggered when a note is released
|
|
55
|
+
* @param {boolean} [props.disabled=false] - Whether the interaction is disabled
|
|
56
|
+
* @param {React.PointerEventHandler} [props.onPointerDown] - Optional user-provided pointer down handler
|
|
57
|
+
* @param {React.PointerEventHandler} [props.onPointerMove] - Optional user-provided pointer move handler
|
|
58
|
+
* @param {React.PointerEventHandler} [props.onPointerUp] - Optional user-provided pointer up handler
|
|
59
|
+
* @param {React.PointerEventHandler} [props.onPointerCancel] - Optional user-provided pointer cancel handler
|
|
60
|
+
* @returns {UseNoteInteractionResult} Object containing pointer event handlers and styles
|
|
61
|
+
*
|
|
62
|
+
* @example
|
|
63
|
+
* ```tsx
|
|
64
|
+
* const { onPointerDown, onPointerMove, onPointerUp, style } = useNoteInteraction({
|
|
65
|
+
* onNoteOn: (note) => synth.noteOn(note),
|
|
66
|
+
* onNoteOff: (note) => synth.noteOff(note)
|
|
67
|
+
* });
|
|
68
|
+
*
|
|
69
|
+
* return (
|
|
70
|
+
* <svg
|
|
71
|
+
* onPointerDown={onPointerDown}
|
|
72
|
+
* onPointerMove={onPointerMove}
|
|
73
|
+
* onPointerUp={onPointerUp}
|
|
74
|
+
* style={style}
|
|
75
|
+
* >
|
|
76
|
+
* {keys.map(key => (
|
|
77
|
+
* <rect key={key.note} data-note={key.note} {...key.rectProps} />
|
|
78
|
+
* ))}
|
|
79
|
+
* </svg>
|
|
80
|
+
* );
|
|
81
|
+
* ```
|
|
82
|
+
*/
|
|
83
|
+
export declare function useNoteInteraction({ onNoteOn, onNoteOff, disabled, onPointerDown: userOnPointerDown, onPointerMove: userOnPointerMove, onPointerUp: userOnPointerUp, onPointerCancel: userOnPointerCancel, }: UseNoteInteractionProps): UseNoteInteractionResult;
|
|
84
|
+
//# sourceMappingURL=useNoteInteraction.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"useNoteInteraction.d.ts","sourceRoot":"","sources":["../../src/hooks/useNoteInteraction.ts"],"names":[],"mappings":"AAMA,OAAO,KAAyC,MAAM,OAAO,CAAC;AAG9D;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACpC,gDAAgD;IAChD,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IACjC,iDAAiD;IACjD,SAAS,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,0CAA0C;IAC1C,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,kDAAkD;IAClD,aAAa,CAAC,EAAE,KAAK,CAAC,mBAAmB,CAAC;IAC1C,kDAAkD;IAClD,aAAa,CAAC,EAAE,KAAK,CAAC,mBAAmB,CAAC;IAC1C,gDAAgD;IAChD,WAAW,CAAC,EAAE,KAAK,CAAC,mBAAmB,CAAC;IACxC,oDAAoD;IACpD,eAAe,CAAC,EAAE,KAAK,CAAC,mBAAmB,CAAC;CAC/C;AAED;;GAEG;AACH,MAAM,WAAW,wBAAwB;IACrC,gEAAgE;IAChE,aAAa,EAAE,KAAK,CAAC,mBAAmB,CAAC;IACzC,gEAAgE;IAChE,aAAa,EAAE,KAAK,CAAC,mBAAmB,CAAC;IACzC,8DAA8D;IAC9D,WAAW,EAAE,KAAK,CAAC,mBAAmB,CAAC;IACvC,kEAAkE;IAClE,eAAe,EAAE,KAAK,CAAC,mBAAmB,CAAC;IAC3C,kFAAkF;IAClF,KAAK,EAAE,KAAK,CAAC,aAAa,CAAC;CAC9B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6CG;AACH,wBAAgB,kBAAkB,CAAC,EAC/B,QAAQ,EACR,SAAS,EACT,QAAgB,EAChB,aAAa,EAAE,iBAAiB,EAChC,aAAa,EAAE,iBAAiB,EAChC,WAAW,EAAE,eAAe,EAC5B,eAAe,EAAE,mBAAmB,GACvC,EAAE,uBAAuB,GAAG,wBAAwB,CA0FpD"}
|