@ambientcss/components 2.1.0 → 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 +1540 -391
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +749 -52
- package/dist/index.d.ts +749 -52
- package/dist/index.js +1501 -391
- package/dist/index.js.map +1 -1
- package/dist/styles.css +998 -291
- package/package.json +2 -2
- package/src/components/AmbientButton.tsx +23 -27
- package/src/components/AmbientFader.tsx +29 -115
- package/src/components/AmbientKnob.tsx +58 -220
- package/src/components/AmbientPanel.tsx +8 -2
- package/src/components/AmbientProvider.tsx +3 -0
- package/src/components/AmbientSelect.tsx +40 -0
- package/src/components/AmbientSlider.tsx +28 -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 +122 -2
- 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 +998 -291
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
|
|
@@ -73,497 +73,1607 @@ function AmbientRack({
|
|
|
73
73
|
);
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
// src/
|
|
77
|
-
import {
|
|
78
|
-
|
|
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,
|
|
79
276
|
className,
|
|
277
|
+
mode,
|
|
278
|
+
value,
|
|
279
|
+
defaultValue,
|
|
280
|
+
onChange,
|
|
281
|
+
onPress,
|
|
282
|
+
repeatDelay,
|
|
283
|
+
repeatInterval,
|
|
284
|
+
disabled,
|
|
80
285
|
children,
|
|
81
|
-
|
|
82
|
-
shape = "pill",
|
|
83
|
-
size = "md",
|
|
84
|
-
...props
|
|
286
|
+
...rest
|
|
85
287
|
}) {
|
|
86
|
-
|
|
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(
|
|
87
303
|
"button",
|
|
88
304
|
{
|
|
89
|
-
|
|
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
|
+
{
|
|
90
398
|
className: cn(
|
|
91
|
-
"amb-
|
|
92
|
-
`
|
|
93
|
-
shape === "round" && "amb-button-round",
|
|
94
|
-
shape === "square" && "amb-button-square",
|
|
399
|
+
"amb-knob-body ambient amb-thickness-2 amb-surface",
|
|
400
|
+
material && `amb-mat-${material}`,
|
|
95
401
|
className
|
|
96
402
|
),
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
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
|
|
106
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` }
|
|
449
|
+
},
|
|
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
|
|
107
502
|
)
|
|
108
503
|
}
|
|
109
504
|
);
|
|
110
505
|
}
|
|
111
506
|
|
|
112
|
-
// src/
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
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",
|
|
116
516
|
className,
|
|
117
|
-
|
|
118
|
-
defaultChecked,
|
|
119
|
-
onCheckedChange,
|
|
120
|
-
onClick,
|
|
121
|
-
size = "md",
|
|
122
|
-
label,
|
|
123
|
-
led,
|
|
124
|
-
children,
|
|
125
|
-
...props
|
|
517
|
+
children
|
|
126
518
|
}) {
|
|
127
|
-
const
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
const active = isControlled ? checked ?? false : internalChecked;
|
|
131
|
-
const button = /* @__PURE__ */ jsxs(
|
|
132
|
-
"button",
|
|
519
|
+
const relief = isRelief(material);
|
|
520
|
+
return /* @__PURE__ */ jsxs3(
|
|
521
|
+
"span",
|
|
133
522
|
{
|
|
134
|
-
type: "button",
|
|
135
|
-
role: "switch",
|
|
136
|
-
"aria-checked": active,
|
|
137
|
-
"aria-labelledby": label ? labelId : props["aria-labelledby"],
|
|
138
523
|
className: cn(
|
|
139
|
-
"amb-
|
|
140
|
-
|
|
141
|
-
"ambx-switch",
|
|
142
|
-
`ambx-switch-${size}`,
|
|
524
|
+
"amb-button-cap ambient amb-chamfer amb-surface amb-heading-3",
|
|
525
|
+
relief ? void 0 : `amb-mat-${material}`,
|
|
143
526
|
className
|
|
144
527
|
),
|
|
145
|
-
onClick: (event) => {
|
|
146
|
-
const next = !active;
|
|
147
|
-
if (!isControlled) setInternalChecked(next);
|
|
148
|
-
onCheckedChange?.(next);
|
|
149
|
-
onClick?.(event);
|
|
150
|
-
},
|
|
151
|
-
...props,
|
|
152
528
|
children: [
|
|
153
|
-
|
|
529
|
+
relief ? /* @__PURE__ */ jsx9(
|
|
154
530
|
"span",
|
|
155
531
|
{
|
|
156
|
-
className: cn("amb-
|
|
157
|
-
|
|
532
|
+
className: cn("ambx-cap-face ambient amb-chamfer amb-surface", `amb-mat-${material}`),
|
|
533
|
+
"aria-hidden": true
|
|
158
534
|
}
|
|
159
535
|
) : null,
|
|
160
|
-
/* @__PURE__ */ jsx5("span", { className: "amb-switch-track amb-groove", children: /* @__PURE__ */ jsx5("span", { className: "amb-switch-pill ambient amb-fillet amb-surface-convex" }) }),
|
|
161
536
|
children
|
|
162
537
|
]
|
|
163
538
|
}
|
|
164
539
|
);
|
|
165
|
-
if (!label) return button;
|
|
166
|
-
return /* @__PURE__ */ jsxs("div", { className: "ambx-stack", children: [
|
|
167
|
-
button,
|
|
168
|
-
/* @__PURE__ */ jsx5("span", { id: labelId, className: "ambx-label", children: label })
|
|
169
|
-
] });
|
|
170
540
|
}
|
|
171
541
|
|
|
172
|
-
// src/
|
|
173
|
-
import {
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
/*
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
[0, root],
|
|
191
|
-
[rise, outer],
|
|
192
|
-
[fall[0], outer],
|
|
193
|
-
[fall[1], root]
|
|
194
|
-
];
|
|
195
|
-
for (const [frac, radius] of tooth) {
|
|
196
|
-
const t = a + frac * pitch;
|
|
197
|
-
pts.push(
|
|
198
|
-
`${(0.5 + radius * Math.cos(t)).toFixed(4)} ${(0.5 + radius * Math.sin(t)).toFixed(4)}`
|
|
199
|
-
);
|
|
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
|
|
200
560
|
}
|
|
201
|
-
|
|
202
|
-
return `M${pts.join(" L")} Z`;
|
|
561
|
+
);
|
|
203
562
|
}
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
};
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
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
|
+
}
|
|
215
659
|
};
|
|
216
|
-
|
|
217
|
-
|
|
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
|
+
);
|
|
218
682
|
}
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
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",
|
|
224
734
|
label,
|
|
225
|
-
|
|
226
|
-
|
|
735
|
+
className,
|
|
736
|
+
value,
|
|
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({
|
|
227
779
|
size = "md",
|
|
780
|
+
led,
|
|
781
|
+
label,
|
|
782
|
+
look,
|
|
783
|
+
value,
|
|
784
|
+
defaultValue,
|
|
228
785
|
onChange,
|
|
786
|
+
animate,
|
|
229
787
|
className,
|
|
230
|
-
...
|
|
788
|
+
...rest
|
|
231
789
|
}) {
|
|
232
|
-
const
|
|
233
|
-
const
|
|
234
|
-
const
|
|
235
|
-
const
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
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]);
|
|
254
862
|
};
|
|
255
|
-
const
|
|
256
|
-
const
|
|
257
|
-
|
|
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]);
|
|
258
868
|
};
|
|
259
|
-
const onKeyDown = (event) => {
|
|
260
|
-
const
|
|
869
|
+
const onKeyDown = (event, index) => {
|
|
870
|
+
const back = orientation === "vertical" ? "ArrowUp" : "ArrowLeft";
|
|
871
|
+
const forward = orientation === "vertical" ? "ArrowDown" : "ArrowRight";
|
|
261
872
|
switch (event.key) {
|
|
262
|
-
case
|
|
263
|
-
case "ArrowRight":
|
|
264
|
-
event.preventDefault();
|
|
265
|
-
setValue(value + safeStep);
|
|
266
|
-
break;
|
|
267
|
-
case "ArrowDown":
|
|
268
|
-
case "ArrowLeft":
|
|
873
|
+
case back:
|
|
269
874
|
event.preventDefault();
|
|
270
|
-
|
|
875
|
+
step(index, -1);
|
|
271
876
|
break;
|
|
272
|
-
case
|
|
877
|
+
case forward:
|
|
273
878
|
event.preventDefault();
|
|
274
|
-
|
|
275
|
-
break;
|
|
276
|
-
case "PageDown":
|
|
277
|
-
event.preventDefault();
|
|
278
|
-
setValue(value - pageStep);
|
|
879
|
+
step(index, 1);
|
|
279
880
|
break;
|
|
280
881
|
case "Home":
|
|
281
882
|
event.preventDefault();
|
|
282
|
-
|
|
883
|
+
edge("first");
|
|
283
884
|
break;
|
|
284
885
|
case "End":
|
|
285
886
|
event.preventDefault();
|
|
286
|
-
|
|
887
|
+
edge("last");
|
|
888
|
+
break;
|
|
889
|
+
case " ":
|
|
890
|
+
case "Enter":
|
|
891
|
+
event.preventDefault();
|
|
892
|
+
select(items[index]);
|
|
287
893
|
break;
|
|
288
894
|
default:
|
|
289
895
|
break;
|
|
290
896
|
}
|
|
291
897
|
};
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
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",
|
|
326
998
|
{
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
children: [
|
|
336
|
-
variant === "dot" ? /* @__PURE__ */ jsx6("span", { className: "amb-knob-indicator-dot" }) : null,
|
|
337
|
-
variant === "line" ? /* @__PURE__ */ jsx6("span", { className: "amb-knob-indicator-line" }) : null,
|
|
338
|
-
variant === "flute" ? /* @__PURE__ */ jsx6("span", { className: "amb-knob-indicator-dot amb-knob-indicator-dot-center" }) : null
|
|
339
|
-
]
|
|
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 }) }) })
|
|
340
1007
|
}
|
|
341
|
-
)
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
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 })
|
|
346
1017
|
] });
|
|
347
1018
|
}
|
|
348
1019
|
|
|
349
|
-
// src/components/
|
|
350
|
-
import {
|
|
351
|
-
|
|
352
|
-
|
|
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) {
|
|
353
1043
|
return Math.min(max, Math.max(min, value));
|
|
354
1044
|
}
|
|
355
|
-
function
|
|
356
|
-
value
|
|
357
|
-
min
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
const
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
const snapped = Math.round(nextValue / safeStep) * safeStep;
|
|
378
|
-
onChange?.(clamp2(snapped, min, max));
|
|
379
|
-
};
|
|
380
|
-
const setValue = (nextValue) => {
|
|
381
|
-
const snapped = Math.round(nextValue / safeStep) * safeStep;
|
|
382
|
-
onChange?.(clamp2(snapped, min, max));
|
|
383
|
-
};
|
|
384
|
-
const onKeyDown = (event) => {
|
|
385
|
-
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
|
+
};
|
|
386
1067
|
switch (event.key) {
|
|
387
1068
|
case "ArrowUp":
|
|
388
1069
|
case "ArrowRight":
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
break;
|
|
1070
|
+
set(value + step * dir);
|
|
1071
|
+
return true;
|
|
392
1072
|
case "ArrowDown":
|
|
393
1073
|
case "ArrowLeft":
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
break;
|
|
1074
|
+
set(value - step * dir);
|
|
1075
|
+
return true;
|
|
397
1076
|
case "PageUp":
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
break;
|
|
1077
|
+
set(value + step * 10 * dir);
|
|
1078
|
+
return true;
|
|
401
1079
|
case "PageDown":
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
break;
|
|
1080
|
+
set(value - step * 10 * dir);
|
|
1081
|
+
return true;
|
|
405
1082
|
case "Home":
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
break;
|
|
1083
|
+
set(min);
|
|
1084
|
+
return true;
|
|
409
1085
|
case "End":
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
break;
|
|
1086
|
+
set(max);
|
|
1087
|
+
return true;
|
|
413
1088
|
default:
|
|
414
|
-
|
|
1089
|
+
return false;
|
|
415
1090
|
}
|
|
416
1091
|
};
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
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;
|
|
420
1154
|
};
|
|
421
|
-
|
|
422
|
-
|
|
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 }) })
|
|
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));
|
|
1377
|
+
};
|
|
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
|
+
}
|
|
1438
|
+
};
|
|
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(
|
|
423
1481
|
"div",
|
|
424
1482
|
{
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
"
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
updateFromClientY(event.clientY);
|
|
438
|
-
},
|
|
439
|
-
onPointerMove,
|
|
440
|
-
onKeyDown,
|
|
441
|
-
children: /* @__PURE__ */ jsx7(
|
|
442
|
-
"div",
|
|
443
|
-
{
|
|
444
|
-
className: cn("amb-fader-thumb ambient amb-fillet ambx-fader-thumb", material !== "glass" && "amb-surface-concave", material && `amb-mat-${material}`),
|
|
445
|
-
style: { top: `${100 - percent}%` },
|
|
446
|
-
children: /* @__PURE__ */ jsx7("span", { className: "amb-fader-gripline" })
|
|
447
|
-
}
|
|
448
|
-
)
|
|
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 }) })
|
|
449
1495
|
}
|
|
450
1496
|
),
|
|
451
|
-
label ? /* @__PURE__ */
|
|
1497
|
+
label ? /* @__PURE__ */ jsx20("span", { id: labelId, className: "ambx-label", children: label }) : null
|
|
452
1498
|
] });
|
|
453
1499
|
}
|
|
454
1500
|
|
|
455
|
-
// src/components/
|
|
456
|
-
import {
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
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
|
+
);
|
|
460
1527
|
}
|
|
1528
|
+
|
|
1529
|
+
// src/components/AmbientSlider.tsx
|
|
1530
|
+
import { jsx as jsx22 } from "react/jsx-runtime";
|
|
461
1531
|
function AmbientSlider({
|
|
462
|
-
value,
|
|
463
|
-
min = 0,
|
|
464
|
-
max = 100,
|
|
465
|
-
step = 1,
|
|
466
|
-
label,
|
|
467
1532
|
material,
|
|
1533
|
+
look,
|
|
468
1534
|
size = "md",
|
|
469
|
-
|
|
1535
|
+
animate,
|
|
470
1536
|
className,
|
|
471
|
-
...
|
|
1537
|
+
...rest
|
|
472
1538
|
}) {
|
|
473
|
-
const
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
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, {})
|
|
521
1600
|
}
|
|
522
1601
|
};
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
1602
|
+
}
|
|
1603
|
+
function latch2() {
|
|
1604
|
+
return {
|
|
1605
|
+
className: "amb-console-toggle",
|
|
1606
|
+
parts: { base: /* @__PURE__ */ jsx24(ToggleTrack, {}), actuator: /* @__PURE__ */ jsx24(ToggleThumb, {}) }
|
|
526
1607
|
};
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
"div",
|
|
549
|
-
{
|
|
550
|
-
className: cn("amb-slider-thumb ambient amb-fillet ambx-slider-thumb", material !== "glass" && "amb-surface-convex", material && `amb-mat-${material}`),
|
|
551
|
-
style: { left: `${percent}%` }
|
|
552
|
-
}
|
|
553
|
-
)
|
|
554
|
-
}
|
|
555
|
-
),
|
|
556
|
-
label ? /* @__PURE__ */ jsx8("span", { id, className: "ambx-label", children: label }) : null
|
|
557
|
-
] });
|
|
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 });
|
|
558
1629
|
}
|
|
559
1630
|
export {
|
|
1631
|
+
AmbientBank,
|
|
560
1632
|
AmbientButton,
|
|
561
1633
|
AmbientFader,
|
|
1634
|
+
AmbientKitProvider,
|
|
562
1635
|
AmbientKnob,
|
|
1636
|
+
AmbientLatch,
|
|
563
1637
|
AmbientPanel,
|
|
1638
|
+
AmbientPress,
|
|
564
1639
|
AmbientProvider,
|
|
565
1640
|
AmbientRack,
|
|
1641
|
+
AmbientRotary,
|
|
1642
|
+
AmbientSelect,
|
|
566
1643
|
AmbientSlider,
|
|
567
|
-
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
|
|
568
1678
|
};
|
|
569
1679
|
//# sourceMappingURL=index.js.map
|