@ambientcss/components 1.2.1 → 2.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +97 -28
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +7 -3
- package/dist/index.d.ts +7 -3
- package/dist/index.js +97 -28
- package/dist/index.js.map +1 -1
- package/dist/styles.css +311 -66
- package/package.json +2 -2
- package/src/components/AmbientButton.tsx +27 -4
- package/src/components/AmbientFader.tsx +3 -7
- package/src/components/AmbientKnob.tsx +95 -9
- package/src/components/AmbientSlider.tsx +3 -9
- package/src/components/AmbientSwitch.tsx +5 -2
- package/src/index.ts +2 -2
- package/src/styles.css +311 -66
package/dist/index.cjs
CHANGED
|
@@ -84,18 +84,34 @@ function AmbientPanel({ className, material = "matte", ...props }) {
|
|
|
84
84
|
|
|
85
85
|
// src/components/AmbientButton.tsx
|
|
86
86
|
var import_jsx_runtime3 = require("react/jsx-runtime");
|
|
87
|
-
function AmbientButton({
|
|
87
|
+
function AmbientButton({
|
|
88
|
+
className,
|
|
89
|
+
children,
|
|
90
|
+
material = "matte",
|
|
91
|
+
shape = "pill",
|
|
92
|
+
...props
|
|
93
|
+
}) {
|
|
88
94
|
return /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
89
95
|
"button",
|
|
90
96
|
{
|
|
91
97
|
type: "button",
|
|
92
98
|
className: cn(
|
|
93
|
-
"
|
|
94
|
-
|
|
99
|
+
"amb-button amb-groove ambx-button",
|
|
100
|
+
shape === "round" && "amb-button-round",
|
|
101
|
+
shape === "square" && "amb-button-square",
|
|
95
102
|
className
|
|
96
103
|
),
|
|
97
104
|
...props,
|
|
98
|
-
children
|
|
105
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime3.jsx)(
|
|
106
|
+
"span",
|
|
107
|
+
{
|
|
108
|
+
className: cn(
|
|
109
|
+
"amb-button-cap ambient amb-chamfer amb-surface amb-heading-3",
|
|
110
|
+
material === "matte" ? "amb-mat-matte" : material === "shiny" ? "amb-mat-shiny" : "amb-mat-glass"
|
|
111
|
+
),
|
|
112
|
+
children
|
|
113
|
+
}
|
|
114
|
+
)
|
|
99
115
|
}
|
|
100
116
|
);
|
|
101
117
|
}
|
|
@@ -127,8 +143,8 @@ function AmbientSwitch({
|
|
|
127
143
|
"aria-checked": active,
|
|
128
144
|
"aria-labelledby": label ? labelId : props["aria-labelledby"],
|
|
129
145
|
className: cn(
|
|
130
|
-
"
|
|
131
|
-
active
|
|
146
|
+
"amb-switch",
|
|
147
|
+
active && "amb-switch-on",
|
|
132
148
|
"ambx-switch",
|
|
133
149
|
`ambx-switch-${size}`,
|
|
134
150
|
className
|
|
@@ -148,6 +164,7 @@ function AmbientSwitch({
|
|
|
148
164
|
style: typeof led === "string" ? { "--amb-led-color": led } : void 0
|
|
149
165
|
}
|
|
150
166
|
) : null,
|
|
167
|
+
/* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "amb-switch-track amb-groove", children: /* @__PURE__ */ (0, import_jsx_runtime4.jsx)("span", { className: "amb-switch-pill ambient amb-fillet amb-surface-convex" }) }),
|
|
151
168
|
children
|
|
152
169
|
]
|
|
153
170
|
}
|
|
@@ -162,6 +179,47 @@ function AmbientSwitch({
|
|
|
162
179
|
// src/components/AmbientKnob.tsx
|
|
163
180
|
var import_react2 = require("react");
|
|
164
181
|
var import_jsx_runtime5 = require("react/jsx-runtime");
|
|
182
|
+
var KNURLS = {
|
|
183
|
+
/* 36 ribs — the grounded referent knob (dot and line variants) */
|
|
184
|
+
standard: { teeth: 36, root: 0.468, rise: 0.12, fall: [0.5, 0.62] },
|
|
185
|
+
/* 14 broad flutes with deeper roots (OP-Z-style flute variant) */
|
|
186
|
+
flute: { teeth: 14, root: 0.44, rise: 0.08, fall: [0.72, 0.8] },
|
|
187
|
+
/* 48-rib fine knurl, shallower (cap and wheel variants) */
|
|
188
|
+
fine: { teeth: 48, root: 0.476, rise: 0.12, fall: [0.5, 0.62] }
|
|
189
|
+
};
|
|
190
|
+
function knurlPath({ teeth, root, rise, fall }) {
|
|
191
|
+
const outer = 0.5;
|
|
192
|
+
const pitch = Math.PI * 2 / teeth;
|
|
193
|
+
const pts = [];
|
|
194
|
+
for (let i = 0; i < teeth; i++) {
|
|
195
|
+
const a = i * pitch;
|
|
196
|
+
const tooth = [
|
|
197
|
+
[0, root],
|
|
198
|
+
[rise, outer],
|
|
199
|
+
[fall[0], outer],
|
|
200
|
+
[fall[1], root]
|
|
201
|
+
];
|
|
202
|
+
for (const [frac, radius] of tooth) {
|
|
203
|
+
const t = a + frac * pitch;
|
|
204
|
+
pts.push(
|
|
205
|
+
`${(0.5 + radius * Math.cos(t)).toFixed(4)} ${(0.5 + radius * Math.sin(t)).toFixed(4)}`
|
|
206
|
+
);
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
return `M${pts.join(" L")} Z`;
|
|
210
|
+
}
|
|
211
|
+
var KNURL_PATHS = {
|
|
212
|
+
standard: knurlPath(KNURLS.standard),
|
|
213
|
+
flute: knurlPath(KNURLS.flute),
|
|
214
|
+
fine: knurlPath(KNURLS.fine)
|
|
215
|
+
};
|
|
216
|
+
var VARIANT_FAMILY = {
|
|
217
|
+
dot: "standard",
|
|
218
|
+
line: "standard",
|
|
219
|
+
flute: "flute",
|
|
220
|
+
cap: "fine",
|
|
221
|
+
wheel: "fine"
|
|
222
|
+
};
|
|
165
223
|
function clamp(value, min, max) {
|
|
166
224
|
return Math.min(max, Math.max(min, value));
|
|
167
225
|
}
|
|
@@ -172,14 +230,17 @@ function AmbientKnob({
|
|
|
172
230
|
step = 1,
|
|
173
231
|
label,
|
|
174
232
|
material,
|
|
233
|
+
variant = "dot",
|
|
175
234
|
onChange,
|
|
176
235
|
className,
|
|
177
236
|
...props
|
|
178
237
|
}) {
|
|
179
238
|
const id = (0, import_react2.useId)();
|
|
239
|
+
const clipId = `amb-knurl-${id.replace(/:/g, "")}`;
|
|
180
240
|
const draggingRef = (0, import_react2.useRef)(false);
|
|
181
241
|
const knobRef = (0, import_react2.useRef)(null);
|
|
182
242
|
const safeStep = step > 0 ? step : 1;
|
|
243
|
+
const family = VARIANT_FAMILY[variant];
|
|
183
244
|
const percent = (value - min) / (max - min || 1);
|
|
184
245
|
const rotation = percent * 270 - 135;
|
|
185
246
|
const pointerToValue = (event) => {
|
|
@@ -235,11 +296,11 @@ function AmbientKnob({
|
|
|
235
296
|
}
|
|
236
297
|
};
|
|
237
298
|
return /* @__PURE__ */ (0, import_jsx_runtime5.jsxs)("div", { className: cn("ambx-stack", className), ...props, children: [
|
|
238
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.
|
|
299
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
239
300
|
"div",
|
|
240
301
|
{
|
|
241
302
|
ref: knobRef,
|
|
242
|
-
className:
|
|
303
|
+
className: "amb-knob ambx-knob",
|
|
243
304
|
role: "slider",
|
|
244
305
|
"aria-label": label,
|
|
245
306
|
"aria-valuemin": min,
|
|
@@ -263,11 +324,28 @@ function AmbientKnob({
|
|
|
263
324
|
draggingRef.current = false;
|
|
264
325
|
},
|
|
265
326
|
onKeyDown,
|
|
266
|
-
children:
|
|
267
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("
|
|
268
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "amb-
|
|
269
|
-
/* @__PURE__ */ (0, import_jsx_runtime5.
|
|
270
|
-
|
|
327
|
+
children: [
|
|
328
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("svg", { width: 0, height: 0, style: { position: "absolute" }, "aria-hidden": true, focusable: false, children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("defs", { children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("clipPath", { id: clipId, clipPathUnits: "objectBoundingBox", children: /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("path", { d: KNURL_PATHS[family] }) }) }) }),
|
|
329
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "amb-knob-body ambient amb-thickness-2 amb-surface" }),
|
|
330
|
+
/* @__PURE__ */ (0, import_jsx_runtime5.jsxs)(
|
|
331
|
+
"div",
|
|
332
|
+
{
|
|
333
|
+
className: cn(
|
|
334
|
+
"ambx-knob-rotation amb-knob-face",
|
|
335
|
+
family === "flute" && "amb-knob-face-flute",
|
|
336
|
+
family === "fine" && "amb-knob-face-fine",
|
|
337
|
+
variant === "cap" && "amb-knob-face-cap",
|
|
338
|
+
material && `amb-mat-${material}`
|
|
339
|
+
),
|
|
340
|
+
style: { transform: `rotate(${rotation}deg)`, clipPath: `url(#${clipId})` },
|
|
341
|
+
children: [
|
|
342
|
+
variant === "dot" ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "amb-knob-indicator-dot" }) : null,
|
|
343
|
+
variant === "line" ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "amb-knob-indicator-line" }) : null,
|
|
344
|
+
variant === "flute" ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { className: "amb-knob-indicator-dot amb-knob-indicator-dot-center" }) : null
|
|
345
|
+
]
|
|
346
|
+
}
|
|
347
|
+
)
|
|
348
|
+
]
|
|
271
349
|
}
|
|
272
350
|
),
|
|
273
351
|
label ? /* @__PURE__ */ (0, import_jsx_runtime5.jsx)("span", { id, className: "ambx-label", children: label }) : null
|
|
@@ -349,7 +427,7 @@ function AmbientFader({
|
|
|
349
427
|
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
350
428
|
"div",
|
|
351
429
|
{
|
|
352
|
-
className: "amb-fader ambx-fader",
|
|
430
|
+
className: "amb-fader amb-groove ambx-fader",
|
|
353
431
|
ref: trackRef,
|
|
354
432
|
role: "slider",
|
|
355
433
|
"aria-label": label,
|
|
@@ -368,13 +446,9 @@ function AmbientFader({
|
|
|
368
446
|
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)(
|
|
369
447
|
"div",
|
|
370
448
|
{
|
|
371
|
-
className: cn("amb-fader-thumb ambient amb-fillet
|
|
449
|
+
className: cn("amb-fader-thumb ambient amb-fillet ambx-fader-thumb", material !== "glass" && "amb-surface-concave", material && `amb-mat-${material}`),
|
|
372
450
|
style: { top: `${100 - percent}%` },
|
|
373
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime6.
|
|
374
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "amb-fader-dot" }),
|
|
375
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "amb-fader-dot" }),
|
|
376
|
-
/* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "amb-fader-dot" })
|
|
377
|
-
] })
|
|
451
|
+
children: /* @__PURE__ */ (0, import_jsx_runtime6.jsx)("span", { className: "amb-fader-gripline" })
|
|
378
452
|
}
|
|
379
453
|
)
|
|
380
454
|
}
|
|
@@ -458,7 +532,7 @@ function AmbientSlider({
|
|
|
458
532
|
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
459
533
|
"div",
|
|
460
534
|
{
|
|
461
|
-
className: "amb-slider ambx-slider",
|
|
535
|
+
className: "amb-slider amb-groove ambx-slider",
|
|
462
536
|
ref: trackRef,
|
|
463
537
|
role: "slider",
|
|
464
538
|
"aria-label": label,
|
|
@@ -477,13 +551,8 @@ function AmbientSlider({
|
|
|
477
551
|
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(
|
|
478
552
|
"div",
|
|
479
553
|
{
|
|
480
|
-
className: cn("amb-slider-thumb ambient amb-fillet
|
|
481
|
-
style: { left: `${percent}%` }
|
|
482
|
-
children: /* @__PURE__ */ (0, import_jsx_runtime7.jsxs)("div", { className: "amb-slider-grip", children: [
|
|
483
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "amb-fader-dot" }),
|
|
484
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "amb-fader-dot" }),
|
|
485
|
-
/* @__PURE__ */ (0, import_jsx_runtime7.jsx)("span", { className: "amb-fader-dot" })
|
|
486
|
-
] })
|
|
554
|
+
className: cn("amb-slider-thumb ambient amb-fillet ambx-slider-thumb", material !== "glass" && "amb-surface-convex", material && `amb-mat-${material}`),
|
|
555
|
+
style: { left: `${percent}%` }
|
|
487
556
|
}
|
|
488
557
|
)
|
|
489
558
|
}
|
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../src/components/AmbientProvider.tsx","../src/lib/cn.ts","../src/components/AmbientPanel.tsx","../src/components/AmbientButton.tsx","../src/components/AmbientSwitch.tsx","../src/components/AmbientKnob.tsx","../src/components/AmbientFader.tsx","../src/components/AmbientSlider.tsx"],"sourcesContent":["export { AmbientProvider } from \"./components/AmbientProvider\";\nexport type { AmbientProviderProps, AmbientTheme } from \"./components/AmbientProvider\";\n\nexport { AmbientPanel } from \"./components/AmbientPanel\";\nexport type { AmbientPanelProps } from \"./components/AmbientPanel\";\n\nexport { AmbientButton } from \"./components/AmbientButton\";\nexport type { AmbientButtonProps } from \"./components/AmbientButton\";\n\nexport { AmbientSwitch } from \"./components/AmbientSwitch\";\nexport type { AmbientSwitchProps, AmbientSwitchSize } from \"./components/AmbientSwitch\";\n\nexport { AmbientKnob } from \"./components/AmbientKnob\";\nexport type { AmbientKnobProps } from \"./components/AmbientKnob\";\n\nexport { AmbientFader } from \"./components/AmbientFader\";\nexport type { AmbientFaderProps } from \"./components/AmbientFader\";\n\nexport { AmbientSlider } from \"./components/AmbientSlider\";\nexport type { AmbientSliderProps } from \"./components/AmbientSlider\";\n","import type { CSSProperties, PropsWithChildren } from \"react\";\n\nexport type AmbientTheme = {\n lightX?: number;\n lightY?: number;\n keyLight?: number;\n fillLight?: number;\n lightHue?: number;\n lightSaturation?: number;\n highlightColor?: string;\n lumeHue?: number;\n};\n\nexport type AmbientProviderProps = PropsWithChildren<{\n className?: string;\n style?: CSSProperties;\n theme?: AmbientTheme;\n}>;\n\nconst VAR_MAP: Record<string, keyof AmbientTheme> = {\n \"--amb-light-x\": \"lightX\",\n \"--amb-light-y\": \"lightY\",\n \"--amb-key-light-intensity\": \"keyLight\",\n \"--amb-fill-light-intensity\": \"fillLight\",\n \"--amb-light-hue\": \"lightHue\",\n \"--amb-light-saturation\": \"lightSaturation\",\n \"--amb-highlight-color\": \"highlightColor\",\n \"--amb-lume-hue\": \"lumeHue\",\n};\n\nexport function AmbientProvider({ children, className, style, theme }: AmbientProviderProps) {\n const themeVars: Record<string, string> = {};\n for (const [varName, key] of Object.entries(VAR_MAP)) {\n const value = theme?.[key];\n if (value !== undefined) {\n themeVars[varName] = key === \"lightSaturation\" ? `${value}%` : String(value);\n }\n }\n // Derived variables must be re-declared here so they recompute using the\n // overridden input variables on this element rather than inheriting the\n // already-resolved values from :root.\n themeVars[\"--amb-lume\"] = [\n \"color-mix(in oklab,\",\n \"hsl(var(--amb-lume-hue) 100% 74%) calc(clamp(0, (0.5 - var(--amb-key-light-intensity)) / 0.2, 1) * 100%),\",\n \"hsl(var(--amb-light-hue) var(--amb-light-saturation)\",\n \"calc((1 - sign(var(--amb-key-light-intensity) - 0.5)) * 50% + 25%)))\",\n ].join(\" \");\n themeVars[\"--amb-label\"] =\n \"hsl(var(--amb-light-hue) var(--amb-light-saturation) calc((1 - var(--amb-key-light-intensity)) * 60% + 20%))\";\n const mergedStyle = { ...themeVars, ...style } as CSSProperties;\n\n return (\n <div className={className} style={mergedStyle}>\n {children}\n </div>\n );\n}\n","export function cn(...values: Array<string | false | null | undefined>): string {\n return values.filter(Boolean).join(\" \");\n}\n","import type { HTMLAttributes } from \"react\";\nimport { cn } from \"../lib/cn\";\n\nexport interface AmbientPanelProps extends HTMLAttributes<HTMLDivElement> {\n material?: \"matte\" | \"shiny\" | \"glass\";\n}\n\nexport function AmbientPanel({ className, material = \"matte\", ...props }: AmbientPanelProps) {\n return (\n <div\n className={cn(\n \"ambient amb-surface amb-chamfer amb-elevation-2 ambx-panel\",\n material === \"matte\" ? \"amb-mat-matte\" : material === \"shiny\" ? \"amb-mat-shiny\" : \"amb-mat-glass\",\n className\n )}\n {...props}\n />\n );\n}\n","import type { ButtonHTMLAttributes } from \"react\";\nimport { cn } from \"../lib/cn\";\n\nexport interface AmbientButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n material?: \"matte\" | \"shiny\" | \"glass\";\n}\n\nexport function AmbientButton({ className, children, material = \"matte\", ...props }: AmbientButtonProps) {\n return (\n <button\n type=\"button\"\n className={cn(\n \"ambient amb-button amb-chamfer amb-elevation-1 ambx-button amb-heading-3\",\n material === \"matte\" ? \"amb-mat-matte\" : material === \"shiny\" ? \"amb-mat-shiny\" : \"amb-mat-glass\",\n className\n )}\n {...props}\n >\n {children}\n </button>\n );\n}\n","import { useId, useState } from \"react\";\nimport type { ButtonHTMLAttributes } from \"react\";\nimport { cn } from \"../lib/cn\";\n\nexport type AmbientSwitchSize = \"sm\" | \"md\" | \"lg\";\n\nexport type AmbientSwitchProps = Omit<ButtonHTMLAttributes<HTMLButtonElement>, \"onChange\"> & {\n checked?: boolean;\n defaultChecked?: boolean;\n onCheckedChange?: (checked: boolean) => void;\n size?: AmbientSwitchSize;\n label?: string;\n /** Show a small LED indicator that lights up when the switch is on. Pass `true` for default green or a CSS color string. */\n led?: boolean | string;\n};\n\nexport function AmbientSwitch({\n className,\n checked,\n defaultChecked,\n onCheckedChange,\n onClick,\n size = \"md\",\n label,\n led,\n children,\n ...props\n}: AmbientSwitchProps) {\n const labelId = useId();\n const isControlled = checked !== undefined;\n const [internalChecked, setInternalChecked] = useState(defaultChecked ?? false);\n const active = isControlled ? (checked ?? false) : internalChecked;\n\n const button = (\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={active}\n aria-labelledby={label ? labelId : props[\"aria-labelledby\"]}\n className={cn(\n \"ambient amb-switch amb-chamfer amb-elevation-1 amb-heading-3\",\n active ? \"amb-surface-convex amb-switch-on\" : \"amb-surface-concave\",\n \"ambx-switch\",\n `ambx-switch-${size}`,\n className\n )}\n onClick={(event) => {\n const next = !active;\n if (!isControlled) setInternalChecked(next);\n onCheckedChange?.(next);\n onClick?.(event);\n }}\n {...props}\n >\n {led ? (\n <span\n className={cn(\"amb-led\", !active && \"amb-led-off\")}\n style={typeof led === \"string\" ? { \"--amb-led-color\": led } as React.CSSProperties : undefined}\n />\n ) : null}\n {children}\n </button>\n );\n\n if (!label) return button;\n\n return (\n <div className=\"ambx-stack\">\n {button}\n <span id={labelId} className=\"ambx-label\">\n {label}\n </span>\n </div>\n );\n}\n","import { useId, useRef } from \"react\";\nimport type { HTMLAttributes, KeyboardEvent, PointerEvent } from \"react\";\nimport { cn } from \"../lib/cn\";\n\nexport type AmbientKnobProps = Omit<HTMLAttributes<HTMLDivElement>, \"onChange\"> & {\n value: number;\n min?: number;\n max?: number;\n step?: number;\n label?: string;\n material?: \"matte\" | \"shiny\" | \"glass\";\n onChange?: (nextValue: number) => void;\n};\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, value));\n}\n\nexport function AmbientKnob({\n value,\n min = 0,\n max = 100,\n step = 1,\n label,\n material,\n onChange,\n className,\n ...props\n}: AmbientKnobProps) {\n const id = useId();\n const draggingRef = useRef(false);\n const knobRef = useRef<HTMLDivElement>(null);\n const safeStep = step > 0 ? step : 1;\n\n const percent = (value - min) / (max - min || 1);\n const rotation = percent * 270 - 135;\n\n // Convert pointer position to a knob angle in [-180, 180] where 0 = up,\n // positive = clockwise. The knob's active range is [-135, 135] (270°),\n // with the dead zone at the bottom (~135° to ~225° i.e. past ±135°).\n const pointerToValue = (event: PointerEvent<HTMLDivElement>) => {\n const rect = knobRef.current!.getBoundingClientRect();\n const cx = rect.left + rect.width / 2;\n const cy = rect.top + rect.height / 2;\n // atan2 with screen coords: 0=right, 90=down; add 90 to rotate so 0=up\n const atan2Deg = Math.atan2(event.clientY - cy, event.clientX - cx) * (180 / Math.PI);\n let angle = atan2Deg + 90;\n // Normalize to [-180, 180]\n if (angle > 180) angle -= 360;\n\n // Clamp dead zone based on current value position\n if (angle < -135 || angle > 135) {\n angle = percent >= 0.5 ? 135 : -135;\n }\n\n const range = max - min;\n const raw = min + ((angle + 135) / 270) * range;\n const snapped = Math.round(raw / safeStep) * safeStep;\n onChange?.(clamp(snapped, min, max));\n };\n\n const setValue = (nextValue: number) => {\n const snapped = Math.round(nextValue / safeStep) * safeStep;\n onChange?.(clamp(snapped, min, max));\n };\n\n const onKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n const pageStep = safeStep * 10;\n switch (event.key) {\n case \"ArrowUp\":\n case \"ArrowRight\":\n event.preventDefault();\n setValue(value + safeStep);\n break;\n case \"ArrowDown\":\n case \"ArrowLeft\":\n event.preventDefault();\n setValue(value - safeStep);\n break;\n case \"PageUp\":\n event.preventDefault();\n setValue(value + pageStep);\n break;\n case \"PageDown\":\n event.preventDefault();\n setValue(value - pageStep);\n break;\n case \"Home\":\n event.preventDefault();\n setValue(min);\n break;\n case \"End\":\n event.preventDefault();\n setValue(max);\n break;\n default:\n break;\n }\n };\n\n return (\n <div className={cn(\"ambx-stack\", className)} {...props}>\n <div\n ref={knobRef}\n className={cn(\"ambient amb-knob amb-chamfer amb-elevation-2 amb-surface ambx-knob\", material && `amb-mat-${material}`)}\n role=\"slider\"\n aria-label={label}\n aria-valuemin={min}\n aria-valuemax={max}\n aria-valuenow={value}\n aria-labelledby={label ? id : undefined}\n aria-orientation=\"vertical\"\n tabIndex={0}\n onPointerDown={(event) => {\n event.currentTarget.setPointerCapture(event.pointerId);\n draggingRef.current = true;\n pointerToValue(event);\n }}\n onPointerMove={(event) => {\n if (draggingRef.current) pointerToValue(event);\n }}\n onPointerUp={() => {\n draggingRef.current = false;\n }}\n onPointerCancel={() => {\n draggingRef.current = false;\n }}\n onKeyDown={onKeyDown}\n >\n <div className=\"ambx-knob-rotation\" style={{ transform: `rotate(${rotation}deg)` }}>\n <div className=\"amb-knob-indicator\">\n <div className=\"amb-knob-grip\">\n <span className=\"amb-fader-dot\" />\n <span className=\"amb-fader-dot\" />\n <span className=\"amb-fader-dot\" />\n </div>\n </div>\n </div>\n </div>\n {label ? (\n <span id={id} className=\"ambx-label\">\n {label}\n </span>\n ) : null}\n </div>\n );\n}\n","import { useId, useRef } from \"react\";\nimport type { HTMLAttributes, KeyboardEvent, PointerEvent } from \"react\";\nimport { cn } from \"../lib/cn\";\n\nexport type AmbientFaderProps = Omit<HTMLAttributes<HTMLDivElement>, \"onChange\"> & {\n value: number;\n min?: number;\n max?: number;\n step?: number;\n label?: string;\n material?: \"matte\" | \"shiny\" | \"glass\";\n onChange?: (nextValue: number) => void;\n};\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, value));\n}\n\nexport function AmbientFader({\n value,\n min = 0,\n max = 100,\n step = 1,\n label,\n material,\n onChange,\n className,\n ...props\n}: AmbientFaderProps) {\n const id = useId();\n const trackRef = useRef<HTMLDivElement | null>(null);\n const safeStep = step > 0 ? step : 1;\n\n const percent = ((value - min) / (max - min || 1)) * 100;\n\n const updateFromClientY = (clientY: number) => {\n const track = trackRef.current;\n if (!track) return;\n\n const rect = track.getBoundingClientRect();\n const ratio = 1 - (clientY - rect.top) / rect.height;\n const nextValue = min + clamp(ratio, 0, 1) * (max - min);\n const snapped = Math.round(nextValue / safeStep) * safeStep;\n onChange?.(clamp(snapped, min, max));\n };\n\n const setValue = (nextValue: number) => {\n const snapped = Math.round(nextValue / safeStep) * safeStep;\n onChange?.(clamp(snapped, min, max));\n };\n\n const onKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n const pageStep = safeStep * 10;\n switch (event.key) {\n case \"ArrowUp\":\n case \"ArrowRight\":\n event.preventDefault();\n setValue(value + safeStep);\n break;\n case \"ArrowDown\":\n case \"ArrowLeft\":\n event.preventDefault();\n setValue(value - safeStep);\n break;\n case \"PageUp\":\n event.preventDefault();\n setValue(value + pageStep);\n break;\n case \"PageDown\":\n event.preventDefault();\n setValue(value - pageStep);\n break;\n case \"Home\":\n event.preventDefault();\n setValue(min);\n break;\n case \"End\":\n event.preventDefault();\n setValue(max);\n break;\n default:\n break;\n }\n };\n\n const onPointerMove = (event: PointerEvent<HTMLDivElement>) => {\n if (event.buttons !== 1) return;\n updateFromClientY(event.clientY);\n };\n\n return (\n <div className={cn(\"ambx-stack\", className)} {...props}>\n <div\n className=\"amb-fader ambx-fader\"\n ref={trackRef}\n role=\"slider\"\n aria-label={label}\n aria-labelledby={label ? id : undefined}\n aria-valuemin={min}\n aria-valuemax={max}\n aria-valuenow={value}\n aria-orientation=\"vertical\"\n tabIndex={0}\n onPointerDown={(event) => {\n event.currentTarget.setPointerCapture(event.pointerId);\n updateFromClientY(event.clientY);\n }}\n onPointerMove={onPointerMove}\n onKeyDown={onKeyDown}\n >\n <div\n className={cn(\"amb-fader-thumb ambient amb-fillet amb-elevation-1 ambx-fader-thumb\", material !== \"glass\" && \"amb-surface-concave\", material && `amb-mat-${material}`)}\n style={{ top: `${100 - percent}%` }}\n >\n <div className=\"amb-fader-grip\">\n <span className=\"amb-fader-dot\" />\n <span className=\"amb-fader-dot\" />\n <span className=\"amb-fader-dot\" />\n </div>\n </div>\n </div>\n {label ? (\n <span id={id} className=\"ambx-label\">\n {label}\n </span>\n ) : null}\n </div>\n );\n}\n","import { useId, useRef } from \"react\";\nimport type { HTMLAttributes, KeyboardEvent, PointerEvent } from \"react\";\nimport { cn } from \"../lib/cn\";\n\nexport type AmbientSliderProps = Omit<HTMLAttributes<HTMLDivElement>, \"onChange\"> & {\n value: number;\n min?: number;\n max?: number;\n step?: number;\n label?: string;\n material?: \"matte\" | \"shiny\" | \"glass\";\n onChange?: (nextValue: number) => void;\n};\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, value));\n}\n\nexport function AmbientSlider({\n value,\n min = 0,\n max = 100,\n step = 1,\n label,\n material,\n onChange,\n className,\n ...props\n}: AmbientSliderProps) {\n const id = useId();\n const trackRef = useRef<HTMLDivElement | null>(null);\n const safeStep = step > 0 ? step : 1;\n\n const percent = ((value - min) / (max - min || 1)) * 100;\n\n const updateFromClientX = (clientX: number) => {\n const track = trackRef.current;\n if (!track) return;\n\n const rect = track.getBoundingClientRect();\n const ratio = (clientX - rect.left) / rect.width;\n const nextValue = min + clamp(ratio, 0, 1) * (max - min);\n const snapped = Math.round(nextValue / safeStep) * safeStep;\n onChange?.(clamp(snapped, min, max));\n };\n\n const setValue = (nextValue: number) => {\n const snapped = Math.round(nextValue / safeStep) * safeStep;\n onChange?.(clamp(snapped, min, max));\n };\n\n const onKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n const pageStep = safeStep * 10;\n switch (event.key) {\n case \"ArrowRight\":\n case \"ArrowUp\":\n event.preventDefault();\n setValue(value + safeStep);\n break;\n case \"ArrowLeft\":\n case \"ArrowDown\":\n event.preventDefault();\n setValue(value - safeStep);\n break;\n case \"PageUp\":\n event.preventDefault();\n setValue(value + pageStep);\n break;\n case \"PageDown\":\n event.preventDefault();\n setValue(value - pageStep);\n break;\n case \"Home\":\n event.preventDefault();\n setValue(min);\n break;\n case \"End\":\n event.preventDefault();\n setValue(max);\n break;\n default:\n break;\n }\n };\n\n const onPointerMove = (event: PointerEvent<HTMLDivElement>) => {\n if (event.buttons !== 1) return;\n updateFromClientX(event.clientX);\n };\n\n return (\n <div className={cn(\"ambx-stack\", className)} {...props}>\n <div\n className=\"amb-slider ambx-slider\"\n ref={trackRef}\n role=\"slider\"\n aria-label={label}\n aria-labelledby={label ? id : undefined}\n aria-valuemin={min}\n aria-valuemax={max}\n aria-valuenow={value}\n aria-orientation=\"horizontal\"\n tabIndex={0}\n onPointerDown={(event) => {\n event.currentTarget.setPointerCapture(event.pointerId);\n updateFromClientX(event.clientX);\n }}\n onPointerMove={onPointerMove}\n onKeyDown={onKeyDown}\n >\n <div\n className={cn(\"amb-slider-thumb ambient amb-fillet amb-elevation-1 ambx-slider-thumb\", material !== \"glass\" && \"amb-surface-concave-h\", material && `amb-mat-${material}`)}\n style={{ left: `${percent}%` }}\n >\n <div className=\"amb-slider-grip\">\n <span className=\"amb-fader-dot\" />\n <span className=\"amb-fader-dot\" />\n <span className=\"amb-fader-dot\" />\n </div>\n </div>\n </div>\n {label ? (\n <span id={id} className=\"ambx-label\">\n {label}\n </span>\n ) : null}\n </div>\n );\n}\n"],"mappings":"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","names":["import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_react","import_jsx_runtime","import_react","import_jsx_runtime","clamp","import_react","import_jsx_runtime","clamp"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/components/AmbientProvider.tsx","../src/lib/cn.ts","../src/components/AmbientPanel.tsx","../src/components/AmbientButton.tsx","../src/components/AmbientSwitch.tsx","../src/components/AmbientKnob.tsx","../src/components/AmbientFader.tsx","../src/components/AmbientSlider.tsx"],"sourcesContent":["export { AmbientProvider } from \"./components/AmbientProvider\";\nexport type { AmbientProviderProps, AmbientTheme } from \"./components/AmbientProvider\";\n\nexport { AmbientPanel } from \"./components/AmbientPanel\";\nexport type { AmbientPanelProps } from \"./components/AmbientPanel\";\n\nexport { AmbientButton } from \"./components/AmbientButton\";\nexport type { AmbientButtonProps, AmbientButtonShape } from \"./components/AmbientButton\";\n\nexport { AmbientSwitch } from \"./components/AmbientSwitch\";\nexport type { AmbientSwitchProps, AmbientSwitchSize } from \"./components/AmbientSwitch\";\n\nexport { AmbientKnob } from \"./components/AmbientKnob\";\nexport type { AmbientKnobProps, AmbientKnobVariant } from \"./components/AmbientKnob\";\n\nexport { AmbientFader } from \"./components/AmbientFader\";\nexport type { AmbientFaderProps } from \"./components/AmbientFader\";\n\nexport { AmbientSlider } from \"./components/AmbientSlider\";\nexport type { AmbientSliderProps } from \"./components/AmbientSlider\";\n","import type { CSSProperties, PropsWithChildren } from \"react\";\n\nexport type AmbientTheme = {\n lightX?: number;\n lightY?: number;\n keyLight?: number;\n fillLight?: number;\n lightHue?: number;\n lightSaturation?: number;\n highlightColor?: string;\n lumeHue?: number;\n};\n\nexport type AmbientProviderProps = PropsWithChildren<{\n className?: string;\n style?: CSSProperties;\n theme?: AmbientTheme;\n}>;\n\nconst VAR_MAP: Record<string, keyof AmbientTheme> = {\n \"--amb-light-x\": \"lightX\",\n \"--amb-light-y\": \"lightY\",\n \"--amb-key-light-intensity\": \"keyLight\",\n \"--amb-fill-light-intensity\": \"fillLight\",\n \"--amb-light-hue\": \"lightHue\",\n \"--amb-light-saturation\": \"lightSaturation\",\n \"--amb-highlight-color\": \"highlightColor\",\n \"--amb-lume-hue\": \"lumeHue\",\n};\n\nexport function AmbientProvider({ children, className, style, theme }: AmbientProviderProps) {\n const themeVars: Record<string, string> = {};\n for (const [varName, key] of Object.entries(VAR_MAP)) {\n const value = theme?.[key];\n if (value !== undefined) {\n themeVars[varName] = key === \"lightSaturation\" ? `${value}%` : String(value);\n }\n }\n // Derived variables must be re-declared here so they recompute using the\n // overridden input variables on this element rather than inheriting the\n // already-resolved values from :root.\n themeVars[\"--amb-lume\"] = [\n \"color-mix(in oklab,\",\n \"hsl(var(--amb-lume-hue) 100% 74%) calc(clamp(0, (0.5 - var(--amb-key-light-intensity)) / 0.2, 1) * 100%),\",\n \"hsl(var(--amb-light-hue) var(--amb-light-saturation)\",\n \"calc((1 - sign(var(--amb-key-light-intensity) - 0.5)) * 50% + 25%)))\",\n ].join(\" \");\n themeVars[\"--amb-label\"] =\n \"hsl(var(--amb-light-hue) var(--amb-light-saturation) calc((1 - var(--amb-key-light-intensity)) * 60% + 20%))\";\n const mergedStyle = { ...themeVars, ...style } as CSSProperties;\n\n return (\n <div className={className} style={mergedStyle}>\n {children}\n </div>\n );\n}\n","export function cn(...values: Array<string | false | null | undefined>): string {\n return values.filter(Boolean).join(\" \");\n}\n","import type { HTMLAttributes } from \"react\";\nimport { cn } from \"../lib/cn\";\n\nexport interface AmbientPanelProps extends HTMLAttributes<HTMLDivElement> {\n material?: \"matte\" | \"shiny\" | \"glass\";\n}\n\nexport function AmbientPanel({ className, material = \"matte\", ...props }: AmbientPanelProps) {\n return (\n <div\n className={cn(\n \"ambient amb-surface amb-chamfer amb-elevation-2 ambx-panel\",\n material === \"matte\" ? \"amb-mat-matte\" : material === \"shiny\" ? \"amb-mat-shiny\" : \"amb-mat-glass\",\n className\n )}\n {...props}\n />\n );\n}\n","import type { ButtonHTMLAttributes } from \"react\";\nimport { cn } from \"../lib/cn\";\n\n/* Cap silhouettes from the referent lineup (ambient3d/generate.py):\n - \"pill\": the default wide stadium key (transport-key style)\n - \"round\": a circular key — pair with material=\"shiny\" for the\n machined metal-button look\n - \"square\": a squarer, flatter pad (EP-133-style, tighter corners,\n lower cap) */\nexport type AmbientButtonShape = \"pill\" | \"round\" | \"square\";\n\nexport interface AmbientButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n material?: \"matte\" | \"shiny\" | \"glass\";\n shape?: AmbientButtonShape;\n}\n\nexport function AmbientButton({\n className,\n children,\n material = \"matte\",\n shape = \"pill\",\n ...props\n}: AmbientButtonProps) {\n return (\n <button\n type=\"button\"\n className={cn(\n \"amb-button amb-groove ambx-button\",\n shape === \"round\" && \"amb-button-round\",\n shape === \"square\" && \"amb-button-square\",\n className\n )}\n {...props}\n >\n <span\n className={cn(\n \"amb-button-cap ambient amb-chamfer amb-surface amb-heading-3\",\n material === \"matte\" ? \"amb-mat-matte\" : material === \"shiny\" ? \"amb-mat-shiny\" : \"amb-mat-glass\"\n )}\n >\n {children}\n </span>\n </button>\n );\n}\n","import { useId, useState } from \"react\";\nimport type { ButtonHTMLAttributes } from \"react\";\nimport { cn } from \"../lib/cn\";\n\nexport type AmbientSwitchSize = \"sm\" | \"md\" | \"lg\";\n\nexport type AmbientSwitchProps = Omit<ButtonHTMLAttributes<HTMLButtonElement>, \"onChange\"> & {\n checked?: boolean;\n defaultChecked?: boolean;\n onCheckedChange?: (checked: boolean) => void;\n size?: AmbientSwitchSize;\n label?: string;\n /** Show a small LED indicator that lights up when the switch is on. Pass `true` for default green or a CSS color string. */\n led?: boolean | string;\n};\n\nexport function AmbientSwitch({\n className,\n checked,\n defaultChecked,\n onCheckedChange,\n onClick,\n size = \"md\",\n label,\n led,\n children,\n ...props\n}: AmbientSwitchProps) {\n const labelId = useId();\n const isControlled = checked !== undefined;\n const [internalChecked, setInternalChecked] = useState(defaultChecked ?? false);\n const active = isControlled ? (checked ?? false) : internalChecked;\n\n const button = (\n <button\n type=\"button\"\n role=\"switch\"\n aria-checked={active}\n aria-labelledby={label ? labelId : props[\"aria-labelledby\"]}\n className={cn(\n \"amb-switch\",\n active && \"amb-switch-on\",\n \"ambx-switch\",\n `ambx-switch-${size}`,\n className\n )}\n onClick={(event) => {\n const next = !active;\n if (!isControlled) setInternalChecked(next);\n onCheckedChange?.(next);\n onClick?.(event);\n }}\n {...props}\n >\n {led ? (\n <span\n className={cn(\"amb-led\", !active && \"amb-led-off\")}\n style={typeof led === \"string\" ? { \"--amb-led-color\": led } as React.CSSProperties : undefined}\n />\n ) : null}\n <span className=\"amb-switch-track amb-groove\">\n <span className=\"amb-switch-pill ambient amb-fillet amb-surface-convex\" />\n </span>\n {children}\n </button>\n );\n\n if (!label) return button;\n\n return (\n <div className=\"ambx-stack\">\n {button}\n <span id={labelId} className=\"ambx-label\">\n {label}\n </span>\n </div>\n );\n}\n","import { useId, useRef } from \"react\";\nimport type { HTMLAttributes, KeyboardEvent, PointerEvent } from \"react\";\nimport { cn } from \"../lib/cn\";\n\n/* Straight-knurled silhouettes for the rotating face, in\n objectBoundingBox units so the clip scales with the component. Each\n variant family mirrors its referent's rib section\n (ambient3d/ground_components.py): trapezoid teeth between the outer\n radius and the tooth-root radius. The circular body underneath keeps\n the smooth drop shadow. */\ntype KnurlSpec = {\n teeth: number; // rib count\n root: number; // tooth-root radius (bounding-box units; outer is 0.5)\n rise: number; // fraction of the pitch spent climbing to the crest\n fall: [number, number]; // crest-end and root-return pitch fractions\n};\n\nconst KNURLS: Record<\"standard\" | \"flute\" | \"fine\", KnurlSpec> = {\n /* 36 ribs — the grounded referent knob (dot and line variants) */\n standard: { teeth: 36, root: 0.468, rise: 0.12, fall: [0.5, 0.62] },\n /* 14 broad flutes with deeper roots (OP-Z-style flute variant) */\n flute: { teeth: 14, root: 0.44, rise: 0.08, fall: [0.72, 0.8] },\n /* 48-rib fine knurl, shallower (cap and wheel variants) */\n fine: { teeth: 48, root: 0.476, rise: 0.12, fall: [0.5, 0.62] }\n};\n\nfunction knurlPath({ teeth, root, rise, fall }: KnurlSpec): string {\n const outer = 0.5;\n const pitch = (Math.PI * 2) / teeth;\n const pts: string[] = [];\n for (let i = 0; i < teeth; i++) {\n const a = i * pitch;\n const tooth: Array<[number, number]> = [\n [0, root],\n [rise, outer],\n [fall[0], outer],\n [fall[1], root]\n ];\n for (const [frac, radius] of tooth) {\n const t = a + frac * pitch;\n pts.push(\n `${(0.5 + radius * Math.cos(t)).toFixed(4)} ${(0.5 + radius * Math.sin(t)).toFixed(4)}`\n );\n }\n }\n return `M${pts.join(\" L\")} Z`;\n}\n\nconst KNURL_PATHS = {\n standard: knurlPath(KNURLS.standard),\n flute: knurlPath(KNURLS.flute),\n fine: knurlPath(KNURLS.fine)\n};\n\n/* Knob types from the referent lineup (ambient3d/generate.py):\n - \"dot\": the grounded referent — 36-rib knurl, offset indicator dot\n - \"line\": same body with a radial indicator line (classic pot)\n - \"flute\": 14 broad flutes, centered dot (OP-Z-style encoder)\n - \"cap\": fine knurl under a smooth accent top disc (OP-1-style)\n - \"wheel\": bare fine knurl, no indicator (machined wheel — pair with\n material=\"shiny\") */\nexport type AmbientKnobVariant = \"dot\" | \"line\" | \"flute\" | \"cap\" | \"wheel\";\n\nconst VARIANT_FAMILY: Record<AmbientKnobVariant, keyof typeof KNURL_PATHS> = {\n dot: \"standard\",\n line: \"standard\",\n flute: \"flute\",\n cap: \"fine\",\n wheel: \"fine\"\n};\n\nexport type AmbientKnobProps = Omit<HTMLAttributes<HTMLDivElement>, \"onChange\"> & {\n value: number;\n min?: number;\n max?: number;\n step?: number;\n label?: string;\n material?: \"matte\" | \"shiny\" | \"glass\";\n variant?: AmbientKnobVariant;\n onChange?: (nextValue: number) => void;\n};\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, value));\n}\n\nexport function AmbientKnob({\n value,\n min = 0,\n max = 100,\n step = 1,\n label,\n material,\n variant = \"dot\",\n onChange,\n className,\n ...props\n}: AmbientKnobProps) {\n const id = useId();\n const clipId = `amb-knurl-${id.replace(/:/g, \"\")}`;\n const draggingRef = useRef(false);\n const knobRef = useRef<HTMLDivElement>(null);\n const safeStep = step > 0 ? step : 1;\n const family = VARIANT_FAMILY[variant];\n\n const percent = (value - min) / (max - min || 1);\n const rotation = percent * 270 - 135;\n\n // Convert pointer position to a knob angle in [-180, 180] where 0 = up,\n // positive = clockwise. The knob's active range is [-135, 135] (270°),\n // with the dead zone at the bottom (~135° to ~225° i.e. past ±135°).\n const pointerToValue = (event: PointerEvent<HTMLDivElement>) => {\n const rect = knobRef.current!.getBoundingClientRect();\n const cx = rect.left + rect.width / 2;\n const cy = rect.top + rect.height / 2;\n // atan2 with screen coords: 0=right, 90=down; add 90 to rotate so 0=up\n const atan2Deg = Math.atan2(event.clientY - cy, event.clientX - cx) * (180 / Math.PI);\n let angle = atan2Deg + 90;\n // Normalize to [-180, 180]\n if (angle > 180) angle -= 360;\n\n // Clamp dead zone based on current value position\n if (angle < -135 || angle > 135) {\n angle = percent >= 0.5 ? 135 : -135;\n }\n\n const range = max - min;\n const raw = min + ((angle + 135) / 270) * range;\n const snapped = Math.round(raw / safeStep) * safeStep;\n onChange?.(clamp(snapped, min, max));\n };\n\n const setValue = (nextValue: number) => {\n const snapped = Math.round(nextValue / safeStep) * safeStep;\n onChange?.(clamp(snapped, min, max));\n };\n\n const onKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n const pageStep = safeStep * 10;\n switch (event.key) {\n case \"ArrowUp\":\n case \"ArrowRight\":\n event.preventDefault();\n setValue(value + safeStep);\n break;\n case \"ArrowDown\":\n case \"ArrowLeft\":\n event.preventDefault();\n setValue(value - safeStep);\n break;\n case \"PageUp\":\n event.preventDefault();\n setValue(value + pageStep);\n break;\n case \"PageDown\":\n event.preventDefault();\n setValue(value - pageStep);\n break;\n case \"Home\":\n event.preventDefault();\n setValue(min);\n break;\n case \"End\":\n event.preventDefault();\n setValue(max);\n break;\n default:\n break;\n }\n };\n\n return (\n <div className={cn(\"ambx-stack\", className)} {...props}>\n <div\n ref={knobRef}\n className=\"amb-knob ambx-knob\"\n role=\"slider\"\n aria-label={label}\n aria-valuemin={min}\n aria-valuemax={max}\n aria-valuenow={value}\n aria-labelledby={label ? id : undefined}\n aria-orientation=\"vertical\"\n tabIndex={0}\n onPointerDown={(event) => {\n event.currentTarget.setPointerCapture(event.pointerId);\n draggingRef.current = true;\n pointerToValue(event);\n }}\n onPointerMove={(event) => {\n if (draggingRef.current) pointerToValue(event);\n }}\n onPointerUp={() => {\n draggingRef.current = false;\n }}\n onPointerCancel={() => {\n draggingRef.current = false;\n }}\n onKeyDown={onKeyDown}\n >\n <svg width={0} height={0} style={{ position: \"absolute\" }} aria-hidden focusable={false}>\n <defs>\n <clipPath id={clipId} clipPathUnits=\"objectBoundingBox\">\n <path d={KNURL_PATHS[family]} />\n </clipPath>\n </defs>\n </svg>\n <span className=\"amb-knob-body ambient amb-thickness-2 amb-surface\" />\n <div\n className={cn(\n \"ambx-knob-rotation amb-knob-face\",\n family === \"flute\" && \"amb-knob-face-flute\",\n family === \"fine\" && \"amb-knob-face-fine\",\n variant === \"cap\" && \"amb-knob-face-cap\",\n material && `amb-mat-${material}`\n )}\n style={{ transform: `rotate(${rotation}deg)`, clipPath: `url(#${clipId})` }}\n >\n {variant === \"dot\" ? <span className=\"amb-knob-indicator-dot\" /> : null}\n {variant === \"line\" ? <span className=\"amb-knob-indicator-line\" /> : null}\n {variant === \"flute\" ? (\n <span className=\"amb-knob-indicator-dot amb-knob-indicator-dot-center\" />\n ) : null}\n </div>\n </div>\n {label ? (\n <span id={id} className=\"ambx-label\">\n {label}\n </span>\n ) : null}\n </div>\n );\n}\n","import { useId, useRef } from \"react\";\nimport type { HTMLAttributes, KeyboardEvent, PointerEvent } from \"react\";\nimport { cn } from \"../lib/cn\";\n\nexport type AmbientFaderProps = Omit<HTMLAttributes<HTMLDivElement>, \"onChange\"> & {\n value: number;\n min?: number;\n max?: number;\n step?: number;\n label?: string;\n material?: \"matte\" | \"shiny\" | \"glass\";\n onChange?: (nextValue: number) => void;\n};\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, value));\n}\n\nexport function AmbientFader({\n value,\n min = 0,\n max = 100,\n step = 1,\n label,\n material,\n onChange,\n className,\n ...props\n}: AmbientFaderProps) {\n const id = useId();\n const trackRef = useRef<HTMLDivElement | null>(null);\n const safeStep = step > 0 ? step : 1;\n\n const percent = ((value - min) / (max - min || 1)) * 100;\n\n const updateFromClientY = (clientY: number) => {\n const track = trackRef.current;\n if (!track) return;\n\n const rect = track.getBoundingClientRect();\n const ratio = 1 - (clientY - rect.top) / rect.height;\n const nextValue = min + clamp(ratio, 0, 1) * (max - min);\n const snapped = Math.round(nextValue / safeStep) * safeStep;\n onChange?.(clamp(snapped, min, max));\n };\n\n const setValue = (nextValue: number) => {\n const snapped = Math.round(nextValue / safeStep) * safeStep;\n onChange?.(clamp(snapped, min, max));\n };\n\n const onKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n const pageStep = safeStep * 10;\n switch (event.key) {\n case \"ArrowUp\":\n case \"ArrowRight\":\n event.preventDefault();\n setValue(value + safeStep);\n break;\n case \"ArrowDown\":\n case \"ArrowLeft\":\n event.preventDefault();\n setValue(value - safeStep);\n break;\n case \"PageUp\":\n event.preventDefault();\n setValue(value + pageStep);\n break;\n case \"PageDown\":\n event.preventDefault();\n setValue(value - pageStep);\n break;\n case \"Home\":\n event.preventDefault();\n setValue(min);\n break;\n case \"End\":\n event.preventDefault();\n setValue(max);\n break;\n default:\n break;\n }\n };\n\n const onPointerMove = (event: PointerEvent<HTMLDivElement>) => {\n if (event.buttons !== 1) return;\n updateFromClientY(event.clientY);\n };\n\n return (\n <div className={cn(\"ambx-stack\", className)} {...props}>\n <div\n className=\"amb-fader amb-groove ambx-fader\"\n ref={trackRef}\n role=\"slider\"\n aria-label={label}\n aria-labelledby={label ? id : undefined}\n aria-valuemin={min}\n aria-valuemax={max}\n aria-valuenow={value}\n aria-orientation=\"vertical\"\n tabIndex={0}\n onPointerDown={(event) => {\n event.currentTarget.setPointerCapture(event.pointerId);\n updateFromClientY(event.clientY);\n }}\n onPointerMove={onPointerMove}\n onKeyDown={onKeyDown}\n >\n <div\n className={cn(\"amb-fader-thumb ambient amb-fillet ambx-fader-thumb\", material !== \"glass\" && \"amb-surface-concave\", material && `amb-mat-${material}`)}\n style={{ top: `${100 - percent}%` }}\n >\n <span className=\"amb-fader-gripline\" />\n </div>\n </div>\n {label ? (\n <span id={id} className=\"ambx-label\">\n {label}\n </span>\n ) : null}\n </div>\n );\n}\n","import { useId, useRef } from \"react\";\nimport type { HTMLAttributes, KeyboardEvent, PointerEvent } from \"react\";\nimport { cn } from \"../lib/cn\";\n\nexport type AmbientSliderProps = Omit<HTMLAttributes<HTMLDivElement>, \"onChange\"> & {\n value: number;\n min?: number;\n max?: number;\n step?: number;\n label?: string;\n material?: \"matte\" | \"shiny\" | \"glass\";\n onChange?: (nextValue: number) => void;\n};\n\nfunction clamp(value: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, value));\n}\n\nexport function AmbientSlider({\n value,\n min = 0,\n max = 100,\n step = 1,\n label,\n material,\n onChange,\n className,\n ...props\n}: AmbientSliderProps) {\n const id = useId();\n const trackRef = useRef<HTMLDivElement | null>(null);\n const safeStep = step > 0 ? step : 1;\n\n const percent = ((value - min) / (max - min || 1)) * 100;\n\n const updateFromClientX = (clientX: number) => {\n const track = trackRef.current;\n if (!track) return;\n\n const rect = track.getBoundingClientRect();\n const ratio = (clientX - rect.left) / rect.width;\n const nextValue = min + clamp(ratio, 0, 1) * (max - min);\n const snapped = Math.round(nextValue / safeStep) * safeStep;\n onChange?.(clamp(snapped, min, max));\n };\n\n const setValue = (nextValue: number) => {\n const snapped = Math.round(nextValue / safeStep) * safeStep;\n onChange?.(clamp(snapped, min, max));\n };\n\n const onKeyDown = (event: KeyboardEvent<HTMLDivElement>) => {\n const pageStep = safeStep * 10;\n switch (event.key) {\n case \"ArrowRight\":\n case \"ArrowUp\":\n event.preventDefault();\n setValue(value + safeStep);\n break;\n case \"ArrowLeft\":\n case \"ArrowDown\":\n event.preventDefault();\n setValue(value - safeStep);\n break;\n case \"PageUp\":\n event.preventDefault();\n setValue(value + pageStep);\n break;\n case \"PageDown\":\n event.preventDefault();\n setValue(value - pageStep);\n break;\n case \"Home\":\n event.preventDefault();\n setValue(min);\n break;\n case \"End\":\n event.preventDefault();\n setValue(max);\n break;\n default:\n break;\n }\n };\n\n const onPointerMove = (event: PointerEvent<HTMLDivElement>) => {\n if (event.buttons !== 1) return;\n updateFromClientX(event.clientX);\n };\n\n return (\n <div className={cn(\"ambx-stack\", className)} {...props}>\n <div\n className=\"amb-slider amb-groove ambx-slider\"\n ref={trackRef}\n role=\"slider\"\n aria-label={label}\n aria-labelledby={label ? id : undefined}\n aria-valuemin={min}\n aria-valuemax={max}\n aria-valuenow={value}\n aria-orientation=\"horizontal\"\n tabIndex={0}\n onPointerDown={(event) => {\n event.currentTarget.setPointerCapture(event.pointerId);\n updateFromClientX(event.clientX);\n }}\n onPointerMove={onPointerMove}\n onKeyDown={onKeyDown}\n >\n <div\n className={cn(\"amb-slider-thumb ambient amb-fillet ambx-slider-thumb\", material !== \"glass\" && \"amb-surface-convex\", material && `amb-mat-${material}`)}\n style={{ left: `${percent}%` }}\n />\n </div>\n {label ? (\n <span id={id} className=\"ambx-label\">\n {label}\n </span>\n ) : null}\n </div>\n );\n}\n"],"mappings":"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","names":["import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_react","import_jsx_runtime","import_react","import_jsx_runtime","clamp","import_react","import_jsx_runtime","clamp"]}
|
package/dist/index.d.cts
CHANGED
|
@@ -23,10 +23,12 @@ interface AmbientPanelProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
23
23
|
}
|
|
24
24
|
declare function AmbientPanel({ className, material, ...props }: AmbientPanelProps): react_jsx_runtime.JSX.Element;
|
|
25
25
|
|
|
26
|
+
type AmbientButtonShape = "pill" | "round" | "square";
|
|
26
27
|
interface AmbientButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
27
28
|
material?: "matte" | "shiny" | "glass";
|
|
29
|
+
shape?: AmbientButtonShape;
|
|
28
30
|
}
|
|
29
|
-
declare function AmbientButton({ className, children, material, ...props }: AmbientButtonProps): react_jsx_runtime.JSX.Element;
|
|
31
|
+
declare function AmbientButton({ className, children, material, shape, ...props }: AmbientButtonProps): react_jsx_runtime.JSX.Element;
|
|
30
32
|
|
|
31
33
|
type AmbientSwitchSize = "sm" | "md" | "lg";
|
|
32
34
|
type AmbientSwitchProps = Omit<ButtonHTMLAttributes<HTMLButtonElement>, "onChange"> & {
|
|
@@ -40,6 +42,7 @@ type AmbientSwitchProps = Omit<ButtonHTMLAttributes<HTMLButtonElement>, "onChang
|
|
|
40
42
|
};
|
|
41
43
|
declare function AmbientSwitch({ className, checked, defaultChecked, onCheckedChange, onClick, size, label, led, children, ...props }: AmbientSwitchProps): react_jsx_runtime.JSX.Element;
|
|
42
44
|
|
|
45
|
+
type AmbientKnobVariant = "dot" | "line" | "flute" | "cap" | "wheel";
|
|
43
46
|
type AmbientKnobProps = Omit<HTMLAttributes<HTMLDivElement>, "onChange"> & {
|
|
44
47
|
value: number;
|
|
45
48
|
min?: number;
|
|
@@ -47,9 +50,10 @@ type AmbientKnobProps = Omit<HTMLAttributes<HTMLDivElement>, "onChange"> & {
|
|
|
47
50
|
step?: number;
|
|
48
51
|
label?: string;
|
|
49
52
|
material?: "matte" | "shiny" | "glass";
|
|
53
|
+
variant?: AmbientKnobVariant;
|
|
50
54
|
onChange?: (nextValue: number) => void;
|
|
51
55
|
};
|
|
52
|
-
declare function AmbientKnob({ value, min, max, step, label, material, onChange, className, ...props }: AmbientKnobProps): react_jsx_runtime.JSX.Element;
|
|
56
|
+
declare function AmbientKnob({ value, min, max, step, label, material, variant, onChange, className, ...props }: AmbientKnobProps): react_jsx_runtime.JSX.Element;
|
|
53
57
|
|
|
54
58
|
type AmbientFaderProps = Omit<HTMLAttributes<HTMLDivElement>, "onChange"> & {
|
|
55
59
|
value: number;
|
|
@@ -73,4 +77,4 @@ type AmbientSliderProps = Omit<HTMLAttributes<HTMLDivElement>, "onChange"> & {
|
|
|
73
77
|
};
|
|
74
78
|
declare function AmbientSlider({ value, min, max, step, label, material, onChange, className, ...props }: AmbientSliderProps): react_jsx_runtime.JSX.Element;
|
|
75
79
|
|
|
76
|
-
export { AmbientButton, type AmbientButtonProps, AmbientFader, type AmbientFaderProps, AmbientKnob, type AmbientKnobProps, AmbientPanel, type AmbientPanelProps, AmbientProvider, type AmbientProviderProps, AmbientSlider, type AmbientSliderProps, AmbientSwitch, type AmbientSwitchProps, type AmbientSwitchSize, type AmbientTheme };
|
|
80
|
+
export { AmbientButton, type AmbientButtonProps, type AmbientButtonShape, AmbientFader, type AmbientFaderProps, AmbientKnob, type AmbientKnobProps, type AmbientKnobVariant, AmbientPanel, type AmbientPanelProps, AmbientProvider, type AmbientProviderProps, AmbientSlider, type AmbientSliderProps, AmbientSwitch, type AmbientSwitchProps, type AmbientSwitchSize, type AmbientTheme };
|
package/dist/index.d.ts
CHANGED
|
@@ -23,10 +23,12 @@ interface AmbientPanelProps extends HTMLAttributes<HTMLDivElement> {
|
|
|
23
23
|
}
|
|
24
24
|
declare function AmbientPanel({ className, material, ...props }: AmbientPanelProps): react_jsx_runtime.JSX.Element;
|
|
25
25
|
|
|
26
|
+
type AmbientButtonShape = "pill" | "round" | "square";
|
|
26
27
|
interface AmbientButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
|
|
27
28
|
material?: "matte" | "shiny" | "glass";
|
|
29
|
+
shape?: AmbientButtonShape;
|
|
28
30
|
}
|
|
29
|
-
declare function AmbientButton({ className, children, material, ...props }: AmbientButtonProps): react_jsx_runtime.JSX.Element;
|
|
31
|
+
declare function AmbientButton({ className, children, material, shape, ...props }: AmbientButtonProps): react_jsx_runtime.JSX.Element;
|
|
30
32
|
|
|
31
33
|
type AmbientSwitchSize = "sm" | "md" | "lg";
|
|
32
34
|
type AmbientSwitchProps = Omit<ButtonHTMLAttributes<HTMLButtonElement>, "onChange"> & {
|
|
@@ -40,6 +42,7 @@ type AmbientSwitchProps = Omit<ButtonHTMLAttributes<HTMLButtonElement>, "onChang
|
|
|
40
42
|
};
|
|
41
43
|
declare function AmbientSwitch({ className, checked, defaultChecked, onCheckedChange, onClick, size, label, led, children, ...props }: AmbientSwitchProps): react_jsx_runtime.JSX.Element;
|
|
42
44
|
|
|
45
|
+
type AmbientKnobVariant = "dot" | "line" | "flute" | "cap" | "wheel";
|
|
43
46
|
type AmbientKnobProps = Omit<HTMLAttributes<HTMLDivElement>, "onChange"> & {
|
|
44
47
|
value: number;
|
|
45
48
|
min?: number;
|
|
@@ -47,9 +50,10 @@ type AmbientKnobProps = Omit<HTMLAttributes<HTMLDivElement>, "onChange"> & {
|
|
|
47
50
|
step?: number;
|
|
48
51
|
label?: string;
|
|
49
52
|
material?: "matte" | "shiny" | "glass";
|
|
53
|
+
variant?: AmbientKnobVariant;
|
|
50
54
|
onChange?: (nextValue: number) => void;
|
|
51
55
|
};
|
|
52
|
-
declare function AmbientKnob({ value, min, max, step, label, material, onChange, className, ...props }: AmbientKnobProps): react_jsx_runtime.JSX.Element;
|
|
56
|
+
declare function AmbientKnob({ value, min, max, step, label, material, variant, onChange, className, ...props }: AmbientKnobProps): react_jsx_runtime.JSX.Element;
|
|
53
57
|
|
|
54
58
|
type AmbientFaderProps = Omit<HTMLAttributes<HTMLDivElement>, "onChange"> & {
|
|
55
59
|
value: number;
|
|
@@ -73,4 +77,4 @@ type AmbientSliderProps = Omit<HTMLAttributes<HTMLDivElement>, "onChange"> & {
|
|
|
73
77
|
};
|
|
74
78
|
declare function AmbientSlider({ value, min, max, step, label, material, onChange, className, ...props }: AmbientSliderProps): react_jsx_runtime.JSX.Element;
|
|
75
79
|
|
|
76
|
-
export { AmbientButton, type AmbientButtonProps, AmbientFader, type AmbientFaderProps, AmbientKnob, type AmbientKnobProps, AmbientPanel, type AmbientPanelProps, AmbientProvider, type AmbientProviderProps, AmbientSlider, type AmbientSliderProps, AmbientSwitch, type AmbientSwitchProps, type AmbientSwitchSize, type AmbientTheme };
|
|
80
|
+
export { AmbientButton, type AmbientButtonProps, type AmbientButtonShape, AmbientFader, type AmbientFaderProps, AmbientKnob, type AmbientKnobProps, type AmbientKnobVariant, AmbientPanel, type AmbientPanelProps, AmbientProvider, type AmbientProviderProps, AmbientSlider, type AmbientSliderProps, AmbientSwitch, type AmbientSwitchProps, type AmbientSwitchSize, type AmbientTheme };
|