@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.
Files changed (107) hide show
  1. package/LICENSE.md +690 -0
  2. package/README.md +228 -0
  3. package/dist/components/defaults/controls/Button.d.ts +51 -0
  4. package/dist/components/defaults/controls/Button.d.ts.map +1 -0
  5. package/dist/components/defaults/controls/ButtonView.d.ts +20 -0
  6. package/dist/components/defaults/controls/ButtonView.d.ts.map +1 -0
  7. package/dist/components/defaults/controls/CycleButton.d.ts +82 -0
  8. package/dist/components/defaults/controls/CycleButton.d.ts.map +1 -0
  9. package/dist/components/defaults/controls/Knob.d.ts +82 -0
  10. package/dist/components/defaults/controls/Knob.d.ts.map +1 -0
  11. package/dist/components/defaults/controls/KnobView.d.ts +43 -0
  12. package/dist/components/defaults/controls/KnobView.d.ts.map +1 -0
  13. package/dist/components/defaults/controls/Slider.d.ts +79 -0
  14. package/dist/components/defaults/controls/Slider.d.ts.map +1 -0
  15. package/dist/components/defaults/controls/SliderView.d.ts +90 -0
  16. package/dist/components/defaults/controls/SliderView.d.ts.map +1 -0
  17. package/dist/components/defaults/devices/Keys.d.ts +104 -0
  18. package/dist/components/defaults/devices/Keys.d.ts.map +1 -0
  19. package/dist/components/generic/controls/FilmStripBooleanControl.d.ts +58 -0
  20. package/dist/components/generic/controls/FilmStripBooleanControl.d.ts.map +1 -0
  21. package/dist/components/generic/controls/FilmStripContinuousControl.d.ts +82 -0
  22. package/dist/components/generic/controls/FilmStripContinuousControl.d.ts.map +1 -0
  23. package/dist/components/generic/controls/FilmStripDiscreteControl.d.ts +55 -0
  24. package/dist/components/generic/controls/FilmStripDiscreteControl.d.ts.map +1 -0
  25. package/dist/components/generic/controls/FilmstripView.d.ts +36 -0
  26. package/dist/components/generic/controls/FilmstripView.d.ts.map +1 -0
  27. package/dist/components/generic/controls/ImageKnob.d.ts +74 -0
  28. package/dist/components/generic/controls/ImageKnob.d.ts.map +1 -0
  29. package/dist/components/generic/controls/ImageKnobView.d.ts +38 -0
  30. package/dist/components/generic/controls/ImageKnobView.d.ts.map +1 -0
  31. package/dist/components/generic/controls/ImageRotarySwitch.d.ts +54 -0
  32. package/dist/components/generic/controls/ImageRotarySwitch.d.ts.map +1 -0
  33. package/dist/components/generic/controls/ImageSwitch.d.ts +62 -0
  34. package/dist/components/generic/controls/ImageSwitch.d.ts.map +1 -0
  35. package/dist/components/generic/controls/ImageSwitchView.d.ts +26 -0
  36. package/dist/components/generic/controls/ImageSwitchView.d.ts.map +1 -0
  37. package/dist/components/primitives/AdaptiveBox.d.ts +127 -0
  38. package/dist/components/primitives/AdaptiveBox.d.ts.map +1 -0
  39. package/dist/components/primitives/controls/BooleanControl.d.ts +66 -0
  40. package/dist/components/primitives/controls/BooleanControl.d.ts.map +1 -0
  41. package/dist/components/primitives/controls/ContinuousControl.d.ts +46 -0
  42. package/dist/components/primitives/controls/ContinuousControl.d.ts.map +1 -0
  43. package/dist/components/primitives/controls/DiscreteControl.d.ts +70 -0
  44. package/dist/components/primitives/controls/DiscreteControl.d.ts.map +1 -0
  45. package/dist/components/primitives/controls/OptionView.d.ts +12 -0
  46. package/dist/components/primitives/controls/OptionView.d.ts.map +1 -0
  47. package/dist/components/primitives/svg/FilmstripImage.d.ts +60 -0
  48. package/dist/components/primitives/svg/FilmstripImage.d.ts.map +1 -0
  49. package/dist/components/primitives/svg/Image.d.ts +50 -0
  50. package/dist/components/primitives/svg/Image.d.ts.map +1 -0
  51. package/dist/components/primitives/svg/LabelRing.d.ts +42 -0
  52. package/dist/components/primitives/svg/LabelRing.d.ts.map +1 -0
  53. package/dist/components/primitives/svg/LinearCursor.d.ts +72 -0
  54. package/dist/components/primitives/svg/LinearCursor.d.ts.map +1 -0
  55. package/dist/components/primitives/svg/LinearStrip.d.ts +49 -0
  56. package/dist/components/primitives/svg/LinearStrip.d.ts.map +1 -0
  57. package/dist/components/primitives/svg/RadialHtmlOverlay.d.ts +29 -0
  58. package/dist/components/primitives/svg/RadialHtmlOverlay.d.ts.map +1 -0
  59. package/dist/components/primitives/svg/RadialImage.d.ts +36 -0
  60. package/dist/components/primitives/svg/RadialImage.d.ts.map +1 -0
  61. package/dist/components/primitives/svg/RevealingPath.d.ts +37 -0
  62. package/dist/components/primitives/svg/RevealingPath.d.ts.map +1 -0
  63. package/dist/components/primitives/svg/RingArc.d.ts +21 -0
  64. package/dist/components/primitives/svg/RingArc.d.ts.map +1 -0
  65. package/dist/components/primitives/svg/RotaryImage.d.ts +43 -0
  66. package/dist/components/primitives/svg/RotaryImage.d.ts.map +1 -0
  67. package/dist/components/primitives/svg/TickRing.d.ts +53 -0
  68. package/dist/components/primitives/svg/TickRing.d.ts.map +1 -0
  69. package/dist/components/primitives/svg/ValueRing.d.ts +38 -0
  70. package/dist/components/primitives/svg/ValueRing.d.ts.map +1 -0
  71. package/dist/components/primitives/svg/ValueStrip.d.ts +59 -0
  72. package/dist/components/primitives/svg/ValueStrip.d.ts.map +1 -0
  73. package/dist/components/types.d.ts +451 -0
  74. package/dist/components/types.d.ts.map +1 -0
  75. package/dist/hooks/useAdaptiveSize.d.ts +32 -0
  76. package/dist/hooks/useAdaptiveSize.d.ts.map +1 -0
  77. package/dist/hooks/useArcAngle.d.ts +23 -0
  78. package/dist/hooks/useArcAngle.d.ts.map +1 -0
  79. package/dist/hooks/useAudioParameter.d.ts +89 -0
  80. package/dist/hooks/useAudioParameter.d.ts.map +1 -0
  81. package/dist/hooks/useBooleanInteraction.d.ts +106 -0
  82. package/dist/hooks/useBooleanInteraction.d.ts.map +1 -0
  83. package/dist/hooks/useBooleanParameterResolution.d.ts +54 -0
  84. package/dist/hooks/useBooleanParameterResolution.d.ts.map +1 -0
  85. package/dist/hooks/useContinuousInteraction.d.ts +94 -0
  86. package/dist/hooks/useContinuousInteraction.d.ts.map +1 -0
  87. package/dist/hooks/useContinuousParameterResolution.d.ts +75 -0
  88. package/dist/hooks/useContinuousParameterResolution.d.ts.map +1 -0
  89. package/dist/hooks/useDiscreteInteraction.d.ts +70 -0
  90. package/dist/hooks/useDiscreteInteraction.d.ts.map +1 -0
  91. package/dist/hooks/useDiscreteParameterResolution.d.ts +120 -0
  92. package/dist/hooks/useDiscreteParameterResolution.d.ts.map +1 -0
  93. package/dist/hooks/useNoteInteraction.d.ts +84 -0
  94. package/dist/hooks/useNoteInteraction.d.ts.map +1 -0
  95. package/dist/hooks/useThemableProps.d.ts +68 -0
  96. package/dist/hooks/useThemableProps.d.ts.map +1 -0
  97. package/dist/index.d.ts +77 -0
  98. package/dist/index.d.ts.map +1 -0
  99. package/dist/index.js +3197 -0
  100. package/dist/index.js.map +1 -0
  101. package/dist/stats.html +4949 -0
  102. package/dist/style.css +1 -0
  103. package/dist/utils/textUtils.d.ts +15 -0
  104. package/dist/utils/textUtils.d.ts.map +1 -0
  105. package/dist/utils/theme.d.ts +88 -0
  106. package/dist/utils/theme.d.ts.map +1 -0
  107. 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"}