@ambientcss/components 2.0.1 → 2.1.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
@@ -50,27 +50,52 @@ function AmbientPanel({ className, material = "matte", ...props }) {
50
50
  );
51
51
  }
52
52
 
53
- // src/components/AmbientButton.tsx
53
+ // src/components/AmbientRack.tsx
54
54
  import { jsx as jsx3 } from "react/jsx-runtime";
55
+ function AmbientRack({
56
+ className,
57
+ gap = "normal",
58
+ direction = "row",
59
+ ...props
60
+ }) {
61
+ return /* @__PURE__ */ jsx3(
62
+ "div",
63
+ {
64
+ className: cn(
65
+ "ambx-rack",
66
+ gap === "tight" && "ambx-rack-tight",
67
+ gap === "loose" && "ambx-rack-loose",
68
+ direction === "column" && "ambx-rack-column",
69
+ className
70
+ ),
71
+ ...props
72
+ }
73
+ );
74
+ }
75
+
76
+ // src/components/AmbientButton.tsx
77
+ import { jsx as jsx4 } from "react/jsx-runtime";
55
78
  function AmbientButton({
56
79
  className,
57
80
  children,
58
81
  material = "matte",
59
82
  shape = "pill",
83
+ size = "md",
60
84
  ...props
61
85
  }) {
62
- return /* @__PURE__ */ jsx3(
86
+ return /* @__PURE__ */ jsx4(
63
87
  "button",
64
88
  {
65
89
  type: "button",
66
90
  className: cn(
67
91
  "amb-button amb-groove ambx-button",
92
+ `ambx-button-${size}`,
68
93
  shape === "round" && "amb-button-round",
69
94
  shape === "square" && "amb-button-square",
70
95
  className
71
96
  ),
72
97
  ...props,
73
- children: /* @__PURE__ */ jsx3(
98
+ children: /* @__PURE__ */ jsx4(
74
99
  "span",
75
100
  {
76
101
  className: cn(
@@ -86,7 +111,7 @@ function AmbientButton({
86
111
 
87
112
  // src/components/AmbientSwitch.tsx
88
113
  import { useId, useState } from "react";
89
- import { jsx as jsx4, jsxs } from "react/jsx-runtime";
114
+ import { jsx as jsx5, jsxs } from "react/jsx-runtime";
90
115
  function AmbientSwitch({
91
116
  className,
92
117
  checked,
@@ -125,14 +150,14 @@ function AmbientSwitch({
125
150
  },
126
151
  ...props,
127
152
  children: [
128
- led ? /* @__PURE__ */ jsx4(
153
+ led ? /* @__PURE__ */ jsx5(
129
154
  "span",
130
155
  {
131
156
  className: cn("amb-led", !active && "amb-led-off"),
132
157
  style: typeof led === "string" ? { "--amb-led-color": led } : void 0
133
158
  }
134
159
  ) : 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" }) }),
160
+ /* @__PURE__ */ jsx5("span", { className: "amb-switch-track amb-groove", children: /* @__PURE__ */ jsx5("span", { className: "amb-switch-pill ambient amb-fillet amb-surface-convex" }) }),
136
161
  children
137
162
  ]
138
163
  }
@@ -140,13 +165,13 @@ function AmbientSwitch({
140
165
  if (!label) return button;
141
166
  return /* @__PURE__ */ jsxs("div", { className: "ambx-stack", children: [
142
167
  button,
143
- /* @__PURE__ */ jsx4("span", { id: labelId, className: "ambx-label", children: label })
168
+ /* @__PURE__ */ jsx5("span", { id: labelId, className: "ambx-label", children: label })
144
169
  ] });
145
170
  }
146
171
 
147
172
  // src/components/AmbientKnob.tsx
148
173
  import { useId as useId2, useRef } from "react";
149
- import { jsx as jsx5, jsxs as jsxs2 } from "react/jsx-runtime";
174
+ import { jsx as jsx6, jsxs as jsxs2 } from "react/jsx-runtime";
150
175
  var KNURLS = {
151
176
  /* 36 ribs — the grounded referent knob (dot and line variants) */
152
177
  standard: { teeth: 36, root: 0.468, rise: 0.12, fall: [0.5, 0.62] },
@@ -199,6 +224,7 @@ function AmbientKnob({
199
224
  label,
200
225
  material,
201
226
  variant = "dot",
227
+ size = "md",
202
228
  onChange,
203
229
  className,
204
230
  ...props
@@ -268,7 +294,7 @@ function AmbientKnob({
268
294
  "div",
269
295
  {
270
296
  ref: knobRef,
271
- className: "amb-knob ambx-knob",
297
+ className: cn("amb-knob ambx-knob", `ambx-knob-${size}`),
272
298
  role: "slider",
273
299
  "aria-label": label,
274
300
  "aria-valuemin": min,
@@ -293,8 +319,8 @@ function AmbientKnob({
293
319
  },
294
320
  onKeyDown,
295
321
  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" }),
322
+ /* @__PURE__ */ jsx6("svg", { width: 0, height: 0, style: { position: "absolute" }, "aria-hidden": true, focusable: false, children: /* @__PURE__ */ jsx6("defs", { children: /* @__PURE__ */ jsx6("clipPath", { id: clipId, clipPathUnits: "objectBoundingBox", children: /* @__PURE__ */ jsx6("path", { d: KNURL_PATHS[family] }) }) }) }),
323
+ /* @__PURE__ */ jsx6("span", { className: "amb-knob-body ambient amb-thickness-2 amb-surface" }),
298
324
  /* @__PURE__ */ jsxs2(
299
325
  "div",
300
326
  {
@@ -307,22 +333,22 @@ function AmbientKnob({
307
333
  ),
308
334
  style: { transform: `rotate(${rotation}deg)`, clipPath: `url(#${clipId})` },
309
335
  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
336
+ variant === "dot" ? /* @__PURE__ */ jsx6("span", { className: "amb-knob-indicator-dot" }) : null,
337
+ variant === "line" ? /* @__PURE__ */ jsx6("span", { className: "amb-knob-indicator-line" }) : null,
338
+ variant === "flute" ? /* @__PURE__ */ jsx6("span", { className: "amb-knob-indicator-dot amb-knob-indicator-dot-center" }) : null
313
339
  ]
314
340
  }
315
341
  )
316
342
  ]
317
343
  }
318
344
  ),
319
- label ? /* @__PURE__ */ jsx5("span", { id, className: "ambx-label", children: label }) : null
345
+ label ? /* @__PURE__ */ jsx6("span", { id, className: "ambx-label", children: label }) : null
320
346
  ] });
321
347
  }
322
348
 
323
349
  // src/components/AmbientFader.tsx
324
350
  import { useId as useId3, useRef as useRef2 } from "react";
325
- import { jsx as jsx6, jsxs as jsxs3 } from "react/jsx-runtime";
351
+ import { jsx as jsx7, jsxs as jsxs3 } from "react/jsx-runtime";
326
352
  function clamp2(value, min, max) {
327
353
  return Math.min(max, Math.max(min, value));
328
354
  }
@@ -333,6 +359,7 @@ function AmbientFader({
333
359
  step = 1,
334
360
  label,
335
361
  material,
362
+ size = "md",
336
363
  onChange,
337
364
  className,
338
365
  ...props
@@ -392,10 +419,10 @@ function AmbientFader({
392
419
  updateFromClientY(event.clientY);
393
420
  };
394
421
  return /* @__PURE__ */ jsxs3("div", { className: cn("ambx-stack", className), ...props, children: [
395
- /* @__PURE__ */ jsx6(
422
+ /* @__PURE__ */ jsx7(
396
423
  "div",
397
424
  {
398
- className: "amb-fader amb-groove ambx-fader",
425
+ className: cn("amb-fader amb-groove ambx-fader", `ambx-fader-${size}`),
399
426
  ref: trackRef,
400
427
  role: "slider",
401
428
  "aria-label": label,
@@ -411,23 +438,23 @@ function AmbientFader({
411
438
  },
412
439
  onPointerMove,
413
440
  onKeyDown,
414
- children: /* @__PURE__ */ jsx6(
441
+ children: /* @__PURE__ */ jsx7(
415
442
  "div",
416
443
  {
417
444
  className: cn("amb-fader-thumb ambient amb-fillet ambx-fader-thumb", material !== "glass" && "amb-surface-concave", material && `amb-mat-${material}`),
418
445
  style: { top: `${100 - percent}%` },
419
- children: /* @__PURE__ */ jsx6("span", { className: "amb-fader-gripline" })
446
+ children: /* @__PURE__ */ jsx7("span", { className: "amb-fader-gripline" })
420
447
  }
421
448
  )
422
449
  }
423
450
  ),
424
- label ? /* @__PURE__ */ jsx6("span", { id, className: "ambx-label", children: label }) : null
451
+ label ? /* @__PURE__ */ jsx7("span", { id, className: "ambx-label", children: label }) : null
425
452
  ] });
426
453
  }
427
454
 
428
455
  // src/components/AmbientSlider.tsx
429
456
  import { useId as useId4, useRef as useRef3 } from "react";
430
- import { jsx as jsx7, jsxs as jsxs4 } from "react/jsx-runtime";
457
+ import { jsx as jsx8, jsxs as jsxs4 } from "react/jsx-runtime";
431
458
  function clamp3(value, min, max) {
432
459
  return Math.min(max, Math.max(min, value));
433
460
  }
@@ -438,6 +465,7 @@ function AmbientSlider({
438
465
  step = 1,
439
466
  label,
440
467
  material,
468
+ size = "md",
441
469
  onChange,
442
470
  className,
443
471
  ...props
@@ -497,10 +525,10 @@ function AmbientSlider({
497
525
  updateFromClientX(event.clientX);
498
526
  };
499
527
  return /* @__PURE__ */ jsxs4("div", { className: cn("ambx-stack", className), ...props, children: [
500
- /* @__PURE__ */ jsx7(
528
+ /* @__PURE__ */ jsx8(
501
529
  "div",
502
530
  {
503
- className: "amb-slider amb-groove ambx-slider",
531
+ className: cn("amb-slider amb-groove ambx-slider", `ambx-slider-${size}`),
504
532
  ref: trackRef,
505
533
  role: "slider",
506
534
  "aria-label": label,
@@ -516,7 +544,7 @@ function AmbientSlider({
516
544
  },
517
545
  onPointerMove,
518
546
  onKeyDown,
519
- children: /* @__PURE__ */ jsx7(
547
+ children: /* @__PURE__ */ jsx8(
520
548
  "div",
521
549
  {
522
550
  className: cn("amb-slider-thumb ambient amb-fillet ambx-slider-thumb", material !== "glass" && "amb-surface-convex", material && `amb-mat-${material}`),
@@ -525,7 +553,7 @@ function AmbientSlider({
525
553
  )
526
554
  }
527
555
  ),
528
- label ? /* @__PURE__ */ jsx7("span", { id, className: "ambx-label", children: label }) : null
556
+ label ? /* @__PURE__ */ jsx8("span", { id, className: "ambx-label", children: label }) : null
529
557
  ] });
530
558
  }
531
559
  export {
@@ -534,6 +562,7 @@ export {
534
562
  AmbientKnob,
535
563
  AmbientPanel,
536
564
  AmbientProvider,
565
+ AmbientRack,
537
566
  AmbientSlider,
538
567
  AmbientSwitch
539
568
  };
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\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"]}
1
+ {"version":3,"sources":["../src/components/AmbientProvider.tsx","../src/lib/cn.ts","../src/components/AmbientPanel.tsx","../src/components/AmbientRack.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 { HTMLAttributes } from \"react\";\nimport { cn } from \"../lib/cn\";\n\nexport type AmbientRackGap = \"tight\" | \"normal\" | \"loose\";\n\nexport interface AmbientRackProps extends HTMLAttributes<HTMLDivElement> {\n /** Clearance between controls: tight for one functional unit/repeated\n * row, normal (default) for a few related controls, loose for\n * separating distinct zones. */\n gap?: AmbientRackGap;\n direction?: \"row\" | \"column\";\n}\n\nexport function AmbientRack({\n className,\n gap = \"normal\",\n direction = \"row\",\n ...props\n}: AmbientRackProps) {\n return (\n <div\n className={cn(\n \"ambx-rack\",\n gap === \"tight\" && \"ambx-rack-tight\",\n gap === \"loose\" && \"ambx-rack-loose\",\n direction === \"column\" && \"ambx-rack-column\",\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\";\nexport type AmbientButtonSize = \"sm\" | \"md\" | \"lg\";\n\nexport interface AmbientButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {\n material?: \"matte\" | \"shiny\" | \"glass\";\n shape?: AmbientButtonShape;\n size?: AmbientButtonSize;\n}\n\nexport function AmbientButton({\n className,\n children,\n material = \"matte\",\n shape = \"pill\",\n size = \"md\",\n ...props\n}: AmbientButtonProps) {\n return (\n <button\n type=\"button\"\n className={cn(\n \"amb-button amb-groove ambx-button\",\n `ambx-button-${size}`,\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 AmbientKnobSize = \"sm\" | \"md\" | \"lg\";\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 size?: AmbientKnobSize;\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 size = \"md\",\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={cn(\"amb-knob ambx-knob\", `ambx-knob-${size}`)}\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 AmbientFaderSize = \"sm\" | \"md\" | \"lg\";\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 size?: AmbientFaderSize;\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 size = \"md\",\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={cn(\"amb-fader amb-groove ambx-fader\", `ambx-fader-${size}`)}\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 AmbientSliderSize = \"sm\" | \"md\" | \"lg\";\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 size?: AmbientSliderSize;\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 size = \"md\",\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={cn(\"amb-slider amb-groove ambx-slider\", `ambx-slider-${size}`)}\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","jsx","useId","jsx","jsxs","useId","useId","useRef","jsx","jsxs","clamp","useId","useRef","useId","useRef","jsx","jsxs","clamp","useId","useRef"]}