@ambientcss/components 2.0.1 → 3.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +35 -0
- package/dist/index.cjs +1563 -384
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +763 -48
- package/dist/index.d.ts +763 -48
- package/dist/index.js +1524 -385
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1102 -256
- package/package.json +2 -2
- package/src/components/AmbientButton.tsx +25 -25
- package/src/components/AmbientFader.tsx +33 -115
- package/src/components/AmbientKnob.tsx +64 -222
- package/src/components/AmbientPanel.tsx +8 -2
- package/src/components/AmbientProvider.tsx +3 -0
- package/src/components/AmbientRack.tsx +32 -0
- package/src/components/AmbientSelect.tsx +40 -0
- package/src/components/AmbientSlider.tsx +32 -113
- package/src/components/AmbientSwitch.tsx +58 -58
- package/src/controls/AmbientBank.tsx +138 -0
- package/src/controls/AmbientLatch.tsx +78 -0
- package/src/controls/AmbientPress.tsx +74 -0
- package/src/controls/AmbientRotary.tsx +94 -0
- package/src/controls/AmbientTravel.tsx +83 -0
- package/src/core/context.tsx +46 -0
- package/src/core/controllable.ts +33 -0
- package/src/core/dev.ts +15 -0
- package/src/core/frames.tsx +63 -0
- package/src/core/kit.tsx +107 -0
- package/src/core/material.ts +27 -0
- package/src/core/numeric.ts +88 -0
- package/src/core/types.ts +116 -0
- package/src/core/useBank.ts +163 -0
- package/src/core/useLatch.ts +54 -0
- package/src/core/usePress.ts +120 -0
- package/src/core/useRotary.ts +253 -0
- package/src/core/useTravel.ts +141 -0
- package/src/index.ts +127 -4
- package/src/kits/console.tsx +80 -0
- package/src/kits/grounded.tsx +113 -0
- package/src/parts/bank.tsx +32 -0
- package/src/parts/console.tsx +99 -0
- package/src/parts/knob.tsx +203 -0
- package/src/parts/latch.tsx +33 -0
- package/src/parts/press.tsx +56 -0
- package/src/parts/travel.tsx +70 -0
- package/src/styles.css +1102 -256
package/dist/index.js
CHANGED
|
@@ -42,7 +42,7 @@ function AmbientPanel({ className, material = "matte", ...props }) {
|
|
|
42
42
|
{
|
|
43
43
|
className: cn(
|
|
44
44
|
"ambient amb-surface amb-chamfer amb-elevation-2 ambx-panel",
|
|
45
|
-
|
|
45
|
+
`amb-mat-${material}`,
|
|
46
46
|
className
|
|
47
47
|
),
|
|
48
48
|
...props
|
|
@@ -50,491 +50,1630 @@ function AmbientPanel({ className, material = "matte", ...props }) {
|
|
|
50
50
|
);
|
|
51
51
|
}
|
|
52
52
|
|
|
53
|
-
// src/components/
|
|
53
|
+
// src/components/AmbientRack.tsx
|
|
54
54
|
import { jsx as jsx3 } from "react/jsx-runtime";
|
|
55
|
-
function
|
|
55
|
+
function AmbientRack({
|
|
56
56
|
className,
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
shape = "pill",
|
|
57
|
+
gap = "normal",
|
|
58
|
+
direction = "row",
|
|
60
59
|
...props
|
|
61
60
|
}) {
|
|
62
61
|
return /* @__PURE__ */ jsx3(
|
|
63
|
-
"
|
|
62
|
+
"div",
|
|
64
63
|
{
|
|
65
|
-
type: "button",
|
|
66
64
|
className: cn(
|
|
67
|
-
"
|
|
68
|
-
|
|
69
|
-
|
|
65
|
+
"ambx-rack",
|
|
66
|
+
gap === "tight" && "ambx-rack-tight",
|
|
67
|
+
gap === "loose" && "ambx-rack-loose",
|
|
68
|
+
direction === "column" && "ambx-rack-column",
|
|
70
69
|
className
|
|
71
70
|
),
|
|
72
|
-
...props
|
|
73
|
-
children: /* @__PURE__ */ jsx3(
|
|
74
|
-
"span",
|
|
75
|
-
{
|
|
76
|
-
className: cn(
|
|
77
|
-
"amb-button-cap ambient amb-chamfer amb-surface amb-heading-3",
|
|
78
|
-
material === "matte" ? "amb-mat-matte" : material === "shiny" ? "amb-mat-shiny" : "amb-mat-glass"
|
|
79
|
-
),
|
|
80
|
-
children
|
|
81
|
-
}
|
|
82
|
-
)
|
|
71
|
+
...props
|
|
83
72
|
}
|
|
84
73
|
);
|
|
85
74
|
}
|
|
86
75
|
|
|
87
|
-
// src/
|
|
88
|
-
import {
|
|
89
|
-
|
|
90
|
-
|
|
76
|
+
// src/controls/AmbientPress.tsx
|
|
77
|
+
import { useRef as useRef4 } from "react";
|
|
78
|
+
|
|
79
|
+
// src/core/context.tsx
|
|
80
|
+
import { createContext, useContext } from "react";
|
|
81
|
+
var ControlStateContext = createContext(null);
|
|
82
|
+
var ControlStateProvider = ControlStateContext.Provider;
|
|
83
|
+
function useControlState() {
|
|
84
|
+
const state = useContext(ControlStateContext);
|
|
85
|
+
if (!state) {
|
|
86
|
+
throw new Error(
|
|
87
|
+
"useControlState() must be called from inside a control's parts. Pass the component through `parts` on AmbientRotary, AmbientTravel, AmbientPress, AmbientLatch or AmbientBank."
|
|
88
|
+
);
|
|
89
|
+
}
|
|
90
|
+
return state;
|
|
91
|
+
}
|
|
92
|
+
var BankKeyContext = createContext(null);
|
|
93
|
+
var BankKeyProvider = BankKeyContext.Provider;
|
|
94
|
+
function useBankKey() {
|
|
95
|
+
const key = useContext(BankKeyContext);
|
|
96
|
+
if (!key) {
|
|
97
|
+
throw new Error(
|
|
98
|
+
"useBankKey() must be called from inside a bank key's parts. Pass the component through `keyParts` on AmbientBank."
|
|
99
|
+
);
|
|
100
|
+
}
|
|
101
|
+
return key;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
// src/core/frames.tsx
|
|
105
|
+
import { useEffect, useRef } from "react";
|
|
106
|
+
|
|
107
|
+
// src/core/dev.ts
|
|
108
|
+
var isDev = (() => {
|
|
109
|
+
try {
|
|
110
|
+
return process.env.NODE_ENV !== "production";
|
|
111
|
+
} catch {
|
|
112
|
+
return false;
|
|
113
|
+
}
|
|
114
|
+
})();
|
|
115
|
+
|
|
116
|
+
// src/core/types.ts
|
|
117
|
+
var FRAME_ORDER = ["panel", "base", "actuator", "fixture"];
|
|
118
|
+
function stateStyle(state) {
|
|
119
|
+
return {
|
|
120
|
+
"--ambx-value": state.value,
|
|
121
|
+
"--ambx-percent": state.percent,
|
|
122
|
+
"--ambx-angle": `${state.angle}deg`,
|
|
123
|
+
"--ambx-travel-start": `${state.travelStart}deg`,
|
|
124
|
+
"--ambx-travel-sweep": `${state.travelSweep}deg`,
|
|
125
|
+
"--ambx-detents": state.detents
|
|
126
|
+
};
|
|
127
|
+
}
|
|
128
|
+
function stateData(state) {
|
|
129
|
+
return {
|
|
130
|
+
"data-dragging": state.dragging ? "" : void 0,
|
|
131
|
+
"data-disabled": state.disabled ? "" : void 0,
|
|
132
|
+
"data-at-min": state.atMin ? "" : void 0,
|
|
133
|
+
"data-at-max": state.atMax ? "" : void 0
|
|
134
|
+
};
|
|
135
|
+
}
|
|
136
|
+
function sizeProps(family, size) {
|
|
137
|
+
if (size === void 0) return {};
|
|
138
|
+
if (size === "sm" || size === "md" || size === "lg") {
|
|
139
|
+
return { className: `ambx-${family}-${size}` };
|
|
140
|
+
}
|
|
141
|
+
return { style: { "--ambx-size": size } };
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// src/core/frames.tsx
|
|
145
|
+
import { Fragment, jsx as jsx4 } from "react/jsx-runtime";
|
|
146
|
+
function Frames({ parts }) {
|
|
147
|
+
if (!parts) return null;
|
|
148
|
+
return /* @__PURE__ */ jsx4(Fragment, { children: FRAME_ORDER.map(
|
|
149
|
+
(name) => parts[name] == null ? null : /* @__PURE__ */ jsx4("div", { "data-frame": name, className: `ambx-frame ambx-frame-${name}`, children: parts[name] }, name)
|
|
150
|
+
) });
|
|
151
|
+
}
|
|
152
|
+
var FOCUSABLE = "a[href], button, input, select, textarea, [tabindex], [contenteditable=true],[role=button], [role=checkbox], [role=radio], [role=slider], [role=switch], [role=link]";
|
|
153
|
+
function useDevPartCheck(ref, control) {
|
|
154
|
+
const warned2 = useRef(false);
|
|
155
|
+
useEffect(() => {
|
|
156
|
+
if (!isDev || warned2.current) return;
|
|
157
|
+
const root = ref.current;
|
|
158
|
+
if (!root) return;
|
|
159
|
+
const offenders = root.querySelectorAll(`[data-frame] :is(${FOCUSABLE})`);
|
|
160
|
+
if (offenders.length === 0) return;
|
|
161
|
+
warned2.current = true;
|
|
162
|
+
const tags = Array.from(offenders, (node) => `<${node.tagName.toLowerCase()}>`).join(", ");
|
|
163
|
+
console.warn(
|
|
164
|
+
`[@ambientcss/components] ${control}: a part contains a focusable element (${tags}). Parts are presentational \u2014 the control root already owns the role, the tab stop and the keyboard handler, so this creates a second tab stop and usually a conflicting role.`
|
|
165
|
+
);
|
|
166
|
+
}, [ref, control]);
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
// src/core/usePress.ts
|
|
170
|
+
import { useCallback as useCallback2, useEffect as useEffect2, useMemo, useRef as useRef3, useState as useState2 } from "react";
|
|
171
|
+
|
|
172
|
+
// src/core/controllable.ts
|
|
173
|
+
import { useCallback, useRef as useRef2, useState } from "react";
|
|
174
|
+
function useControllableValue(controlled, defaultValue, onChange) {
|
|
175
|
+
const isControlled = controlled !== void 0;
|
|
176
|
+
const [internal, setInternal] = useState(defaultValue);
|
|
177
|
+
const onChangeRef = useRef2(onChange);
|
|
178
|
+
onChangeRef.current = onChange;
|
|
179
|
+
const controlledRef = useRef2(isControlled);
|
|
180
|
+
controlledRef.current = isControlled;
|
|
181
|
+
const set = useCallback((next) => {
|
|
182
|
+
if (!controlledRef.current) setInternal(next);
|
|
183
|
+
onChangeRef.current?.(next);
|
|
184
|
+
}, []);
|
|
185
|
+
return [isControlled ? controlled : internal, set];
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// src/core/usePress.ts
|
|
189
|
+
function usePress(options) {
|
|
190
|
+
const {
|
|
191
|
+
mode = "momentary",
|
|
192
|
+
repeatDelay = 400,
|
|
193
|
+
repeatInterval = 60,
|
|
194
|
+
disabled = false
|
|
195
|
+
} = options;
|
|
196
|
+
const [on, setOn] = useControllableValue(
|
|
197
|
+
options.value,
|
|
198
|
+
options.defaultValue ?? false,
|
|
199
|
+
options.onChange
|
|
200
|
+
);
|
|
201
|
+
const [held, setHeld] = useState2(false);
|
|
202
|
+
const onPressRef = useRef3(options.onPress);
|
|
203
|
+
onPressRef.current = options.onPress;
|
|
204
|
+
const timers = useRef3(
|
|
205
|
+
{}
|
|
206
|
+
);
|
|
207
|
+
const stopRepeat = useCallback2(() => {
|
|
208
|
+
if (timers.current.delay) clearTimeout(timers.current.delay);
|
|
209
|
+
if (timers.current.tick) clearInterval(timers.current.tick);
|
|
210
|
+
timers.current = {};
|
|
211
|
+
}, []);
|
|
212
|
+
useEffect2(() => stopRepeat, [stopRepeat]);
|
|
213
|
+
const activate = useCallback2(() => {
|
|
214
|
+
if (mode === "toggle") setOn(!on);
|
|
215
|
+
onPressRef.current?.();
|
|
216
|
+
}, [mode, on, setOn]);
|
|
217
|
+
const pressed = mode === "toggle" ? on : held;
|
|
218
|
+
const state = useMemo(
|
|
219
|
+
() => ({
|
|
220
|
+
value: pressed ? 1 : 0,
|
|
221
|
+
min: 0,
|
|
222
|
+
max: 1,
|
|
223
|
+
percent: pressed ? 1 : 0,
|
|
224
|
+
angle: 0,
|
|
225
|
+
travelStart: 0,
|
|
226
|
+
travelSweep: 0,
|
|
227
|
+
detents: 2,
|
|
228
|
+
dragging: held,
|
|
229
|
+
disabled,
|
|
230
|
+
atMin: !pressed,
|
|
231
|
+
atMax: pressed
|
|
232
|
+
}),
|
|
233
|
+
[pressed, held, disabled]
|
|
234
|
+
);
|
|
235
|
+
const rootProps = {
|
|
236
|
+
type: "button",
|
|
237
|
+
disabled,
|
|
238
|
+
"aria-pressed": mode === "toggle" ? on : void 0,
|
|
239
|
+
style: stateStyle(state),
|
|
240
|
+
"data-pressed": pressed ? "" : void 0,
|
|
241
|
+
"data-mode": mode,
|
|
242
|
+
...stateData(state),
|
|
243
|
+
onPointerDown: (event) => {
|
|
244
|
+
if (disabled || event.button !== 0) return;
|
|
245
|
+
setHeld(true);
|
|
246
|
+
if (mode !== "repeat") return;
|
|
247
|
+
onPressRef.current?.();
|
|
248
|
+
timers.current.delay = setTimeout(() => {
|
|
249
|
+
timers.current.tick = setInterval(() => onPressRef.current?.(), repeatInterval);
|
|
250
|
+
}, repeatDelay);
|
|
251
|
+
},
|
|
252
|
+
onPointerUp: () => {
|
|
253
|
+
setHeld(false);
|
|
254
|
+
stopRepeat();
|
|
255
|
+
},
|
|
256
|
+
onPointerCancel: () => {
|
|
257
|
+
setHeld(false);
|
|
258
|
+
stopRepeat();
|
|
259
|
+
},
|
|
260
|
+
onPointerLeave: () => {
|
|
261
|
+
setHeld(false);
|
|
262
|
+
stopRepeat();
|
|
263
|
+
},
|
|
264
|
+
onClick: () => {
|
|
265
|
+
if (mode !== "repeat") activate();
|
|
266
|
+
}
|
|
267
|
+
};
|
|
268
|
+
return { state, rootProps, pressed, on, setOn };
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
// src/controls/AmbientPress.tsx
|
|
272
|
+
import { jsx as jsx5, jsxs } from "react/jsx-runtime";
|
|
273
|
+
function AmbientPress({
|
|
274
|
+
parts,
|
|
275
|
+
size,
|
|
91
276
|
className,
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
277
|
+
mode,
|
|
278
|
+
value,
|
|
279
|
+
defaultValue,
|
|
280
|
+
onChange,
|
|
281
|
+
onPress,
|
|
282
|
+
repeatDelay,
|
|
283
|
+
repeatInterval,
|
|
284
|
+
disabled,
|
|
99
285
|
children,
|
|
100
|
-
...
|
|
286
|
+
...rest
|
|
101
287
|
}) {
|
|
102
|
-
const
|
|
103
|
-
const
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
288
|
+
const ref = useRef4(null);
|
|
289
|
+
const { state, rootProps } = usePress({
|
|
290
|
+
mode,
|
|
291
|
+
value,
|
|
292
|
+
defaultValue,
|
|
293
|
+
onChange,
|
|
294
|
+
onPress,
|
|
295
|
+
repeatDelay,
|
|
296
|
+
repeatInterval,
|
|
297
|
+
disabled
|
|
298
|
+
});
|
|
299
|
+
useDevPartCheck(ref, "AmbientPress");
|
|
300
|
+
const sized = sizeProps("press", size);
|
|
301
|
+
const { style: restStyle, onClick, ...restProps } = rest;
|
|
302
|
+
return /* @__PURE__ */ jsx5(
|
|
107
303
|
"button",
|
|
108
304
|
{
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
305
|
+
...restProps,
|
|
306
|
+
...rootProps,
|
|
307
|
+
ref,
|
|
308
|
+
className: cn("ambx-control ambx-press", sized.className, className),
|
|
309
|
+
style: { ...rootProps.style, ...sized.style, ...restStyle },
|
|
310
|
+
onClick: (event) => {
|
|
311
|
+
rootProps.onClick();
|
|
312
|
+
onClick?.(event);
|
|
313
|
+
},
|
|
314
|
+
children: /* @__PURE__ */ jsxs(ControlStateProvider, { value: state, children: [
|
|
315
|
+
/* @__PURE__ */ jsx5(Frames, { parts }),
|
|
316
|
+
children
|
|
317
|
+
] })
|
|
318
|
+
}
|
|
319
|
+
);
|
|
320
|
+
}
|
|
321
|
+
|
|
322
|
+
// src/core/kit.tsx
|
|
323
|
+
import { createContext as createContext2, useContext as useContext2 } from "react";
|
|
324
|
+
import { jsx as jsx6 } from "react/jsx-runtime";
|
|
325
|
+
var KitContext = createContext2(null);
|
|
326
|
+
function AmbientKitProvider({ kit, children }) {
|
|
327
|
+
return /* @__PURE__ */ jsx6(KitContext.Provider, { value: kit, children });
|
|
328
|
+
}
|
|
329
|
+
function useKit() {
|
|
330
|
+
return useContext2(KitContext);
|
|
331
|
+
}
|
|
332
|
+
var warned = /* @__PURE__ */ new Set();
|
|
333
|
+
function useDress(family, look, fallback) {
|
|
334
|
+
const kit = useKit();
|
|
335
|
+
const dressed = kit?.[family];
|
|
336
|
+
if (isDev && kit && dressed) {
|
|
337
|
+
const honoured = kit.looks?.[family];
|
|
338
|
+
if (honoured) {
|
|
339
|
+
for (const key of Object.keys(look)) {
|
|
340
|
+
if (look[key] === void 0 || honoured.includes(key)) continue;
|
|
341
|
+
const id = `${kit.name}:${family}:${key}`;
|
|
342
|
+
if (warned.has(id)) continue;
|
|
343
|
+
warned.add(id);
|
|
344
|
+
console.warn(
|
|
345
|
+
`[@ambientcss/components] the "${kit.name}" kit's ${family} does not use \`${key}\` \u2014 it is a look prop from another kit's vocabulary, so it will have no effect here.`
|
|
346
|
+
);
|
|
347
|
+
}
|
|
348
|
+
}
|
|
349
|
+
}
|
|
350
|
+
return {
|
|
351
|
+
dress: (dressed ?? fallback)(look),
|
|
352
|
+
/* Defaults come from the kit that actually dressed the control: a kit
|
|
353
|
+
that falls through to grounded for a family has no say in how that
|
|
354
|
+
family behaves either. */
|
|
355
|
+
defaults: dressed ? kit?.defaults?.[family] : void 0
|
|
356
|
+
};
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
// src/parts/knob.tsx
|
|
360
|
+
import { useId } from "react";
|
|
361
|
+
import { Fragment as Fragment2, jsx as jsx7, jsxs as jsxs2 } from "react/jsx-runtime";
|
|
362
|
+
var KNURLS = {
|
|
363
|
+
/* 48 ribs — the referent lineup's fine knurl (referents.py knob_cap /
|
|
364
|
+
knob_wheel) rather than the 36 of its coarse one, because a band a tenth
|
|
365
|
+
of the radius wide reads as a machined grip only if the ribs are finer
|
|
366
|
+
than it is; at 36 the same band came out a bottle cap. */
|
|
367
|
+
standard: { teeth: 48, depth: 9e-3, sharpness: 1.6, band: 0.05 }
|
|
368
|
+
};
|
|
369
|
+
var KNURL_BAND = KNURLS.standard.band;
|
|
370
|
+
var SEAM = 5e-3;
|
|
371
|
+
var STEPS = 6;
|
|
372
|
+
function knurlPath({ teeth, depth, sharpness, band }) {
|
|
373
|
+
const outer = 0.5;
|
|
374
|
+
const inner = outer - band - SEAM;
|
|
375
|
+
const segs = teeth * STEPS;
|
|
376
|
+
const pts = [];
|
|
377
|
+
for (let i = 0; i < segs; i++) {
|
|
378
|
+
const t = i / segs * Math.PI * 2;
|
|
379
|
+
const r2 = outer - depth * (0.5 + 0.5 * Math.cos(teeth * t)) ** sharpness;
|
|
380
|
+
pts.push(
|
|
381
|
+
`${(0.5 + r2 * Math.cos(t)).toFixed(4)} ${(0.5 + r2 * Math.sin(t)).toFixed(4)}`
|
|
382
|
+
);
|
|
383
|
+
}
|
|
384
|
+
const l = (0.5 - inner).toFixed(4);
|
|
385
|
+
const r = (0.5 + inner).toFixed(4);
|
|
386
|
+
const hole = `M${l} 0.5 A${inner} ${inner} 0 0 0 ${r} 0.5 A${inner} ${inner} 0 0 0 ${l} 0.5 Z`;
|
|
387
|
+
return `M${pts.join(" L")} Z ${hole}`;
|
|
388
|
+
}
|
|
389
|
+
var KNURL_PATH = knurlPath(KNURLS.standard);
|
|
390
|
+
function KnobBody({
|
|
391
|
+
material,
|
|
392
|
+
flush = false,
|
|
393
|
+
className
|
|
394
|
+
}) {
|
|
395
|
+
return /* @__PURE__ */ jsx7(
|
|
396
|
+
"span",
|
|
397
|
+
{
|
|
113
398
|
className: cn(
|
|
114
|
-
"amb-
|
|
115
|
-
|
|
116
|
-
"ambx-switch",
|
|
117
|
-
`ambx-switch-${size}`,
|
|
399
|
+
"amb-knob-body ambient amb-thickness-2 amb-surface",
|
|
400
|
+
material && `amb-mat-${material}`,
|
|
118
401
|
className
|
|
119
402
|
),
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
403
|
+
style: flush ? void 0 : { inset: `${KNURL_BAND * 100}%` }
|
|
404
|
+
}
|
|
405
|
+
);
|
|
406
|
+
}
|
|
407
|
+
function KnurledFace({
|
|
408
|
+
material,
|
|
409
|
+
color,
|
|
410
|
+
className
|
|
411
|
+
}) {
|
|
412
|
+
const id = `amb-knurl-${useId().replace(/:/g, "")}`;
|
|
413
|
+
return /* @__PURE__ */ jsxs2(Fragment2, { children: [
|
|
414
|
+
/* @__PURE__ */ jsx7("svg", { width: 0, height: 0, style: { position: "absolute" }, "aria-hidden": true, focusable: false, children: /* @__PURE__ */ jsx7("defs", { children: /* @__PURE__ */ jsx7("clipPath", { id, clipPathUnits: "objectBoundingBox", children: /* @__PURE__ */ jsx7("path", { d: KNURL_PATH, clipRule: "evenodd" }) }) }) }),
|
|
415
|
+
/* @__PURE__ */ jsx7(
|
|
416
|
+
"span",
|
|
417
|
+
{
|
|
418
|
+
className: cn("amb-knob-face", material && `amb-mat-${material}`, className),
|
|
419
|
+
style: {
|
|
420
|
+
clipPath: `url(#${id})`,
|
|
421
|
+
/* Not a paint colour: --amb-albedo is the ribs' REFLECTANCE, so a
|
|
422
|
+
dark knurl still takes the scene's exposure, the lamp's cast and
|
|
423
|
+
the rim's own --amb-shade step, and still goes dark when the
|
|
424
|
+
lights do. Inline, so it beats the albedo a micro-relief material
|
|
425
|
+
would otherwise set on this element — an explicit colour wins
|
|
426
|
+
over the finish's own, and the finish keeps its grain. */
|
|
427
|
+
...color ? { "--amb-albedo": color } : null
|
|
428
|
+
}
|
|
429
|
+
}
|
|
430
|
+
)
|
|
431
|
+
] });
|
|
432
|
+
}
|
|
433
|
+
function IndicatorDot({ className }) {
|
|
434
|
+
return /* @__PURE__ */ jsx7("span", { className: cn("amb-knob-indicator-circle", className) });
|
|
435
|
+
}
|
|
436
|
+
function IndicatorBar({ className }) {
|
|
437
|
+
return /* @__PURE__ */ jsx7("span", { className: cn("amb-knob-indicator-rectangle", className) });
|
|
438
|
+
}
|
|
439
|
+
function ScaleRing({ count = 13, className, children }) {
|
|
440
|
+
const { travelStart, travelSweep } = useControlState();
|
|
441
|
+
const divisions = Math.max(1, count - 1);
|
|
442
|
+
const angles = count <= 1 ? [travelStart] : Array.from({ length: count }, (_, i) => travelStart + i / divisions * travelSweep);
|
|
443
|
+
return /* @__PURE__ */ jsxs2("span", { className: cn("amb-knob-marker-ring", className), "aria-hidden": true, children: [
|
|
444
|
+
angles.map((angle) => /* @__PURE__ */ jsx7(
|
|
445
|
+
"span",
|
|
446
|
+
{
|
|
447
|
+
className: "amb-knob-marker",
|
|
448
|
+
style: { "--amb-marker-angle": `${angle}deg` }
|
|
125
449
|
},
|
|
126
|
-
|
|
450
|
+
angle
|
|
451
|
+
)),
|
|
452
|
+
children
|
|
453
|
+
] });
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
// src/parts/travel.tsx
|
|
457
|
+
import { jsx as jsx8 } from "react/jsx-runtime";
|
|
458
|
+
function TravelTrack({
|
|
459
|
+
depth = "slot",
|
|
460
|
+
className
|
|
461
|
+
}) {
|
|
462
|
+
return /* @__PURE__ */ jsx8(
|
|
463
|
+
"span",
|
|
464
|
+
{
|
|
465
|
+
className: cn(
|
|
466
|
+
"amb-travel-track amb-groove",
|
|
467
|
+
depth === "channel" && "amb-travel-track-channel",
|
|
468
|
+
className
|
|
469
|
+
)
|
|
470
|
+
}
|
|
471
|
+
);
|
|
472
|
+
}
|
|
473
|
+
function FaderCap({
|
|
474
|
+
material,
|
|
475
|
+
className
|
|
476
|
+
}) {
|
|
477
|
+
return /* @__PURE__ */ jsx8(
|
|
478
|
+
"span",
|
|
479
|
+
{
|
|
480
|
+
className: cn(
|
|
481
|
+
"amb-fader-thumb ambient amb-fillet",
|
|
482
|
+
material !== "glass" && "amb-surface-concave",
|
|
483
|
+
material && `amb-mat-${material}`,
|
|
484
|
+
className
|
|
485
|
+
),
|
|
486
|
+
children: /* @__PURE__ */ jsx8("span", { className: "amb-fader-gripline" })
|
|
487
|
+
}
|
|
488
|
+
);
|
|
489
|
+
}
|
|
490
|
+
function SliderThumb({
|
|
491
|
+
material,
|
|
492
|
+
className
|
|
493
|
+
}) {
|
|
494
|
+
return /* @__PURE__ */ jsx8(
|
|
495
|
+
"span",
|
|
496
|
+
{
|
|
497
|
+
className: cn(
|
|
498
|
+
"amb-slider-thumb ambient amb-fillet",
|
|
499
|
+
material !== "glass" && "amb-surface-convex",
|
|
500
|
+
material && `amb-mat-${material}`,
|
|
501
|
+
className
|
|
502
|
+
)
|
|
503
|
+
}
|
|
504
|
+
);
|
|
505
|
+
}
|
|
506
|
+
|
|
507
|
+
// src/core/material.ts
|
|
508
|
+
function isRelief(material) {
|
|
509
|
+
return material === "brushed" || material === "brushed-round" || material === "blasted";
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
// src/parts/press.tsx
|
|
513
|
+
import { jsx as jsx9, jsxs as jsxs3 } from "react/jsx-runtime";
|
|
514
|
+
function ButtonCap({
|
|
515
|
+
material = "matte",
|
|
516
|
+
className,
|
|
517
|
+
children
|
|
518
|
+
}) {
|
|
519
|
+
const relief = isRelief(material);
|
|
520
|
+
return /* @__PURE__ */ jsxs3(
|
|
521
|
+
"span",
|
|
522
|
+
{
|
|
523
|
+
className: cn(
|
|
524
|
+
"amb-button-cap ambient amb-chamfer amb-surface amb-heading-3",
|
|
525
|
+
relief ? void 0 : `amb-mat-${material}`,
|
|
526
|
+
className
|
|
527
|
+
),
|
|
127
528
|
children: [
|
|
128
|
-
|
|
529
|
+
relief ? /* @__PURE__ */ jsx9(
|
|
129
530
|
"span",
|
|
130
531
|
{
|
|
131
|
-
className: cn("amb-
|
|
132
|
-
|
|
532
|
+
className: cn("ambx-cap-face ambient amb-chamfer amb-surface", `amb-mat-${material}`),
|
|
533
|
+
"aria-hidden": true
|
|
133
534
|
}
|
|
134
535
|
) : null,
|
|
135
|
-
/* @__PURE__ */ jsx4("span", { className: "amb-switch-track amb-groove", children: /* @__PURE__ */ jsx4("span", { className: "amb-switch-pill ambient amb-fillet amb-surface-convex" }) }),
|
|
136
536
|
children
|
|
137
537
|
]
|
|
138
538
|
}
|
|
139
539
|
);
|
|
140
|
-
if (!label) return button;
|
|
141
|
-
return /* @__PURE__ */ jsxs("div", { className: "ambx-stack", children: [
|
|
142
|
-
button,
|
|
143
|
-
/* @__PURE__ */ jsx4("span", { id: labelId, className: "ambx-label", children: label })
|
|
144
|
-
] });
|
|
145
540
|
}
|
|
146
541
|
|
|
147
|
-
// src/
|
|
148
|
-
import {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
/*
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
[0, root],
|
|
166
|
-
[rise, outer],
|
|
167
|
-
[fall[0], outer],
|
|
168
|
-
[fall[1], root]
|
|
169
|
-
];
|
|
170
|
-
for (const [frac, radius] of tooth) {
|
|
171
|
-
const t = a + frac * pitch;
|
|
172
|
-
pts.push(
|
|
173
|
-
`${(0.5 + radius * Math.cos(t)).toFixed(4)} ${(0.5 + radius * Math.sin(t)).toFixed(4)}`
|
|
174
|
-
);
|
|
542
|
+
// src/parts/latch.tsx
|
|
543
|
+
import { jsx as jsx10 } from "react/jsx-runtime";
|
|
544
|
+
function SwitchTrack({ className }) {
|
|
545
|
+
return /* @__PURE__ */ jsx10("span", { className: cn("amb-switch-track amb-groove", className) });
|
|
546
|
+
}
|
|
547
|
+
function SwitchPill({ className }) {
|
|
548
|
+
return /* @__PURE__ */ jsx10("span", { className: cn("amb-switch-pill ambient amb-fillet amb-surface-convex", className) });
|
|
549
|
+
}
|
|
550
|
+
function Led({
|
|
551
|
+
on = true,
|
|
552
|
+
color,
|
|
553
|
+
className
|
|
554
|
+
}) {
|
|
555
|
+
return /* @__PURE__ */ jsx10(
|
|
556
|
+
"span",
|
|
557
|
+
{
|
|
558
|
+
className: cn("amb-led", !on && "amb-led-off", className),
|
|
559
|
+
style: color ? { "--amb-led-color": color } : void 0
|
|
175
560
|
}
|
|
176
|
-
|
|
177
|
-
return `M${pts.join(" L")} Z`;
|
|
561
|
+
);
|
|
178
562
|
}
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
};
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
563
|
+
|
|
564
|
+
// src/parts/bank.tsx
|
|
565
|
+
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
566
|
+
function KeyLens({ className }) {
|
|
567
|
+
return /* @__PURE__ */ jsx11("span", { className: cn("amb-select-lens", className) });
|
|
568
|
+
}
|
|
569
|
+
function KeyCap({
|
|
570
|
+
className,
|
|
571
|
+
children
|
|
572
|
+
}) {
|
|
573
|
+
const { option } = useBankKey();
|
|
574
|
+
return /* @__PURE__ */ jsx11("span", { className: cn("amb-select-cap ambient amb-chamfer amb-mat-glass", className), children: children ?? option.label ?? option.value });
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
// src/kits/grounded.tsx
|
|
578
|
+
import { Fragment as Fragment3, jsx as jsx12, jsxs as jsxs4 } from "react/jsx-runtime";
|
|
579
|
+
var FULL_MARKERS = 13;
|
|
580
|
+
function rotary(look) {
|
|
581
|
+
const material = look.material;
|
|
582
|
+
const knurling = look.knurling !== false;
|
|
583
|
+
const knurlColor = look.knurlColor;
|
|
584
|
+
const markers = look.markers ?? "none";
|
|
585
|
+
const indicator = look.indicator ?? "circle";
|
|
586
|
+
return {
|
|
587
|
+
/* The full ring reaches past the knob's own box, so its layout clearance
|
|
588
|
+
has to be reserved — and only the kit knows it put a ring there. */
|
|
589
|
+
className: cn("amb-knob", markers === "full" && "amb-knob-markers-full"),
|
|
590
|
+
parts: {
|
|
591
|
+
panel: markers === "none" ? null : /* @__PURE__ */ jsx12(ScaleRing, { count: markers === "ends" ? 2 : FULL_MARKERS }),
|
|
592
|
+
/* `material` goes on every element that paints. The cap always does —
|
|
593
|
+
it is the knob's top face either way — and the knurl ring does too
|
|
594
|
+
when there is one, so a knurled knob's rim and cap are the same
|
|
595
|
+
material rather than the rim being the only thing wearing it.
|
|
596
|
+
|
|
597
|
+
`knurlColor` is the one thing the ring may hold on its own: a
|
|
598
|
+
two-tone knob — dark grip round a pale cap — is a real piece of
|
|
599
|
+
hardware, and the cap has no matching prop because the cap's colour
|
|
600
|
+
is the control's colour, set the ordinary way with --amb-albedo. */
|
|
601
|
+
base: /* @__PURE__ */ jsx12(KnobBody, { flush: !knurling, material }),
|
|
602
|
+
actuator: /* @__PURE__ */ jsxs4(Fragment3, { children: [
|
|
603
|
+
knurling ? /* @__PURE__ */ jsx12(KnurledFace, { material, color: knurlColor }) : null,
|
|
604
|
+
indicator === "circle" ? /* @__PURE__ */ jsx12(IndicatorDot, {}) : /* @__PURE__ */ jsx12(IndicatorBar, {})
|
|
605
|
+
] })
|
|
606
|
+
}
|
|
607
|
+
};
|
|
608
|
+
}
|
|
609
|
+
function travel(look) {
|
|
610
|
+
const material = look.material;
|
|
611
|
+
const upright = look.orientation === "vertical";
|
|
612
|
+
return {
|
|
613
|
+
className: upright ? "amb-fader" : "amb-slider",
|
|
614
|
+
parts: {
|
|
615
|
+
base: /* @__PURE__ */ jsx12(TravelTrack, { depth: upright ? "slot" : "channel" }),
|
|
616
|
+
actuator: upright ? /* @__PURE__ */ jsx12(FaderCap, { material }) : /* @__PURE__ */ jsx12(SliderThumb, { material })
|
|
617
|
+
}
|
|
618
|
+
};
|
|
619
|
+
}
|
|
620
|
+
function press(look) {
|
|
621
|
+
const shape = look.shape ?? "pill";
|
|
622
|
+
return {
|
|
623
|
+
className: cn(
|
|
624
|
+
"amb-button amb-groove",
|
|
625
|
+
shape === "round" && "amb-button-round",
|
|
626
|
+
shape === "square" && "amb-button-square"
|
|
627
|
+
),
|
|
628
|
+
parts: {
|
|
629
|
+
actuator: /* @__PURE__ */ jsx12(ButtonCap, { material: look.material ?? "matte", children: look.children })
|
|
630
|
+
}
|
|
631
|
+
};
|
|
632
|
+
}
|
|
633
|
+
function latch() {
|
|
634
|
+
return {
|
|
635
|
+
className: "amb-switch",
|
|
636
|
+
parts: { base: /* @__PURE__ */ jsx12(SwitchTrack, {}), actuator: /* @__PURE__ */ jsx12(SwitchPill, {}) }
|
|
637
|
+
};
|
|
638
|
+
}
|
|
639
|
+
function bank() {
|
|
640
|
+
return {
|
|
641
|
+
className: "amb-select amb-groove",
|
|
642
|
+
parts: { base: /* @__PURE__ */ jsx12(KeyLens, {}), actuator: /* @__PURE__ */ jsx12(KeyCap, {}) }
|
|
643
|
+
};
|
|
644
|
+
}
|
|
645
|
+
var groundedKit = {
|
|
646
|
+
name: "grounded",
|
|
647
|
+
rotary,
|
|
648
|
+
travel,
|
|
649
|
+
press,
|
|
650
|
+
latch,
|
|
651
|
+
bank,
|
|
652
|
+
looks: {
|
|
653
|
+
rotary: ["material", "knurling", "knurlColor", "markers", "indicator"],
|
|
654
|
+
travel: ["material", "orientation"],
|
|
655
|
+
press: ["material", "shape", "children"],
|
|
656
|
+
latch: [],
|
|
657
|
+
bank: []
|
|
658
|
+
}
|
|
190
659
|
};
|
|
191
|
-
|
|
192
|
-
|
|
660
|
+
|
|
661
|
+
// src/components/AmbientButton.tsx
|
|
662
|
+
import { jsx as jsx13 } from "react/jsx-runtime";
|
|
663
|
+
function AmbientButton({
|
|
664
|
+
className,
|
|
665
|
+
children,
|
|
666
|
+
look,
|
|
667
|
+
material = "matte",
|
|
668
|
+
shape = "pill",
|
|
669
|
+
size = "md",
|
|
670
|
+
...rest
|
|
671
|
+
}) {
|
|
672
|
+
const { dress } = useDress("press", { material, shape, children, ...look }, groundedKit.press);
|
|
673
|
+
return /* @__PURE__ */ jsx13(
|
|
674
|
+
AmbientPress,
|
|
675
|
+
{
|
|
676
|
+
...rest,
|
|
677
|
+
size,
|
|
678
|
+
className: cn(dress.className, className),
|
|
679
|
+
parts: dress.parts
|
|
680
|
+
}
|
|
681
|
+
);
|
|
193
682
|
}
|
|
194
|
-
|
|
683
|
+
|
|
684
|
+
// src/components/AmbientSwitch.tsx
|
|
685
|
+
import { useId as useId3 } from "react";
|
|
686
|
+
|
|
687
|
+
// src/controls/AmbientLatch.tsx
|
|
688
|
+
import { useId as useId2, useRef as useRef5 } from "react";
|
|
689
|
+
|
|
690
|
+
// src/core/useLatch.ts
|
|
691
|
+
import { useMemo as useMemo2 } from "react";
|
|
692
|
+
function useLatch(options) {
|
|
693
|
+
const { disabled = false } = options;
|
|
694
|
+
const [on, setOn] = useControllableValue(
|
|
695
|
+
options.value,
|
|
696
|
+
options.defaultValue ?? false,
|
|
697
|
+
options.onChange
|
|
698
|
+
);
|
|
699
|
+
const state = useMemo2(
|
|
700
|
+
() => ({
|
|
701
|
+
value: on ? 1 : 0,
|
|
702
|
+
min: 0,
|
|
703
|
+
max: 1,
|
|
704
|
+
percent: on ? 1 : 0,
|
|
705
|
+
angle: 0,
|
|
706
|
+
travelStart: 0,
|
|
707
|
+
travelSweep: 0,
|
|
708
|
+
detents: 2,
|
|
709
|
+
dragging: false,
|
|
710
|
+
disabled,
|
|
711
|
+
atMin: !on,
|
|
712
|
+
atMax: on
|
|
713
|
+
}),
|
|
714
|
+
[on, disabled]
|
|
715
|
+
);
|
|
716
|
+
const rootProps = {
|
|
717
|
+
type: "button",
|
|
718
|
+
role: "switch",
|
|
719
|
+
"aria-checked": on,
|
|
720
|
+
disabled,
|
|
721
|
+
style: stateStyle(state),
|
|
722
|
+
...stateData(state),
|
|
723
|
+
onClick: () => setOn(!on)
|
|
724
|
+
};
|
|
725
|
+
return { state, rootProps, on, setOn };
|
|
726
|
+
}
|
|
727
|
+
|
|
728
|
+
// src/controls/AmbientLatch.tsx
|
|
729
|
+
import { jsx as jsx14, jsxs as jsxs5 } from "react/jsx-runtime";
|
|
730
|
+
function AmbientLatch({
|
|
731
|
+
parts,
|
|
732
|
+
size,
|
|
733
|
+
animate = "auto",
|
|
734
|
+
label,
|
|
735
|
+
className,
|
|
195
736
|
value,
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
737
|
+
defaultValue,
|
|
738
|
+
onChange,
|
|
739
|
+
disabled,
|
|
740
|
+
children,
|
|
741
|
+
...rest
|
|
742
|
+
}) {
|
|
743
|
+
const labelId = useId2();
|
|
744
|
+
const ref = useRef5(null);
|
|
745
|
+
const { state, rootProps } = useLatch({ value, defaultValue, onChange, disabled });
|
|
746
|
+
useDevPartCheck(ref, "AmbientLatch");
|
|
747
|
+
const sized = sizeProps("latch", size);
|
|
748
|
+
const { style: restStyle, onClick, ...restProps } = rest;
|
|
749
|
+
const control = /* @__PURE__ */ jsx14(
|
|
750
|
+
"button",
|
|
751
|
+
{
|
|
752
|
+
...restProps,
|
|
753
|
+
...rootProps,
|
|
754
|
+
ref,
|
|
755
|
+
"aria-labelledby": label ? labelId : rest["aria-labelledby"],
|
|
756
|
+
"data-animate": animate,
|
|
757
|
+
className: cn("ambx-control ambx-latch", sized.className, className),
|
|
758
|
+
style: { ...rootProps.style, ...sized.style, ...restStyle },
|
|
759
|
+
onClick: (event) => {
|
|
760
|
+
rootProps.onClick();
|
|
761
|
+
onClick?.(event);
|
|
762
|
+
},
|
|
763
|
+
children: /* @__PURE__ */ jsxs5(ControlStateProvider, { value: state, children: [
|
|
764
|
+
/* @__PURE__ */ jsx14(Frames, { parts }),
|
|
765
|
+
children
|
|
766
|
+
] })
|
|
767
|
+
}
|
|
768
|
+
);
|
|
769
|
+
if (!label) return control;
|
|
770
|
+
return /* @__PURE__ */ jsxs5("div", { className: "ambx-stack", children: [
|
|
771
|
+
control,
|
|
772
|
+
/* @__PURE__ */ jsx14("span", { id: labelId, className: "ambx-label", children: label })
|
|
773
|
+
] });
|
|
774
|
+
}
|
|
775
|
+
|
|
776
|
+
// src/components/AmbientSwitch.tsx
|
|
777
|
+
import { jsx as jsx15, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
778
|
+
function AmbientSwitch({
|
|
779
|
+
size = "md",
|
|
780
|
+
led,
|
|
199
781
|
label,
|
|
200
|
-
|
|
201
|
-
|
|
782
|
+
look,
|
|
783
|
+
value,
|
|
784
|
+
defaultValue,
|
|
202
785
|
onChange,
|
|
786
|
+
animate,
|
|
203
787
|
className,
|
|
204
|
-
...
|
|
788
|
+
...rest
|
|
205
789
|
}) {
|
|
206
|
-
const
|
|
207
|
-
const
|
|
208
|
-
const
|
|
209
|
-
const
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
790
|
+
const labelId = useId3();
|
|
791
|
+
const [on, setOn] = useControllableValue(value, defaultValue ?? false, onChange);
|
|
792
|
+
const { dress, defaults } = useDress("latch", { ...look }, groundedKit.latch);
|
|
793
|
+
const control = /* @__PURE__ */ jsx15(
|
|
794
|
+
AmbientLatch,
|
|
795
|
+
{
|
|
796
|
+
...rest,
|
|
797
|
+
value: on,
|
|
798
|
+
onChange: setOn,
|
|
799
|
+
size,
|
|
800
|
+
animate: animate ?? defaults?.animate,
|
|
801
|
+
"aria-labelledby": label ? labelId : rest["aria-labelledby"],
|
|
802
|
+
className: cn(dress.className, className),
|
|
803
|
+
parts: dress.parts
|
|
804
|
+
}
|
|
805
|
+
);
|
|
806
|
+
if (!led && !label) return control;
|
|
807
|
+
return /* @__PURE__ */ jsxs6("div", { className: "ambx-stack", children: [
|
|
808
|
+
led ? /* @__PURE__ */ jsxs6("span", { className: "ambx-switch-mount", children: [
|
|
809
|
+
/* @__PURE__ */ jsx15(Led, { on, ...typeof led === "string" ? { color: led } : null }),
|
|
810
|
+
control
|
|
811
|
+
] }) : control,
|
|
812
|
+
label ? /* @__PURE__ */ jsx15("span", { id: labelId, className: "ambx-label", children: label }) : null
|
|
813
|
+
] });
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
// src/controls/AmbientBank.tsx
|
|
817
|
+
import { useId as useId4 } from "react";
|
|
818
|
+
|
|
819
|
+
// src/core/useBank.ts
|
|
820
|
+
import { useCallback as useCallback3, useRef as useRef6 } from "react";
|
|
821
|
+
function toArray(value) {
|
|
822
|
+
if (value === void 0) return [];
|
|
823
|
+
return Array.isArray(value) ? value : [value];
|
|
824
|
+
}
|
|
825
|
+
function useBank(options) {
|
|
826
|
+
const { options: items, multiple = false, orientation = "vertical", disabled = false } = options;
|
|
827
|
+
const [raw, setRaw] = useControllableValue(
|
|
828
|
+
options.value,
|
|
829
|
+
options.defaultValue ?? (multiple ? [] : ""),
|
|
830
|
+
options.onChange
|
|
831
|
+
);
|
|
832
|
+
const selected = toArray(raw);
|
|
833
|
+
const keyRefs = useRef6([]);
|
|
834
|
+
const commit2 = useCallback3(
|
|
835
|
+
(next) => setRaw(multiple ? next : next[0] ?? ""),
|
|
836
|
+
[setRaw, multiple]
|
|
837
|
+
);
|
|
838
|
+
const select = useCallback3(
|
|
839
|
+
(option) => {
|
|
840
|
+
if (!option || option.disabled || disabled) return;
|
|
841
|
+
if (!multiple) return commit2([option.value]);
|
|
842
|
+
commit2(
|
|
843
|
+
selected.includes(option.value) ? selected.filter((v) => v !== option.value) : [...selected, option.value]
|
|
844
|
+
);
|
|
845
|
+
},
|
|
846
|
+
[commit2, multiple, selected, disabled]
|
|
847
|
+
);
|
|
848
|
+
const enabled = items.filter((o) => !o.disabled);
|
|
849
|
+
const litIndex = items.findIndex((o) => selected.includes(o.value) && !o.disabled);
|
|
850
|
+
const firstEnabled = items.findIndex((o) => !o.disabled);
|
|
851
|
+
const tabStop = multiple ? -1 : litIndex >= 0 ? litIndex : firstEnabled;
|
|
852
|
+
const focusAt = (index) => keyRefs.current[index]?.focus();
|
|
853
|
+
const step = (from, delta) => {
|
|
854
|
+
if (enabled.length === 0) return;
|
|
855
|
+
let i = from;
|
|
856
|
+
for (let guard = 0; guard < items.length; guard += 1) {
|
|
857
|
+
i = (i + delta + items.length) % items.length;
|
|
858
|
+
if (!items[i]?.disabled) break;
|
|
859
|
+
}
|
|
860
|
+
focusAt(i);
|
|
861
|
+
if (!multiple) select(items[i]);
|
|
228
862
|
};
|
|
229
|
-
const
|
|
230
|
-
const
|
|
231
|
-
|
|
863
|
+
const edge = (which) => {
|
|
864
|
+
const i = which === "first" ? firstEnabled : items.map((o) => !o.disabled).lastIndexOf(true);
|
|
865
|
+
if (i < 0) return;
|
|
866
|
+
focusAt(i);
|
|
867
|
+
if (!multiple) select(items[i]);
|
|
232
868
|
};
|
|
233
|
-
const onKeyDown = (event) => {
|
|
234
|
-
const
|
|
869
|
+
const onKeyDown = (event, index) => {
|
|
870
|
+
const back = orientation === "vertical" ? "ArrowUp" : "ArrowLeft";
|
|
871
|
+
const forward = orientation === "vertical" ? "ArrowDown" : "ArrowRight";
|
|
235
872
|
switch (event.key) {
|
|
236
|
-
case
|
|
237
|
-
case "ArrowRight":
|
|
873
|
+
case back:
|
|
238
874
|
event.preventDefault();
|
|
239
|
-
|
|
875
|
+
step(index, -1);
|
|
240
876
|
break;
|
|
241
|
-
case
|
|
242
|
-
case "ArrowLeft":
|
|
877
|
+
case forward:
|
|
243
878
|
event.preventDefault();
|
|
244
|
-
|
|
245
|
-
break;
|
|
246
|
-
case "PageUp":
|
|
247
|
-
event.preventDefault();
|
|
248
|
-
setValue(value + pageStep);
|
|
249
|
-
break;
|
|
250
|
-
case "PageDown":
|
|
251
|
-
event.preventDefault();
|
|
252
|
-
setValue(value - pageStep);
|
|
879
|
+
step(index, 1);
|
|
253
880
|
break;
|
|
254
881
|
case "Home":
|
|
255
882
|
event.preventDefault();
|
|
256
|
-
|
|
883
|
+
edge("first");
|
|
257
884
|
break;
|
|
258
885
|
case "End":
|
|
259
886
|
event.preventDefault();
|
|
260
|
-
|
|
887
|
+
edge("last");
|
|
888
|
+
break;
|
|
889
|
+
case " ":
|
|
890
|
+
case "Enter":
|
|
891
|
+
event.preventDefault();
|
|
892
|
+
select(items[index]);
|
|
261
893
|
break;
|
|
262
894
|
default:
|
|
263
895
|
break;
|
|
264
896
|
}
|
|
265
897
|
};
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
898
|
+
const rootProps = {
|
|
899
|
+
role: multiple ? "group" : "radiogroup",
|
|
900
|
+
"aria-orientation": multiple ? void 0 : orientation,
|
|
901
|
+
"aria-disabled": disabled || void 0,
|
|
902
|
+
"data-orientation": orientation,
|
|
903
|
+
"data-disabled": disabled ? "" : void 0
|
|
904
|
+
};
|
|
905
|
+
const keyProps = (option, index) => {
|
|
906
|
+
const on = selected.includes(option.value);
|
|
907
|
+
return {
|
|
908
|
+
key: option.value,
|
|
909
|
+
type: "button",
|
|
910
|
+
ref: (node) => {
|
|
911
|
+
keyRefs.current[index] = node;
|
|
912
|
+
},
|
|
913
|
+
role: multiple ? "checkbox" : "radio",
|
|
914
|
+
"aria-checked": on,
|
|
915
|
+
"aria-label": option.ariaLabel,
|
|
916
|
+
title: option.ariaLabel,
|
|
917
|
+
disabled: option.disabled || disabled,
|
|
918
|
+
tabIndex: multiple ? 0 : index === tabStop ? 0 : -1,
|
|
919
|
+
"data-on": on ? "" : void 0,
|
|
920
|
+
onClick: () => select(option),
|
|
921
|
+
onKeyDown: (event) => onKeyDown(event, index)
|
|
922
|
+
};
|
|
923
|
+
};
|
|
924
|
+
return { selected, select, rootProps, keyProps };
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
// src/controls/AmbientBank.tsx
|
|
928
|
+
import { jsx as jsx16, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
929
|
+
function keyState(on, disabled) {
|
|
930
|
+
return {
|
|
931
|
+
value: on ? 1 : 0,
|
|
932
|
+
min: 0,
|
|
933
|
+
max: 1,
|
|
934
|
+
percent: on ? 1 : 0,
|
|
935
|
+
angle: 0,
|
|
936
|
+
travelStart: 0,
|
|
937
|
+
travelSweep: 0,
|
|
938
|
+
detents: 2,
|
|
939
|
+
dragging: false,
|
|
940
|
+
disabled,
|
|
941
|
+
atMin: !on,
|
|
942
|
+
atMax: on
|
|
943
|
+
};
|
|
944
|
+
}
|
|
945
|
+
function AmbientBank({
|
|
946
|
+
options,
|
|
947
|
+
keyParts,
|
|
948
|
+
parts,
|
|
949
|
+
size,
|
|
950
|
+
color,
|
|
951
|
+
label,
|
|
952
|
+
renderKey,
|
|
953
|
+
className,
|
|
954
|
+
style,
|
|
955
|
+
value,
|
|
956
|
+
defaultValue,
|
|
957
|
+
onChange,
|
|
958
|
+
multiple,
|
|
959
|
+
orientation = "vertical",
|
|
960
|
+
disabled = false,
|
|
961
|
+
...rest
|
|
962
|
+
}) {
|
|
963
|
+
const labelId = useId4();
|
|
964
|
+
const { selected, rootProps, keyProps } = useBank({
|
|
965
|
+
options,
|
|
966
|
+
value,
|
|
967
|
+
defaultValue,
|
|
968
|
+
onChange,
|
|
969
|
+
multiple,
|
|
970
|
+
orientation,
|
|
971
|
+
disabled
|
|
972
|
+
});
|
|
973
|
+
const sized = sizeProps("bank", size);
|
|
974
|
+
const bank2 = /* @__PURE__ */ jsxs7(
|
|
975
|
+
"div",
|
|
976
|
+
{
|
|
977
|
+
...rest,
|
|
978
|
+
...rootProps,
|
|
979
|
+
"aria-labelledby": label ? labelId : rest["aria-labelledby"],
|
|
980
|
+
className: cn(
|
|
981
|
+
"ambx-control ambx-bank",
|
|
982
|
+
`ambx-bank-${orientation}`,
|
|
983
|
+
sized.className,
|
|
984
|
+
className
|
|
985
|
+
),
|
|
986
|
+
style: {
|
|
987
|
+
...color ? { "--amb-led-color": color } : null,
|
|
988
|
+
...sized.style,
|
|
989
|
+
...style
|
|
990
|
+
},
|
|
991
|
+
children: [
|
|
992
|
+
/* @__PURE__ */ jsx16(Frames, { parts }),
|
|
993
|
+
options.map((option, index) => {
|
|
994
|
+
const on = selected.includes(option.value);
|
|
995
|
+
const ks = keyState(on, option.disabled || disabled);
|
|
996
|
+
return /* @__PURE__ */ jsx16(
|
|
997
|
+
"button",
|
|
300
998
|
{
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
children: [
|
|
310
|
-
variant === "dot" ? /* @__PURE__ */ jsx5("span", { className: "amb-knob-indicator-dot" }) : null,
|
|
311
|
-
variant === "line" ? /* @__PURE__ */ jsx5("span", { className: "amb-knob-indicator-line" }) : null,
|
|
312
|
-
variant === "flute" ? /* @__PURE__ */ jsx5("span", { className: "amb-knob-indicator-dot amb-knob-indicator-dot-center" }) : null
|
|
313
|
-
]
|
|
999
|
+
...keyProps(option, index),
|
|
1000
|
+
...stateData(ks),
|
|
1001
|
+
className: "ambx-key",
|
|
1002
|
+
style: {
|
|
1003
|
+
...stateStyle(ks),
|
|
1004
|
+
...option.color ? { "--amb-led-color": option.color } : null
|
|
1005
|
+
},
|
|
1006
|
+
children: /* @__PURE__ */ jsx16(ControlStateProvider, { value: ks, children: /* @__PURE__ */ jsx16(BankKeyProvider, { value: { option, on, index }, children: renderKey ? renderKey(option, on) : /* @__PURE__ */ jsx16(Frames, { parts: keyParts }) }) })
|
|
314
1007
|
}
|
|
315
|
-
)
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
1008
|
+
);
|
|
1009
|
+
})
|
|
1010
|
+
]
|
|
1011
|
+
}
|
|
1012
|
+
);
|
|
1013
|
+
if (!label) return bank2;
|
|
1014
|
+
return /* @__PURE__ */ jsxs7("div", { className: "ambx-stack", children: [
|
|
1015
|
+
bank2,
|
|
1016
|
+
/* @__PURE__ */ jsx16("span", { id: labelId, className: "ambx-label", children: label })
|
|
320
1017
|
] });
|
|
321
1018
|
}
|
|
322
1019
|
|
|
323
|
-
// src/components/
|
|
324
|
-
import {
|
|
325
|
-
|
|
326
|
-
|
|
1020
|
+
// src/components/AmbientSelect.tsx
|
|
1021
|
+
import { jsx as jsx17 } from "react/jsx-runtime";
|
|
1022
|
+
function AmbientSelect({ size = "md", look, className, ...rest }) {
|
|
1023
|
+
const { dress } = useDress("bank", { ...look }, groundedKit.bank);
|
|
1024
|
+
return /* @__PURE__ */ jsx17(
|
|
1025
|
+
AmbientBank,
|
|
1026
|
+
{
|
|
1027
|
+
...rest,
|
|
1028
|
+
size,
|
|
1029
|
+
className: cn(dress.className, className),
|
|
1030
|
+
keyParts: dress.parts
|
|
1031
|
+
}
|
|
1032
|
+
);
|
|
1033
|
+
}
|
|
1034
|
+
|
|
1035
|
+
// src/controls/AmbientRotary.tsx
|
|
1036
|
+
import { useId as useId5, useRef as useRef8 } from "react";
|
|
1037
|
+
|
|
1038
|
+
// src/core/useRotary.ts
|
|
1039
|
+
import { useCallback as useCallback4, useMemo as useMemo3, useRef as useRef7, useState as useState3 } from "react";
|
|
1040
|
+
|
|
1041
|
+
// src/core/numeric.ts
|
|
1042
|
+
function clamp(value, min, max) {
|
|
327
1043
|
return Math.min(max, Math.max(min, value));
|
|
328
1044
|
}
|
|
329
|
-
function
|
|
330
|
-
value
|
|
331
|
-
min
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
const
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
onChange?.(clamp2(snapped, min, max));
|
|
352
|
-
};
|
|
353
|
-
const setValue = (nextValue) => {
|
|
354
|
-
const snapped = Math.round(nextValue / safeStep) * safeStep;
|
|
355
|
-
onChange?.(clamp2(snapped, min, max));
|
|
356
|
-
};
|
|
357
|
-
const onKeyDown = (event) => {
|
|
358
|
-
const pageStep = safeStep * 10;
|
|
1045
|
+
function snap(value, min, step) {
|
|
1046
|
+
if (!(step > 0)) return value;
|
|
1047
|
+
return min + Math.round((value - min) / step) * step;
|
|
1048
|
+
}
|
|
1049
|
+
function normalise(value, min, max) {
|
|
1050
|
+
return (value - min) / (max - min || 1);
|
|
1051
|
+
}
|
|
1052
|
+
function denormalise(t, min, max) {
|
|
1053
|
+
return min + t * (max - min);
|
|
1054
|
+
}
|
|
1055
|
+
function commit(value, min, max, step) {
|
|
1056
|
+
return clamp(snap(value, min, max === min ? 1 : step), min, max);
|
|
1057
|
+
}
|
|
1058
|
+
function valueKeyHandler(options) {
|
|
1059
|
+
return (event) => {
|
|
1060
|
+
const { value, min, max, step, invert, onChange, disabled } = options;
|
|
1061
|
+
if (disabled) return false;
|
|
1062
|
+
const dir = invert ? -1 : 1;
|
|
1063
|
+
const set = (next) => {
|
|
1064
|
+
event.preventDefault();
|
|
1065
|
+
onChange(commit(next, min, max, step));
|
|
1066
|
+
};
|
|
359
1067
|
switch (event.key) {
|
|
360
1068
|
case "ArrowUp":
|
|
361
1069
|
case "ArrowRight":
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
break;
|
|
1070
|
+
set(value + step * dir);
|
|
1071
|
+
return true;
|
|
365
1072
|
case "ArrowDown":
|
|
366
1073
|
case "ArrowLeft":
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
break;
|
|
1074
|
+
set(value - step * dir);
|
|
1075
|
+
return true;
|
|
370
1076
|
case "PageUp":
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
break;
|
|
1077
|
+
set(value + step * 10 * dir);
|
|
1078
|
+
return true;
|
|
374
1079
|
case "PageDown":
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
break;
|
|
1080
|
+
set(value - step * 10 * dir);
|
|
1081
|
+
return true;
|
|
378
1082
|
case "Home":
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
break;
|
|
1083
|
+
set(min);
|
|
1084
|
+
return true;
|
|
382
1085
|
case "End":
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
break;
|
|
1086
|
+
set(max);
|
|
1087
|
+
return true;
|
|
386
1088
|
default:
|
|
387
|
-
|
|
1089
|
+
return false;
|
|
1090
|
+
}
|
|
1091
|
+
};
|
|
1092
|
+
}
|
|
1093
|
+
|
|
1094
|
+
// src/core/useRotary.ts
|
|
1095
|
+
var DEFAULT_TRAVEL = { start: -135, sweep: 270 };
|
|
1096
|
+
function wrapDeg(deg) {
|
|
1097
|
+
return ((deg + 180) % 360 + 360) % 360 - 180;
|
|
1098
|
+
}
|
|
1099
|
+
function resolveTravel(travel2) {
|
|
1100
|
+
if (travel2 === void 0) return DEFAULT_TRAVEL;
|
|
1101
|
+
if (typeof travel2 === "number") return { start: -travel2 / 2, sweep: travel2 };
|
|
1102
|
+
return travel2;
|
|
1103
|
+
}
|
|
1104
|
+
var warnedFullTurn = false;
|
|
1105
|
+
function capturePointer(target, pointerId) {
|
|
1106
|
+
try {
|
|
1107
|
+
target.setPointerCapture?.(pointerId);
|
|
1108
|
+
} catch {
|
|
1109
|
+
}
|
|
1110
|
+
}
|
|
1111
|
+
function useRotary(options) {
|
|
1112
|
+
const {
|
|
1113
|
+
min = 0,
|
|
1114
|
+
max = 100,
|
|
1115
|
+
step = 1,
|
|
1116
|
+
dragDistance = 200,
|
|
1117
|
+
wrap = false,
|
|
1118
|
+
disabled = false
|
|
1119
|
+
} = options;
|
|
1120
|
+
const { start, sweep } = resolveTravel(options.travel);
|
|
1121
|
+
let input = options.input ?? "drag";
|
|
1122
|
+
if (input === "angle" && Math.abs(sweep) >= 360) {
|
|
1123
|
+
if (isDev && !warnedFullTurn) {
|
|
1124
|
+
warnedFullTurn = true;
|
|
1125
|
+
console.warn(
|
|
1126
|
+
`[@ambientcss/components] input="angle" needs a sweep under a full turn (got ${sweep}deg): an absolute angle is ambiguous at 360deg, where the first and last values share a screen position. Falling back to "drag".`
|
|
1127
|
+
);
|
|
1128
|
+
}
|
|
1129
|
+
input = "drag";
|
|
1130
|
+
}
|
|
1131
|
+
const [value, setValue] = useControllableValue(
|
|
1132
|
+
options.value,
|
|
1133
|
+
options.defaultValue ?? min,
|
|
1134
|
+
options.onChange
|
|
1135
|
+
);
|
|
1136
|
+
const [dragging, setDragging] = useState3(false);
|
|
1137
|
+
const draggingRef = useRef7(false);
|
|
1138
|
+
const rootRef = useRef7(null);
|
|
1139
|
+
const drag = useRef7({ value: 0, clientY: 0, angle: 0, accum: 0 });
|
|
1140
|
+
const range = max - min;
|
|
1141
|
+
const keyStep = step > 0 ? step : range / 100 || 1;
|
|
1142
|
+
const percent = clamp(normalise(value, min, max), 0, 1);
|
|
1143
|
+
const angle = start + percent * sweep;
|
|
1144
|
+
const set = useCallback4(
|
|
1145
|
+
(next) => setValue(commit(next, min, max, step)),
|
|
1146
|
+
[setValue, min, max, step]
|
|
1147
|
+
);
|
|
1148
|
+
const pointerAngle = (event) => {
|
|
1149
|
+
const rect = rootRef.current?.getBoundingClientRect();
|
|
1150
|
+
if (!rect) return null;
|
|
1151
|
+
const dx = event.clientX - (rect.left + rect.width / 2);
|
|
1152
|
+
const dy = event.clientY - (rect.top + rect.height / 2);
|
|
1153
|
+
return Math.atan2(dy, dx) * (180 / Math.PI) + 90;
|
|
1154
|
+
};
|
|
1155
|
+
const fromAngle = (event) => {
|
|
1156
|
+
const raw = pointerAngle(event);
|
|
1157
|
+
if (raw === null) return;
|
|
1158
|
+
const mid = start + sweep / 2;
|
|
1159
|
+
let a = mid + wrapDeg(raw - mid);
|
|
1160
|
+
const end = start + sweep;
|
|
1161
|
+
if (a < Math.min(start, end) || a > Math.max(start, end)) {
|
|
1162
|
+
const toStart = Math.abs(wrapDeg(a - start));
|
|
1163
|
+
const toEnd = Math.abs(wrapDeg(a - end));
|
|
1164
|
+
a = toStart <= toEnd ? start : end;
|
|
1165
|
+
}
|
|
1166
|
+
set(denormalise((a - start) / (sweep || 1), min, max));
|
|
1167
|
+
};
|
|
1168
|
+
const fromDrag = (event) => {
|
|
1169
|
+
const dy = drag.current.clientY - event.clientY;
|
|
1170
|
+
drag.current.clientY = event.clientY;
|
|
1171
|
+
drag.current.accum += dy * (event.shiftKey ? 0.25 : 1);
|
|
1172
|
+
set(drag.current.value + drag.current.accum / dragDistance * range);
|
|
1173
|
+
};
|
|
1174
|
+
const fromDelta = (event) => {
|
|
1175
|
+
const raw = pointerAngle(event);
|
|
1176
|
+
if (raw === null) return;
|
|
1177
|
+
drag.current.accum += wrapDeg(raw - drag.current.angle);
|
|
1178
|
+
drag.current.angle = raw;
|
|
1179
|
+
const next = drag.current.value + drag.current.accum / (sweep || 360) * range;
|
|
1180
|
+
set(wrap && range > 0 ? min + ((next - min) % range + range) % range : next);
|
|
1181
|
+
};
|
|
1182
|
+
const track = (event) => {
|
|
1183
|
+
if (input === "angle") fromAngle(event);
|
|
1184
|
+
else if (input === "delta") fromDelta(event);
|
|
1185
|
+
else fromDrag(event);
|
|
1186
|
+
};
|
|
1187
|
+
const state = useMemo3(
|
|
1188
|
+
() => ({
|
|
1189
|
+
value,
|
|
1190
|
+
min,
|
|
1191
|
+
max,
|
|
1192
|
+
percent,
|
|
1193
|
+
angle,
|
|
1194
|
+
travelStart: start,
|
|
1195
|
+
travelSweep: sweep,
|
|
1196
|
+
detents: options.detents ?? (step > 0 && range > 0 ? Math.round(range / step) : 0),
|
|
1197
|
+
dragging,
|
|
1198
|
+
disabled,
|
|
1199
|
+
atMin: value <= min,
|
|
1200
|
+
atMax: value >= max
|
|
1201
|
+
}),
|
|
1202
|
+
[value, min, max, percent, angle, start, sweep, options.detents, step, range, dragging, disabled]
|
|
1203
|
+
);
|
|
1204
|
+
const onKeyDown = valueKeyHandler({ value, min, max, step: keyStep, disabled, onChange: setValue });
|
|
1205
|
+
const rootProps = {
|
|
1206
|
+
ref: rootRef,
|
|
1207
|
+
role: "slider",
|
|
1208
|
+
"aria-valuemin": min,
|
|
1209
|
+
"aria-valuemax": max,
|
|
1210
|
+
"aria-valuenow": value,
|
|
1211
|
+
"aria-orientation": "vertical",
|
|
1212
|
+
"aria-disabled": disabled || void 0,
|
|
1213
|
+
tabIndex: disabled ? -1 : 0,
|
|
1214
|
+
style: stateStyle(state),
|
|
1215
|
+
...stateData(state),
|
|
1216
|
+
onPointerDown: (event) => {
|
|
1217
|
+
if (disabled || event.button !== 0) return;
|
|
1218
|
+
capturePointer(event.currentTarget, event.pointerId);
|
|
1219
|
+
draggingRef.current = true;
|
|
1220
|
+
setDragging(true);
|
|
1221
|
+
drag.current = {
|
|
1222
|
+
value,
|
|
1223
|
+
clientY: event.clientY,
|
|
1224
|
+
angle: pointerAngle(event) ?? 0,
|
|
1225
|
+
accum: 0
|
|
1226
|
+
};
|
|
1227
|
+
if (input === "angle") fromAngle(event);
|
|
1228
|
+
},
|
|
1229
|
+
onPointerMove: (event) => {
|
|
1230
|
+
if (!draggingRef.current || disabled) return;
|
|
1231
|
+
track(event);
|
|
1232
|
+
},
|
|
1233
|
+
onPointerUp: () => {
|
|
1234
|
+
draggingRef.current = false;
|
|
1235
|
+
setDragging(false);
|
|
1236
|
+
},
|
|
1237
|
+
onPointerCancel: () => {
|
|
1238
|
+
draggingRef.current = false;
|
|
1239
|
+
setDragging(false);
|
|
1240
|
+
},
|
|
1241
|
+
onKeyDown: (event) => {
|
|
1242
|
+
onKeyDown(event);
|
|
1243
|
+
}
|
|
1244
|
+
};
|
|
1245
|
+
return { state, rootProps, setValue: set };
|
|
1246
|
+
}
|
|
1247
|
+
|
|
1248
|
+
// src/controls/AmbientRotary.tsx
|
|
1249
|
+
import { jsx as jsx18, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1250
|
+
function AmbientRotary({
|
|
1251
|
+
parts,
|
|
1252
|
+
size,
|
|
1253
|
+
animate = "auto",
|
|
1254
|
+
label,
|
|
1255
|
+
className,
|
|
1256
|
+
value,
|
|
1257
|
+
defaultValue,
|
|
1258
|
+
min,
|
|
1259
|
+
max,
|
|
1260
|
+
step,
|
|
1261
|
+
detents,
|
|
1262
|
+
travel: travel2,
|
|
1263
|
+
input,
|
|
1264
|
+
dragDistance,
|
|
1265
|
+
wrap,
|
|
1266
|
+
disabled,
|
|
1267
|
+
onChange,
|
|
1268
|
+
...rest
|
|
1269
|
+
}) {
|
|
1270
|
+
const labelId = useId5();
|
|
1271
|
+
const stackRef = useRef8(null);
|
|
1272
|
+
const { state, rootProps } = useRotary({
|
|
1273
|
+
value,
|
|
1274
|
+
defaultValue,
|
|
1275
|
+
min,
|
|
1276
|
+
max,
|
|
1277
|
+
step,
|
|
1278
|
+
detents,
|
|
1279
|
+
travel: travel2,
|
|
1280
|
+
input,
|
|
1281
|
+
dragDistance,
|
|
1282
|
+
wrap,
|
|
1283
|
+
disabled,
|
|
1284
|
+
onChange
|
|
1285
|
+
});
|
|
1286
|
+
useDevPartCheck(stackRef, "AmbientRotary");
|
|
1287
|
+
const sized = sizeProps("rotary", size);
|
|
1288
|
+
const { style: restStyle, ...restProps } = rest;
|
|
1289
|
+
const control = /* @__PURE__ */ jsx18(
|
|
1290
|
+
"div",
|
|
1291
|
+
{
|
|
1292
|
+
...restProps,
|
|
1293
|
+
...rootProps,
|
|
1294
|
+
"aria-labelledby": label ? labelId : rest["aria-labelledby"],
|
|
1295
|
+
"data-animate": animate,
|
|
1296
|
+
className: cn("ambx-control ambx-rotary", sized.className, className),
|
|
1297
|
+
style: { ...rootProps.style, ...sized.style, ...restStyle },
|
|
1298
|
+
children: /* @__PURE__ */ jsx18(ControlStateProvider, { value: state, children: /* @__PURE__ */ jsx18(Frames, { parts }) })
|
|
388
1299
|
}
|
|
1300
|
+
);
|
|
1301
|
+
return /* @__PURE__ */ jsxs8("div", { className: "ambx-stack", ref: stackRef, children: [
|
|
1302
|
+
control,
|
|
1303
|
+
label ? /* @__PURE__ */ jsx18("span", { id: labelId, className: "ambx-label", children: label }) : null
|
|
1304
|
+
] });
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1307
|
+
// src/components/AmbientKnob.tsx
|
|
1308
|
+
import { jsx as jsx19 } from "react/jsx-runtime";
|
|
1309
|
+
function AmbientKnob({
|
|
1310
|
+
material,
|
|
1311
|
+
knurling,
|
|
1312
|
+
knurlColor,
|
|
1313
|
+
markers,
|
|
1314
|
+
indicator,
|
|
1315
|
+
look,
|
|
1316
|
+
size = "md",
|
|
1317
|
+
className,
|
|
1318
|
+
travel: travel2,
|
|
1319
|
+
input,
|
|
1320
|
+
animate,
|
|
1321
|
+
...rest
|
|
1322
|
+
}) {
|
|
1323
|
+
const { dress, defaults } = useDress(
|
|
1324
|
+
"rotary",
|
|
1325
|
+
{ material, knurling, knurlColor, markers, indicator, ...look },
|
|
1326
|
+
groundedKit.rotary
|
|
1327
|
+
);
|
|
1328
|
+
return /* @__PURE__ */ jsx19(
|
|
1329
|
+
AmbientRotary,
|
|
1330
|
+
{
|
|
1331
|
+
...rest,
|
|
1332
|
+
travel: travel2 ?? defaults?.travel,
|
|
1333
|
+
input: input ?? defaults?.input,
|
|
1334
|
+
animate: animate ?? defaults?.animate,
|
|
1335
|
+
size,
|
|
1336
|
+
className: cn(dress.className, className),
|
|
1337
|
+
parts: dress.parts
|
|
1338
|
+
}
|
|
1339
|
+
);
|
|
1340
|
+
}
|
|
1341
|
+
|
|
1342
|
+
// src/controls/AmbientTravel.tsx
|
|
1343
|
+
import { useId as useId6, useRef as useRef10 } from "react";
|
|
1344
|
+
|
|
1345
|
+
// src/core/useTravel.ts
|
|
1346
|
+
import { useCallback as useCallback5, useMemo as useMemo4, useRef as useRef9, useState as useState4 } from "react";
|
|
1347
|
+
function useTravel(options) {
|
|
1348
|
+
const {
|
|
1349
|
+
min = 0,
|
|
1350
|
+
max = 100,
|
|
1351
|
+
step = 1,
|
|
1352
|
+
orientation = "horizontal",
|
|
1353
|
+
invert = false,
|
|
1354
|
+
disabled = false
|
|
1355
|
+
} = options;
|
|
1356
|
+
const [value, setValue] = useControllableValue(
|
|
1357
|
+
options.value,
|
|
1358
|
+
options.defaultValue ?? min,
|
|
1359
|
+
options.onChange
|
|
1360
|
+
);
|
|
1361
|
+
const [dragging, setDragging] = useState4(false);
|
|
1362
|
+
const draggingRef = useRef9(false);
|
|
1363
|
+
const rootRef = useRef9(null);
|
|
1364
|
+
const vertical = orientation === "vertical";
|
|
1365
|
+
const range = max - min;
|
|
1366
|
+
const keyStep = step > 0 ? step : range / 100 || 1;
|
|
1367
|
+
const percent = clamp(normalise(value, min, max), 0, 1);
|
|
1368
|
+
const set = useCallback5(
|
|
1369
|
+
(next) => setValue(commit(next, min, max, step)),
|
|
1370
|
+
[setValue, min, max, step]
|
|
1371
|
+
);
|
|
1372
|
+
const track = (event) => {
|
|
1373
|
+
const rect = rootRef.current?.getBoundingClientRect();
|
|
1374
|
+
if (!rect) return;
|
|
1375
|
+
const raw = vertical ? 1 - (event.clientY - rect.top) / (rect.height || 1) : (event.clientX - rect.left) / (rect.width || 1);
|
|
1376
|
+
set(denormalise(clamp(invert ? 1 - raw : raw, 0, 1), min, max));
|
|
389
1377
|
};
|
|
390
|
-
const
|
|
391
|
-
|
|
392
|
-
|
|
1378
|
+
const state = useMemo4(
|
|
1379
|
+
() => ({
|
|
1380
|
+
value,
|
|
1381
|
+
min,
|
|
1382
|
+
max,
|
|
1383
|
+
percent,
|
|
1384
|
+
angle: 0,
|
|
1385
|
+
travelStart: 0,
|
|
1386
|
+
travelSweep: 0,
|
|
1387
|
+
detents: options.detents ?? (step > 0 && range > 0 ? Math.round(range / step) : 0),
|
|
1388
|
+
dragging,
|
|
1389
|
+
disabled,
|
|
1390
|
+
atMin: value <= min,
|
|
1391
|
+
atMax: value >= max
|
|
1392
|
+
}),
|
|
1393
|
+
[value, min, max, percent, options.detents, step, range, dragging, disabled]
|
|
1394
|
+
);
|
|
1395
|
+
const onKeyDown = valueKeyHandler({
|
|
1396
|
+
value,
|
|
1397
|
+
min,
|
|
1398
|
+
max,
|
|
1399
|
+
step: keyStep,
|
|
1400
|
+
disabled,
|
|
1401
|
+
invert,
|
|
1402
|
+
onChange: setValue
|
|
1403
|
+
});
|
|
1404
|
+
const rootProps = {
|
|
1405
|
+
ref: rootRef,
|
|
1406
|
+
role: "slider",
|
|
1407
|
+
"aria-valuemin": min,
|
|
1408
|
+
"aria-valuemax": max,
|
|
1409
|
+
"aria-valuenow": value,
|
|
1410
|
+
"aria-orientation": orientation,
|
|
1411
|
+
"aria-disabled": disabled || void 0,
|
|
1412
|
+
tabIndex: disabled ? -1 : 0,
|
|
1413
|
+
style: stateStyle(state),
|
|
1414
|
+
"data-orientation": orientation,
|
|
1415
|
+
...stateData(state),
|
|
1416
|
+
onPointerDown: (event) => {
|
|
1417
|
+
if (disabled || event.button !== 0) return;
|
|
1418
|
+
capturePointer(event.currentTarget, event.pointerId);
|
|
1419
|
+
draggingRef.current = true;
|
|
1420
|
+
setDragging(true);
|
|
1421
|
+
track(event);
|
|
1422
|
+
},
|
|
1423
|
+
onPointerMove: (event) => {
|
|
1424
|
+
if (!draggingRef.current || disabled) return;
|
|
1425
|
+
track(event);
|
|
1426
|
+
},
|
|
1427
|
+
onPointerUp: () => {
|
|
1428
|
+
draggingRef.current = false;
|
|
1429
|
+
setDragging(false);
|
|
1430
|
+
},
|
|
1431
|
+
onPointerCancel: () => {
|
|
1432
|
+
draggingRef.current = false;
|
|
1433
|
+
setDragging(false);
|
|
1434
|
+
},
|
|
1435
|
+
onKeyDown: (event) => {
|
|
1436
|
+
onKeyDown(event);
|
|
1437
|
+
}
|
|
393
1438
|
};
|
|
394
|
-
return
|
|
395
|
-
|
|
1439
|
+
return { state, rootProps, setValue: set };
|
|
1440
|
+
}
|
|
1441
|
+
|
|
1442
|
+
// src/controls/AmbientTravel.tsx
|
|
1443
|
+
import { jsx as jsx20, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1444
|
+
function AmbientTravel({
|
|
1445
|
+
parts,
|
|
1446
|
+
size,
|
|
1447
|
+
animate = "auto",
|
|
1448
|
+
label,
|
|
1449
|
+
className,
|
|
1450
|
+
value,
|
|
1451
|
+
defaultValue,
|
|
1452
|
+
min,
|
|
1453
|
+
max,
|
|
1454
|
+
step,
|
|
1455
|
+
detents,
|
|
1456
|
+
orientation = "horizontal",
|
|
1457
|
+
invert,
|
|
1458
|
+
disabled,
|
|
1459
|
+
onChange,
|
|
1460
|
+
...rest
|
|
1461
|
+
}) {
|
|
1462
|
+
const labelId = useId6();
|
|
1463
|
+
const stackRef = useRef10(null);
|
|
1464
|
+
const { state, rootProps } = useTravel({
|
|
1465
|
+
value,
|
|
1466
|
+
defaultValue,
|
|
1467
|
+
min,
|
|
1468
|
+
max,
|
|
1469
|
+
step,
|
|
1470
|
+
detents,
|
|
1471
|
+
orientation,
|
|
1472
|
+
invert,
|
|
1473
|
+
disabled,
|
|
1474
|
+
onChange
|
|
1475
|
+
});
|
|
1476
|
+
useDevPartCheck(stackRef, "AmbientTravel");
|
|
1477
|
+
const sized = sizeProps("travel", size);
|
|
1478
|
+
const { style: restStyle, ...restProps } = rest;
|
|
1479
|
+
return /* @__PURE__ */ jsxs9("div", { className: "ambx-stack", ref: stackRef, children: [
|
|
1480
|
+
/* @__PURE__ */ jsx20(
|
|
396
1481
|
"div",
|
|
397
1482
|
{
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
|
|
401
|
-
"
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
updateFromClientY(event.clientY);
|
|
411
|
-
},
|
|
412
|
-
onPointerMove,
|
|
413
|
-
onKeyDown,
|
|
414
|
-
children: /* @__PURE__ */ jsx6(
|
|
415
|
-
"div",
|
|
416
|
-
{
|
|
417
|
-
className: cn("amb-fader-thumb ambient amb-fillet ambx-fader-thumb", material !== "glass" && "amb-surface-concave", material && `amb-mat-${material}`),
|
|
418
|
-
style: { top: `${100 - percent}%` },
|
|
419
|
-
children: /* @__PURE__ */ jsx6("span", { className: "amb-fader-gripline" })
|
|
420
|
-
}
|
|
421
|
-
)
|
|
1483
|
+
...restProps,
|
|
1484
|
+
...rootProps,
|
|
1485
|
+
"aria-labelledby": label ? labelId : rest["aria-labelledby"],
|
|
1486
|
+
"data-animate": animate,
|
|
1487
|
+
className: cn(
|
|
1488
|
+
"ambx-control ambx-travel",
|
|
1489
|
+
`ambx-travel-${orientation}`,
|
|
1490
|
+
sized.className,
|
|
1491
|
+
className
|
|
1492
|
+
),
|
|
1493
|
+
style: { ...rootProps.style, ...sized.style, ...restStyle },
|
|
1494
|
+
children: /* @__PURE__ */ jsx20(ControlStateProvider, { value: state, children: /* @__PURE__ */ jsx20(Frames, { parts }) })
|
|
422
1495
|
}
|
|
423
1496
|
),
|
|
424
|
-
label ? /* @__PURE__ */
|
|
1497
|
+
label ? /* @__PURE__ */ jsx20("span", { id: labelId, className: "ambx-label", children: label }) : null
|
|
425
1498
|
] });
|
|
426
1499
|
}
|
|
427
1500
|
|
|
428
|
-
// src/components/
|
|
429
|
-
import {
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
1501
|
+
// src/components/AmbientFader.tsx
|
|
1502
|
+
import { jsx as jsx21 } from "react/jsx-runtime";
|
|
1503
|
+
function AmbientFader({
|
|
1504
|
+
material,
|
|
1505
|
+
look,
|
|
1506
|
+
size = "md",
|
|
1507
|
+
animate,
|
|
1508
|
+
className,
|
|
1509
|
+
...rest
|
|
1510
|
+
}) {
|
|
1511
|
+
const { dress, defaults } = useDress(
|
|
1512
|
+
"travel",
|
|
1513
|
+
{ material, orientation: "vertical", ...look },
|
|
1514
|
+
groundedKit.travel
|
|
1515
|
+
);
|
|
1516
|
+
return /* @__PURE__ */ jsx21(
|
|
1517
|
+
AmbientTravel,
|
|
1518
|
+
{
|
|
1519
|
+
...rest,
|
|
1520
|
+
orientation: "vertical",
|
|
1521
|
+
size,
|
|
1522
|
+
animate: animate ?? defaults?.animate,
|
|
1523
|
+
className: cn(dress.className, className),
|
|
1524
|
+
parts: dress.parts
|
|
1525
|
+
}
|
|
1526
|
+
);
|
|
433
1527
|
}
|
|
1528
|
+
|
|
1529
|
+
// src/components/AmbientSlider.tsx
|
|
1530
|
+
import { jsx as jsx22 } from "react/jsx-runtime";
|
|
434
1531
|
function AmbientSlider({
|
|
435
|
-
value,
|
|
436
|
-
min = 0,
|
|
437
|
-
max = 100,
|
|
438
|
-
step = 1,
|
|
439
|
-
label,
|
|
440
1532
|
material,
|
|
441
|
-
|
|
1533
|
+
look,
|
|
1534
|
+
size = "md",
|
|
1535
|
+
animate,
|
|
442
1536
|
className,
|
|
443
|
-
...
|
|
1537
|
+
...rest
|
|
444
1538
|
}) {
|
|
445
|
-
const
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
1539
|
+
const { dress, defaults } = useDress(
|
|
1540
|
+
"travel",
|
|
1541
|
+
{ material, orientation: "horizontal", ...look },
|
|
1542
|
+
groundedKit.travel
|
|
1543
|
+
);
|
|
1544
|
+
return /* @__PURE__ */ jsx22(
|
|
1545
|
+
AmbientTravel,
|
|
1546
|
+
{
|
|
1547
|
+
...rest,
|
|
1548
|
+
orientation: "horizontal",
|
|
1549
|
+
size,
|
|
1550
|
+
animate: animate ?? defaults?.animate,
|
|
1551
|
+
className: cn(dress.className, className),
|
|
1552
|
+
parts: dress.parts
|
|
1553
|
+
}
|
|
1554
|
+
);
|
|
1555
|
+
}
|
|
1556
|
+
|
|
1557
|
+
// src/parts/console.tsx
|
|
1558
|
+
import { Fragment as Fragment4, jsx as jsx23, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1559
|
+
function ConsoleWell({ className }) {
|
|
1560
|
+
return /* @__PURE__ */ jsx23("span", { className: cn("amb-console-housing amb-groove", className), children: /* @__PURE__ */ jsx23("span", { className: "amb-console-face amb-surface" }) });
|
|
1561
|
+
}
|
|
1562
|
+
function ConsoleBar({ className }) {
|
|
1563
|
+
return /* @__PURE__ */ jsx23("span", { className: cn("amb-console-bar", className), children: /* @__PURE__ */ jsx23("span", { className: "amb-console-bar-body ambient amb-surface amb-chamfer amb-thickness-2", children: /* @__PURE__ */ jsx23("span", { className: "amb-console-indicator" }) }) });
|
|
1564
|
+
}
|
|
1565
|
+
function ConsoleMarks({
|
|
1566
|
+
mark = true,
|
|
1567
|
+
legend = true,
|
|
1568
|
+
className
|
|
1569
|
+
}) {
|
|
1570
|
+
return /* @__PURE__ */ jsxs10("span", { className: cn("amb-console-marks", className), "aria-hidden": true, children: [
|
|
1571
|
+
mark ? /* @__PURE__ */ jsx23("span", { className: "amb-console-mark" }) : null,
|
|
1572
|
+
legend ? /* @__PURE__ */ jsxs10(Fragment4, { children: [
|
|
1573
|
+
/* @__PURE__ */ jsx23("span", { className: "amb-console-legend amb-console-legend-min", children: "\u2212" }),
|
|
1574
|
+
/* @__PURE__ */ jsx23("span", { className: "amb-console-legend amb-console-legend-max", children: "+" })
|
|
1575
|
+
] }) : null
|
|
1576
|
+
] });
|
|
1577
|
+
}
|
|
1578
|
+
function ToggleTrack({ className }) {
|
|
1579
|
+
return /* @__PURE__ */ jsx23("span", { className: cn("amb-console-track amb-groove", className) });
|
|
1580
|
+
}
|
|
1581
|
+
function ToggleThumb({ className }) {
|
|
1582
|
+
return /* @__PURE__ */ jsx23("span", { className: cn("amb-console-thumb ambient amb-thickness-2", className) });
|
|
1583
|
+
}
|
|
1584
|
+
|
|
1585
|
+
// src/kits/console.tsx
|
|
1586
|
+
import { jsx as jsx24 } from "react/jsx-runtime";
|
|
1587
|
+
function rotary2(look) {
|
|
1588
|
+
const mark = look.mark !== false;
|
|
1589
|
+
const legend = look.legend !== false;
|
|
1590
|
+
return {
|
|
1591
|
+
className: cn(
|
|
1592
|
+
"amb-console-knob",
|
|
1593
|
+
mark && "amb-console-knob-marked",
|
|
1594
|
+
legend && "amb-console-knob-legended"
|
|
1595
|
+
),
|
|
1596
|
+
parts: {
|
|
1597
|
+
panel: mark || legend ? /* @__PURE__ */ jsx24(ConsoleMarks, { mark, legend }) : null,
|
|
1598
|
+
base: /* @__PURE__ */ jsx24(ConsoleWell, {}),
|
|
1599
|
+
actuator: /* @__PURE__ */ jsx24(ConsoleBar, {})
|
|
493
1600
|
}
|
|
494
1601
|
};
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
1602
|
+
}
|
|
1603
|
+
function latch2() {
|
|
1604
|
+
return {
|
|
1605
|
+
className: "amb-console-toggle",
|
|
1606
|
+
parts: { base: /* @__PURE__ */ jsx24(ToggleTrack, {}), actuator: /* @__PURE__ */ jsx24(ToggleThumb, {}) }
|
|
498
1607
|
};
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
"div",
|
|
521
|
-
{
|
|
522
|
-
className: cn("amb-slider-thumb ambient amb-fillet ambx-slider-thumb", material !== "glass" && "amb-surface-convex", material && `amb-mat-${material}`),
|
|
523
|
-
style: { left: `${percent}%` }
|
|
524
|
-
}
|
|
525
|
-
)
|
|
526
|
-
}
|
|
527
|
-
),
|
|
528
|
-
label ? /* @__PURE__ */ jsx7("span", { id, className: "ambx-label", children: label }) : null
|
|
529
|
-
] });
|
|
1608
|
+
}
|
|
1609
|
+
var consoleKit = {
|
|
1610
|
+
name: "console",
|
|
1611
|
+
rotary: rotary2,
|
|
1612
|
+
latch: latch2,
|
|
1613
|
+
/* A visual identity may say how its controls feel to turn. The desk knob
|
|
1614
|
+
this is drawn from is an absolute-position pot with a centre detent, so
|
|
1615
|
+
it grabs where you press rather than tracking a drag. */
|
|
1616
|
+
defaults: {
|
|
1617
|
+
rotary: { input: "angle", travel: 280 }
|
|
1618
|
+
},
|
|
1619
|
+
looks: {
|
|
1620
|
+
rotary: ["mark", "legend"],
|
|
1621
|
+
latch: []
|
|
1622
|
+
}
|
|
1623
|
+
};
|
|
1624
|
+
function ConsoleKnob({ mark, legend, ...rest }) {
|
|
1625
|
+
return /* @__PURE__ */ jsx24(AmbientKnob, { ...rest, look: { mark, legend } });
|
|
1626
|
+
}
|
|
1627
|
+
function ConsoleToggle(props) {
|
|
1628
|
+
return /* @__PURE__ */ jsx24(AmbientSwitch, { ...props });
|
|
530
1629
|
}
|
|
531
1630
|
export {
|
|
1631
|
+
AmbientBank,
|
|
532
1632
|
AmbientButton,
|
|
533
1633
|
AmbientFader,
|
|
1634
|
+
AmbientKitProvider,
|
|
534
1635
|
AmbientKnob,
|
|
1636
|
+
AmbientLatch,
|
|
535
1637
|
AmbientPanel,
|
|
1638
|
+
AmbientPress,
|
|
536
1639
|
AmbientProvider,
|
|
1640
|
+
AmbientRack,
|
|
1641
|
+
AmbientRotary,
|
|
1642
|
+
AmbientSelect,
|
|
537
1643
|
AmbientSlider,
|
|
538
|
-
AmbientSwitch
|
|
1644
|
+
AmbientSwitch,
|
|
1645
|
+
AmbientTravel,
|
|
1646
|
+
ButtonCap,
|
|
1647
|
+
ConsoleBar,
|
|
1648
|
+
ConsoleKnob,
|
|
1649
|
+
ConsoleMarks,
|
|
1650
|
+
ConsoleToggle,
|
|
1651
|
+
ConsoleWell,
|
|
1652
|
+
FaderCap,
|
|
1653
|
+
IndicatorBar,
|
|
1654
|
+
IndicatorDot,
|
|
1655
|
+
KeyCap,
|
|
1656
|
+
KeyLens,
|
|
1657
|
+
KnobBody,
|
|
1658
|
+
KnurledFace,
|
|
1659
|
+
Led,
|
|
1660
|
+
ScaleRing,
|
|
1661
|
+
SliderThumb,
|
|
1662
|
+
SwitchPill,
|
|
1663
|
+
SwitchTrack,
|
|
1664
|
+
ToggleThumb,
|
|
1665
|
+
ToggleTrack,
|
|
1666
|
+
TravelTrack,
|
|
1667
|
+
consoleKit,
|
|
1668
|
+
groundedKit,
|
|
1669
|
+
useBank,
|
|
1670
|
+
useBankKey,
|
|
1671
|
+
useControlState,
|
|
1672
|
+
useDress,
|
|
1673
|
+
useKit,
|
|
1674
|
+
useLatch,
|
|
1675
|
+
usePress,
|
|
1676
|
+
useRotary,
|
|
1677
|
+
useTravel
|
|
539
1678
|
};
|
|
540
1679
|
//# sourceMappingURL=index.js.map
|