@ambientcss/components 2.1.0 → 3.0.1
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 +1544 -392
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +750 -52
- package/dist/index.d.ts +750 -52
- package/dist/index.js +1505 -392
- package/dist/index.js.map +1 -1
- package/dist/styles.css +1045 -298
- package/package.json +10 -4
- 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 +139 -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 +165 -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 +101 -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 +1045 -298
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,1610 @@ 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
|
-
children: [
|
|
322
|
-
/* @__PURE__ */ jsx6("svg", { width: 0, height: 0, style: { position: "absolute" }, "aria-hidden": true, focusable: false, children: /* @__PURE__ */ jsx6("defs", { children: /* @__PURE__ */ jsx6("clipPath", { id: clipId, clipPathUnits: "objectBoundingBox", children: /* @__PURE__ */ jsx6("path", { d: KNURL_PATHS[family] }) }) }) }),
|
|
323
|
-
/* @__PURE__ */ jsx6("span", { className: "amb-knob-body ambient amb-thickness-2 amb-surface" }),
|
|
324
|
-
/* @__PURE__ */ jsxs2(
|
|
325
|
-
"div",
|
|
326
|
-
{
|
|
327
|
-
className: cn(
|
|
328
|
-
"ambx-knob-rotation amb-knob-face",
|
|
329
|
-
family === "flute" && "amb-knob-face-flute",
|
|
330
|
-
family === "fine" && "amb-knob-face-fine",
|
|
331
|
-
variant === "cap" && "amb-knob-face-cap",
|
|
332
|
-
material && `amb-mat-${material}`
|
|
333
|
-
),
|
|
334
|
-
style: { transform: `rotate(${rotation}deg)`, clipPath: `url(#${clipId})` },
|
|
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
|
-
]
|
|
340
|
-
}
|
|
341
|
-
)
|
|
342
|
-
]
|
|
343
|
-
}
|
|
344
|
-
),
|
|
345
|
-
label ? /* @__PURE__ */ jsx6("span", { id, className: "ambx-label", children: label }) : null
|
|
346
|
-
] });
|
|
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
|
+
/* No `key` here on purpose: the caller maps the options, so it owns
|
|
909
|
+
the list key. Spreading one into JSX makes React warn and drops
|
|
910
|
+
the key on release builds. */
|
|
911
|
+
type: "button",
|
|
912
|
+
ref: (node) => {
|
|
913
|
+
keyRefs.current[index] = node;
|
|
914
|
+
},
|
|
915
|
+
role: multiple ? "checkbox" : "radio",
|
|
916
|
+
"aria-checked": on,
|
|
917
|
+
"aria-label": option.ariaLabel,
|
|
918
|
+
title: option.ariaLabel,
|
|
919
|
+
disabled: option.disabled || disabled,
|
|
920
|
+
tabIndex: multiple ? 0 : index === tabStop ? 0 : -1,
|
|
921
|
+
"data-on": on ? "" : void 0,
|
|
922
|
+
onClick: () => select(option),
|
|
923
|
+
onKeyDown: (event) => onKeyDown(event, index)
|
|
924
|
+
};
|
|
925
|
+
};
|
|
926
|
+
return { selected, select, rootProps, keyProps };
|
|
347
927
|
}
|
|
348
928
|
|
|
349
|
-
// src/
|
|
350
|
-
import {
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
929
|
+
// src/controls/AmbientBank.tsx
|
|
930
|
+
import { jsx as jsx16, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
931
|
+
function keyState(on, disabled) {
|
|
932
|
+
return {
|
|
933
|
+
value: on ? 1 : 0,
|
|
934
|
+
min: 0,
|
|
935
|
+
max: 1,
|
|
936
|
+
percent: on ? 1 : 0,
|
|
937
|
+
angle: 0,
|
|
938
|
+
travelStart: 0,
|
|
939
|
+
travelSweep: 0,
|
|
940
|
+
detents: 2,
|
|
941
|
+
dragging: false,
|
|
942
|
+
disabled,
|
|
943
|
+
atMin: !on,
|
|
944
|
+
atMax: on
|
|
945
|
+
};
|
|
354
946
|
}
|
|
355
|
-
function
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
947
|
+
function AmbientBank({
|
|
948
|
+
options,
|
|
949
|
+
keyParts,
|
|
950
|
+
parts,
|
|
951
|
+
size,
|
|
952
|
+
color,
|
|
360
953
|
label,
|
|
361
|
-
|
|
362
|
-
size = "md",
|
|
363
|
-
onChange,
|
|
954
|
+
renderKey,
|
|
364
955
|
className,
|
|
365
|
-
|
|
956
|
+
style,
|
|
957
|
+
value,
|
|
958
|
+
defaultValue,
|
|
959
|
+
onChange,
|
|
960
|
+
multiple,
|
|
961
|
+
orientation = "vertical",
|
|
962
|
+
disabled = false,
|
|
963
|
+
...rest
|
|
366
964
|
}) {
|
|
367
|
-
const
|
|
368
|
-
const
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
965
|
+
const labelId = useId4();
|
|
966
|
+
const { selected, rootProps, keyProps } = useBank({
|
|
967
|
+
options,
|
|
968
|
+
value,
|
|
969
|
+
defaultValue,
|
|
970
|
+
onChange,
|
|
971
|
+
multiple,
|
|
972
|
+
orientation,
|
|
973
|
+
disabled
|
|
974
|
+
});
|
|
975
|
+
const sized = sizeProps("bank", size);
|
|
976
|
+
const bank2 = /* @__PURE__ */ jsxs7(
|
|
977
|
+
"div",
|
|
978
|
+
{
|
|
979
|
+
...rest,
|
|
980
|
+
...rootProps,
|
|
981
|
+
"aria-labelledby": label ? labelId : rest["aria-labelledby"],
|
|
982
|
+
className: cn(
|
|
983
|
+
"ambx-control ambx-bank",
|
|
984
|
+
`ambx-bank-${orientation}`,
|
|
985
|
+
sized.className,
|
|
986
|
+
className
|
|
987
|
+
),
|
|
988
|
+
style: {
|
|
989
|
+
...color ? { "--amb-led-color": color } : null,
|
|
990
|
+
...sized.style,
|
|
991
|
+
...style
|
|
992
|
+
},
|
|
993
|
+
children: [
|
|
994
|
+
/* @__PURE__ */ jsx16(Frames, { parts }),
|
|
995
|
+
options.map((option, index) => {
|
|
996
|
+
const on = selected.includes(option.value);
|
|
997
|
+
const ks = keyState(on, option.disabled || disabled);
|
|
998
|
+
return /* @__PURE__ */ jsx16(
|
|
999
|
+
"button",
|
|
1000
|
+
{
|
|
1001
|
+
...keyProps(option, index),
|
|
1002
|
+
...stateData(ks),
|
|
1003
|
+
className: "ambx-key",
|
|
1004
|
+
style: {
|
|
1005
|
+
...stateStyle(ks),
|
|
1006
|
+
...option.color ? { "--amb-led-color": option.color } : null
|
|
1007
|
+
},
|
|
1008
|
+
children: /* @__PURE__ */ jsx16(ControlStateProvider, { value: ks, children: /* @__PURE__ */ jsx16(BankKeyProvider, { value: { option, on, index }, children: renderKey ? renderKey(option, on) : /* @__PURE__ */ jsx16(Frames, { parts: keyParts }) }) })
|
|
1009
|
+
},
|
|
1010
|
+
option.value
|
|
1011
|
+
);
|
|
1012
|
+
})
|
|
1013
|
+
]
|
|
1014
|
+
}
|
|
1015
|
+
);
|
|
1016
|
+
if (!label) return bank2;
|
|
1017
|
+
return /* @__PURE__ */ jsxs7("div", { className: "ambx-stack", children: [
|
|
1018
|
+
bank2,
|
|
1019
|
+
/* @__PURE__ */ jsx16("span", { id: labelId, className: "ambx-label", children: label })
|
|
1020
|
+
] });
|
|
1021
|
+
}
|
|
1022
|
+
|
|
1023
|
+
// src/components/AmbientSelect.tsx
|
|
1024
|
+
import { jsx as jsx17 } from "react/jsx-runtime";
|
|
1025
|
+
function AmbientSelect({ size = "md", look, className, ...rest }) {
|
|
1026
|
+
const { dress } = useDress("bank", { ...look }, groundedKit.bank);
|
|
1027
|
+
return /* @__PURE__ */ jsx17(
|
|
1028
|
+
AmbientBank,
|
|
1029
|
+
{
|
|
1030
|
+
...rest,
|
|
1031
|
+
size,
|
|
1032
|
+
className: cn(dress.className, className),
|
|
1033
|
+
keyParts: dress.parts
|
|
1034
|
+
}
|
|
1035
|
+
);
|
|
1036
|
+
}
|
|
1037
|
+
|
|
1038
|
+
// src/controls/AmbientRotary.tsx
|
|
1039
|
+
import { useId as useId5, useRef as useRef8 } from "react";
|
|
1040
|
+
|
|
1041
|
+
// src/core/useRotary.ts
|
|
1042
|
+
import { useCallback as useCallback4, useMemo as useMemo3, useRef as useRef7, useState as useState3 } from "react";
|
|
1043
|
+
|
|
1044
|
+
// src/core/numeric.ts
|
|
1045
|
+
function clamp(value, min, max) {
|
|
1046
|
+
return Math.min(max, Math.max(min, value));
|
|
1047
|
+
}
|
|
1048
|
+
function snap(value, min, step) {
|
|
1049
|
+
if (!(step > 0)) return value;
|
|
1050
|
+
return min + Math.round((value - min) / step) * step;
|
|
1051
|
+
}
|
|
1052
|
+
function normalise(value, min, max) {
|
|
1053
|
+
return (value - min) / (max - min || 1);
|
|
1054
|
+
}
|
|
1055
|
+
function denormalise(t, min, max) {
|
|
1056
|
+
return min + t * (max - min);
|
|
1057
|
+
}
|
|
1058
|
+
function commit(value, min, max, step) {
|
|
1059
|
+
return clamp(snap(value, min, max === min ? 1 : step), min, max);
|
|
1060
|
+
}
|
|
1061
|
+
function valueKeyHandler(options) {
|
|
1062
|
+
return (event) => {
|
|
1063
|
+
const { value, min, max, step, invert, onChange, disabled } = options;
|
|
1064
|
+
if (disabled) return false;
|
|
1065
|
+
const dir = invert ? -1 : 1;
|
|
1066
|
+
const set = (next) => {
|
|
1067
|
+
event.preventDefault();
|
|
1068
|
+
onChange(commit(next, min, max, step));
|
|
1069
|
+
};
|
|
386
1070
|
switch (event.key) {
|
|
387
1071
|
case "ArrowUp":
|
|
388
1072
|
case "ArrowRight":
|
|
389
|
-
|
|
390
|
-
|
|
391
|
-
break;
|
|
1073
|
+
set(value + step * dir);
|
|
1074
|
+
return true;
|
|
392
1075
|
case "ArrowDown":
|
|
393
1076
|
case "ArrowLeft":
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
break;
|
|
1077
|
+
set(value - step * dir);
|
|
1078
|
+
return true;
|
|
397
1079
|
case "PageUp":
|
|
398
|
-
|
|
399
|
-
|
|
400
|
-
break;
|
|
1080
|
+
set(value + step * 10 * dir);
|
|
1081
|
+
return true;
|
|
401
1082
|
case "PageDown":
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
break;
|
|
1083
|
+
set(value - step * 10 * dir);
|
|
1084
|
+
return true;
|
|
405
1085
|
case "Home":
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
break;
|
|
1086
|
+
set(min);
|
|
1087
|
+
return true;
|
|
409
1088
|
case "End":
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
break;
|
|
1089
|
+
set(max);
|
|
1090
|
+
return true;
|
|
413
1091
|
default:
|
|
414
|
-
|
|
1092
|
+
return false;
|
|
415
1093
|
}
|
|
416
1094
|
};
|
|
417
|
-
|
|
418
|
-
|
|
419
|
-
|
|
1095
|
+
}
|
|
1096
|
+
|
|
1097
|
+
// src/core/useRotary.ts
|
|
1098
|
+
var DEFAULT_TRAVEL = { start: -135, sweep: 270 };
|
|
1099
|
+
function wrapDeg(deg) {
|
|
1100
|
+
return ((deg + 180) % 360 + 360) % 360 - 180;
|
|
1101
|
+
}
|
|
1102
|
+
function resolveTravel(travel2) {
|
|
1103
|
+
if (travel2 === void 0) return DEFAULT_TRAVEL;
|
|
1104
|
+
if (typeof travel2 === "number") return { start: -travel2 / 2, sweep: travel2 };
|
|
1105
|
+
return travel2;
|
|
1106
|
+
}
|
|
1107
|
+
var warnedFullTurn = false;
|
|
1108
|
+
function capturePointer(target, pointerId) {
|
|
1109
|
+
try {
|
|
1110
|
+
target.setPointerCapture?.(pointerId);
|
|
1111
|
+
} catch {
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
function useRotary(options) {
|
|
1115
|
+
const {
|
|
1116
|
+
min = 0,
|
|
1117
|
+
max = 100,
|
|
1118
|
+
step = 1,
|
|
1119
|
+
dragDistance = 200,
|
|
1120
|
+
wrap = false,
|
|
1121
|
+
disabled = false
|
|
1122
|
+
} = options;
|
|
1123
|
+
const { start, sweep } = resolveTravel(options.travel);
|
|
1124
|
+
let input = options.input ?? "drag";
|
|
1125
|
+
if (input === "angle" && Math.abs(sweep) >= 360) {
|
|
1126
|
+
if (isDev && !warnedFullTurn) {
|
|
1127
|
+
warnedFullTurn = true;
|
|
1128
|
+
console.warn(
|
|
1129
|
+
`[@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".`
|
|
1130
|
+
);
|
|
1131
|
+
}
|
|
1132
|
+
input = "drag";
|
|
1133
|
+
}
|
|
1134
|
+
const [value, setValue] = useControllableValue(
|
|
1135
|
+
options.value,
|
|
1136
|
+
options.defaultValue ?? min,
|
|
1137
|
+
options.onChange
|
|
1138
|
+
);
|
|
1139
|
+
const [dragging, setDragging] = useState3(false);
|
|
1140
|
+
const draggingRef = useRef7(false);
|
|
1141
|
+
const rootRef = useRef7(null);
|
|
1142
|
+
const drag = useRef7({ value: 0, clientY: 0, angle: 0, accum: 0 });
|
|
1143
|
+
const range = max - min;
|
|
1144
|
+
const keyStep = step > 0 ? step : range / 100 || 1;
|
|
1145
|
+
const percent = clamp(normalise(value, min, max), 0, 1);
|
|
1146
|
+
const angle = start + percent * sweep;
|
|
1147
|
+
const set = useCallback4(
|
|
1148
|
+
(next) => setValue(commit(next, min, max, step)),
|
|
1149
|
+
[setValue, min, max, step]
|
|
1150
|
+
);
|
|
1151
|
+
const pointerAngle = (event) => {
|
|
1152
|
+
const rect = rootRef.current?.getBoundingClientRect();
|
|
1153
|
+
if (!rect) return null;
|
|
1154
|
+
const dx = event.clientX - (rect.left + rect.width / 2);
|
|
1155
|
+
const dy = event.clientY - (rect.top + rect.height / 2);
|
|
1156
|
+
return Math.atan2(dy, dx) * (180 / Math.PI) + 90;
|
|
420
1157
|
};
|
|
421
|
-
|
|
422
|
-
|
|
1158
|
+
const fromAngle = (event) => {
|
|
1159
|
+
const raw = pointerAngle(event);
|
|
1160
|
+
if (raw === null) return;
|
|
1161
|
+
const mid = start + sweep / 2;
|
|
1162
|
+
let a = mid + wrapDeg(raw - mid);
|
|
1163
|
+
const end = start + sweep;
|
|
1164
|
+
if (a < Math.min(start, end) || a > Math.max(start, end)) {
|
|
1165
|
+
const toStart = Math.abs(wrapDeg(a - start));
|
|
1166
|
+
const toEnd = Math.abs(wrapDeg(a - end));
|
|
1167
|
+
a = toStart <= toEnd ? start : end;
|
|
1168
|
+
}
|
|
1169
|
+
set(denormalise((a - start) / (sweep || 1), min, max));
|
|
1170
|
+
};
|
|
1171
|
+
const fromDrag = (event) => {
|
|
1172
|
+
const dy = drag.current.clientY - event.clientY;
|
|
1173
|
+
drag.current.clientY = event.clientY;
|
|
1174
|
+
drag.current.accum += dy * (event.shiftKey ? 0.25 : 1);
|
|
1175
|
+
set(drag.current.value + drag.current.accum / dragDistance * range);
|
|
1176
|
+
};
|
|
1177
|
+
const fromDelta = (event) => {
|
|
1178
|
+
const raw = pointerAngle(event);
|
|
1179
|
+
if (raw === null) return;
|
|
1180
|
+
drag.current.accum += wrapDeg(raw - drag.current.angle);
|
|
1181
|
+
drag.current.angle = raw;
|
|
1182
|
+
const next = drag.current.value + drag.current.accum / (sweep || 360) * range;
|
|
1183
|
+
set(wrap && range > 0 ? min + ((next - min) % range + range) % range : next);
|
|
1184
|
+
};
|
|
1185
|
+
const track = (event) => {
|
|
1186
|
+
if (input === "angle") fromAngle(event);
|
|
1187
|
+
else if (input === "delta") fromDelta(event);
|
|
1188
|
+
else fromDrag(event);
|
|
1189
|
+
};
|
|
1190
|
+
const state = useMemo3(
|
|
1191
|
+
() => ({
|
|
1192
|
+
value,
|
|
1193
|
+
min,
|
|
1194
|
+
max,
|
|
1195
|
+
percent,
|
|
1196
|
+
angle,
|
|
1197
|
+
travelStart: start,
|
|
1198
|
+
travelSweep: sweep,
|
|
1199
|
+
detents: options.detents ?? (step > 0 && range > 0 ? Math.round(range / step) : 0),
|
|
1200
|
+
dragging,
|
|
1201
|
+
disabled,
|
|
1202
|
+
atMin: value <= min,
|
|
1203
|
+
atMax: value >= max
|
|
1204
|
+
}),
|
|
1205
|
+
[value, min, max, percent, angle, start, sweep, options.detents, step, range, dragging, disabled]
|
|
1206
|
+
);
|
|
1207
|
+
const onKeyDown = valueKeyHandler({ value, min, max, step: keyStep, disabled, onChange: setValue });
|
|
1208
|
+
const rootProps = {
|
|
1209
|
+
ref: rootRef,
|
|
1210
|
+
role: "slider",
|
|
1211
|
+
"aria-valuemin": min,
|
|
1212
|
+
"aria-valuemax": max,
|
|
1213
|
+
"aria-valuenow": value,
|
|
1214
|
+
"aria-orientation": "vertical",
|
|
1215
|
+
"aria-disabled": disabled || void 0,
|
|
1216
|
+
tabIndex: disabled ? -1 : 0,
|
|
1217
|
+
style: stateStyle(state),
|
|
1218
|
+
...stateData(state),
|
|
1219
|
+
onPointerDown: (event) => {
|
|
1220
|
+
if (disabled || event.button !== 0) return;
|
|
1221
|
+
capturePointer(event.currentTarget, event.pointerId);
|
|
1222
|
+
draggingRef.current = true;
|
|
1223
|
+
setDragging(true);
|
|
1224
|
+
drag.current = {
|
|
1225
|
+
value,
|
|
1226
|
+
clientY: event.clientY,
|
|
1227
|
+
angle: pointerAngle(event) ?? 0,
|
|
1228
|
+
accum: 0
|
|
1229
|
+
};
|
|
1230
|
+
if (input === "angle") fromAngle(event);
|
|
1231
|
+
},
|
|
1232
|
+
onPointerMove: (event) => {
|
|
1233
|
+
if (!draggingRef.current || disabled) return;
|
|
1234
|
+
track(event);
|
|
1235
|
+
},
|
|
1236
|
+
onPointerUp: () => {
|
|
1237
|
+
draggingRef.current = false;
|
|
1238
|
+
setDragging(false);
|
|
1239
|
+
},
|
|
1240
|
+
onPointerCancel: () => {
|
|
1241
|
+
draggingRef.current = false;
|
|
1242
|
+
setDragging(false);
|
|
1243
|
+
},
|
|
1244
|
+
onKeyDown: (event) => {
|
|
1245
|
+
onKeyDown(event);
|
|
1246
|
+
}
|
|
1247
|
+
};
|
|
1248
|
+
return { state, rootProps, setValue: set };
|
|
1249
|
+
}
|
|
1250
|
+
|
|
1251
|
+
// src/controls/AmbientRotary.tsx
|
|
1252
|
+
import { jsx as jsx18, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
1253
|
+
function AmbientRotary({
|
|
1254
|
+
parts,
|
|
1255
|
+
size,
|
|
1256
|
+
animate = "auto",
|
|
1257
|
+
label,
|
|
1258
|
+
className,
|
|
1259
|
+
value,
|
|
1260
|
+
defaultValue,
|
|
1261
|
+
min,
|
|
1262
|
+
max,
|
|
1263
|
+
step,
|
|
1264
|
+
detents,
|
|
1265
|
+
travel: travel2,
|
|
1266
|
+
input,
|
|
1267
|
+
dragDistance,
|
|
1268
|
+
wrap,
|
|
1269
|
+
disabled,
|
|
1270
|
+
onChange,
|
|
1271
|
+
...rest
|
|
1272
|
+
}) {
|
|
1273
|
+
const labelId = useId5();
|
|
1274
|
+
const stackRef = useRef8(null);
|
|
1275
|
+
const { state, rootProps } = useRotary({
|
|
1276
|
+
value,
|
|
1277
|
+
defaultValue,
|
|
1278
|
+
min,
|
|
1279
|
+
max,
|
|
1280
|
+
step,
|
|
1281
|
+
detents,
|
|
1282
|
+
travel: travel2,
|
|
1283
|
+
input,
|
|
1284
|
+
dragDistance,
|
|
1285
|
+
wrap,
|
|
1286
|
+
disabled,
|
|
1287
|
+
onChange
|
|
1288
|
+
});
|
|
1289
|
+
useDevPartCheck(stackRef, "AmbientRotary");
|
|
1290
|
+
const sized = sizeProps("rotary", size);
|
|
1291
|
+
const { style: restStyle, ...restProps } = rest;
|
|
1292
|
+
const control = /* @__PURE__ */ jsx18(
|
|
1293
|
+
"div",
|
|
1294
|
+
{
|
|
1295
|
+
...restProps,
|
|
1296
|
+
...rootProps,
|
|
1297
|
+
"aria-labelledby": label ? labelId : rest["aria-labelledby"],
|
|
1298
|
+
"data-animate": animate,
|
|
1299
|
+
className: cn("ambx-control ambx-rotary", sized.className, className),
|
|
1300
|
+
style: { ...rootProps.style, ...sized.style, ...restStyle },
|
|
1301
|
+
children: /* @__PURE__ */ jsx18(ControlStateProvider, { value: state, children: /* @__PURE__ */ jsx18(Frames, { parts }) })
|
|
1302
|
+
}
|
|
1303
|
+
);
|
|
1304
|
+
return /* @__PURE__ */ jsxs8("div", { className: "ambx-stack", ref: stackRef, children: [
|
|
1305
|
+
control,
|
|
1306
|
+
label ? /* @__PURE__ */ jsx18("span", { id: labelId, className: "ambx-label", children: label }) : null
|
|
1307
|
+
] });
|
|
1308
|
+
}
|
|
1309
|
+
|
|
1310
|
+
// src/components/AmbientKnob.tsx
|
|
1311
|
+
import { jsx as jsx19 } from "react/jsx-runtime";
|
|
1312
|
+
function AmbientKnob({
|
|
1313
|
+
material,
|
|
1314
|
+
knurling,
|
|
1315
|
+
knurlColor,
|
|
1316
|
+
markers,
|
|
1317
|
+
indicator,
|
|
1318
|
+
look,
|
|
1319
|
+
size = "md",
|
|
1320
|
+
className,
|
|
1321
|
+
travel: travel2,
|
|
1322
|
+
input,
|
|
1323
|
+
animate,
|
|
1324
|
+
...rest
|
|
1325
|
+
}) {
|
|
1326
|
+
const { dress, defaults } = useDress(
|
|
1327
|
+
"rotary",
|
|
1328
|
+
{ material, knurling, knurlColor, markers, indicator, ...look },
|
|
1329
|
+
groundedKit.rotary
|
|
1330
|
+
);
|
|
1331
|
+
return /* @__PURE__ */ jsx19(
|
|
1332
|
+
AmbientRotary,
|
|
1333
|
+
{
|
|
1334
|
+
...rest,
|
|
1335
|
+
travel: travel2 ?? defaults?.travel,
|
|
1336
|
+
input: input ?? defaults?.input,
|
|
1337
|
+
animate: animate ?? defaults?.animate,
|
|
1338
|
+
size,
|
|
1339
|
+
className: cn(dress.className, className),
|
|
1340
|
+
parts: dress.parts
|
|
1341
|
+
}
|
|
1342
|
+
);
|
|
1343
|
+
}
|
|
1344
|
+
|
|
1345
|
+
// src/controls/AmbientTravel.tsx
|
|
1346
|
+
import { useId as useId6, useRef as useRef10 } from "react";
|
|
1347
|
+
|
|
1348
|
+
// src/core/useTravel.ts
|
|
1349
|
+
import { useCallback as useCallback5, useMemo as useMemo4, useRef as useRef9, useState as useState4 } from "react";
|
|
1350
|
+
function useTravel(options) {
|
|
1351
|
+
const {
|
|
1352
|
+
min = 0,
|
|
1353
|
+
max = 100,
|
|
1354
|
+
step = 1,
|
|
1355
|
+
orientation = "horizontal",
|
|
1356
|
+
invert = false,
|
|
1357
|
+
disabled = false
|
|
1358
|
+
} = options;
|
|
1359
|
+
const [value, setValue] = useControllableValue(
|
|
1360
|
+
options.value,
|
|
1361
|
+
options.defaultValue ?? min,
|
|
1362
|
+
options.onChange
|
|
1363
|
+
);
|
|
1364
|
+
const [dragging, setDragging] = useState4(false);
|
|
1365
|
+
const draggingRef = useRef9(false);
|
|
1366
|
+
const rootRef = useRef9(null);
|
|
1367
|
+
const vertical = orientation === "vertical";
|
|
1368
|
+
const range = max - min;
|
|
1369
|
+
const keyStep = step > 0 ? step : range / 100 || 1;
|
|
1370
|
+
const percent = clamp(normalise(value, min, max), 0, 1);
|
|
1371
|
+
const set = useCallback5(
|
|
1372
|
+
(next) => setValue(commit(next, min, max, step)),
|
|
1373
|
+
[setValue, min, max, step]
|
|
1374
|
+
);
|
|
1375
|
+
const track = (event) => {
|
|
1376
|
+
const rect = rootRef.current?.getBoundingClientRect();
|
|
1377
|
+
if (!rect) return;
|
|
1378
|
+
const raw = vertical ? 1 - (event.clientY - rect.top) / (rect.height || 1) : (event.clientX - rect.left) / (rect.width || 1);
|
|
1379
|
+
set(denormalise(clamp(invert ? 1 - raw : raw, 0, 1), min, max));
|
|
1380
|
+
};
|
|
1381
|
+
const state = useMemo4(
|
|
1382
|
+
() => ({
|
|
1383
|
+
value,
|
|
1384
|
+
min,
|
|
1385
|
+
max,
|
|
1386
|
+
percent,
|
|
1387
|
+
angle: 0,
|
|
1388
|
+
travelStart: 0,
|
|
1389
|
+
travelSweep: 0,
|
|
1390
|
+
detents: options.detents ?? (step > 0 && range > 0 ? Math.round(range / step) : 0),
|
|
1391
|
+
dragging,
|
|
1392
|
+
disabled,
|
|
1393
|
+
atMin: value <= min,
|
|
1394
|
+
atMax: value >= max
|
|
1395
|
+
}),
|
|
1396
|
+
[value, min, max, percent, options.detents, step, range, dragging, disabled]
|
|
1397
|
+
);
|
|
1398
|
+
const onKeyDown = valueKeyHandler({
|
|
1399
|
+
value,
|
|
1400
|
+
min,
|
|
1401
|
+
max,
|
|
1402
|
+
step: keyStep,
|
|
1403
|
+
disabled,
|
|
1404
|
+
invert,
|
|
1405
|
+
onChange: setValue
|
|
1406
|
+
});
|
|
1407
|
+
const rootProps = {
|
|
1408
|
+
ref: rootRef,
|
|
1409
|
+
role: "slider",
|
|
1410
|
+
"aria-valuemin": min,
|
|
1411
|
+
"aria-valuemax": max,
|
|
1412
|
+
"aria-valuenow": value,
|
|
1413
|
+
"aria-orientation": orientation,
|
|
1414
|
+
"aria-disabled": disabled || void 0,
|
|
1415
|
+
tabIndex: disabled ? -1 : 0,
|
|
1416
|
+
style: stateStyle(state),
|
|
1417
|
+
"data-orientation": orientation,
|
|
1418
|
+
...stateData(state),
|
|
1419
|
+
onPointerDown: (event) => {
|
|
1420
|
+
if (disabled || event.button !== 0) return;
|
|
1421
|
+
capturePointer(event.currentTarget, event.pointerId);
|
|
1422
|
+
draggingRef.current = true;
|
|
1423
|
+
setDragging(true);
|
|
1424
|
+
track(event);
|
|
1425
|
+
},
|
|
1426
|
+
onPointerMove: (event) => {
|
|
1427
|
+
if (!draggingRef.current || disabled) return;
|
|
1428
|
+
track(event);
|
|
1429
|
+
},
|
|
1430
|
+
onPointerUp: () => {
|
|
1431
|
+
draggingRef.current = false;
|
|
1432
|
+
setDragging(false);
|
|
1433
|
+
},
|
|
1434
|
+
onPointerCancel: () => {
|
|
1435
|
+
draggingRef.current = false;
|
|
1436
|
+
setDragging(false);
|
|
1437
|
+
},
|
|
1438
|
+
onKeyDown: (event) => {
|
|
1439
|
+
onKeyDown(event);
|
|
1440
|
+
}
|
|
1441
|
+
};
|
|
1442
|
+
return { state, rootProps, setValue: set };
|
|
1443
|
+
}
|
|
1444
|
+
|
|
1445
|
+
// src/controls/AmbientTravel.tsx
|
|
1446
|
+
import { jsx as jsx20, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
1447
|
+
function AmbientTravel({
|
|
1448
|
+
parts,
|
|
1449
|
+
size,
|
|
1450
|
+
animate = "auto",
|
|
1451
|
+
label,
|
|
1452
|
+
className,
|
|
1453
|
+
value,
|
|
1454
|
+
defaultValue,
|
|
1455
|
+
min,
|
|
1456
|
+
max,
|
|
1457
|
+
step,
|
|
1458
|
+
detents,
|
|
1459
|
+
orientation = "horizontal",
|
|
1460
|
+
invert,
|
|
1461
|
+
disabled,
|
|
1462
|
+
onChange,
|
|
1463
|
+
...rest
|
|
1464
|
+
}) {
|
|
1465
|
+
const labelId = useId6();
|
|
1466
|
+
const stackRef = useRef10(null);
|
|
1467
|
+
const { state, rootProps } = useTravel({
|
|
1468
|
+
value,
|
|
1469
|
+
defaultValue,
|
|
1470
|
+
min,
|
|
1471
|
+
max,
|
|
1472
|
+
step,
|
|
1473
|
+
detents,
|
|
1474
|
+
orientation,
|
|
1475
|
+
invert,
|
|
1476
|
+
disabled,
|
|
1477
|
+
onChange
|
|
1478
|
+
});
|
|
1479
|
+
useDevPartCheck(stackRef, "AmbientTravel");
|
|
1480
|
+
const sized = sizeProps("travel", size);
|
|
1481
|
+
const { style: restStyle, ...restProps } = rest;
|
|
1482
|
+
return /* @__PURE__ */ jsxs9("div", { className: "ambx-stack", ref: stackRef, children: [
|
|
1483
|
+
/* @__PURE__ */ jsx20(
|
|
423
1484
|
"div",
|
|
424
1485
|
{
|
|
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
|
-
)
|
|
1486
|
+
...restProps,
|
|
1487
|
+
...rootProps,
|
|
1488
|
+
"aria-labelledby": label ? labelId : rest["aria-labelledby"],
|
|
1489
|
+
"data-animate": animate,
|
|
1490
|
+
className: cn(
|
|
1491
|
+
"ambx-control ambx-travel",
|
|
1492
|
+
`ambx-travel-${orientation}`,
|
|
1493
|
+
sized.className,
|
|
1494
|
+
className
|
|
1495
|
+
),
|
|
1496
|
+
style: { ...rootProps.style, ...sized.style, ...restStyle },
|
|
1497
|
+
children: /* @__PURE__ */ jsx20(ControlStateProvider, { value: state, children: /* @__PURE__ */ jsx20(Frames, { parts }) })
|
|
449
1498
|
}
|
|
450
1499
|
),
|
|
451
|
-
label ? /* @__PURE__ */
|
|
1500
|
+
label ? /* @__PURE__ */ jsx20("span", { id: labelId, className: "ambx-label", children: label }) : null
|
|
452
1501
|
] });
|
|
453
1502
|
}
|
|
454
1503
|
|
|
455
|
-
// src/components/
|
|
456
|
-
import {
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
1504
|
+
// src/components/AmbientFader.tsx
|
|
1505
|
+
import { jsx as jsx21 } from "react/jsx-runtime";
|
|
1506
|
+
function AmbientFader({
|
|
1507
|
+
material,
|
|
1508
|
+
look,
|
|
1509
|
+
size = "md",
|
|
1510
|
+
animate,
|
|
1511
|
+
className,
|
|
1512
|
+
...rest
|
|
1513
|
+
}) {
|
|
1514
|
+
const { dress, defaults } = useDress(
|
|
1515
|
+
"travel",
|
|
1516
|
+
{ material, orientation: "vertical", ...look },
|
|
1517
|
+
groundedKit.travel
|
|
1518
|
+
);
|
|
1519
|
+
return /* @__PURE__ */ jsx21(
|
|
1520
|
+
AmbientTravel,
|
|
1521
|
+
{
|
|
1522
|
+
...rest,
|
|
1523
|
+
orientation: "vertical",
|
|
1524
|
+
size,
|
|
1525
|
+
animate: animate ?? defaults?.animate,
|
|
1526
|
+
className: cn(dress.className, className),
|
|
1527
|
+
parts: dress.parts
|
|
1528
|
+
}
|
|
1529
|
+
);
|
|
460
1530
|
}
|
|
1531
|
+
|
|
1532
|
+
// src/components/AmbientSlider.tsx
|
|
1533
|
+
import { jsx as jsx22 } from "react/jsx-runtime";
|
|
461
1534
|
function AmbientSlider({
|
|
462
|
-
value,
|
|
463
|
-
min = 0,
|
|
464
|
-
max = 100,
|
|
465
|
-
step = 1,
|
|
466
|
-
label,
|
|
467
1535
|
material,
|
|
1536
|
+
look,
|
|
468
1537
|
size = "md",
|
|
469
|
-
|
|
1538
|
+
animate,
|
|
470
1539
|
className,
|
|
471
|
-
...
|
|
1540
|
+
...rest
|
|
472
1541
|
}) {
|
|
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
|
-
|
|
1542
|
+
const { dress, defaults } = useDress(
|
|
1543
|
+
"travel",
|
|
1544
|
+
{ material, orientation: "horizontal", ...look },
|
|
1545
|
+
groundedKit.travel
|
|
1546
|
+
);
|
|
1547
|
+
return /* @__PURE__ */ jsx22(
|
|
1548
|
+
AmbientTravel,
|
|
1549
|
+
{
|
|
1550
|
+
...rest,
|
|
1551
|
+
orientation: "horizontal",
|
|
1552
|
+
size,
|
|
1553
|
+
animate: animate ?? defaults?.animate,
|
|
1554
|
+
className: cn(dress.className, className),
|
|
1555
|
+
parts: dress.parts
|
|
1556
|
+
}
|
|
1557
|
+
);
|
|
1558
|
+
}
|
|
1559
|
+
|
|
1560
|
+
// src/parts/console.tsx
|
|
1561
|
+
import { Fragment as Fragment4, jsx as jsx23, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
1562
|
+
function ConsoleWell({ className }) {
|
|
1563
|
+
return /* @__PURE__ */ jsx23("span", { className: cn("amb-console-housing amb-groove", className), children: /* @__PURE__ */ jsx23("span", { className: "amb-console-face amb-surface" }) });
|
|
1564
|
+
}
|
|
1565
|
+
function ConsoleBar({ className }) {
|
|
1566
|
+
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" }) }) });
|
|
1567
|
+
}
|
|
1568
|
+
function ConsoleMarks({
|
|
1569
|
+
mark = true,
|
|
1570
|
+
legend = true,
|
|
1571
|
+
className
|
|
1572
|
+
}) {
|
|
1573
|
+
return /* @__PURE__ */ jsxs10("span", { className: cn("amb-console-marks", className), "aria-hidden": true, children: [
|
|
1574
|
+
mark ? /* @__PURE__ */ jsx23("span", { className: "amb-console-mark amb-surface" }) : null,
|
|
1575
|
+
legend ? /* @__PURE__ */ jsxs10(Fragment4, { children: [
|
|
1576
|
+
/* @__PURE__ */ jsx23("span", { className: "amb-console-legend amb-console-legend-min", children: "\u2212" }),
|
|
1577
|
+
/* @__PURE__ */ jsx23("span", { className: "amb-console-legend amb-console-legend-max", children: "+" })
|
|
1578
|
+
] }) : null
|
|
1579
|
+
] });
|
|
1580
|
+
}
|
|
1581
|
+
function ToggleTrack({ className }) {
|
|
1582
|
+
return /* @__PURE__ */ jsx23("span", { className: cn("amb-console-track amb-groove", className) });
|
|
1583
|
+
}
|
|
1584
|
+
function ToggleThumb({ className }) {
|
|
1585
|
+
return /* @__PURE__ */ jsx23("span", { className: cn("amb-console-thumb ambient amb-surface amb-thickness-2", className) });
|
|
1586
|
+
}
|
|
1587
|
+
|
|
1588
|
+
// src/kits/console.tsx
|
|
1589
|
+
import { jsx as jsx24 } from "react/jsx-runtime";
|
|
1590
|
+
function rotary2(look) {
|
|
1591
|
+
const mark = look.mark !== false;
|
|
1592
|
+
const legend = look.legend !== false;
|
|
1593
|
+
return {
|
|
1594
|
+
className: cn(
|
|
1595
|
+
"amb-console-knob",
|
|
1596
|
+
mark && "amb-console-knob-marked",
|
|
1597
|
+
legend && "amb-console-knob-legended"
|
|
1598
|
+
),
|
|
1599
|
+
parts: {
|
|
1600
|
+
panel: mark || legend ? /* @__PURE__ */ jsx24(ConsoleMarks, { mark, legend }) : null,
|
|
1601
|
+
base: /* @__PURE__ */ jsx24(ConsoleWell, {}),
|
|
1602
|
+
actuator: /* @__PURE__ */ jsx24(ConsoleBar, {})
|
|
521
1603
|
}
|
|
522
1604
|
};
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
1605
|
+
}
|
|
1606
|
+
function latch2() {
|
|
1607
|
+
return {
|
|
1608
|
+
className: "amb-console-toggle",
|
|
1609
|
+
parts: { base: /* @__PURE__ */ jsx24(ToggleTrack, {}), actuator: /* @__PURE__ */ jsx24(ToggleThumb, {}) }
|
|
526
1610
|
};
|
|
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
|
-
] });
|
|
1611
|
+
}
|
|
1612
|
+
var consoleKit = {
|
|
1613
|
+
name: "console",
|
|
1614
|
+
rotary: rotary2,
|
|
1615
|
+
latch: latch2,
|
|
1616
|
+
/* A visual identity may say how its controls feel to turn. The desk knob
|
|
1617
|
+
this is drawn from is an absolute-position pot with a centre detent, so
|
|
1618
|
+
it grabs where you press rather than tracking a drag. */
|
|
1619
|
+
defaults: {
|
|
1620
|
+
rotary: { input: "angle", travel: 280 }
|
|
1621
|
+
},
|
|
1622
|
+
looks: {
|
|
1623
|
+
rotary: ["mark", "legend"],
|
|
1624
|
+
latch: []
|
|
1625
|
+
}
|
|
1626
|
+
};
|
|
1627
|
+
function ConsoleKnob({ mark, legend, ...rest }) {
|
|
1628
|
+
return /* @__PURE__ */ jsx24(AmbientKnob, { ...rest, look: { mark, legend } });
|
|
1629
|
+
}
|
|
1630
|
+
function ConsoleToggle(props) {
|
|
1631
|
+
return /* @__PURE__ */ jsx24(AmbientSwitch, { ...props });
|
|
558
1632
|
}
|
|
559
1633
|
export {
|
|
1634
|
+
AmbientBank,
|
|
560
1635
|
AmbientButton,
|
|
561
1636
|
AmbientFader,
|
|
1637
|
+
AmbientKitProvider,
|
|
562
1638
|
AmbientKnob,
|
|
1639
|
+
AmbientLatch,
|
|
563
1640
|
AmbientPanel,
|
|
1641
|
+
AmbientPress,
|
|
564
1642
|
AmbientProvider,
|
|
565
1643
|
AmbientRack,
|
|
1644
|
+
AmbientRotary,
|
|
1645
|
+
AmbientSelect,
|
|
566
1646
|
AmbientSlider,
|
|
567
|
-
AmbientSwitch
|
|
1647
|
+
AmbientSwitch,
|
|
1648
|
+
AmbientTravel,
|
|
1649
|
+
ButtonCap,
|
|
1650
|
+
ConsoleBar,
|
|
1651
|
+
ConsoleKnob,
|
|
1652
|
+
ConsoleMarks,
|
|
1653
|
+
ConsoleToggle,
|
|
1654
|
+
ConsoleWell,
|
|
1655
|
+
FaderCap,
|
|
1656
|
+
IndicatorBar,
|
|
1657
|
+
IndicatorDot,
|
|
1658
|
+
KeyCap,
|
|
1659
|
+
KeyLens,
|
|
1660
|
+
KnobBody,
|
|
1661
|
+
KnurledFace,
|
|
1662
|
+
Led,
|
|
1663
|
+
ScaleRing,
|
|
1664
|
+
SliderThumb,
|
|
1665
|
+
SwitchPill,
|
|
1666
|
+
SwitchTrack,
|
|
1667
|
+
ToggleThumb,
|
|
1668
|
+
ToggleTrack,
|
|
1669
|
+
TravelTrack,
|
|
1670
|
+
consoleKit,
|
|
1671
|
+
groundedKit,
|
|
1672
|
+
useBank,
|
|
1673
|
+
useBankKey,
|
|
1674
|
+
useControlState,
|
|
1675
|
+
useDress,
|
|
1676
|
+
useKit,
|
|
1677
|
+
useLatch,
|
|
1678
|
+
usePress,
|
|
1679
|
+
useRotary,
|
|
1680
|
+
useTravel
|
|
568
1681
|
};
|
|
569
1682
|
//# sourceMappingURL=index.js.map
|