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