@ambientcss/components 1.2.0 → 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.js CHANGED
@@ -52,18 +52,34 @@ function AmbientPanel({ className, material = "matte", ...props }) {
52
52
 
53
53
  // src/components/AmbientButton.tsx
54
54
  import { jsx as jsx3 } from "react/jsx-runtime";
55
- function AmbientButton({ className, children, material = "matte", ...props }) {
55
+ function AmbientButton({
56
+ className,
57
+ children,
58
+ material = "matte",
59
+ shape = "pill",
60
+ ...props
61
+ }) {
56
62
  return /* @__PURE__ */ jsx3(
57
63
  "button",
58
64
  {
59
65
  type: "button",
60
66
  className: cn(
61
- "ambient amb-button amb-chamfer amb-elevation-1 ambx-button amb-heading-3",
62
- material === "matte" ? "amb-mat-matte" : material === "shiny" ? "amb-mat-shiny" : "amb-mat-glass",
67
+ "amb-button amb-groove ambx-button",
68
+ shape === "round" && "amb-button-round",
69
+ shape === "square" && "amb-button-square",
63
70
  className
64
71
  ),
65
72
  ...props,
66
- children
73
+ children: /* @__PURE__ */ jsx3(
74
+ "span",
75
+ {
76
+ className: cn(
77
+ "amb-button-cap ambient amb-chamfer amb-surface amb-heading-3",
78
+ material === "matte" ? "amb-mat-matte" : material === "shiny" ? "amb-mat-shiny" : "amb-mat-glass"
79
+ ),
80
+ children
81
+ }
82
+ )
67
83
  }
68
84
  );
69
85
  }
@@ -95,8 +111,8 @@ function AmbientSwitch({
95
111
  "aria-checked": active,
96
112
  "aria-labelledby": label ? labelId : props["aria-labelledby"],
97
113
  className: cn(
98
- "ambient amb-switch amb-chamfer amb-elevation-1 amb-heading-3",
99
- active ? "amb-surface-convex amb-switch-on" : "amb-surface-concave",
114
+ "amb-switch",
115
+ active && "amb-switch-on",
100
116
  "ambx-switch",
101
117
  `ambx-switch-${size}`,
102
118
  className
@@ -116,6 +132,7 @@ function AmbientSwitch({
116
132
  style: typeof led === "string" ? { "--amb-led-color": led } : void 0
117
133
  }
118
134
  ) : null,
135
+ /* @__PURE__ */ jsx4("span", { className: "amb-switch-track amb-groove", children: /* @__PURE__ */ jsx4("span", { className: "amb-switch-pill ambient amb-fillet amb-surface-convex" }) }),
119
136
  children
120
137
  ]
121
138
  }
@@ -130,6 +147,47 @@ function AmbientSwitch({
130
147
  // src/components/AmbientKnob.tsx
131
148
  import { useId as useId2, useRef } from "react";
132
149
  import { jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
150
+ var KNURLS = {
151
+ /* 36 ribs — the grounded referent knob (dot and line variants) */
152
+ standard: { teeth: 36, root: 0.468, rise: 0.12, fall: [0.5, 0.62] },
153
+ /* 14 broad flutes with deeper roots (OP-Z-style flute variant) */
154
+ flute: { teeth: 14, root: 0.44, rise: 0.08, fall: [0.72, 0.8] },
155
+ /* 48-rib fine knurl, shallower (cap and wheel variants) */
156
+ fine: { teeth: 48, root: 0.476, rise: 0.12, fall: [0.5, 0.62] }
157
+ };
158
+ function knurlPath({ teeth, root, rise, fall }) {
159
+ const outer = 0.5;
160
+ const pitch = Math.PI * 2 / teeth;
161
+ const pts = [];
162
+ for (let i = 0; i < teeth; i++) {
163
+ const a = i * pitch;
164
+ const tooth = [
165
+ [0, root],
166
+ [rise, outer],
167
+ [fall[0], outer],
168
+ [fall[1], root]
169
+ ];
170
+ for (const [frac, radius] of tooth) {
171
+ const t = a + frac * pitch;
172
+ pts.push(
173
+ `${(0.5 + radius * Math.cos(t)).toFixed(4)} ${(0.5 + radius * Math.sin(t)).toFixed(4)}`
174
+ );
175
+ }
176
+ }
177
+ return `M${pts.join(" L")} Z`;
178
+ }
179
+ var KNURL_PATHS = {
180
+ standard: knurlPath(KNURLS.standard),
181
+ flute: knurlPath(KNURLS.flute),
182
+ fine: knurlPath(KNURLS.fine)
183
+ };
184
+ var VARIANT_FAMILY = {
185
+ dot: "standard",
186
+ line: "standard",
187
+ flute: "flute",
188
+ cap: "fine",
189
+ wheel: "fine"
190
+ };
133
191
  function clamp(value, min, max) {
134
192
  return Math.min(max, Math.max(min, value));
135
193
  }
@@ -140,14 +198,17 @@ function AmbientKnob({
140
198
  step = 1,
141
199
  label,
142
200
  material,
201
+ variant = "dot",
143
202
  onChange,
144
203
  className,
145
204
  ...props
146
205
  }) {
147
206
  const id = useId2();
207
+ const clipId = `amb-knurl-${id.replace(/:/g, "")}`;
148
208
  const draggingRef = useRef(false);
149
209
  const knobRef = useRef(null);
150
210
  const safeStep = step > 0 ? step : 1;
211
+ const family = VARIANT_FAMILY[variant];
151
212
  const percent = (value - min) / (max - min || 1);
152
213
  const rotation = percent * 270 - 135;
153
214
  const pointerToValue = (event) => {
@@ -203,11 +264,11 @@ function AmbientKnob({
203
264
  }
204
265
  };
205
266
  return /* @__PURE__ */ jsxs2("div", { className: cn("ambx-stack", className), ...props, children: [
206
- /* @__PURE__ */ jsx5(
267
+ /* @__PURE__ */ jsxs2(
207
268
  "div",
208
269
  {
209
270
  ref: knobRef,
210
- className: cn("ambient amb-knob amb-chamfer amb-elevation-2 amb-surface ambx-knob", material && `amb-mat-${material}`),
271
+ className: "amb-knob ambx-knob",
211
272
  role: "slider",
212
273
  "aria-label": label,
213
274
  "aria-valuemin": min,
@@ -231,11 +292,28 @@ function AmbientKnob({
231
292
  draggingRef.current = false;
232
293
  },
233
294
  onKeyDown,
234
- children: /* @__PURE__ */ jsx5("div", { className: "ambx-knob-rotation", style: { transform: `rotate(${rotation}deg)` }, children: /* @__PURE__ */ jsx5("div", { className: "amb-knob-indicator", children: /* @__PURE__ */ jsxs2("div", { className: "amb-knob-grip", children: [
235
- /* @__PURE__ */ jsx5("span", { className: "amb-fader-dot" }),
236
- /* @__PURE__ */ jsx5("span", { className: "amb-fader-dot" }),
237
- /* @__PURE__ */ jsx5("span", { className: "amb-fader-dot" })
238
- ] }) }) })
295
+ children: [
296
+ /* @__PURE__ */ jsx5("svg", { width: 0, height: 0, style: { position: "absolute" }, "aria-hidden": true, focusable: false, children: /* @__PURE__ */ jsx5("defs", { children: /* @__PURE__ */ jsx5("clipPath", { id: clipId, clipPathUnits: "objectBoundingBox", children: /* @__PURE__ */ jsx5("path", { d: KNURL_PATHS[family] }) }) }) }),
297
+ /* @__PURE__ */ jsx5("span", { className: "amb-knob-body ambient amb-thickness-2 amb-surface" }),
298
+ /* @__PURE__ */ jsxs2(
299
+ "div",
300
+ {
301
+ className: cn(
302
+ "ambx-knob-rotation amb-knob-face",
303
+ family === "flute" && "amb-knob-face-flute",
304
+ family === "fine" && "amb-knob-face-fine",
305
+ variant === "cap" && "amb-knob-face-cap",
306
+ material && `amb-mat-${material}`
307
+ ),
308
+ style: { transform: `rotate(${rotation}deg)`, clipPath: `url(#${clipId})` },
309
+ children: [
310
+ variant === "dot" ? /* @__PURE__ */ jsx5("span", { className: "amb-knob-indicator-dot" }) : null,
311
+ variant === "line" ? /* @__PURE__ */ jsx5("span", { className: "amb-knob-indicator-line" }) : null,
312
+ variant === "flute" ? /* @__PURE__ */ jsx5("span", { className: "amb-knob-indicator-dot amb-knob-indicator-dot-center" }) : null
313
+ ]
314
+ }
315
+ )
316
+ ]
239
317
  }
240
318
  ),
241
319
  label ? /* @__PURE__ */ jsx5("span", { id, className: "ambx-label", children: label }) : null
@@ -317,7 +395,7 @@ function AmbientFader({
317
395
  /* @__PURE__ */ jsx6(
318
396
  "div",
319
397
  {
320
- className: "amb-fader ambx-fader",
398
+ className: "amb-fader amb-groove ambx-fader",
321
399
  ref: trackRef,
322
400
  role: "slider",
323
401
  "aria-label": label,
@@ -336,13 +414,9 @@ function AmbientFader({
336
414
  children: /* @__PURE__ */ jsx6(
337
415
  "div",
338
416
  {
339
- className: cn("amb-fader-thumb ambient amb-fillet amb-elevation-1 ambx-fader-thumb", material !== "glass" && "amb-surface-concave", material && `amb-mat-${material}`),
417
+ className: cn("amb-fader-thumb ambient amb-fillet ambx-fader-thumb", material !== "glass" && "amb-surface-concave", material && `amb-mat-${material}`),
340
418
  style: { top: `${100 - percent}%` },
341
- children: /* @__PURE__ */ jsxs3("div", { className: "amb-fader-grip", children: [
342
- /* @__PURE__ */ jsx6("span", { className: "amb-fader-dot" }),
343
- /* @__PURE__ */ jsx6("span", { className: "amb-fader-dot" }),
344
- /* @__PURE__ */ jsx6("span", { className: "amb-fader-dot" })
345
- ] })
419
+ children: /* @__PURE__ */ jsx6("span", { className: "amb-fader-gripline" })
346
420
  }
347
421
  )
348
422
  }
@@ -426,7 +500,7 @@ function AmbientSlider({
426
500
  /* @__PURE__ */ jsx7(
427
501
  "div",
428
502
  {
429
- className: "amb-slider ambx-slider",
503
+ className: "amb-slider amb-groove ambx-slider",
430
504
  ref: trackRef,
431
505
  role: "slider",
432
506
  "aria-label": label,
@@ -445,13 +519,8 @@ function AmbientSlider({
445
519
  children: /* @__PURE__ */ jsx7(
446
520
  "div",
447
521
  {
448
- className: cn("amb-slider-thumb ambient amb-fillet amb-elevation-1 ambx-slider-thumb", material !== "glass" && "amb-surface-concave-h", material && `amb-mat-${material}`),
449
- style: { left: `${percent}%` },
450
- children: /* @__PURE__ */ jsxs4("div", { className: "amb-slider-grip", children: [
451
- /* @__PURE__ */ jsx7("span", { className: "amb-fader-dot" }),
452
- /* @__PURE__ */ jsx7("span", { className: "amb-fader-dot" }),
453
- /* @__PURE__ */ jsx7("span", { className: "amb-fader-dot" })
454
- ] })
522
+ className: cn("amb-slider-thumb ambient amb-fillet ambx-slider-thumb", material !== "glass" && "amb-surface-convex", material && `amb-mat-${material}`),
523
+ style: { left: `${percent}%` }
455
524
  }
456
525
  )
457
526
  }
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../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":["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":["jsx","jsx","jsx","useId","jsx","jsxs","useId","useId","useRef","jsx","jsxs","clamp","useId","useRef","useId","useRef","jsx","jsxs","clamp","useId","useRef"]}
1
+ {"version":3,"sources":["../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":["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":["jsx","jsx","jsx","useId","jsx","jsxs","useId","useId","useRef","jsx","jsxs","clamp","useId","useRef","useId","useRef","jsx","jsxs","clamp","useId","useRef"]}