@vessel-dsp/control-ui 0.6.4

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 (76) hide show
  1. package/LICENSE.md +21 -0
  2. package/README.md +74 -0
  3. package/dist/ControlSurface.d.ts +14 -0
  4. package/dist/ControlSurface.d.ts.map +1 -0
  5. package/dist/ControlSurface.js +81 -0
  6. package/dist/ControlSurface.js.map +1 -0
  7. package/dist/appearance.d.ts +3 -0
  8. package/dist/appearance.d.ts.map +1 -0
  9. package/dist/appearance.js +25 -0
  10. package/dist/appearance.js.map +1 -0
  11. package/dist/components/ControlFrame.d.ts +12 -0
  12. package/dist/components/ControlFrame.d.ts.map +1 -0
  13. package/dist/components/ControlFrame.js +6 -0
  14. package/dist/components/ControlFrame.js.map +1 -0
  15. package/dist/components/DetentedRotarySelect.d.ts +13 -0
  16. package/dist/components/DetentedRotarySelect.d.ts.map +1 -0
  17. package/dist/components/DetentedRotarySelect.js +13 -0
  18. package/dist/components/DetentedRotarySelect.js.map +1 -0
  19. package/dist/components/FootswitchButton.d.ts +15 -0
  20. package/dist/components/FootswitchButton.d.ts.map +1 -0
  21. package/dist/components/FootswitchButton.js +36 -0
  22. package/dist/components/FootswitchButton.js.map +1 -0
  23. package/dist/components/GraphicEqSlider.d.ts +13 -0
  24. package/dist/components/GraphicEqSlider.d.ts.map +1 -0
  25. package/dist/components/GraphicEqSlider.js +13 -0
  26. package/dist/components/GraphicEqSlider.js.map +1 -0
  27. package/dist/components/KnobControl.d.ts +13 -0
  28. package/dist/components/KnobControl.d.ts.map +1 -0
  29. package/dist/components/KnobControl.js +201 -0
  30. package/dist/components/KnobControl.js.map +1 -0
  31. package/dist/components/LedIndicator.d.ts +12 -0
  32. package/dist/components/LedIndicator.d.ts.map +1 -0
  33. package/dist/components/LedIndicator.js +11 -0
  34. package/dist/components/LedIndicator.js.map +1 -0
  35. package/dist/components/SwitchSelectControl.d.ts +13 -0
  36. package/dist/components/SwitchSelectControl.d.ts.map +1 -0
  37. package/dist/components/SwitchSelectControl.js +7 -0
  38. package/dist/components/SwitchSelectControl.js.map +1 -0
  39. package/dist/components/ToggleSwitchControl.d.ts +13 -0
  40. package/dist/components/ToggleSwitchControl.d.ts.map +1 -0
  41. package/dist/components/ToggleSwitchControl.js +13 -0
  42. package/dist/components/ToggleSwitchControl.js.map +1 -0
  43. package/dist/controls.d.ts +11 -0
  44. package/dist/controls.d.ts.map +1 -0
  45. package/dist/controls.js +115 -0
  46. package/dist/controls.js.map +1 -0
  47. package/dist/index.d.ts +29 -0
  48. package/dist/index.d.ts.map +1 -0
  49. package/dist/index.js +16 -0
  50. package/dist/index.js.map +1 -0
  51. package/dist/render-plan.d.ts +16 -0
  52. package/dist/render-plan.d.ts.map +1 -0
  53. package/dist/render-plan.js +58 -0
  54. package/dist/render-plan.js.map +1 -0
  55. package/dist/state.d.ts +5 -0
  56. package/dist/state.d.ts.map +1 -0
  57. package/dist/state.js +33 -0
  58. package/dist/state.js.map +1 -0
  59. package/dist/styles.css +333 -0
  60. package/dist/theme.d.ts +14 -0
  61. package/dist/theme.d.ts.map +1 -0
  62. package/dist/theme.js +30 -0
  63. package/dist/theme.js.map +1 -0
  64. package/dist/types.d.ts +43 -0
  65. package/dist/types.d.ts.map +1 -0
  66. package/dist/types.js +2 -0
  67. package/dist/types.js.map +1 -0
  68. package/dist/useControlState.d.ts +13 -0
  69. package/dist/useControlState.d.ts.map +1 -0
  70. package/dist/useControlState.js +23 -0
  71. package/dist/useControlState.js.map +1 -0
  72. package/dist/utils.d.ts +4 -0
  73. package/dist/utils.d.ts.map +1 -0
  74. package/dist/utils.js +23 -0
  75. package/dist/utils.js.map +1 -0
  76. package/package.json +72 -0
package/dist/state.js ADDED
@@ -0,0 +1,33 @@
1
+ import { applyControlMessage, defaultControlState, validateMessage } from '@vessel-dsp/core';
2
+ import { findPanelControl, valueForControl } from './controls.js';
3
+ export function createControlUiState(panel) {
4
+ return defaultControlState(panel);
5
+ }
6
+ export function applyControlUiMessage(panel, state, message) {
7
+ const validationError = validateMessage(panel, message);
8
+ if (validationError !== null) {
9
+ throw new Error(validationError);
10
+ }
11
+ return applyControlMessage(state, message);
12
+ }
13
+ export function controlMessageForValue(panel, controlId, value, requestId) {
14
+ const control = findPanelControl(panel, controlId);
15
+ if (control === undefined) {
16
+ throw new Error(`unknown control id "${controlId}"`);
17
+ }
18
+ if (control.kind === 'led') {
19
+ throw new Error(`LED control "${controlId}" is read-only in control-ui`);
20
+ }
21
+ const message = {
22
+ type: 'control/set',
23
+ controlId,
24
+ value: valueForControl(control, value),
25
+ ...(requestId === undefined ? {} : { requestId }),
26
+ };
27
+ const validationError = validateMessage(panel, message);
28
+ if (validationError !== null) {
29
+ throw new Error(validationError);
30
+ }
31
+ return message;
32
+ }
33
+ //# sourceMappingURL=state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.js","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,mBAAmB,EAAE,mBAAmB,EAAE,eAAe,EAAE,MAAM,kBAAkB,CAAC;AAC7F,OAAO,EAAE,gBAAgB,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAE/D,MAAM,UAAU,oBAAoB,CAAC,KAAY;IAC7C,OAAO,mBAAmB,CAAC,KAAK,CAAC,CAAC;AACtC,CAAC;AAED,MAAM,UAAU,qBAAqB,CAAC,KAAY,EAAE,KAAmB,EAAE,OAAqB;IAC1F,MAAM,eAAe,GAAG,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IACxD,IAAI,eAAe,KAAK,IAAI,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC;IACrC,CAAC;IACD,OAAO,mBAAmB,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,sBAAsB,CAClC,KAAY,EACZ,SAAiB,EACjB,KAAsC,EACtC,SAAkB;IAElB,MAAM,OAAO,GAAG,gBAAgB,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;IACnD,IAAI,OAAO,KAAK,SAAS,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CAAC,uBAAuB,SAAS,GAAG,CAAC,CAAC;IACzD,CAAC;IACD,IAAI,OAAO,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;QACzB,MAAM,IAAI,KAAK,CAAC,gBAAgB,SAAS,8BAA8B,CAAC,CAAC;IAC7E,CAAC;IAED,MAAM,OAAO,GAAiB;QAC1B,IAAI,EAAE,aAAa;QACnB,SAAS;QACT,KAAK,EAAE,eAAe,CAAC,OAAO,EAAE,KAAK,CAAC;QACtC,GAAG,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC;KACpD,CAAC;IACF,MAAM,eAAe,GAAG,eAAe,CAAC,KAAK,EAAE,OAAO,CAAC,CAAC;IACxD,IAAI,eAAe,KAAK,IAAI,EAAE,CAAC;QAC3B,MAAM,IAAI,KAAK,CAAC,eAAe,CAAC,CAAC;IACrC,CAAC;IACD,OAAO,OAAO,CAAC;AACnB,CAAC"}
@@ -0,0 +1,333 @@
1
+ :where(.vdsp-control-ui-theme, .vdsp-control-ui-surface) {
2
+ --vdsp-control-ui-accent-color: #f97316;
3
+ --vdsp-control-ui-background-color: #f8fafc;
4
+ --vdsp-control-ui-border-color: #94a3b8;
5
+ --vdsp-control-ui-control-color: #111827;
6
+ --vdsp-control-ui-text-color: #111827;
7
+ --vdsp-control-ui-muted-text-color: #64748b;
8
+ --vdsp-control-ui-focus-ring-color: #f59e0b;
9
+ color: var(--vdsp-control-ui-text-color);
10
+ }
11
+
12
+ .vdsp-control-ui-theme {
13
+ display: contents;
14
+ }
15
+
16
+ .vdsp-control-ui-surface {
17
+ display: grid;
18
+ grid-template-columns: repeat(auto-fit, minmax(88px, 1fr));
19
+ gap: 12px;
20
+ align-items: start;
21
+ max-width: 100%;
22
+ }
23
+
24
+ .vdsp-control-ui-surface__item {
25
+ min-width: 0;
26
+ }
27
+
28
+ .vdsp-control-ui-frame {
29
+ display: grid;
30
+ justify-items: center;
31
+ align-content: start;
32
+ gap: 6px;
33
+ min-width: 0;
34
+ color: var(--vdsp-control-ui-text-color);
35
+ }
36
+
37
+ .vdsp-control-ui-label,
38
+ .vdsp-control-ui-readout {
39
+ max-width: 100%;
40
+ overflow-wrap: anywhere;
41
+ text-align: center;
42
+ line-height: 1.2;
43
+ }
44
+
45
+ .vdsp-control-ui-label {
46
+ color: color-mix(in srgb, var(--vdsp-control-ui-text-color) 72%, white);
47
+ font-size: 0.78rem;
48
+ font-weight: 650;
49
+ }
50
+
51
+ .vdsp-control-ui-readout {
52
+ color: var(--vdsp-control-ui-muted-text-color);
53
+ font-size: 0.72rem;
54
+ }
55
+
56
+ .vdsp-control-ui-control {
57
+ box-sizing: border-box;
58
+ font: inherit;
59
+ color: var(--vdsp-control-ui-text-color);
60
+ }
61
+
62
+ .vdsp-control-ui-control:focus-visible {
63
+ outline: 2px solid var(--vdsp-control-ui-focus-ring-color);
64
+ outline-offset: 3px;
65
+ }
66
+
67
+ .vdsp-control-ui-frame.is-disabled {
68
+ opacity: 0.55;
69
+ }
70
+
71
+ .vdsp-control-ui-knob {
72
+ position: relative;
73
+ display: grid;
74
+ place-items: center;
75
+ width: 64px;
76
+ height: 64px;
77
+ aspect-ratio: 1;
78
+ border: 0;
79
+ border-radius: 50%;
80
+ background: transparent;
81
+ padding: 0;
82
+ cursor: ew-resize;
83
+ touch-action: none;
84
+ user-select: none;
85
+ }
86
+
87
+ .vdsp-control-ui-knob:active {
88
+ cursor: ew-resize;
89
+ }
90
+
91
+ .vdsp-control-ui-knob.is-dragging {
92
+ cursor: ew-resize;
93
+ }
94
+
95
+ .vdsp-control-ui-is-knob-dragging,
96
+ .vdsp-control-ui-is-knob-dragging * {
97
+ cursor: ew-resize !important;
98
+ }
99
+
100
+ .vdsp-control-ui-knob:disabled {
101
+ cursor: not-allowed;
102
+ }
103
+
104
+ .vdsp-control-ui-knob__progress,
105
+ .vdsp-control-ui-knob__progress-fill {
106
+ position: absolute;
107
+ inset: 0;
108
+ border-radius: 50%;
109
+ pointer-events: none;
110
+ -webkit-mask: radial-gradient(farthest-side, transparent calc(100% - 2px), #000 calc(100% - 2px));
111
+ mask: radial-gradient(farthest-side, transparent calc(100% - 2px), #000 calc(100% - 2px));
112
+ }
113
+
114
+ .vdsp-control-ui-knob__progress {
115
+ background: conic-gradient(
116
+ from -150deg,
117
+ var(--vdsp-control-ui-border-color) 0 var(--vdsp-control-ui-knob-sweep, 300deg),
118
+ transparent var(--vdsp-control-ui-knob-sweep, 300deg) 360deg
119
+ );
120
+ }
121
+
122
+ .vdsp-control-ui-knob__progress-fill {
123
+ background: conic-gradient(
124
+ from -150deg,
125
+ var(--vdsp-control-ui-accent-color) 0 var(--vdsp-control-ui-knob-progress, 0deg),
126
+ transparent var(--vdsp-control-ui-knob-progress, 0deg) 360deg
127
+ );
128
+ }
129
+
130
+ .vdsp-control-ui-knob__body {
131
+ position: absolute;
132
+ inset: 7px;
133
+ border: 1px solid color-mix(in srgb, var(--vdsp-control-ui-control-color) 72%, white);
134
+ border-radius: 50%;
135
+ background: var(--vdsp-control-ui-control-color);
136
+ box-shadow: inset 0 1px 2px rgb(255 255 255 / 0.18), 0 2px 5px rgb(0 0 0 / 0.2);
137
+ pointer-events: none;
138
+ }
139
+
140
+ .vdsp-control-ui-knob__indicator-line {
141
+ position: absolute;
142
+ left: 50%;
143
+ top: 6px;
144
+ width: 2px;
145
+ height: 18px;
146
+ border-radius: 999px;
147
+ background: var(--vdsp-control-ui-background-color);
148
+ box-shadow: 0 0 0 1px rgb(0 0 0 / 0.08);
149
+ transform: translateX(-50%) rotate(var(--vdsp-control-ui-knob-rotation, 0deg));
150
+ transform-origin: 50% 19px;
151
+ }
152
+
153
+ .vdsp-control-ui-footswitch {
154
+ width: 58px;
155
+ height: 58px;
156
+ aspect-ratio: 1;
157
+ border: 1px solid var(--vdsp-control-ui-border-color);
158
+ border-radius: 50%;
159
+ background: var(--vdsp-control-ui-control-color);
160
+ box-shadow: none;
161
+ cursor: pointer;
162
+ }
163
+
164
+ .vdsp-control-ui-footswitch.is-pressing,
165
+ .vdsp-control-ui-footswitch:active {
166
+ border-width: 3px;
167
+ }
168
+
169
+ .vdsp-control-ui-footswitch__cap {
170
+ display: none;
171
+ width: 28px;
172
+ height: 28px;
173
+ margin: auto;
174
+ border-radius: 50%;
175
+ background: #f8fafc;
176
+ }
177
+
178
+ .vdsp-control-ui-toggle {
179
+ display: inline-flex;
180
+ align-items: center;
181
+ width: 52px;
182
+ height: 30px;
183
+ border: 1px solid var(--vdsp-control-ui-border-color);
184
+ border-radius: 999px;
185
+ background: var(--vdsp-control-ui-control-color);
186
+ box-shadow: none;
187
+ padding: 3px;
188
+ cursor: pointer;
189
+ }
190
+
191
+ .vdsp-control-ui-toggle.is-checked {
192
+ background: var(--vdsp-control-ui-accent-color);
193
+ }
194
+
195
+ .vdsp-control-ui-toggle__track {
196
+ display: block;
197
+ width: 100%;
198
+ }
199
+
200
+ .vdsp-control-ui-toggle__thumb {
201
+ display: block;
202
+ width: 22px;
203
+ height: 22px;
204
+ border-radius: 50%;
205
+ background: var(--vdsp-control-ui-background-color);
206
+ box-shadow: none;
207
+ transition: transform 120ms ease;
208
+ }
209
+
210
+ .vdsp-control-ui-toggle.is-checked .vdsp-control-ui-toggle__thumb {
211
+ transform: translateX(20px);
212
+ }
213
+
214
+ .vdsp-control-ui-slider-shell {
215
+ position: relative;
216
+ display: grid;
217
+ place-items: center;
218
+ width: 100%;
219
+ min-height: 32px;
220
+ }
221
+
222
+ .vdsp-control-ui-slider-shell.is-vertical {
223
+ min-height: 112px;
224
+ }
225
+
226
+ .vdsp-control-ui-slider {
227
+ --vdsp-control-ui-slider-position: 50%;
228
+ width: min(132px, 100%);
229
+ accent-color: var(--vdsp-control-ui-accent-color);
230
+ background: transparent;
231
+ -webkit-appearance: none;
232
+ appearance: none;
233
+ }
234
+
235
+ .vdsp-control-ui-slider[data-orientation="vertical"] {
236
+ width: 112px;
237
+ transform: rotate(-90deg);
238
+ }
239
+
240
+ .vdsp-control-ui-slider::-webkit-slider-runnable-track {
241
+ height: 4px;
242
+ border: 0;
243
+ border-radius: 999px;
244
+ background: linear-gradient(
245
+ 90deg,
246
+ var(--vdsp-control-ui-accent-color) 0 var(--vdsp-control-ui-slider-position),
247
+ color-mix(in srgb, var(--vdsp-control-ui-control-color) 52%, white)
248
+ var(--vdsp-control-ui-slider-position) 100%
249
+ );
250
+ box-shadow: none;
251
+ -webkit-appearance: none;
252
+ }
253
+
254
+ .vdsp-control-ui-slider::-webkit-slider-thumb {
255
+ width: 14px;
256
+ height: 14px;
257
+ margin-top: -5px;
258
+ border: 0;
259
+ border-radius: 50%;
260
+ background: var(--vdsp-control-ui-accent-color);
261
+ box-shadow: none;
262
+ -webkit-appearance: none;
263
+ }
264
+
265
+ .vdsp-control-ui-slider::-moz-range-track {
266
+ height: 4px;
267
+ border: 0;
268
+ border-radius: 999px;
269
+ background: linear-gradient(
270
+ 90deg,
271
+ var(--vdsp-control-ui-accent-color) 0 var(--vdsp-control-ui-slider-position),
272
+ color-mix(in srgb, var(--vdsp-control-ui-control-color) 52%, white)
273
+ var(--vdsp-control-ui-slider-position) 100%
274
+ );
275
+ box-shadow: none;
276
+ }
277
+
278
+ .vdsp-control-ui-slider::-moz-range-thumb {
279
+ width: 14px;
280
+ height: 14px;
281
+ border: 0;
282
+ border-radius: 50%;
283
+ background: var(--vdsp-control-ui-accent-color);
284
+ box-shadow: none;
285
+ }
286
+
287
+ .vdsp-control-ui-select {
288
+ width: min(100%, 144px);
289
+ min-height: 34px;
290
+ border: 1px solid var(--vdsp-control-ui-border-color);
291
+ border-radius: 0;
292
+ background-color: var(--vdsp-control-ui-control-color);
293
+ background-image:
294
+ linear-gradient(45deg, transparent 50%, currentColor 50%),
295
+ linear-gradient(135deg, currentColor 50%, transparent 50%);
296
+ background-position: calc(100% - 17px) 50%, calc(100% - 12px) 50%;
297
+ background-repeat: no-repeat;
298
+ background-size: 5px 5px, 5px 5px;
299
+ box-shadow: none;
300
+ color: var(--vdsp-control-ui-background-color);
301
+ padding: 4px 28px 4px 8px;
302
+ appearance: none;
303
+ cursor: pointer;
304
+ }
305
+
306
+ .vdsp-control-ui-select option {
307
+ background-color: var(--vdsp-control-ui-control-color);
308
+ color: var(--vdsp-control-ui-background-color);
309
+ }
310
+
311
+ .vdsp-control-ui-led {
312
+ width: 22px;
313
+ height: 22px;
314
+ aspect-ratio: 1;
315
+ border: 1px solid color-mix(in srgb, var(--vdsp-control-ui-border-color) 70%, black);
316
+ border-radius: 50%;
317
+ background: #7f1d1d;
318
+ box-shadow: inset 0 1px 4px rgb(0 0 0 / 0.45);
319
+ }
320
+
321
+ .vdsp-control-ui-led.is-on {
322
+ background: color-mix(
323
+ in srgb,
324
+ var(--vdsp-control-ui-accent-color) calc(var(--vdsp-control-ui-led-intensity, 1) * 100%),
325
+ #7f1d1d
326
+ );
327
+ box-shadow: 0 0 14px color-mix(in srgb, var(--vdsp-control-ui-accent-color) 70%, transparent);
328
+ }
329
+
330
+ .vdsp-control-ui-control:disabled,
331
+ .vdsp-control-ui-surface.is-disabled .vdsp-control-ui-control {
332
+ cursor: not-allowed;
333
+ }
@@ -0,0 +1,14 @@
1
+ import type { CSSProperties, ReactNode } from 'react';
2
+ import type { ControlUiTheme } from './types';
3
+ type ThemeStyle = CSSProperties & Record<`--vdsp-control-ui-${string}`, string | number | undefined>;
4
+ export type ControlUiThemeProviderProps = Readonly<{
5
+ theme: ControlUiTheme;
6
+ className?: string | undefined;
7
+ style?: CSSProperties | undefined;
8
+ children: ReactNode;
9
+ }>;
10
+ export declare function ControlUiThemeProvider({ theme, className, style, children }: ControlUiThemeProviderProps): import("react").JSX.Element;
11
+ export declare function useControlUiTheme(): ControlUiTheme;
12
+ export declare function themeToCssVariables(theme: ControlUiTheme): ThemeStyle;
13
+ export {};
14
+ //# sourceMappingURL=theme.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme.d.ts","sourceRoot":"","sources":["../src/theme.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,aAAa,EAAE,SAAS,EAAE,MAAM,OAAO,CAAC;AACtD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,SAAS,CAAC;AAG9C,KAAK,UAAU,GAAG,aAAa,GAAG,MAAM,CAAC,qBAAqB,MAAM,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,SAAS,CAAC,CAAC;AAIrG,MAAM,MAAM,2BAA2B,GAAG,QAAQ,CAAC;IAC/C,KAAK,EAAE,cAAc,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,KAAK,CAAC,EAAE,aAAa,GAAG,SAAS,CAAC;IAClC,QAAQ,EAAE,SAAS,CAAC;CACvB,CAAC,CAAC;AAEH,wBAAgB,sBAAsB,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAAE,EAAE,2BAA2B,+BAaxG;AAED,wBAAgB,iBAAiB,IAAI,cAAc,CAElD;AAED,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,cAAc,GAAG,UAAU,CAcrE"}
package/dist/theme.js ADDED
@@ -0,0 +1,30 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { createContext, useContext } from 'react';
3
+ import { cx } from './utils.js';
4
+ const ControlUiThemeContext = createContext({});
5
+ export function ControlUiThemeProvider({ theme, className, style, children }) {
6
+ const themeStyle = {
7
+ ...style,
8
+ ...themeToCssVariables(theme),
9
+ };
10
+ return (_jsx(ControlUiThemeContext.Provider, { value: theme, children: _jsx("div", { className: cx('vdsp-control-ui-theme', className), style: themeStyle, children: children }) }));
11
+ }
12
+ export function useControlUiTheme() {
13
+ return useContext(ControlUiThemeContext);
14
+ }
15
+ export function themeToCssVariables(theme) {
16
+ return {
17
+ ...(theme.accentColor === undefined ? {} : { '--vdsp-control-ui-accent-color': theme.accentColor }),
18
+ ...(theme.backgroundColor === undefined
19
+ ? {}
20
+ : { '--vdsp-control-ui-background-color': theme.backgroundColor }),
21
+ ...(theme.borderColor === undefined ? {} : { '--vdsp-control-ui-border-color': theme.borderColor }),
22
+ ...(theme.controlColor === undefined ? {} : { '--vdsp-control-ui-control-color': theme.controlColor }),
23
+ ...(theme.textColor === undefined ? {} : { '--vdsp-control-ui-text-color': theme.textColor }),
24
+ ...(theme.mutedTextColor === undefined ? {} : { '--vdsp-control-ui-muted-text-color': theme.mutedTextColor }),
25
+ ...(theme.focusRingColor === undefined
26
+ ? {}
27
+ : { '--vdsp-control-ui-focus-ring-color': theme.focusRingColor }),
28
+ };
29
+ }
30
+ //# sourceMappingURL=theme.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"theme.js","sourceRoot":"","sources":["../src/theme.tsx"],"names":[],"mappings":";AAAA,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,OAAO,CAAC;AAGlD,OAAO,EAAE,EAAE,EAAE,MAAM,SAAS,CAAC;AAI7B,MAAM,qBAAqB,GAAG,aAAa,CAAiB,EAAE,CAAC,CAAC;AAShE,MAAM,UAAU,sBAAsB,CAAC,EAAE,KAAK,EAAE,SAAS,EAAE,KAAK,EAAE,QAAQ,EAA+B;IACrG,MAAM,UAAU,GAAe;QAC3B,GAAG,KAAK;QACR,GAAG,mBAAmB,CAAC,KAAK,CAAC;KAChC,CAAC;IAEF,OAAO,CACH,KAAC,qBAAqB,CAAC,QAAQ,IAAC,KAAK,EAAE,KAAK,YACxC,cAAK,SAAS,EAAE,EAAE,CAAC,uBAAuB,EAAE,SAAS,CAAC,EAAE,KAAK,EAAE,UAAU,YACpE,QAAQ,GACP,GACuB,CACpC,CAAC;AACN,CAAC;AAED,MAAM,UAAU,iBAAiB;IAC7B,OAAO,UAAU,CAAC,qBAAqB,CAAC,CAAC;AAC7C,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,KAAqB;IACrD,OAAO;QACH,GAAG,CAAC,KAAK,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,gCAAgC,EAAE,KAAK,CAAC,WAAW,EAAE,CAAC;QACnG,GAAG,CAAC,KAAK,CAAC,eAAe,KAAK,SAAS;YACnC,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC,EAAE,oCAAoC,EAAE,KAAK,CAAC,eAAe,EAAE,CAAC;QACtE,GAAG,CAAC,KAAK,CAAC,WAAW,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,gCAAgC,EAAE,KAAK,CAAC,WAAW,EAAE,CAAC;QACnG,GAAG,CAAC,KAAK,CAAC,YAAY,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,iCAAiC,EAAE,KAAK,CAAC,YAAY,EAAE,CAAC;QACtG,GAAG,CAAC,KAAK,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,8BAA8B,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC;QAC7F,GAAG,CAAC,KAAK,CAAC,cAAc,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,oCAAoC,EAAE,KAAK,CAAC,cAAc,EAAE,CAAC;QAC7G,GAAG,CAAC,KAAK,CAAC,cAAc,KAAK,SAAS;YAClC,CAAC,CAAC,EAAE;YACJ,CAAC,CAAC,EAAE,oCAAoC,EAAE,KAAK,CAAC,cAAc,EAAE,CAAC;KACxE,CAAC;AACN,CAAC"}
@@ -0,0 +1,43 @@
1
+ import type { Knob, LedIndicator, SliderControl, SwitchControl } from '@vessel-dsp/core';
2
+ export type ControlAppearance = 'knob' | 'detented-rotary-select' | 'footswitch' | 'toggle' | 'graphic-eq-slider' | 'slider' | 'led' | 'hidden';
3
+ export type ControlAppearanceMap = Partial<Record<string, ControlAppearance>>;
4
+ export type ControlUiControlRef = Readonly<{
5
+ kind: 'knob';
6
+ control: Knob;
7
+ }> | Readonly<{
8
+ kind: 'slider';
9
+ control: SliderControl;
10
+ }> | Readonly<{
11
+ kind: 'switch';
12
+ control: SwitchControl;
13
+ }> | Readonly<{
14
+ kind: 'led';
15
+ control: LedIndicator;
16
+ }>;
17
+ export type ControlUiTheme = Readonly<{
18
+ accentColor?: string | undefined;
19
+ backgroundColor?: string | undefined;
20
+ borderColor?: string | undefined;
21
+ controlColor?: string | undefined;
22
+ textColor?: string | undefined;
23
+ mutedTextColor?: string | undefined;
24
+ focusRingColor?: string | undefined;
25
+ }>;
26
+ export type ControlFrameClassNames = Readonly<{
27
+ frame?: string | undefined;
28
+ label?: string | undefined;
29
+ readout?: string | undefined;
30
+ control?: string | undefined;
31
+ }>;
32
+ export type ControlSurfaceClassNames = ControlFrameClassNames & Readonly<{
33
+ root?: string | undefined;
34
+ face?: string | undefined;
35
+ item?: string | undefined;
36
+ knob?: string | undefined;
37
+ footswitch?: string | undefined;
38
+ toggle?: string | undefined;
39
+ slider?: string | undefined;
40
+ select?: string | undefined;
41
+ led?: string | undefined;
42
+ }>;
43
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACR,IAAI,EACJ,YAAY,EACZ,aAAa,EACb,aAAa,EAChB,MAAM,kBAAkB,CAAC;AAE1B,MAAM,MAAM,iBAAiB,GACvB,MAAM,GACN,wBAAwB,GACxB,YAAY,GACZ,QAAQ,GACR,mBAAmB,GACnB,QAAQ,GACR,KAAK,GACL,QAAQ,CAAC;AAEf,MAAM,MAAM,oBAAoB,GAAG,OAAO,CAAC,MAAM,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAC,CAAC;AAE9E,MAAM,MAAM,mBAAmB,GACzB,QAAQ,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,OAAO,EAAE,IAAI,CAAA;CAAE,CAAC,GACzC,QAAQ,CAAC;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,aAAa,CAAA;CAAE,CAAC,GACpD,QAAQ,CAAC;IAAE,IAAI,EAAE,QAAQ,CAAC;IAAC,OAAO,EAAE,aAAa,CAAA;CAAE,CAAC,GACpD,QAAQ,CAAC;IAAE,IAAI,EAAE,KAAK,CAAC;IAAC,OAAO,EAAE,YAAY,CAAA;CAAE,CAAC,CAAC;AAEvD,MAAM,MAAM,cAAc,GAAG,QAAQ,CAAC;IAClC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,eAAe,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACrC,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACjC,YAAY,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC/B,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACpC,cAAc,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CACvC,CAAC,CAAC;AAEH,MAAM,MAAM,sBAAsB,GAAG,QAAQ,CAAC;IAC1C,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC3B,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC7B,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAChC,CAAC,CAAC;AAEH,MAAM,MAAM,wBAAwB,GAAG,sBAAsB,GAAG,QAAQ,CAAC;IACrE,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,UAAU,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAChC,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC5B,CAAC,CAAC"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+ export {};
2
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":""}
@@ -0,0 +1,13 @@
1
+ import type { ControlState, ControlValue, Panel, PanelMessage } from '@vessel-dsp/core';
2
+ export type UseControlStateOptions = Readonly<{
3
+ initialState?: ControlState | undefined;
4
+ onMessage?: ((message: PanelMessage) => void) | undefined;
5
+ }>;
6
+ export type UseControlStateResult = Readonly<{
7
+ state: ControlState;
8
+ setState: (state: ControlState) => void;
9
+ dispatchMessage: (message: PanelMessage) => ControlState;
10
+ setControlValue: (controlId: string, value: ControlValue | number | boolean) => ControlState;
11
+ }>;
12
+ export declare function useControlState(panel: Panel, options?: UseControlStateOptions): UseControlStateResult;
13
+ //# sourceMappingURL=useControlState.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useControlState.d.ts","sourceRoot":"","sources":["../src/useControlState.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,KAAK,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAGxF,MAAM,MAAM,sBAAsB,GAAG,QAAQ,CAAC;IAC1C,YAAY,CAAC,EAAE,YAAY,GAAG,SAAS,CAAC;IACxC,SAAS,CAAC,EAAE,CAAC,CAAC,OAAO,EAAE,YAAY,KAAK,IAAI,CAAC,GAAG,SAAS,CAAC;CAC7D,CAAC,CAAC;AAEH,MAAM,MAAM,qBAAqB,GAAG,QAAQ,CAAC;IACzC,KAAK,EAAE,YAAY,CAAC;IACpB,QAAQ,EAAE,CAAC,KAAK,EAAE,YAAY,KAAK,IAAI,CAAC;IACxC,eAAe,EAAE,CAAC,OAAO,EAAE,YAAY,KAAK,YAAY,CAAC;IACzD,eAAe,EAAE,CAAC,SAAS,EAAE,MAAM,EAAE,KAAK,EAAE,YAAY,GAAG,MAAM,GAAG,OAAO,KAAK,YAAY,CAAC;CAChG,CAAC,CAAC;AAEH,wBAAgB,eAAe,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,GAAE,sBAA2B,GAAG,qBAAqB,CA4BzG"}
@@ -0,0 +1,23 @@
1
+ import { useCallback, useMemo, useState } from 'react';
2
+ import { applyControlUiMessage, controlMessageForValue, createControlUiState } from './state.js';
3
+ export function useControlState(panel, options = {}) {
4
+ const defaultState = useMemo(() => options.initialState ?? createControlUiState(panel), [panel, options.initialState]);
5
+ const [state, setState] = useState(defaultState);
6
+ const dispatchMessage = useCallback((message) => {
7
+ const nextState = applyControlUiMessage(panel, state, message);
8
+ setState(nextState);
9
+ options.onMessage?.(message);
10
+ return nextState;
11
+ }, [panel, state, options]);
12
+ const setControlValue = useCallback((controlId, value) => {
13
+ const message = controlMessageForValue(panel, controlId, value);
14
+ return dispatchMessage(message);
15
+ }, [dispatchMessage, panel]);
16
+ return {
17
+ state,
18
+ setState,
19
+ dispatchMessage,
20
+ setControlValue,
21
+ };
22
+ }
23
+ //# sourceMappingURL=useControlState.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"useControlState.js","sourceRoot":"","sources":["../src/useControlState.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAC;AAEvD,OAAO,EAAE,qBAAqB,EAAE,sBAAsB,EAAE,oBAAoB,EAAE,MAAM,SAAS,CAAC;AAc9F,MAAM,UAAU,eAAe,CAAC,KAAY,EAAE,UAAkC,EAAE;IAC9E,MAAM,YAAY,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC,OAAO,CAAC,YAAY,IAAI,oBAAoB,CAAC,KAAK,CAAC,EAAE,CAAC,KAAK,EAAE,OAAO,CAAC,YAAY,CAAC,CAAC,CAAC;IACvH,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAe,YAAY,CAAC,CAAC;IAE/D,MAAM,eAAe,GAAG,WAAW,CAC/B,CAAC,OAAqB,EAAE,EAAE;QACtB,MAAM,SAAS,GAAG,qBAAqB,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,CAAC;QAC/D,QAAQ,CAAC,SAAS,CAAC,CAAC;QACpB,OAAO,CAAC,SAAS,EAAE,CAAC,OAAO,CAAC,CAAC;QAC7B,OAAO,SAAS,CAAC;IACrB,CAAC,EACD,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,CAAC,CAC1B,CAAC;IAEF,MAAM,eAAe,GAAG,WAAW,CAC/B,CAAC,SAAiB,EAAE,KAAsC,EAAE,EAAE;QAC1D,MAAM,OAAO,GAAG,sBAAsB,CAAC,KAAK,EAAE,SAAS,EAAE,KAAK,CAAC,CAAC;QAChE,OAAO,eAAe,CAAC,OAAO,CAAC,CAAC;IACpC,CAAC,EACD,CAAC,eAAe,EAAE,KAAK,CAAC,CAC3B,CAAC;IAEF,OAAO;QACH,KAAK;QACL,QAAQ;QACR,eAAe;QACf,eAAe;KAClB,CAAC;AACN,CAAC"}
@@ -0,0 +1,4 @@
1
+ export declare function cx(...values: readonly (string | false | null | undefined)[]): string | undefined;
2
+ export declare function clampNumber(value: number, min: number, max: number): number;
3
+ export declare function formatNumber(value: number): string;
4
+ //# sourceMappingURL=utils.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.d.ts","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,wBAAgB,EAAE,CAAC,GAAG,MAAM,EAAE,SAAS,CAAC,MAAM,GAAG,KAAK,GAAG,IAAI,GAAG,SAAS,CAAC,EAAE,GAAG,MAAM,GAAG,SAAS,CAGhG;AAED,wBAAgB,WAAW,CAAC,KAAK,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,MAAM,GAAG,MAAM,CAW3E;AAED,wBAAgB,YAAY,CAAC,KAAK,EAAE,MAAM,GAAG,MAAM,CAKlD"}
package/dist/utils.js ADDED
@@ -0,0 +1,23 @@
1
+ export function cx(...values) {
2
+ const className = values.filter((value) => typeof value === 'string' && value.length > 0).join(' ');
3
+ return className.length > 0 ? className : undefined;
4
+ }
5
+ export function clampNumber(value, min, max) {
6
+ if (Number.isNaN(value)) {
7
+ return min;
8
+ }
9
+ if (value === Number.POSITIVE_INFINITY) {
10
+ return max;
11
+ }
12
+ if (value === Number.NEGATIVE_INFINITY) {
13
+ return min;
14
+ }
15
+ return Math.min(max, Math.max(min, value));
16
+ }
17
+ export function formatNumber(value) {
18
+ if (Number.isInteger(value)) {
19
+ return String(value);
20
+ }
21
+ return String(Math.round(value * 1000) / 1000);
22
+ }
23
+ //# sourceMappingURL=utils.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"utils.js","sourceRoot":"","sources":["../src/utils.ts"],"names":[],"mappings":"AAAA,MAAM,UAAU,EAAE,CAAC,GAAG,MAAsD;IACxE,MAAM,SAAS,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAmB,EAAE,CAAC,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACrH,OAAO,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC;AACxD,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,KAAa,EAAE,GAAW,EAAE,GAAW;IAC/D,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,EAAE,CAAC;QACtB,OAAO,GAAG,CAAC;IACf,CAAC;IACD,IAAI,KAAK,KAAK,MAAM,CAAC,iBAAiB,EAAE,CAAC;QACrC,OAAO,GAAG,CAAC;IACf,CAAC;IACD,IAAI,KAAK,KAAK,MAAM,CAAC,iBAAiB,EAAE,CAAC;QACrC,OAAO,GAAG,CAAC;IACf,CAAC;IACD,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,KAAK,CAAC,CAAC,CAAC;AAC/C,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,KAAa;IACtC,IAAI,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,EAAE,CAAC;QAC1B,OAAO,MAAM,CAAC,KAAK,CAAC,CAAC;IACzB,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;AACnD,CAAC"}
package/package.json ADDED
@@ -0,0 +1,72 @@
1
+ {
2
+ "name": "@vessel-dsp/control-ui",
3
+ "version": "0.6.4",
4
+ "description": "React control-surface components for VesselDSP panel data.",
5
+ "keywords": [
6
+ "guitar-pedal",
7
+ "electronics",
8
+ "react",
9
+ "controls",
10
+ "vdsp"
11
+ ],
12
+ "homepage": "https://vessel-dsp.github.io/core/",
13
+ "bugs": {
14
+ "url": "https://github.com/vessel-dsp/core/issues"
15
+ },
16
+ "repository": {
17
+ "type": "git",
18
+ "url": "git+https://github.com/vessel-dsp/core.git"
19
+ },
20
+ "license": "MIT",
21
+ "sideEffects": [
22
+ "./dist/styles.css",
23
+ "./src/styles.css"
24
+ ],
25
+ "type": "module",
26
+ "exports": {
27
+ ".": {
28
+ "types": "./dist/index.d.ts",
29
+ "bun": "./dist/index.js",
30
+ "import": "./dist/index.js"
31
+ },
32
+ "./styles.css": {
33
+ "default": "./dist/styles.css"
34
+ },
35
+ "./package.json": {
36
+ "default": "./package.json"
37
+ }
38
+ },
39
+ "main": "./dist/index.js",
40
+ "module": "./dist/index.js",
41
+ "types": "./dist/index.d.ts",
42
+ "files": [
43
+ "dist",
44
+ "README.md",
45
+ "LICENSE.md"
46
+ ],
47
+ "scripts": {
48
+ "build": "tsc -p tsconfig.build.json && bun run ../../scripts/fix-dist-imports.ts dist && cp src/styles.css dist/styles.css",
49
+ "clean": "rm -rf dist",
50
+ "prepack": "bun run build",
51
+ "pack:dry-run": "npm pack --dry-run",
52
+ "typecheck": "tsc --noEmit -p tsconfig.json"
53
+ },
54
+ "dependencies": {
55
+ "@vessel-dsp/core": "0.6.4"
56
+ },
57
+ "peerDependencies": {
58
+ "react": ">=18.2 <20",
59
+ "react-dom": ">=18.2 <20"
60
+ },
61
+ "devDependencies": {
62
+ "@types/react": "^18.3.18",
63
+ "@types/react-dom": "^18.3.5",
64
+ "@types/react-test-renderer": "^18.3.1",
65
+ "react": "^18.3.1",
66
+ "react-dom": "^18.3.1",
67
+ "react-test-renderer": "^18.3.1"
68
+ },
69
+ "publishConfig": {
70
+ "access": "public"
71
+ }
72
+ }