@cutoff/audio-ui-core 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 (48) hide show
  1. package/LICENSE.md +690 -0
  2. package/dist/constants/cssVars.d.ts +42 -0
  3. package/dist/constants/cssVars.d.ts.map +1 -0
  4. package/dist/constants/cursors.d.ts +2 -0
  5. package/dist/constants/cursors.d.ts.map +1 -0
  6. package/dist/constants/interaction.d.ts +24 -0
  7. package/dist/constants/interaction.d.ts.map +1 -0
  8. package/dist/constants/styles.d.ts +17 -0
  9. package/dist/constants/styles.d.ts.map +1 -0
  10. package/dist/constants/theme.d.ts +66 -0
  11. package/dist/constants/theme.d.ts.map +1 -0
  12. package/dist/constants/themeDefaults.d.ts +16 -0
  13. package/dist/constants/themeDefaults.d.ts.map +1 -0
  14. package/dist/controller/BooleanInteractionController.d.ts +141 -0
  15. package/dist/controller/BooleanInteractionController.d.ts.map +1 -0
  16. package/dist/controller/ContinuousInteractionController.d.ts +114 -0
  17. package/dist/controller/ContinuousInteractionController.d.ts.map +1 -0
  18. package/dist/controller/DiscreteInteractionController.d.ts +51 -0
  19. package/dist/controller/DiscreteInteractionController.d.ts.map +1 -0
  20. package/dist/controller/NoteInteractionController.d.ts +88 -0
  21. package/dist/controller/NoteInteractionController.d.ts.map +1 -0
  22. package/dist/index.d.ts +21 -0
  23. package/dist/index.d.ts.map +1 -0
  24. package/dist/index.js +1404 -0
  25. package/dist/index.js.map +1 -0
  26. package/dist/model/AudioParameter.d.ts +437 -0
  27. package/dist/model/AudioParameter.d.ts.map +1 -0
  28. package/dist/styles/styles.css +256 -0
  29. package/dist/styles/themes.css +193 -0
  30. package/dist/types.d.ts +18 -0
  31. package/dist/types.d.ts.map +1 -0
  32. package/dist/utils/colorUtils.d.ts +102 -0
  33. package/dist/utils/colorUtils.d.ts.map +1 -0
  34. package/dist/utils/math.d.ts +108 -0
  35. package/dist/utils/math.d.ts.map +1 -0
  36. package/dist/utils/normalizedProps.d.ts +22 -0
  37. package/dist/utils/normalizedProps.d.ts.map +1 -0
  38. package/dist/utils/noteUtils.d.ts +71 -0
  39. package/dist/utils/noteUtils.d.ts.map +1 -0
  40. package/dist/utils/propCompare.d.ts +22 -0
  41. package/dist/utils/propCompare.d.ts.map +1 -0
  42. package/dist/utils/sizing.d.ts +39 -0
  43. package/dist/utils/sizing.d.ts.map +1 -0
  44. package/dist/utils/svg.d.ts +27 -0
  45. package/dist/utils/svg.d.ts.map +1 -0
  46. package/dist/utils/valueFormatters.d.ts +167 -0
  47. package/dist/utils/valueFormatters.d.ts.map +1 -0
  48. package/package.json +48 -0
@@ -0,0 +1,437 @@
1
+ import { MidiResolution } from '../types';
2
+
3
+ export type AudioParameterType = "continuous" | "boolean" | "discrete";
4
+ /**
5
+ * A scale function that transforms normalized values (0..1) to scaled values (0..1)
6
+ * Both forward and inverse must be provided for bidirectional conversion.
7
+ *
8
+ * The scale is applied in the normalized domain (0..1) to create non-linear mappings
9
+ * between the real value domain and the normalized/MIDI domain.
10
+ */
11
+ export interface ScaleFunction {
12
+ /**
13
+ * Transform normalized value (0..1) to scaled value (0..1)
14
+ * Used when converting Real -> Normalized (in _normalizeReal)
15
+ *
16
+ * @param normalized - A value in the range [0, 1] representing position in real domain
17
+ * @returns A scaled value in the range [0, 1] for MIDI quantization
18
+ */
19
+ forward: (normalized: number) => number;
20
+ /**
21
+ * Transform scaled value (0..1) back to normalized value (0..1)
22
+ * Used when converting Normalized -> Real (in _denormalizeReal)
23
+ *
24
+ * @param scaled - A value in the range [0, 1] from MIDI domain
25
+ * @returns A normalized value in the range [0, 1] for real domain conversion
26
+ */
27
+ inverse: (scaled: number) => number;
28
+ /**
29
+ * Optional name for debugging/documentation
30
+ */
31
+ name?: string;
32
+ }
33
+ /**
34
+ * Predefined scale functions for common audio parameter transformations
35
+ */
36
+ export declare const LinearScale: ScaleFunction;
37
+ export declare const LogScale: ScaleFunction;
38
+ export declare const ExpScale: ScaleFunction;
39
+ export type ScaleType = ScaleFunction | "linear" | "log" | "exp";
40
+ /**
41
+ * Definition for a single option in a discrete parameter.
42
+ *
43
+ * This type represents the parameter model definition (value, label, MIDI mapping).
44
+ * It is separate from visual content, which is provided via React children in components.
45
+ */
46
+ export interface DiscreteOption {
47
+ /** The value associated with this option */
48
+ value: number | string;
49
+ /** The label for this option (used for display, accessibility, and parameter model) */
50
+ label: string;
51
+ /** Optional explicit MIDI value for custom mapping strategy */
52
+ midiValue?: number;
53
+ }
54
+ interface BaseAudioParameter<T = number | boolean | string> {
55
+ id: string;
56
+ name: string;
57
+ type: AudioParameterType;
58
+ midiResolution?: MidiResolution;
59
+ /** Default value for the parameter */
60
+ defaultValue?: T;
61
+ }
62
+ export interface ContinuousParameter extends BaseAudioParameter<number> {
63
+ type: "continuous";
64
+ min: number;
65
+ max: number;
66
+ step?: number;
67
+ unit?: string;
68
+ scale?: ScaleType;
69
+ /** Whether the parameter operates in bipolar mode (centered around zero) */
70
+ bipolar?: boolean;
71
+ }
72
+ export interface BooleanParameter extends BaseAudioParameter<boolean> {
73
+ type: "boolean";
74
+ mode?: "toggle" | "momentary";
75
+ trueLabel?: string;
76
+ falseLabel?: string;
77
+ }
78
+ export interface DiscreteParameter extends BaseAudioParameter<number | string> {
79
+ type: "discrete";
80
+ /** Array of option definitions (parameter model) */
81
+ options: DiscreteOption[];
82
+ midiMapping?: "spread" | "sequential" | "custom";
83
+ }
84
+ export type AudioParameter = ContinuousParameter | BooleanParameter | DiscreteParameter;
85
+ /**
86
+ * Implementation class that handles normalization, denormalization, and MIDI conversion.
87
+ *
88
+ * ARCHITECTURE NOTE:
89
+ * This class uses the MIDI Integer Value as the central "Pivot" / Source of Truth.
90
+ *
91
+ * Flow:
92
+ * Real Value -> [Quantize] -> MIDI Integer -> [Normalize] -> Normalized Float (0..1)
93
+ * Normalized Float -> [Scale] -> MIDI Integer -> [Convert] -> Real Value
94
+ *
95
+ * This ensures deterministic behavior and alignment with hardware standards.
96
+ */
97
+ export declare class AudioParameterConverter {
98
+ config: AudioParameter;
99
+ private maxMidi;
100
+ private scaleFunction;
101
+ constructor(config: AudioParameter);
102
+ private resolveScale;
103
+ /**
104
+ * [Internal] Pure math normalization from Real to 0..1.
105
+ *
106
+ * This is the first step in the conversion pipeline. It normalizes the real value
107
+ * to 0..1 in the real domain, then applies scale transformation (if not linear).
108
+ * The scale transformation happens in the normalized domain to create non-linear
109
+ * mappings (e.g., logarithmic for volume, exponential for envelope curves).
110
+ */
111
+ private _normalizeReal;
112
+ /**
113
+ * [Internal] Pure math denormalization from 0..1 to Real.
114
+ *
115
+ * This is the inverse of `_normalizeReal()`. It first applies the inverse scale
116
+ * transformation (if not linear), then denormalizes to the real value domain.
117
+ * Finally, it applies step quantization in the real domain (step is always linear,
118
+ * regardless of scale type).
119
+ */
120
+ private _denormalizeReal;
121
+ /**
122
+ * Convert Real Value to MIDI Integer (The Pivot).
123
+ *
124
+ * This is the central conversion method that quantizes real-world values to MIDI integers.
125
+ * The MIDI integer serves as the source of truth, ensuring deterministic behavior and
126
+ * alignment with hardware standards.
127
+ *
128
+ * The conversion flow:
129
+ * 1. Normalize the real value to 0..1 (applying scale transformation if needed)
130
+ * 2. Quantize to the configured MIDI resolution (7-bit = 0-127, 14-bit = 0-16383, etc.)
131
+ *
132
+ * @param realValue The real-world value (number, boolean, or string depending on parameter type)
133
+ * @returns The quantized MIDI integer value
134
+ *
135
+ * @example
136
+ * ```ts
137
+ * const converter = new AudioParameterConverter({
138
+ * type: "continuous",
139
+ * min: 0,
140
+ * max: 100,
141
+ * midiResolution: 7
142
+ * });
143
+ * converter.toMidi(50); // 64 (50% of 0-100 maps to 64 in 0-127 range)
144
+ * ```
145
+ */
146
+ toMidi(realValue: number | boolean | string): number;
147
+ /**
148
+ * Convert MIDI Integer to Real Value.
149
+ *
150
+ * This method performs the inverse of `toMidi()`, converting a quantized MIDI integer
151
+ * back to a real-world value. The conversion flow:
152
+ * 1. Normalize the MIDI integer to 0..1
153
+ * 2. Apply inverse scale transformation (if not linear)
154
+ * 3. Denormalize to the real value domain
155
+ * 4. Apply step quantization (if configured)
156
+ *
157
+ * @param midiValue The MIDI integer value (will be clamped to valid range)
158
+ * @returns The real-world value (number, boolean, or string depending on parameter type)
159
+ *
160
+ * @example
161
+ * ```ts
162
+ * const converter = new AudioParameterConverter({
163
+ * type: "continuous",
164
+ * min: 0,
165
+ * max: 100,
166
+ * step: 1,
167
+ * midiResolution: 7
168
+ * });
169
+ * converter.fromMidi(64); // 50 (64/127 ≈ 0.5, maps to 50 in 0-100 range)
170
+ * ```
171
+ */
172
+ fromMidi(midiValue: number): number | boolean | string;
173
+ normalize(realValue: number | boolean | string): number;
174
+ denormalize(normalized: number): number | boolean | string;
175
+ /**
176
+ * Format a value for display as a string.
177
+ *
178
+ * This method generates a human-readable string representation of the value,
179
+ * including appropriate units and precision based on the parameter configuration.
180
+ *
181
+ * - Continuous parameters: Includes unit suffix and precision based on step size
182
+ * - Boolean parameters: Uses trueLabel/falseLabel or defaults to "On"/"Off"
183
+ * - Discrete parameters: Returns the label of the matching option
184
+ *
185
+ * @param value The value to format (number, boolean, or string)
186
+ * @returns Formatted string representation
187
+ *
188
+ * @example
189
+ * ```ts
190
+ * const converter = new AudioParameterConverter({
191
+ * type: "continuous",
192
+ * min: 0,
193
+ * max: 100,
194
+ * step: 0.1,
195
+ * unit: "dB"
196
+ * });
197
+ * converter.format(50.5); // "50.5 dB"
198
+ *
199
+ * const boolConverter = new AudioParameterConverter({
200
+ * type: "boolean",
201
+ * trueLabel: "Enabled",
202
+ * falseLabel: "Disabled"
203
+ * });
204
+ * boolConverter.format(true); // "Enabled"
205
+ * ```
206
+ */
207
+ format(value: number | boolean | string): string;
208
+ /**
209
+ * Get the maximum display text for sizing purposes.
210
+ * Returns the longest formatted string among all possible values.
211
+ * Useful for RadialText referenceText prop to ensure consistent sizing.
212
+ *
213
+ * @param options - Optional configuration
214
+ * @param options.includeUnit - Whether to include the unit in the result (default: true).
215
+ * Set to false when displaying value and unit on separate lines.
216
+ * @returns The longest formatted display string
217
+ *
218
+ * @example
219
+ * ```ts
220
+ * const converter = new AudioParameterConverter(volumeParam);
221
+ * // Single line with unit
222
+ * <RadialText text={currentValue} referenceText={converter.getMaxDisplayText()} />
223
+ *
224
+ * // Multiline: value on first line, unit on second
225
+ * <RadialText
226
+ * text={[formattedValue, unit]}
227
+ * referenceText={[converter.getMaxDisplayText({ includeUnit: false }), unit]}
228
+ * />
229
+ * ```
230
+ */
231
+ getMaxDisplayText(options?: {
232
+ includeUnit?: boolean;
233
+ }): string;
234
+ }
235
+ /**
236
+ * Configuration for creating a generic continuous control parameter (for knobs, sliders, etc.).
237
+ */
238
+ export interface ContinuousControlConfig {
239
+ id?: string;
240
+ name?: string;
241
+ label?: string;
242
+ min?: number;
243
+ max?: number;
244
+ step?: number;
245
+ bipolar?: boolean;
246
+ unit?: string;
247
+ defaultValue?: number;
248
+ scale?: ScaleType;
249
+ midiResolution?: MidiResolution;
250
+ }
251
+ /**
252
+ * Factory for common AudioParameter configurations (including MIDI-flavoured presets).
253
+ *
254
+ * This factory provides convenient methods for creating standard parameter configurations
255
+ * that match common MIDI and audio industry conventions. All factory methods generate
256
+ * parameter IDs automatically from the name.
257
+ */
258
+ export declare const AudioParameterFactory: {
259
+ /**
260
+ * Creates a standard 7-bit MIDI CC parameter (0-127).
261
+ *
262
+ * This is the most common MIDI control change format, used for most hardware controllers
263
+ * and software synthesizers. The parameter uses 7-bit resolution (128 steps).
264
+ *
265
+ * @param name The parameter name (used to generate ID and name fields)
266
+ * @returns A ContinuousParameter configured for 7-bit MIDI CC
267
+ *
268
+ * @example
269
+ * ```ts
270
+ * const volumeParam = AudioParameterFactory.createMidiStandard7Bit("Volume");
271
+ * // { type: "continuous", min: 0, max: 127, step: 1, midiResolution: 7, ... }
272
+ * ```
273
+ */
274
+ createMidiStandard7Bit: (name: string) => ContinuousParameter;
275
+ /**
276
+ * Creates a standard 14-bit MIDI CC parameter (0-16383).
277
+ *
278
+ * This provides higher resolution than 7-bit CC, useful for parameters that require
279
+ * fine-grained control. The parameter uses 14-bit resolution (16,384 steps).
280
+ *
281
+ * @param name The parameter name (used to generate ID and name fields)
282
+ * @returns A ContinuousParameter configured for 14-bit MIDI CC
283
+ *
284
+ * @example
285
+ * ```ts
286
+ * const fineTuneParam = AudioParameterFactory.createMidiStandard14Bit("Fine Tune");
287
+ * // { type: "continuous", min: 0, max: 16383, step: 1, midiResolution: 14, ... }
288
+ * ```
289
+ */
290
+ createMidiStandard14Bit: (name: string) => ContinuousParameter;
291
+ /**
292
+ * Creates a bipolar 7-bit MIDI CC parameter (-64 to 63, centered at 0).
293
+ *
294
+ * This is useful for parameters that have a center point, such as pan controls or
295
+ * modulation depth. The range is symmetric around zero, with 64 steps in each direction.
296
+ *
297
+ * @param name The parameter name (used to generate ID and name fields)
298
+ * @returns A ContinuousParameter configured for bipolar 7-bit MIDI CC
299
+ *
300
+ * @example
301
+ * ```ts
302
+ * const panParam = AudioParameterFactory.createMidiBipolar7Bit("Pan");
303
+ * // { type: "continuous", min: -64, max: 63, step: 1, defaultValue: 0, ... }
304
+ * ```
305
+ */
306
+ createMidiBipolar7Bit: (name: string) => ContinuousParameter;
307
+ /**
308
+ * Creates a bipolar 14-bit MIDI CC parameter (-8192 to 8191, centered at 0).
309
+ *
310
+ * This provides high-resolution bipolar control, useful for parameters that require
311
+ * fine-grained adjustment around a center point. The range is symmetric around zero,
312
+ * with 8,192 steps in each direction.
313
+ *
314
+ * @param name The parameter name (used to generate ID and name fields)
315
+ * @returns A ContinuousParameter configured for bipolar 14-bit MIDI CC
316
+ *
317
+ * @example
318
+ * ```ts
319
+ * const finePanParam = AudioParameterFactory.createMidiBipolar14Bit("Fine Pan");
320
+ * // { type: "continuous", min: -8192, max: 8191, step: 1, defaultValue: 0, ... }
321
+ * ```
322
+ */
323
+ createMidiBipolar14Bit: (name: string) => ContinuousParameter;
324
+ /**
325
+ * Creates a bipolar parameter with custom range (centered at 0).
326
+ *
327
+ * This is a flexible factory method for creating bipolar parameters with any range.
328
+ * The parameter is symmetric around zero, useful for pan controls, modulation depth,
329
+ * or any parameter that has a neutral center point.
330
+ *
331
+ * @param name The parameter name (used to generate ID and name fields)
332
+ * @param range The range value (default: 100). The parameter will span from -range to +range
333
+ * @param unit Optional unit suffix (e.g., "dB", "%")
334
+ * @returns A ContinuousParameter configured for bipolar control
335
+ *
336
+ * @example
337
+ * ```ts
338
+ * const panParam = AudioParameterFactory.createBipolar("Pan", 100, "%");
339
+ * // { type: "continuous", min: -100, max: 100, step: 1, defaultValue: 0, unit: "%", ... }
340
+ *
341
+ * const modDepthParam = AudioParameterFactory.createBipolar("Mod Depth", 50);
342
+ * // { type: "continuous", min: -50, max: 50, step: 1, defaultValue: 0, ... }
343
+ * ```
344
+ */
345
+ createBipolar: (name: string, range?: number, unit?: string) => ContinuousParameter;
346
+ /**
347
+ * Creates a boolean switch parameter (Off/On).
348
+ *
349
+ * This factory method creates a boolean parameter suitable for on/off controls,
350
+ * with support for both toggle (latch) and momentary modes.
351
+ *
352
+ * @param name The parameter name (used to generate ID and name fields)
353
+ * @param mode The switch mode: "toggle" (latch) or "momentary" (only active while pressed)
354
+ * @returns A BooleanParameter configured as a switch
355
+ *
356
+ * @example
357
+ * ```ts
358
+ * const powerParam = AudioParameterFactory.createSwitch("Power", "toggle");
359
+ * // { type: "boolean", mode: "toggle", trueLabel: "On", falseLabel: "Off", ... }
360
+ *
361
+ * const recordParam = AudioParameterFactory.createSwitch("Record", "momentary");
362
+ * // { type: "boolean", mode: "momentary", ... }
363
+ * ```
364
+ */
365
+ createSwitch: (name: string, mode?: "toggle" | "momentary") => BooleanParameter;
366
+ /**
367
+ * Creates a discrete (selector) parameter.
368
+ *
369
+ * This factory method creates a discrete parameter suitable for mode selectors,
370
+ * preset switches, or any control that cycles through discrete options.
371
+ *
372
+ * @param name The parameter name (used to generate ID and name fields)
373
+ * @param options Array of option objects, each with a value and label
374
+ * @returns A DiscreteParameter configured as a selector
375
+ *
376
+ * @example
377
+ * ```ts
378
+ * const waveParam = AudioParameterFactory.createSelector("Waveform", [
379
+ * { value: "sine", label: "Sine" },
380
+ * { value: "square", label: "Square" },
381
+ * { value: "sawtooth", label: "Sawtooth" }
382
+ * ]);
383
+ * ```
384
+ */
385
+ createSelector: (name: string, options: Array<{
386
+ value: string | number;
387
+ label: string;
388
+ }>) => DiscreteParameter;
389
+ /**
390
+ * Creates a generic continuous control parameter (for ad-hoc UI controls like Knob/Slider).
391
+ *
392
+ * This is the most flexible factory method, allowing you to specify all aspects of a
393
+ * continuous parameter. It's useful when you need a parameter that doesn't fit the
394
+ * standard MIDI presets.
395
+ *
396
+ * The method handles bipolar mode automatically: if `bipolar` is true, it adjusts
397
+ * min/max to be symmetric around zero when only one boundary is provided. For default values:
398
+ * - If `defaultValue` is provided, it is used (even when `bipolar=true`)
399
+ * - If `defaultValue` is not provided and `bipolar=true`, the center of the range is calculated
400
+ * (0 for symmetric ranges, otherwise the midpoint)
401
+ * - If `defaultValue` is not provided and `bipolar=false`, falls back to `min` or 0
402
+ *
403
+ * @param config Configuration object with optional fields for all parameter properties
404
+ * @returns A ContinuousParameter configured according to the provided config
405
+ *
406
+ * @example
407
+ * ```ts
408
+ * const volumeParam = AudioParameterFactory.createControl({
409
+ * name: "Volume",
410
+ * min: 0,
411
+ * max: 100,
412
+ * step: 0.1,
413
+ * unit: "dB",
414
+ * scale: "log"
415
+ * });
416
+ *
417
+ * const panParam = AudioParameterFactory.createControl({
418
+ * name: "Pan",
419
+ * bipolar: true,
420
+ * unit: "%"
421
+ * });
422
+ * // Automatically sets min: -100, max: 100, defaultValue: 0
423
+ *
424
+ * const customBipolarParam = AudioParameterFactory.createControl({
425
+ * name: "Custom",
426
+ * min: 0,
427
+ * max: 127,
428
+ * bipolar: true,
429
+ * defaultValue: 64
430
+ * });
431
+ * // Uses provided defaultValue: 64 (center of 0-127 range)
432
+ * ```
433
+ */
434
+ createControl: (config: ContinuousControlConfig) => ContinuousParameter;
435
+ };
436
+ export {};
437
+ //# sourceMappingURL=AudioParameter.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"AudioParameter.d.ts","sourceRoot":"","sources":["../../src/model/AudioParameter.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,256 @@
1
+ /*
2
+ * Copyright (c) 2026 Tylium.
3
+ * SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-TELF-1.0
4
+ * See LICENSE.md for details.
5
+ */
6
+
7
+ @import url("themes.css");
8
+
9
+ /* ==========================================================================
10
+ Base Element Styles
11
+ ========================================================================== */
12
+
13
+ /* Form input elements - inherit theme text color and font size */
14
+ textarea,
15
+ input {
16
+ color: var(--audioui-text-color);
17
+ background-color: transparent;
18
+ font-size: var(--audioui-default-font-size);
19
+ }
20
+
21
+ /* ==========================================================================
22
+ SVG and Icon Styles
23
+ ========================================================================== */
24
+
25
+ /* Prevent text selection in SVG content */
26
+ svg text,
27
+ svg foreignObject div {
28
+ -webkit-user-select: none;
29
+ user-select: none;
30
+ cursor: default;
31
+ }
32
+
33
+ /* Make inline SVGs in knob content inherit text color */
34
+ /* This works for inline <svg> elements and SVG components from libraries like react-icons */
35
+ svg foreignObject div svg {
36
+ fill: currentColor;
37
+ color: inherit;
38
+ /* Ensure SVG icons scale down to fit, creating a visual margin */
39
+ max-width: 75%;
40
+ max-height: 75%;
41
+ }
42
+
43
+ /* Icon wrapper class for HTML overlay - ensures SVG icons fill their container */
44
+ /* Used by CycleButton and other components that render icons in the overlay */
45
+ .audioui-icon-wrapper {
46
+ display: flex;
47
+ align-items: center;
48
+ justify-content: center;
49
+ }
50
+
51
+ /* Ensure SVG icons inside the wrapper fill the container and inherit color */
52
+ /* Icons automatically inherit text color via currentColor */
53
+ .audioui-icon-wrapper svg {
54
+ width: 100%;
55
+ height: 100%;
56
+ fill: currentColor;
57
+ color: inherit;
58
+ }
59
+
60
+ /* ==========================================================================
61
+ Component Base Classes
62
+ ========================================================================== */
63
+
64
+ /* Root class for all AudioUI components */
65
+ .audioui {
66
+ -webkit-user-select: none;
67
+ user-select: none;
68
+ cursor: default;
69
+ }
70
+
71
+ /* Container helper class for components that manage their own SVG sizing */
72
+ .audioui-component-container {
73
+ height: auto;
74
+ max-width: 100%;
75
+ max-height: 100%;
76
+ }
77
+
78
+ /* Remove default outline from SVG elements */
79
+ .audioui-component-container svg {
80
+ height: auto;
81
+ outline: none;
82
+ }
83
+
84
+ /* ==========================================================================
85
+ Interactive States and Accessibility
86
+ ========================================================================== */
87
+
88
+ /* Highlight effect for interactive components */
89
+ /* Uses --audioui-highlight-effect from themes.css (user-customizable) */
90
+ /*
91
+ * CSS isolation on text and foreignObject elements prevents the filter from affecting them,
92
+ * allowing the filter to affect only the SVG graphics (paths, circles, etc.) without
93
+ * requiring manual filter resets. This is cleaner than resetting filters on each element type.
94
+ */
95
+ .audioui-highlight {
96
+ will-change: filter;
97
+ /* Fast transition for realtime audio UI - instant feedback preferred */
98
+ transition: filter var(--audioui-highlight-transition-duration) linear;
99
+ }
100
+
101
+ /* Apply highlight on hover OR when focused (keyboard/click) */
102
+ /* The actual effect is defined by --audioui-highlight-effect in themes.css */
103
+ /* Using :is() for cleaner selector grouping (modern browsers) */
104
+ .audioui-highlight:hover,
105
+ .audioui-highlight:focus,
106
+ .audioui-highlight:focus-visible {
107
+ filter: var(--audioui-highlight-effect);
108
+ outline: none; /* Remove default browser focus ring */
109
+ }
110
+
111
+ /* Prevent filter from affecting text elements by isolating them */
112
+ .audioui-highlight text {
113
+ isolation: isolate;
114
+ }
115
+
116
+ /* Prevent filter from affecting foreignObject elements (HTML content) by isolating them */
117
+ .audioui-highlight foreignObject {
118
+ isolation: isolate;
119
+ }
120
+
121
+ /* ==========================================================================
122
+ Color Utility Classes
123
+ ========================================================================== */
124
+
125
+ /* Base utility classes - only work if --audioui-primary-color is set by user */
126
+ .audioui-stroke-primary {
127
+ stroke: var(--audioui-primary-color);
128
+ }
129
+
130
+ .audioui-fill-text {
131
+ fill: var(--audioui-text-color);
132
+ }
133
+
134
+ .audioui-fill-primary {
135
+ fill: var(--audioui-primary-color);
136
+ }
137
+
138
+ .audioui-fill-transparent {
139
+ fill: transparent;
140
+ }
141
+
142
+ .audioui-border-primary {
143
+ border-color: var(--audioui-primary-color);
144
+ }
145
+
146
+ .audioui-text-primary {
147
+ color: var(--audioui-primary-color);
148
+ }
149
+
150
+ /* ==========================================================================
151
+ Size Utility Classes
152
+ ========================================================================== */
153
+
154
+ /* Square components (Button, Knob, CycleButton) - 1x1 aspect ratio */
155
+ .audioui-size-square-xsmall {
156
+ width: var(--audioui-size-square-xsmall);
157
+ height: var(--audioui-size-square-xsmall);
158
+ }
159
+
160
+ .audioui-size-square-small {
161
+ width: var(--audioui-size-square-small);
162
+ height: var(--audioui-size-square-small);
163
+ }
164
+
165
+ .audioui-size-square-normal {
166
+ width: var(--audioui-size-square-normal);
167
+ height: var(--audioui-size-square-normal);
168
+ }
169
+
170
+ .audioui-size-square-large {
171
+ width: var(--audioui-size-square-large);
172
+ height: var(--audioui-size-square-large);
173
+ }
174
+
175
+ .audioui-size-square-xlarge {
176
+ width: var(--audioui-size-square-xlarge);
177
+ height: var(--audioui-size-square-xlarge);
178
+ }
179
+
180
+ /* Horizontal Slider (1x2 aspect ratio - width > height) */
181
+ .audioui-size-hslider-xsmall {
182
+ width: var(--audioui-size-hslider-width-xsmall);
183
+ height: var(--audioui-size-hslider-height-xsmall);
184
+ }
185
+
186
+ .audioui-size-hslider-small {
187
+ width: var(--audioui-size-hslider-width-small);
188
+ height: var(--audioui-size-hslider-height-small);
189
+ }
190
+
191
+ .audioui-size-hslider-normal {
192
+ width: var(--audioui-size-hslider-width-normal);
193
+ height: var(--audioui-size-hslider-height-normal);
194
+ }
195
+
196
+ .audioui-size-hslider-large {
197
+ width: var(--audioui-size-hslider-width-large);
198
+ height: var(--audioui-size-hslider-height-large);
199
+ }
200
+
201
+ .audioui-size-hslider-xlarge {
202
+ width: var(--audioui-size-hslider-width-xlarge);
203
+ height: var(--audioui-size-hslider-height-xlarge);
204
+ }
205
+
206
+ /* Vertical Slider (2x1 aspect ratio - height > width) */
207
+ .audioui-size-vslider-xsmall {
208
+ width: var(--audioui-size-vslider-width-xsmall);
209
+ height: var(--audioui-size-vslider-height-xsmall);
210
+ }
211
+
212
+ .audioui-size-vslider-small {
213
+ width: var(--audioui-size-vslider-width-small);
214
+ height: var(--audioui-size-vslider-height-small);
215
+ }
216
+
217
+ .audioui-size-vslider-normal {
218
+ width: var(--audioui-size-vslider-width-normal);
219
+ height: var(--audioui-size-vslider-height-normal);
220
+ }
221
+
222
+ .audioui-size-vslider-large {
223
+ width: var(--audioui-size-vslider-width-large);
224
+ height: var(--audioui-size-vslider-height-large);
225
+ }
226
+
227
+ .audioui-size-vslider-xlarge {
228
+ width: var(--audioui-size-vslider-width-xlarge);
229
+ height: var(--audioui-size-vslider-height-xlarge);
230
+ }
231
+
232
+ /* Keys (1x5 aspect ratio - width > height) */
233
+ .audioui-size-keys-xsmall {
234
+ width: var(--audioui-size-keys-width-xsmall);
235
+ height: var(--audioui-size-keys-height-xsmall);
236
+ }
237
+
238
+ .audioui-size-keys-small {
239
+ width: var(--audioui-size-keys-width-small);
240
+ height: var(--audioui-size-keys-height-small);
241
+ }
242
+
243
+ .audioui-size-keys-normal {
244
+ width: var(--audioui-size-keys-width-normal);
245
+ height: var(--audioui-size-keys-height-normal);
246
+ }
247
+
248
+ .audioui-size-keys-large {
249
+ width: var(--audioui-size-keys-width-large);
250
+ height: var(--audioui-size-keys-height-large);
251
+ }
252
+
253
+ .audioui-size-keys-xlarge {
254
+ width: var(--audioui-size-keys-width-xlarge);
255
+ height: var(--audioui-size-keys-height-xlarge);
256
+ }