@ambientcss/components 3.0.0 → 3.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/index.ts","../src/components/AmbientProvider.tsx","../src/lib/cn.ts","../src/components/AmbientPanel.tsx","../src/components/AmbientRack.tsx","../src/controls/AmbientPress.tsx","../src/core/context.tsx","../src/core/frames.tsx","../src/core/dev.ts","../src/core/types.ts","../src/core/usePress.ts","../src/core/controllable.ts","../src/core/kit.tsx","../src/parts/knob.tsx","../src/parts/travel.tsx","../src/core/material.ts","../src/parts/press.tsx","../src/parts/latch.tsx","../src/parts/bank.tsx","../src/kits/grounded.tsx","../src/components/AmbientButton.tsx","../src/components/AmbientSwitch.tsx","../src/controls/AmbientLatch.tsx","../src/core/useLatch.ts","../src/controls/AmbientBank.tsx","../src/core/useBank.ts","../src/components/AmbientSelect.tsx","../src/controls/AmbientRotary.tsx","../src/core/useRotary.ts","../src/core/numeric.ts","../src/components/AmbientKnob.tsx","../src/controls/AmbientTravel.tsx","../src/core/useTravel.ts","../src/components/AmbientFader.tsx","../src/components/AmbientSlider.tsx","../src/parts/console.tsx","../src/kits/console.tsx"],"sourcesContent":["export { AmbientProvider } from \"./components/AmbientProvider\";\nexport type { AmbientProviderProps, AmbientTheme } from \"./components/AmbientProvider\";\n\nexport { AmbientPanel } from \"./components/AmbientPanel\";\nexport type { AmbientPanelProps } from \"./components/AmbientPanel\";\n\nexport { AmbientRack } from \"./components/AmbientRack\";\nexport type { AmbientRackProps, AmbientRackGap } from \"./components/AmbientRack\";\n\n/* ------------------------------------------------------------------ *\\\n Presets — a mechanism with a set of parts already chosen. Start here.\n\\* ------------------------------------------------------------------ */\n\nexport { AmbientButton } from \"./components/AmbientButton\";\nexport type {\n AmbientButtonProps,\n AmbientButtonShape,\n AmbientButtonSize\n} from \"./components/AmbientButton\";\n\nexport { AmbientSwitch } from \"./components/AmbientSwitch\";\nexport type { AmbientSwitchProps, AmbientSwitchSize } from \"./components/AmbientSwitch\";\n\nexport { AmbientSelect } from \"./components/AmbientSelect\";\nexport type {\n AmbientSelectProps,\n AmbientSelectOption,\n AmbientSelectSize,\n AmbientSelectOrientation\n} from \"./components/AmbientSelect\";\n\nexport { AmbientKnob } from \"./components/AmbientKnob\";\nexport type {\n AmbientKnobProps,\n AmbientKnobMarkers,\n AmbientKnobIndicator,\n AmbientKnobSize\n} from \"./components/AmbientKnob\";\n\nexport { AmbientFader } from \"./components/AmbientFader\";\nexport type { AmbientFaderProps, AmbientFaderSize } from \"./components/AmbientFader\";\n\nexport { AmbientSlider } from \"./components/AmbientSlider\";\nexport type { AmbientSliderProps, AmbientSliderSize } from \"./components/AmbientSlider\";\n\n/* ------------------------------------------------------------------ *\\\n Mechanisms — kinematics, state and ARIA with no appearance at all.\n Give one a set of parts and it becomes whatever you drew.\n\\* ------------------------------------------------------------------ */\n\nexport { AmbientRotary } from \"./controls/AmbientRotary\";\nexport type { AmbientRotaryProps } from \"./controls/AmbientRotary\";\n\nexport { AmbientTravel } from \"./controls/AmbientTravel\";\nexport type { AmbientTravelProps } from \"./controls/AmbientTravel\";\n\nexport { AmbientPress } from \"./controls/AmbientPress\";\nexport type { AmbientPressProps } from \"./controls/AmbientPress\";\n\nexport { AmbientLatch } from \"./controls/AmbientLatch\";\nexport type { AmbientLatchProps } from \"./controls/AmbientLatch\";\n\nexport { AmbientBank } from \"./controls/AmbientBank\";\nexport type { AmbientBankProps } from \"./controls/AmbientBank\";\n\n/* ------------------------------------------------------------------ *\\\n Hooks — the mechanism without the markup, for a control you render\n yourself from the ground up.\n\\* ------------------------------------------------------------------ */\n\nexport { useRotary } from \"./core/useRotary\";\nexport type { UseRotaryOptions, RotaryInput, RotaryTravel } from \"./core/useRotary\";\n\nexport { useTravel } from \"./core/useTravel\";\nexport type { UseTravelOptions, TravelOrientation } from \"./core/useTravel\";\n\nexport { usePress } from \"./core/usePress\";\nexport type { UsePressOptions, PressMode } from \"./core/usePress\";\n\nexport { useLatch } from \"./core/useLatch\";\nexport type { UseLatchOptions } from \"./core/useLatch\";\n\nexport { useBank } from \"./core/useBank\";\nexport type { UseBankOptions, BankOption, BankOrientation } from \"./core/useBank\";\n\n/* ------------------------------------------------------------------ *\\\n Kits — a named bundle of parts, tokens and presentation defaults that\n dresses every control below it. A kit is a plain object, so publishing\n one is publishing a module. A kit that leaves a family undefined falls\n through to `grounded`.\n\\* ------------------------------------------------------------------ */\n\nexport { AmbientKitProvider, useKit, useDress } from \"./core/kit\";\nexport type {\n ControlKit,\n ControlFamily,\n KitDress,\n KitLook,\n KitDefaults\n} from \"./core/kit\";\n\nexport { groundedKit } from \"./kits/grounded\";\nexport { consoleKit, ConsoleKnob, ConsoleToggle } from \"./kits/console\";\nexport type { ConsoleKnobProps, ConsoleToggleProps } from \"./kits/console\";\n\nexport {\n ConsoleBar,\n ConsoleMarks,\n ConsoleWell,\n ToggleTrack,\n ToggleThumb\n} from \"./parts/console\";\n\n/* ------------------------------------------------------------------ *\\\n The state channel — read the enclosing control from inside a part.\n The custom properties on the control root are canonical; these are a\n typed view of the same values, for parts that need JS.\n\\* ------------------------------------------------------------------ */\n\nexport { useControlState, useBankKey } from \"./core/context\";\nexport type { BankKeyState } from \"./core/context\";\nexport type {\n ControlParts,\n ControlState,\n ControlSize,\n ControlAnimate,\n FrameName\n} from \"./core/types\";\nexport type { AmbientMaterial } from \"./core/material\";\n\n/* ------------------------------------------------------------------ *\\\n Default parts. Nothing privileged about them — each is markup with\n some ambient classes, and a replacement of yours stands on exactly the\n same footing. They live in their own modules so an app that ships only\n its own parts does not pay for these.\n\\* ------------------------------------------------------------------ */\n\nexport { KnobBody, KnurledFace, IndicatorDot, IndicatorBar, ScaleRing } from \"./parts/knob\";\nexport type { ScaleRingProps } from \"./parts/knob\";\nexport { TravelTrack, FaderCap, SliderThumb } from \"./parts/travel\";\nexport { ButtonCap } from \"./parts/press\";\nexport { SwitchTrack, SwitchPill, Led } from \"./parts/latch\";\nexport { KeyLens, KeyCap } from \"./parts/bank\";\n","import type { CSSProperties, PropsWithChildren } from \"react\";\n\nexport type AmbientTheme = {\n lightX?: number;\n lightY?: number;\n keyLight?: number;\n fillLight?: number;\n lightHue?: number;\n lightSaturation?: number;\n highlightColor?: string;\n lumeHue?: number;\n};\n\nexport type AmbientProviderProps = PropsWithChildren<{\n className?: string;\n style?: CSSProperties;\n theme?: AmbientTheme;\n}>;\n\nconst VAR_MAP: Record<string, keyof AmbientTheme> = {\n \"--amb-light-x\": \"lightX\",\n \"--amb-light-y\": \"lightY\",\n \"--amb-key-light-intensity\": \"keyLight\",\n \"--amb-fill-light-intensity\": \"fillLight\",\n \"--amb-light-hue\": \"lightHue\",\n \"--amb-light-saturation\": \"lightSaturation\",\n \"--amb-highlight-color\": \"highlightColor\",\n \"--amb-lume-hue\": \"lumeHue\",\n};\n\nexport function AmbientProvider({ children, className, style, theme }: AmbientProviderProps) {\n const themeVars: Record<string, string> = {};\n for (const [varName, key] of Object.entries(VAR_MAP)) {\n const value = theme?.[key];\n if (value !== undefined) {\n themeVars[varName] = key === \"lightSaturation\" ? `${value}%` : String(value);\n }\n }\n // Derived variables must be re-declared here so they recompute using the\n // overridden input variables on this element rather than inheriting the\n // already-resolved values from :root.\n themeVars[\"--amb-lume\"] = [\n \"color-mix(in oklab,\",\n \"hsl(var(--amb-lume-hue) 100% 74%) calc(clamp(0, (0.5 - var(--amb-key-light-intensity)) / 0.2, 1) * 100%),\",\n \"hsl(var(--amb-light-hue) var(--amb-light-saturation)\",\n \"calc((1 - sign(var(--amb-key-light-intensity) - 0.5)) * 50% + 25%)))\",\n ].join(\" \");\n themeVars[\"--amb-label\"] =\n \"hsl(var(--amb-light-hue) var(--amb-light-saturation) calc((1 - var(--amb-key-light-intensity)) * 60% + 20%))\";\n // --amb-curve-delta deliberately absent: unlike these two it is declared\n // per element in ambient.css, so it already re-resolves against the light\n // overridden here. Re-declaring it would only re-copy the fit.\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\";\nimport type { AmbientMaterial } from \"../core/material\";\n\nexport interface AmbientPanelProps extends HTMLAttributes<HTMLDivElement> {\n material?: AmbientMaterial;\n}\n\n/** A panel is a plain surface, so it can wear any finish directly: it spends\n * neither pseudo-element of its own, which is what the two micro-relief\n * materials need. Their grain paints below the panel's children, and their\n * `overflow: hidden` clips whatever hangs outside it — a control's drop\n * shadow at the very edge included. */\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 `amb-mat-${material}`,\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 { useRef } from \"react\";\nimport type { ButtonHTMLAttributes } from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { ControlStateProvider } from \"../core/context\";\nimport { Frames, useDevPartCheck } from \"../core/frames\";\nimport { sizeProps } from \"../core/types\";\nimport type { ControlParts, ControlSize } from \"../core/types\";\nimport { usePress } from \"../core/usePress\";\nimport type { UsePressOptions } from \"../core/usePress\";\n\nexport type AmbientPressProps = Omit<\n ButtonHTMLAttributes<HTMLButtonElement>,\n \"onChange\" | \"value\" | \"defaultValue\" | \"type\"\n> &\n UsePressOptions & {\n parts?: ControlParts | undefined;\n size?: ControlSize | undefined;\n };\n\n/** A key that sinks under a finger, with no appearance of its own.\n *\n * Its frames are `display: contents` markers rather than boxes, because a\n * button is sized by its cap: the width is `min-width` plus the legend.\n * Wrapping the cap in a positioned frame would collapse the control. */\nexport function AmbientPress({\n parts,\n size,\n className,\n mode,\n value,\n defaultValue,\n onChange,\n onPress,\n repeatDelay,\n repeatInterval,\n disabled,\n children,\n ...rest\n}: AmbientPressProps) {\n const ref = useRef<HTMLButtonElement>(null);\n const { state, rootProps } = usePress({\n mode,\n value,\n defaultValue,\n onChange,\n onPress,\n repeatDelay,\n repeatInterval,\n disabled\n });\n useDevPartCheck(ref, \"AmbientPress\");\n\n const sized = sizeProps(\"press\", size);\n const { style: restStyle, onClick, ...restProps } = rest;\n\n return (\n <button\n {...restProps}\n {...rootProps}\n ref={ref}\n className={cn(\"ambx-control ambx-press\", sized.className, className)}\n style={{ ...rootProps.style, ...sized.style, ...restStyle }}\n onClick={(event) => {\n rootProps.onClick();\n onClick?.(event);\n }}\n >\n <ControlStateProvider value={state}>\n <Frames parts={parts} />\n {children}\n </ControlStateProvider>\n </button>\n );\n}\n","import { createContext, useContext } from \"react\";\nimport type { ControlState } from \"./types\";\nimport type { BankOption } from \"./useBank\";\n\nconst ControlStateContext = createContext<ControlState | null>(null);\n\nexport const ControlStateProvider = ControlStateContext.Provider;\n\n/** Read the enclosing control's state from inside a part.\n *\n * This is the third outlet of the state channel, and the one to reach for\n * last: the custom properties on the control root are canonical, and a\n * part that can be styled from CSS should be. Use this when a part needs\n * the value as a JS number — a readout, a tick ring that has to emit N\n * children, an SVG whose path data depends on the value. */\nexport function useControlState(): ControlState {\n const state = useContext(ControlStateContext);\n if (!state) {\n throw new Error(\n \"useControlState() must be called from inside a control's parts. \" +\n \"Pass the component through `parts` on AmbientRotary, AmbientTravel, \" +\n \"AmbientPress, AmbientLatch or AmbientBank.\"\n );\n }\n return state;\n}\n\n/** A bank key carries more than a number: its legend, its accessible name\n * and its own lamp colour all belong to the option, not to the state. So a\n * key's parts get this alongside `useControlState()`. */\nexport type BankKeyState = { option: BankOption; on: boolean; index: number };\n\nconst BankKeyContext = createContext<BankKeyState | null>(null);\n\nexport const BankKeyProvider = BankKeyContext.Provider;\n\nexport function useBankKey(): BankKeyState {\n const key = useContext(BankKeyContext);\n if (!key) {\n throw new Error(\n \"useBankKey() must be called from inside a bank key's parts. Pass the \" +\n \"component through `keyParts` on AmbientBank.\"\n );\n }\n return key;\n}\n","import { useEffect, useRef } from \"react\";\nimport type { RefObject } from \"react\";\nimport { isDev } from \"./dev\";\nimport { FRAME_ORDER } from \"./types\";\nimport type { ControlParts } from \"./types\";\n\n/** Render the frames a control has parts for, in paint order.\n *\n * Frames are markers by default (`display: contents` in styles.css) and\n * become boxes only where the control has a size of its own — a rotary's\n * rotating face, a travel thumb. That distinction is not cosmetic: a\n * button takes its width from `min-width` plus its cap's legend, so an\n * absolutely-positioned actuator would collapse it to nothing. */\nexport function Frames({ parts }: { parts?: ControlParts | undefined }) {\n if (!parts) return null;\n return (\n <>\n {FRAME_ORDER.map((name) =>\n parts[name] == null ? null : (\n <div key={name} data-frame={name} className={`ambx-frame ambx-frame-${name}`}>\n {parts[name]}\n </div>\n )\n )}\n </>\n );\n}\n\nconst FOCUSABLE =\n \"a[href], button, input, select, textarea, [tabindex], [contenteditable=true],\" +\n \"[role=button], [role=checkbox], [role=radio], [role=slider], [role=switch], [role=link]\";\n\n/** Development-only enforcement of the rule that parts are presentational.\n *\n * The control root owns `role`, `aria-value*`, `tabIndex` and the keyboard\n * handler. A part that smuggles in its own focusable element gives the\n * control two tab stops and, usually, a second conflicting role.\n *\n * Scoped to inside `[data-frame]` subtrees rather than to the whole root,\n * because a bank's key IS a `<button>` that the mechanism renders and the\n * frames sit inside it. Querying from the root would flag every preset we\n * ship. */\nexport function useDevPartCheck(ref: RefObject<HTMLElement | null>, control: string): void {\n const warned = useRef(false);\n /* Mount only, and at most once. A part set is fixed by the code that wrote\n it, so re-querying on every render would buy nothing and cost a DOM walk\n on every frame of a drag. */\n useEffect(() => {\n if (!isDev || warned.current) return;\n const root = ref.current;\n if (!root) return;\n const offenders = root.querySelectorAll(`[data-frame] :is(${FOCUSABLE})`);\n if (offenders.length === 0) return;\n warned.current = true;\n const tags = Array.from(offenders, (node) => `<${node.tagName.toLowerCase()}>`).join(\", \");\n console.warn(\n `[@ambientcss/components] ${control}: a part contains a focusable element ` +\n `(${tags}). Parts are presentational — the control root already owns the ` +\n `role, the tab stop and the keyboard handler, so this creates a second ` +\n `tab stop and usually a conflicting role.`\n );\n }, [ref, control]);\n}\n","declare const process: { env: Record<string, string | undefined> };\n\n/** True outside a production build.\n *\n * Written as a bare `process.env.NODE_ENV` comparison so bundlers replace\n * it textually and drop the guarded code from production output, and\n * wrapped in try/catch so an unbundled ESM consumer — a CDN import with no\n * `process` shim — gets `false` rather than a ReferenceError. */\nexport const isDev: boolean = (() => {\n try {\n return process.env.NODE_ENV !== \"production\";\n } catch {\n return false;\n }\n})();\n","import type { CSSProperties, ReactNode } from \"react\";\n\n/** The four frames every control renders, in paint order.\n *\n * - `panel` static, behind the control, allowed to overflow its box\n * - `base` static, the control's own footprint\n * - `actuator` the moving part: the frame the control transforms\n * - `fixture` static, above the actuator\n *\n * A part dropped into a frame is ordinary markup. The control moves the\n * frame; the part only has to look like something. */\nexport type ControlParts = {\n panel?: ReactNode | undefined;\n base?: ReactNode | undefined;\n actuator?: ReactNode | undefined;\n fixture?: ReactNode | undefined;\n};\n\nexport type FrameName = keyof ControlParts;\n\nexport const FRAME_ORDER: FrameName[] = [\"panel\", \"base\", \"actuator\", \"fixture\"];\n\n/** `\"sm\" | \"md\" | \"lg\"` picks a size from the family's table; any other\n * string is used as a CSS length for `--ambx-size`. */\nexport type ControlSize = \"sm\" | \"md\" | \"lg\" | (string & {});\n\n/** How the actuator moves to a new position.\n *\n * - `follow` 1:1 with the pointer, no transition — right while dragging\n * - `ease` transitions, right for keyboard and click-to-set\n * - `snap` instant, for a detented control that should read as clicking\n *\n * The default is contextual: follow while `data-dragging` is on the root,\n * ease otherwise. That needs no JS — see `.ambx-control` in styles.css. */\nexport type ControlAnimate = \"auto\" | \"follow\" | \"ease\" | \"snap\";\n\n/** What a part can read, via `useControlState()`. The same values are on\n * the control root as custom properties, which are canonical; this is a\n * typed view of them for parts that genuinely need JS. */\nexport type ControlState = {\n /** The raw value. Booleans arrive as 0/1, selections as the index. */\n value: number;\n min: number;\n max: number;\n /** Normalised position, 0-1. */\n percent: number;\n /** Degrees clockwise from 12 o'clock. 0 for non-rotary controls. */\n angle: number;\n /** Sweep origin and extent in degrees. 0 for non-rotary controls. */\n travelStart: number;\n travelSweep: number;\n /** Rest positions along the travel; 0 means continuous. */\n detents: number;\n dragging: boolean;\n disabled: boolean;\n atMin: boolean;\n atMax: boolean;\n};\n\nexport const IDLE_STATE: ControlState = {\n value: 0,\n min: 0,\n max: 1,\n percent: 0,\n angle: 0,\n travelStart: 0,\n travelSweep: 0,\n detents: 0,\n dragging: false,\n disabled: false,\n atMin: true,\n atMax: false\n};\n\n/** The state channel, written onto the control root.\n *\n * Every property is declared here even when a family does not use it,\n * because these inherit: a control nested inside another control's frame\n * would otherwise read its ancestor's angle. `.ambx-control` carries the\n * neutral defaults and this overrides them per instance. */\nexport function stateStyle(state: ControlState): CSSProperties {\n return {\n \"--ambx-value\": state.value,\n \"--ambx-percent\": state.percent,\n \"--ambx-angle\": `${state.angle}deg`,\n \"--ambx-travel-start\": `${state.travelStart}deg`,\n \"--ambx-travel-sweep\": `${state.travelSweep}deg`,\n \"--ambx-detents\": state.detents\n } as CSSProperties;\n}\n\n/** The discrete half of the state channel: conditions a part can style\n * against but cannot detect for itself. */\nexport function stateData(state: ControlState): Record<string, string | undefined> {\n return {\n \"data-dragging\": state.dragging ? \"\" : undefined,\n \"data-disabled\": state.disabled ? \"\" : undefined,\n \"data-at-min\": state.atMin ? \"\" : undefined,\n \"data-at-max\": state.atMax ? \"\" : undefined\n };\n}\n\n/** Resolve `size` into the class suffix and/or the `--ambx-size` override.\n * A named size picks the family's table; a length goes straight through,\n * which is what lets a part scale off one property instead of matching a\n * class it cannot know about. */\nexport function sizeProps(\n family: string,\n size: ControlSize | undefined\n): { className?: string; style?: CSSProperties } {\n if (size === undefined) return {};\n if (size === \"sm\" || size === \"md\" || size === \"lg\") {\n return { className: `ambx-${family}-${size}` };\n }\n return { style: { \"--ambx-size\": size } as CSSProperties };\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport type { CSSProperties, PointerEvent } from \"react\";\nimport { useControllableValue } from \"./controllable\";\nimport { stateData, stateStyle } from \"./types\";\nimport type { ControlState } from \"./types\";\n\n/** A transport key, a latching mute and an auto-repeating nudge button are\n * the same object with three state machines and identical paint. */\nexport type PressMode = \"momentary\" | \"toggle\" | \"repeat\";\n\nexport type UsePressOptions = {\n mode?: PressMode | undefined;\n /** `toggle` mode only: the pressed-in state. */\n value?: boolean | undefined;\n defaultValue?: boolean | undefined;\n onChange?: ((next: boolean) => void) | undefined;\n /** Fires once per activation, and repeatedly in `repeat` mode. */\n onPress?: (() => void) | undefined;\n /** `repeat` mode: delay before repeating starts, then its interval. */\n repeatDelay?: number | undefined;\n repeatInterval?: number | undefined;\n disabled?: boolean | undefined;\n};\n\nexport function usePress(options: UsePressOptions) {\n const {\n mode = \"momentary\",\n repeatDelay = 400,\n repeatInterval = 60,\n disabled = false\n } = options;\n\n const [on, setOn] = useControllableValue(\n options.value,\n options.defaultValue ?? false,\n options.onChange\n );\n const [held, setHeld] = useState(false);\n\n const onPressRef = useRef(options.onPress);\n onPressRef.current = options.onPress;\n const timers = useRef<{ delay?: ReturnType<typeof setTimeout>; tick?: ReturnType<typeof setInterval> }>(\n {}\n );\n\n const stopRepeat = useCallback(() => {\n if (timers.current.delay) clearTimeout(timers.current.delay);\n if (timers.current.tick) clearInterval(timers.current.tick);\n timers.current = {};\n }, []);\n\n /* A held key that unmounts must not keep firing. */\n useEffect(() => stopRepeat, [stopRepeat]);\n\n const activate = useCallback(() => {\n if (mode === \"toggle\") setOn(!on);\n onPressRef.current?.();\n }, [mode, on, setOn]);\n\n const pressed = mode === \"toggle\" ? on : held;\n\n const state: ControlState = useMemo(\n () => ({\n value: pressed ? 1 : 0,\n min: 0,\n max: 1,\n percent: pressed ? 1 : 0,\n angle: 0,\n travelStart: 0,\n travelSweep: 0,\n detents: 2,\n dragging: held,\n disabled,\n atMin: !pressed,\n atMax: pressed\n }),\n [pressed, held, disabled]\n );\n\n const rootProps = {\n type: \"button\" as const,\n disabled,\n \"aria-pressed\": mode === \"toggle\" ? on : undefined,\n style: stateStyle(state) as CSSProperties,\n \"data-pressed\": pressed ? \"\" : undefined,\n \"data-mode\": mode,\n ...stateData(state),\n onPointerDown: (event: PointerEvent<HTMLButtonElement>) => {\n if (disabled || event.button !== 0) return;\n setHeld(true);\n if (mode !== \"repeat\") return;\n /* Repeat fires immediately, then accelerates into its interval —\n the same shape a keyboard's own auto-repeat has, so a held nudge\n button does not feel like a different kind of control. */\n onPressRef.current?.();\n timers.current.delay = setTimeout(() => {\n timers.current.tick = setInterval(() => onPressRef.current?.(), repeatInterval);\n }, repeatDelay);\n },\n onPointerUp: () => {\n setHeld(false);\n stopRepeat();\n },\n onPointerCancel: () => {\n setHeld(false);\n stopRepeat();\n },\n onPointerLeave: () => {\n setHeld(false);\n stopRepeat();\n },\n onClick: () => {\n /* Repeat already fired on the press; firing again on click would\n double every tap. */\n if (mode !== \"repeat\") activate();\n }\n };\n\n return { state, rootProps, pressed, on, setOn };\n}\n","import { useCallback, useRef, useState } from \"react\";\n\n/** One controlled/uncontrolled convention for every control.\n *\n * Pass `value` to drive it from outside; pass `defaultValue` (or neither)\n * to let the control hold its own. `onChange` fires either way, so a\n * caller can read an uncontrolled control without taking it over.\n *\n * Before v3 this was inconsistent: AmbientSwitch and AmbientSelect took a\n * default, while knob, slider and fader were controlled-only and would\n * sit frozen if you forgot `onChange`. */\nexport function useControllableValue<T>(\n controlled: T | undefined,\n defaultValue: T,\n onChange?: (next: T) => void\n): [T, (next: T) => void] {\n const isControlled = controlled !== undefined;\n const [internal, setInternal] = useState<T>(defaultValue);\n\n /* The setter is called from pointer handlers that run many times per\n drag, so it must not change identity between renders. */\n const onChangeRef = useRef(onChange);\n onChangeRef.current = onChange;\n const controlledRef = useRef(isControlled);\n controlledRef.current = isControlled;\n\n const set = useCallback((next: T) => {\n if (!controlledRef.current) setInternal(next);\n onChangeRef.current?.(next);\n }, []);\n\n return [isControlled ? (controlled as T) : internal, set];\n}\n","import { createContext, useContext } from \"react\";\nimport type { PropsWithChildren } from \"react\";\nimport { isDev } from \"./dev\";\nimport type { ControlParts } from \"./types\";\nimport type { RotaryInput, RotaryTravel } from \"./useRotary\";\nimport type { ControlAnimate } from \"./types\";\n\n/** The five control families a kit can dress. */\nexport type ControlFamily = \"rotary\" | \"travel\" | \"press\" | \"latch\" | \"bank\";\n\n/** What a preset hands its kit: the look options the caller asked for.\n *\n * Deliberately loose. Look props are *kit vocabulary* — `knurling` and\n * `markers` are words the grounded kit made up — so a kit reads the keys it\n * understands and ignores the rest, exactly as a stylesheet that never\n * implemented a class simply does not react to it. See `looks` below for\n * how that stays honest rather than silent. */\nexport type KitLook = Record<string, unknown>;\n\n/** A dressed control: what goes in the frames, and what the root wears.\n *\n * The class comes from the kit rather than the preset because it is part of\n * the look — `.amb-knob` carries the grounded knob's own token table, and a\n * kit that replaces the parts has no use for it. */\nexport type KitDress = {\n parts: ControlParts;\n className?: string | undefined;\n};\n\n/** Presentation defaults a visual identity may legitimately set.\n *\n * Narrow on purpose: a kit says how its controls should *feel* to turn, not\n * what they are worth. Anything touching value, range or handlers stays with\n * the caller. */\nexport type KitDefaults = {\n rotary?: { travel?: RotaryTravel; input?: RotaryInput; animate?: ControlAnimate } | undefined;\n travel?: { animate?: ControlAnimate } | undefined;\n latch?: { animate?: ControlAnimate } | undefined;\n};\n\nexport type ControlKit = {\n name: string;\n rotary?: ((look: KitLook) => KitDress) | undefined;\n travel?: ((look: KitLook) => KitDress) | undefined;\n press?: ((look: KitLook) => KitDress) | undefined;\n latch?: ((look: KitLook) => KitDress) | undefined;\n bank?: ((look: KitLook) => KitDress) | undefined;\n defaults?: KitDefaults | undefined;\n /** Look keys each family honours. Used only to warn in development when a\n * caller passes a prop the active kit is going to drop on the floor —\n * the one real cost of letting look props pass through untyped. */\n looks?: Partial<Record<ControlFamily, readonly string[]>> | undefined;\n};\n\nconst KitContext = createContext<ControlKit | null>(null);\n\n/** Dress every control below this point in `kit`.\n *\n * A kit is a plain object, so shipping one is shipping a module: no\n * registry, no lifecycle, nothing to initialise. A kit that leaves a family\n * undefined falls through to the default, which is what a real third-party\n * kit will do for most of them. */\nexport function AmbientKitProvider({ kit, children }: PropsWithChildren<{ kit: ControlKit }>) {\n return <KitContext.Provider value={kit}>{children}</KitContext.Provider>;\n}\n\nexport function useKit(): ControlKit | null {\n return useContext(KitContext);\n}\n\nconst warned = new Set<string>();\n\n/** Resolve a family's dressing: the active kit if it dresses this family,\n * otherwise the fallback the preset was built around. */\nexport function useDress<F extends ControlFamily>(\n family: F,\n look: KitLook,\n fallback: (look: KitLook) => KitDress\n): { dress: KitDress; defaults: F extends keyof KitDefaults ? KitDefaults[F] : undefined } {\n const kit = useKit();\n const dressed = kit?.[family];\n\n if (isDev && kit && dressed) {\n const honoured = kit.looks?.[family];\n if (honoured) {\n for (const key of Object.keys(look)) {\n if (look[key] === undefined || honoured.includes(key)) continue;\n const id = `${kit.name}:${family}:${key}`;\n if (warned.has(id)) continue;\n warned.add(id);\n console.warn(\n `[@ambientcss/components] the \"${kit.name}\" kit's ${family} does not use ` +\n `\\`${key}\\` — it is a look prop from another kit's vocabulary, so it will ` +\n `have no effect here.`\n );\n }\n }\n }\n\n return {\n dress: (dressed ?? fallback)(look),\n /* Defaults come from the kit that actually dressed the control: a kit\n that falls through to grounded for a family has no say in how that\n family behaves either. */\n defaults: (dressed ? kit?.defaults?.[family as keyof KitDefaults] : undefined) as never\n };\n}\n","import { useId } from \"react\";\nimport type { CSSProperties, ReactNode } from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { useControlState } from \"../core/context\";\nimport type { AmbientMaterial } from \"../core/material\";\n\n/* The knurl: a rim band of straight ribs around the knob's cap, in\n objectBoundingBox units so the clip scales with the component.\n\n The knob it belongs to reads like the turned-and-knurled hardware knob it\n is named for: a smooth chamfered cap on top, and beyond that cap's edge —\n and a step below it — a ring of knurling standing proud of the outline.\n So the clip is an ANNULUS, not a disc: a rippled outer contour punched\n through by a circle at the cap's radius, filled `evenodd`, which leaves\n the cap and its chamfer bands to paint themselves underneath.\n\n The rib section is the referent's (ambient3d/components/knob.py `wall_r`):\n radius falls from the crest by `depth * (0.5 + 0.5cos(N.theta))^sharpness`,\n so ridges are broad and grooves narrow. Sampling that curve beats the old\n four-point trapezoid — at 36 teeth a square wave silhouette reads as gear\n teeth, which is what this replaces.\n\n One knurl for now, kept in a table because the shape is a data question and\n the referent lineup carries broader flutes (14 ribs) we may expose later.\n A second row is not free, though: `teeth` is shadowed by the conic pitch in\n .amb-knob-face (360/teeth) and `band` by that rule's radial stop, so a knurl\n with different numbers needs its shading parameterised out of the stylesheet\n first. Only `depth` and `sharpness` live here alone. */\ntype KnurlSpec = {\n teeth: number; // rib count\n depth: number; // crest-to-root, bounding-box units (the crest is at 0.5)\n sharpness: number; // >1 narrows the groove and broadens the ridge\n band: number; // rim width the ribs occupy, bounding-box units\n};\n\nconst KNURLS: Record<\"standard\", KnurlSpec> = {\n /* 48 ribs — the referent lineup's fine knurl (referents.py knob_cap /\n knob_wheel) rather than the 36 of its coarse one, because a band a tenth\n of the radius wide reads as a machined grip only if the ribs are finer\n than it is; at 36 the same band came out a bottle cap. */\n standard: { teeth: 48, depth: 0.009, sharpness: 1.6, band: 0.05 }\n};\n\n/** The cap's inset: the knurl band's width, so the ribs stand proud of it.\n * One number, two views of the same edge — the clip's inner radius and the\n * body's inset have to agree or the ring floats off its cap. */\nconst KNURL_BAND = KNURLS.standard.band;\n\n/* The clip's hole is a hair tighter than the cap so their antialiased edges\n overlap instead of leaving a hairline of panel between them. */\nconst SEAM = 0.005;\n\n/* Samples per tooth. The curve's extremes both land on samples: the groove\n at the tooth's start, the ridge at its half-pitch. */\nconst STEPS = 6;\n\nfunction knurlPath({ teeth, depth, sharpness, band }: KnurlSpec): string {\n const outer = 0.5;\n const inner = outer - band - SEAM;\n const segs = teeth * STEPS;\n const pts: string[] = [];\n for (let i = 0; i < segs; i++) {\n const t = (i / segs) * Math.PI * 2;\n const r = outer - depth * (0.5 + 0.5 * Math.cos(teeth * t)) ** sharpness;\n pts.push(\n `${(0.5 + r * Math.cos(t)).toFixed(4)} ${(0.5 + r * Math.sin(t)).toFixed(4)}`\n );\n }\n /* Second subpath: the cap-sized hole, two half arcs. Winding is irrelevant —\n the clip fills evenodd. */\n const l = (0.5 - inner).toFixed(4);\n const r = (0.5 + inner).toFixed(4);\n const hole = `M${l} 0.5 A${inner} ${inner} 0 0 0 ${r} 0.5 A${inner} ${inner} 0 0 0 ${l} 0.5 Z`;\n return `M${pts.join(\" L\")} Z ${hole}`;\n}\n\nconst KNURL_PATH = knurlPath(KNURLS.standard);\n\n/** The knob's cap: the smooth chamfered disc that is most of what you see,\n * and the element that carries the drop shadow.\n *\n * `flush` takes the full width, which is what a smooth turned knob wants.\n * The default sits back by the knurl band so a `KnurledFace` can ring it —\n * the same cap either way, and the chamfer the referent cuts on every knob\n * (knob.py's `chamfer=0.35`, regardless of rib count) either way too. */\nexport function KnobBody({\n material,\n flush = false,\n className\n}: {\n material?: AmbientMaterial | undefined;\n flush?: boolean | undefined;\n className?: string | undefined;\n}) {\n return (\n <span\n className={cn(\n \"amb-knob-body ambient amb-thickness-2 amb-surface\",\n material && `amb-mat-${material}`,\n className\n )}\n /* Geometry, not styling: this is the clip's inner radius seen from the\n other side, so it comes from the same constant the path does. */\n style={flush ? undefined : { inset: `${KNURL_BAND * 100}%` }}\n />\n );\n}\n\n/** The rotating knurl: a rim ring of ribs around the cap, clipped to the\n * toothed annulus so the ribs break the outline instead of being painted\n * inside a circle, and shaded per tooth — a lit flank climbing to each\n * ridge, a shaded one falling away — with a contact-occlusion band along\n * its inner edge where the cap overhangs it.\n *\n * The clip is the part's own business — it generates the path, emits its\n * own `<defs>` and references it by a local id. A rotary mechanism has no\n * idea any of this is happening, which is exactly the point: if this part\n * needed help from the control to exist, the split would not be clean. */\nexport function KnurledFace({\n material,\n color,\n className\n}: {\n material?: AmbientMaterial | undefined;\n /** The ribs' own colour, as an albedo. */\n color?: string | undefined;\n className?: string | undefined;\n}) {\n const id = `amb-knurl-${useId().replace(/:/g, \"\")}`;\n return (\n <>\n <svg width={0} height={0} style={{ position: \"absolute\" }} aria-hidden focusable={false}>\n <defs>\n <clipPath id={id} clipPathUnits=\"objectBoundingBox\">\n <path d={KNURL_PATH} clipRule=\"evenodd\" />\n </clipPath>\n </defs>\n </svg>\n <span\n className={cn(\"amb-knob-face\", material && `amb-mat-${material}`, className)}\n style={{\n clipPath: `url(#${id})`,\n /* Not a paint colour: --amb-albedo is the ribs' REFLECTANCE, so a\n dark knurl still takes the scene's exposure, the lamp's cast and\n the rim's own --amb-shade step, and still goes dark when the\n lights do. Inline, so it beats the albedo a micro-relief material\n would otherwise set on this element — an explicit colour wins\n over the finish's own, and the finish keeps its grain. */\n ...(color ? { \"--amb-albedo\": color } : null)\n } as CSSProperties}\n />\n </>\n );\n}\n\n/** The grounded referent's offset indicator dot (knob() dot_frac 0.12,\n * dot_offset 0.68). Put it in the `actuator` frame and it sweeps; put it\n * in `base` and it stays put while everything else turns. */\nexport function IndicatorDot({ className }: { className?: string | undefined }) {\n return <span className={cn(\"amb-knob-indicator-circle\", className)} />;\n}\n\n/** A short radial bar out near the rim, running 0.50R to 0.84R. */\nexport function IndicatorBar({ className }: { className?: string | undefined }) {\n return <span className={cn(\"amb-knob-indicator-rectangle\", className)} />;\n}\n\nexport type ScaleRingProps = {\n /** Dots to print. `2` is the pair the travel starts and stops at. */\n count?: number | undefined;\n className?: string | undefined;\n children?: ReactNode | undefined;\n};\n\n/** Printed scale dots on the panel around a rotary, on the same arc the\n * value sweeps.\n *\n * This is the part that has to read state as JS rather than CSS: the\n * angles come from the control's own travel, and there is no way to emit\n * N children from a stylesheet. It is also the proof that the context\n * outlet works — the dots land on the sweep whatever `travel` is set to,\n * without the ring being told. */\nexport function ScaleRing({ count = 13, className, children }: ScaleRingProps) {\n const { travelStart, travelSweep } = useControlState();\n const divisions = Math.max(1, count - 1);\n const angles =\n count <= 1\n ? [travelStart]\n : Array.from({ length: count }, (_, i) => travelStart + (i / divisions) * travelSweep);\n\n return (\n <span className={cn(\"amb-knob-marker-ring\", className)} aria-hidden>\n {angles.map((angle) => (\n <span\n key={angle}\n className=\"amb-knob-marker\"\n style={{ \"--amb-marker-angle\": `${angle}deg` } as CSSProperties}\n />\n ))}\n {children}\n </span>\n );\n}\n","import { cn } from \"../lib/cn\";\nimport type { AmbientMaterial } from \"../core/material\";\n\n/** The track a thumb rides in.\n *\n * Both grounded referents are grooves with a lume interior — dark in\n * bright light, glowing in low light — but they are cut to different\n * depths: a fader runs in a through-slot, a slider in a shallow concave\n * channel (slider.py, 1mm deep = thickness 0.22). */\nexport function TravelTrack({\n depth = \"slot\",\n className\n}: {\n depth?: \"slot\" | \"channel\" | undefined;\n className?: string | undefined;\n}) {\n return (\n <span\n className={cn(\n \"amb-travel-track amb-groove\",\n depth === \"channel\" && \"amb-travel-track-channel\",\n className\n )}\n />\n );\n}\n\n/** Fader cap: the referent (fader.py) is a pill on a stem — 7mm tall\n * (thickness 1.5) riding 2.2mm above the plate (elevation 0.28) — with a\n * single grip line across the top. */\nexport function FaderCap({\n material,\n className\n}: {\n material?: AmbientMaterial | undefined;\n className?: string | undefined;\n}) {\n return (\n <span\n className={cn(\n \"amb-fader-thumb ambient amb-fillet\",\n material !== \"glass\" && \"amb-surface-concave\",\n material && `amb-mat-${material}`,\n className\n )}\n >\n <span className=\"amb-fader-gripline\" />\n </span>\n );\n}\n\n/** Slider thumb: a domed disc gliding over the channel. */\nexport function SliderThumb({\n material,\n className\n}: {\n material?: AmbientMaterial | undefined;\n className?: string | undefined;\n}) {\n return (\n <span\n className={cn(\n \"amb-slider-thumb ambient amb-fillet\",\n material !== \"glass\" && \"amb-surface-convex\",\n material && `amb-mat-${material}`,\n className\n )}\n />\n );\n}\n","/** The grounded surface finishes from @ambientcss/css.\n *\n * Lives on parts and presets, never on a mechanism: which element a\n * material belongs on is a fact about a particular control's construction,\n * and a mechanism cannot know that once the parts are yours.\n *\n * `brushed`, `brushed-round` and `blasted` are micro-relief materials: they\n * paint their grain into BOTH of the host's pseudo-elements, so a part that\n * already spends one of its own has to give them an inner layer rather than\n * wear them directly. `ButtonCap` is the only part in this package that does.\n *\n * `brushed-round` is the same aluminium as `brushed` with the grain spun\n * round the element's centre, so it belongs on round faces — a knob cap, a\n * round button — where the centre it turns about is a real feature. */\nexport type AmbientMaterial =\n | \"matte\"\n | \"shiny\"\n | \"glass\"\n | \"brushed\"\n | \"brushed-round\"\n | \"blasted\";\n\n/** Whether a finish carries micro-relief, and therefore needs both\n * pseudo-elements of whatever it is put on. */\nexport function isRelief(material: AmbientMaterial | undefined): boolean {\n return material === \"brushed\" || material === \"brushed-round\" || material === \"blasted\";\n}\n","import type { ReactNode } from \"react\";\nimport { cn } from \"../lib/cn\";\nimport type { AmbientMaterial } from \"../core/material\";\nimport { isRelief } from \"../core/material\";\n\n/** The key cap: a chamfered, subtly dished top that sinks on `:active`.\n *\n * The cap is what sizes a press control — its legend sets the width above\n * the well's `min-width` — which is why a press control's frames are\n * `display: contents` markers rather than boxes.\n *\n * The cap spends its own `::after` on the dish, so the two micro-relief\n * materials cannot ride on it: their grain wants both pseudo-elements, and\n * the dish's `background` shorthand and the grain's tile would each silently\n * win half of the other's declarations. They get `.ambx-cap-face` instead —\n * an inner layer under the dish and under the legend, which is the inner\n * layer @ambientcss/css's own note prescribes. The cap itself stays a plain\n * `amb-surface` when relief is down there: the dish's overlay alphas are\n * derived from `--amb-shade` the ordinary way, and since the relief\n * materials carry no `--amb-albedo` of their own any more, that derivation\n * is already correct for them too — no per-material tone correction to\n * apply. */\nexport function ButtonCap({\n material = \"matte\",\n className,\n children\n}: {\n material?: AmbientMaterial | undefined;\n className?: string | undefined;\n children?: ReactNode | undefined;\n}) {\n const relief = isRelief(material);\n return (\n <span\n className={cn(\n \"amb-button-cap ambient amb-chamfer amb-surface amb-heading-3\",\n relief ? undefined : `amb-mat-${material}`,\n className\n )}\n >\n {relief ? (\n <span\n /* `ambient amb-chamfer` on the face, not just on the cap: the\n chamfer is painted as INSET shadows, which belong to the cap's\n own background layer — and the face, being opaque and covering\n it, would hide them. Wearing the cut itself puts the bevel back,\n and puts it back in the material's own tone rather than the\n cap's. */\n className={cn(\"ambx-cap-face ambient amb-chamfer amb-surface\", `amb-mat-${material}`)}\n aria-hidden\n />\n ) : null}\n {children}\n </span>\n );\n}\n","import type { CSSProperties } from \"react\";\nimport { cn } from \"../lib/cn\";\n\n/** The recess the pill slides in (switch.py: a 1.5mm well, thickness 0.33). */\nexport function SwitchTrack({ className }: { className?: string | undefined }) {\n return <span className={cn(\"amb-switch-track amb-groove\", className)} />;\n}\n\n/** The sliding pill, standing 2.6mm above the recess floor. */\nexport function SwitchPill({ className }: { className?: string | undefined }) {\n return (\n <span className={cn(\"amb-switch-pill ambient amb-fillet amb-surface-convex\", className)} />\n );\n}\n\n/** A pinprick indicator lamp. `color` is any CSS colour; unset it takes the\n * scene's own lamp colour, the same `--amb-led-color` a bank reads. */\nexport function Led({\n on = true,\n color,\n className\n}: {\n on?: boolean | undefined;\n color?: string | undefined;\n className?: string | undefined;\n}) {\n return (\n <span\n className={cn(\"amb-led\", !on && \"amb-led-off\", className)}\n style={color ? ({ \"--amb-led-color\": color } as CSSProperties) : undefined}\n />\n );\n}\n","import type { ReactNode } from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { useBankKey } from \"../core/context\";\n\n/** The lamp under a key: a big disc lying on the pocket floor.\n *\n * It has to paint BEFORE the cap, because the cap's `backdrop-filter` is\n * what diffuses it — which is the whole trick, and the reason the lens\n * belongs in the `base` frame and the cap in `actuator`. */\nexport function KeyLens({ className }: { className?: string | undefined }) {\n return <span className={cn(\"amb-select-lens\", className)} />;\n}\n\n/** The translucent diffuser over the lamp, carrying the key's legend.\n *\n * With no children it prints the option's own label, which is why a bank\n * of numerals needs no `renderKey`: the part reads the option it belongs\n * to out of the key context. */\nexport function KeyCap({\n className,\n children\n}: {\n className?: string | undefined;\n children?: ReactNode | undefined;\n}) {\n const { option } = useBankKey();\n return (\n <span className={cn(\"amb-select-cap ambient amb-chamfer amb-mat-glass\", className)}>\n {children ?? option.label ?? option.value}\n </span>\n );\n}\n","import { cn } from \"../lib/cn\";\nimport type { ControlKit, KitDress, KitLook } from \"../core/kit\";\nimport type { AmbientMaterial } from \"../core/material\";\nimport { IndicatorBar, IndicatorDot, KnobBody, KnurledFace, ScaleRing } from \"../parts/knob\";\nimport { FaderCap, SliderThumb, TravelTrack } from \"../parts/travel\";\nimport { ButtonCap } from \"../parts/press\";\nimport { SwitchPill, SwitchTrack } from \"../parts/latch\";\nimport { KeyCap, KeyLens } from \"../parts/bank\";\n\n/* The built-in look, packaged as a kit rather than hardwired into the\n presets. That is the integrity test for the whole idea: if the grounded\n parts needed a private back door the presets could reach and a third party\n could not, the abstraction would be a fiction. They do not — everything\n below is the same `(look) => { parts, className }` a published kit writes. */\n\n/* 12 divisions — 13 dots over the sweep, the pitch measured off the\n reference panel. */\nconst FULL_MARKERS = 13;\n\nfunction rotary(look: KitLook): KitDress {\n const material = look.material as AmbientMaterial | undefined;\n const knurling = look.knurling !== false;\n const knurlColor = look.knurlColor as string | undefined;\n const markers = (look.markers as \"none\" | \"ends\" | \"full\" | undefined) ?? \"none\";\n const indicator = (look.indicator as \"circle\" | \"rectangle\" | undefined) ?? \"circle\";\n\n return {\n /* The full ring reaches past the knob's own box, so its layout clearance\n has to be reserved — and only the kit knows it put a ring there. */\n className: cn(\"amb-knob\", markers === \"full\" && \"amb-knob-markers-full\"),\n parts: {\n panel:\n markers === \"none\" ? null : <ScaleRing count={markers === \"ends\" ? 2 : FULL_MARKERS} />,\n /* `material` goes on every element that paints. The cap always does —\n it is the knob's top face either way — and the knurl ring does too\n when there is one, so a knurled knob's rim and cap are the same\n material rather than the rim being the only thing wearing it.\n\n `knurlColor` is the one thing the ring may hold on its own: a\n two-tone knob — dark grip round a pale cap — is a real piece of\n hardware, and the cap has no matching prop because the cap's colour\n is the control's colour, set the ordinary way with --amb-albedo. */\n base: <KnobBody flush={!knurling} material={material} />,\n actuator: (\n <>\n {knurling ? <KnurledFace material={material} color={knurlColor} /> : null}\n {indicator === \"circle\" ? <IndicatorDot /> : <IndicatorBar />}\n </>\n )\n }\n };\n}\n\nfunction travel(look: KitLook): KitDress {\n const material = look.material as AmbientMaterial | undefined;\n const upright = look.orientation === \"vertical\";\n return {\n className: upright ? \"amb-fader\" : \"amb-slider\",\n parts: {\n base: <TravelTrack depth={upright ? \"slot\" : \"channel\"} />,\n actuator: upright ? <FaderCap material={material} /> : <SliderThumb material={material} />\n }\n };\n}\n\nfunction press(look: KitLook): KitDress {\n const shape = (look.shape as \"pill\" | \"round\" | \"square\" | undefined) ?? \"pill\";\n return {\n className: cn(\n \"amb-button amb-groove\",\n shape === \"round\" && \"amb-button-round\",\n shape === \"square\" && \"amb-button-square\"\n ),\n parts: {\n actuator: (\n <ButtonCap material={(look.material as AmbientMaterial | undefined) ?? \"matte\"}>\n {look.children as React.ReactNode}\n </ButtonCap>\n )\n }\n };\n}\n\nfunction latch(): KitDress {\n return {\n className: \"amb-switch\",\n parts: { base: <SwitchTrack />, actuator: <SwitchPill /> }\n };\n}\n\nfunction bank(): KitDress {\n return {\n className: \"amb-select amb-groove\",\n parts: { base: <KeyLens />, actuator: <KeyCap /> }\n };\n}\n\n/** The Blender-grounded hardware look: the default every preset falls back to. */\nexport const groundedKit: ControlKit = {\n name: \"grounded\",\n rotary,\n travel,\n press,\n latch,\n bank,\n looks: {\n rotary: [\"material\", \"knurling\", \"knurlColor\", \"markers\", \"indicator\"],\n travel: [\"material\", \"orientation\"],\n press: [\"material\", \"shape\", \"children\"],\n latch: [],\n bank: []\n }\n};\n","import { cn } from \"../lib/cn\";\nimport { AmbientPress } from \"../controls/AmbientPress\";\nimport type { AmbientPressProps } from \"../controls/AmbientPress\";\nimport { useDress } from \"../core/kit\";\nimport type { KitLook } from \"../core/kit\";\nimport { groundedKit } from \"../kits/grounded\";\nimport type { AmbientMaterial } from \"../core/material\";\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 type AmbientButtonProps = Omit<AmbientPressProps, \"parts\" | \"size\"> & {\n material?: AmbientMaterial | undefined;\n shape?: AmbientButtonShape | undefined;\n size?: AmbientButtonSize | undefined;\n /** Look options in the active kit's vocabulary. */\n look?: KitLook | undefined;\n};\n\n/** A key cap seated in a clearance well. */\nexport function AmbientButton({\n className,\n children,\n look,\n material = \"matte\",\n shape = \"pill\",\n size = \"md\",\n ...rest\n}: AmbientButtonProps) {\n const { dress } = useDress(\"press\", { material, shape, children, ...look }, groundedKit.press!);\n return (\n <AmbientPress\n {...rest}\n size={size}\n className={cn(dress.className, className)}\n parts={dress.parts}\n />\n );\n}\n","import { useId } from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { AmbientLatch } from \"../controls/AmbientLatch\";\nimport type { AmbientLatchProps } from \"../controls/AmbientLatch\";\nimport { useControllableValue } from \"../core/controllable\";\nimport { useDress } from \"../core/kit\";\nimport type { KitLook } from \"../core/kit\";\nimport { groundedKit } from \"../kits/grounded\";\nimport { Led } from \"../parts/latch\";\n\nexport type AmbientSwitchSize = \"sm\" | \"md\" | \"lg\";\n\nexport type AmbientSwitchProps = Omit<AmbientLatchProps, \"parts\" | \"size\"> & {\n size?: AmbientSwitchSize | undefined;\n /** A lamp above the switch. `true` for the scene's own colour, or any\n * CSS colour string. */\n led?: boolean | string | undefined;\n /** Look options in the active kit's vocabulary. */\n look?: KitLook | undefined;\n};\n\n/** A pill sliding in a dark stadium recess, with an optional lamp above.\n *\n * The lamp is mounted beside the switch rather than inside it: the latch\n * control IS the track, so anything that is neither track nor pill belongs\n * to whatever composes them. That means the preset has to hold the state —\n * the lamp and the pill read the same boolean, and only their common\n * parent can see both.\n */\nexport function AmbientSwitch({\n size = \"md\",\n led,\n label,\n look,\n value,\n defaultValue,\n onChange,\n animate,\n className,\n ...rest\n}: AmbientSwitchProps) {\n const labelId = useId();\n const [on, setOn] = useControllableValue(value, defaultValue ?? false, onChange);\n const { dress, defaults } = useDress(\"latch\", { ...look }, groundedKit.latch!);\n\n const control = (\n <AmbientLatch\n {...rest}\n value={on}\n onChange={setOn}\n size={size}\n animate={animate ?? defaults?.animate}\n aria-labelledby={label ? labelId : rest[\"aria-labelledby\"]}\n className={cn(dress.className, className)}\n parts={dress.parts}\n />\n );\n\n if (!led && !label) return control;\n\n return (\n <div className=\"ambx-stack\">\n {led ? (\n <span className=\"ambx-switch-mount\">\n <Led on={on} {...(typeof led === \"string\" ? { color: led } : null)} />\n {control}\n </span>\n ) : (\n control\n )}\n {label ? (\n <span id={labelId} className=\"ambx-label\">\n {label}\n </span>\n ) : null}\n </div>\n );\n}\n","import { useId, useRef } from \"react\";\nimport type { ButtonHTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { ControlStateProvider } from \"../core/context\";\nimport { Frames, useDevPartCheck } from \"../core/frames\";\nimport { sizeProps } from \"../core/types\";\nimport type { ControlAnimate, ControlParts, ControlSize } from \"../core/types\";\nimport { useLatch } from \"../core/useLatch\";\nimport type { UseLatchOptions } from \"../core/useLatch\";\n\nexport type AmbientLatchProps = Omit<\n ButtonHTMLAttributes<HTMLButtonElement>,\n \"onChange\" | \"value\" | \"defaultValue\" | \"type\"\n> &\n UseLatchOptions & {\n parts?: ControlParts | undefined;\n size?: ControlSize | undefined;\n animate?: ControlAnimate | undefined;\n label?: ReactNode | undefined;\n };\n\n/** A two-position slide, with no appearance of its own. The control IS the\n * track: its actuator is a pill-sized frame that travels across it, which\n * is why anything sitting beside a switch — a lamp, a legend — belongs to\n * whatever composes it rather than to the switch. */\nexport function AmbientLatch({\n parts,\n size,\n animate = \"auto\",\n label,\n className,\n value,\n defaultValue,\n onChange,\n disabled,\n children,\n ...rest\n}: AmbientLatchProps) {\n const labelId = useId();\n const ref = useRef<HTMLButtonElement>(null);\n const { state, rootProps } = useLatch({ value, defaultValue, onChange, disabled });\n useDevPartCheck(ref, \"AmbientLatch\");\n\n const sized = sizeProps(\"latch\", size);\n const { style: restStyle, onClick, ...restProps } = rest;\n\n const control = (\n <button\n {...restProps}\n {...rootProps}\n ref={ref}\n aria-labelledby={label ? labelId : rest[\"aria-labelledby\"]}\n data-animate={animate}\n className={cn(\"ambx-control ambx-latch\", sized.className, className)}\n style={{ ...rootProps.style, ...sized.style, ...restStyle }}\n onClick={(event) => {\n rootProps.onClick();\n onClick?.(event);\n }}\n >\n <ControlStateProvider value={state}>\n <Frames parts={parts} />\n {children}\n </ControlStateProvider>\n </button>\n );\n\n if (!label) return control;\n\n return (\n <div className=\"ambx-stack\">\n {control}\n <span id={labelId} className=\"ambx-label\">\n {label}\n </span>\n </div>\n );\n}\n","import { useMemo } from \"react\";\nimport type { CSSProperties } from \"react\";\nimport { useControllableValue } from \"./controllable\";\nimport { stateData, stateStyle } from \"./types\";\nimport type { ControlState } from \"./types\";\n\nexport type UseLatchOptions = {\n value?: boolean | undefined;\n defaultValue?: boolean | undefined;\n onChange?: ((next: boolean) => void) | undefined;\n disabled?: boolean | undefined;\n};\n\n/** A two-position travel. Kept distinct from Press because its actuator\n * genuinely slides rather than sinking, and because its ARIA is\n * `role=\"switch\"` — a switch is a state, not an action. */\nexport function useLatch(options: UseLatchOptions) {\n const { disabled = false } = options;\n const [on, setOn] = useControllableValue(\n options.value,\n options.defaultValue ?? false,\n options.onChange\n );\n\n const state: ControlState = useMemo(\n () => ({\n value: on ? 1 : 0,\n min: 0,\n max: 1,\n percent: on ? 1 : 0,\n angle: 0,\n travelStart: 0,\n travelSweep: 0,\n detents: 2,\n dragging: false,\n disabled,\n atMin: !on,\n atMax: on\n }),\n [on, disabled]\n );\n\n const rootProps = {\n type: \"button\" as const,\n role: \"switch\" as const,\n \"aria-checked\": on,\n disabled,\n style: stateStyle(state) as CSSProperties,\n ...stateData(state),\n onClick: () => setOn(!on)\n };\n\n return { state, rootProps, on, setOn };\n}\n","import { useId } from \"react\";\nimport type { CSSProperties, HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { BankKeyProvider, ControlStateProvider } from \"../core/context\";\nimport { Frames } from \"../core/frames\";\nimport { sizeProps, stateData, stateStyle } from \"../core/types\";\nimport type { ControlParts, ControlSize, ControlState } from \"../core/types\";\nimport { useBank } from \"../core/useBank\";\nimport type { BankOption, UseBankOptions } from \"../core/useBank\";\n\nexport type AmbientBankProps = Omit<\n HTMLAttributes<HTMLDivElement>,\n \"onChange\" | \"defaultValue\"\n> &\n UseBankOptions & {\n /** Parts applied to every key. The bank's own frames go in `parts`. */\n keyParts?: ControlParts | undefined;\n parts?: ControlParts | undefined;\n size?: ControlSize | undefined;\n /** Lamp colour. Defaults to the scene's `--amb-highlight-color`. */\n color?: string | undefined;\n label?: ReactNode | undefined;\n /** Per-key override, for a bank whose keys are not interchangeable. */\n renderKey?: ((option: BankOption, on: boolean) => ReactNode) | undefined;\n };\n\nfunction keyState(on: boolean, disabled: boolean): ControlState {\n return {\n value: on ? 1 : 0,\n min: 0,\n max: 1,\n percent: on ? 1 : 0,\n angle: 0,\n travelStart: 0,\n travelSweep: 0,\n detents: 2,\n dragging: false,\n disabled,\n atMin: !on,\n atMax: on\n };\n}\n\n/** N keys sharing a selection model, with no appearance of its own.\n *\n * Parts apply per key rather than once, because that is what a bank is.\n * The focusable element is the key `<button>`, which this mechanism\n * renders — your parts go inside it, which is why the presentational-parts\n * rule still holds here. */\nexport function AmbientBank({\n options,\n keyParts,\n parts,\n size,\n color,\n label,\n renderKey,\n className,\n style,\n value,\n defaultValue,\n onChange,\n multiple,\n orientation = \"vertical\",\n disabled = false,\n ...rest\n}: AmbientBankProps) {\n const labelId = useId();\n const { selected, rootProps, keyProps } = useBank({\n options,\n value,\n defaultValue,\n onChange,\n multiple,\n orientation,\n disabled\n });\n\n const sized = sizeProps(\"bank\", size);\n\n const bank = (\n <div\n {...rest}\n {...rootProps}\n aria-labelledby={label ? labelId : rest[\"aria-labelledby\"]}\n className={cn(\n \"ambx-control ambx-bank\",\n `ambx-bank-${orientation}`,\n sized.className,\n className\n )}\n style={{\n ...(color ? ({ \"--amb-led-color\": color } as CSSProperties) : null),\n ...sized.style,\n ...style\n }}\n >\n <Frames parts={parts} />\n {options.map((option, index) => {\n const on = selected.includes(option.value);\n /* Each key publishes its own state channel, exactly as a standalone\n control does. Without this a key's parts would inherit the bank\n root's neutral --ambx-percent and a pure-CSS part could never see\n that its lamp is lit — the one family where \"the properties are\n canonical\" would quietly not be true. */\n const ks = keyState(on, option.disabled || disabled);\n return (\n <button\n {...keyProps(option, index)}\n {...stateData(ks)}\n className=\"ambx-key\"\n style={{\n ...(stateStyle(ks) as CSSProperties),\n ...(option.color ? ({ \"--amb-led-color\": option.color } as CSSProperties) : null)\n }}\n >\n <ControlStateProvider value={ks}>\n <BankKeyProvider value={{ option, on, index }}>\n {renderKey ? renderKey(option, on) : <Frames parts={keyParts} />}\n </BankKeyProvider>\n </ControlStateProvider>\n </button>\n );\n })}\n </div>\n );\n\n if (!label) return bank;\n\n return (\n <div className=\"ambx-stack\">\n {bank}\n <span id={labelId} className=\"ambx-label\">\n {label}\n </span>\n </div>\n );\n}\n","import { useCallback, useRef } from \"react\";\nimport type { KeyboardEvent, ReactNode } from \"react\";\nimport { useControllableValue } from \"./controllable\";\n\nexport type BankOption = {\n value: string;\n /** Key legend — a numeral in the referent, but any node works. */\n label?: ReactNode | undefined;\n /** Accessible name, and the hover title. Needed whenever the legend is a\n * glyph or an icon: a key reading \"*\" has no name otherwise. */\n ariaLabel?: string | undefined;\n /** Overrides the bank's lamp colour for this key only. */\n color?: string | undefined;\n disabled?: boolean | undefined;\n};\n\nexport type BankOrientation = \"vertical\" | \"horizontal\";\n\nexport type UseBankOptions = {\n options: BankOption[];\n value?: string | string[] | undefined;\n defaultValue?: string | string[] | undefined;\n onChange?: ((value: string | string[]) => void) | undefined;\n /** Let more than one lamp be lit at a time. */\n multiple?: boolean | undefined;\n orientation?: BankOrientation | undefined;\n disabled?: boolean | undefined;\n};\n\nfunction toArray(value: string | string[] | undefined): string[] {\n if (value === undefined) return [];\n return Array.isArray(value) ? value : [value];\n}\n\n/** N presses sharing a selection model.\n *\n * The roving tabindex, the radiogroup-versus-checkbox-group keyboard\n * difference and the selection-follows-focus rule are the reason this\n * mechanism exists: they are the part nobody should have to re-derive in\n * order to change what a key looks like. */\nexport function useBank(options: UseBankOptions) {\n const { options: items, multiple = false, orientation = \"vertical\", disabled = false } = options;\n\n const [raw, setRaw] = useControllableValue<string | string[]>(\n options.value,\n options.defaultValue ?? (multiple ? [] : \"\"),\n options.onChange\n );\n const selected = toArray(raw);\n const keyRefs = useRef<Array<HTMLButtonElement | null>>([]);\n\n const commit = useCallback(\n (next: string[]) => setRaw(multiple ? next : (next[0] ?? \"\")),\n [setRaw, multiple]\n );\n\n const select = useCallback(\n (option: BankOption | undefined) => {\n if (!option || option.disabled || disabled) return;\n if (!multiple) return commit([option.value]);\n commit(\n selected.includes(option.value)\n ? selected.filter((v) => v !== option.value)\n : [...selected, option.value]\n );\n },\n [commit, multiple, selected, disabled]\n );\n\n const enabled = items.filter((o) => !o.disabled);\n /* Roving tabindex: exactly one key is tab-reachable. The lit one owns the\n stop, so Tab lands where the eye already is; with nothing lit (or in\n multiple mode, where every lamp is independent) the first enabled key\n takes it. */\n const litIndex = items.findIndex((o) => selected.includes(o.value) && !o.disabled);\n const firstEnabled = items.findIndex((o) => !o.disabled);\n const tabStop = multiple ? -1 : litIndex >= 0 ? litIndex : firstEnabled;\n\n const focusAt = (index: number) => keyRefs.current[index]?.focus();\n\n const step = (from: number, delta: number) => {\n if (enabled.length === 0) return;\n let i = from;\n for (let guard = 0; guard < items.length; guard += 1) {\n i = (i + delta + items.length) % items.length;\n if (!items[i]?.disabled) break;\n }\n focusAt(i);\n /* A radio group moves selection with focus (WAI-ARIA radiogroup\n pattern); a checkbox group only moves focus, since each lamp toggles\n on its own. */\n if (!multiple) select(items[i]);\n };\n\n const edge = (which: \"first\" | \"last\") => {\n const i =\n which === \"first\" ? firstEnabled : items.map((o) => !o.disabled).lastIndexOf(true);\n if (i < 0) return;\n focusAt(i);\n if (!multiple) select(items[i]);\n };\n\n const onKeyDown = (event: KeyboardEvent<HTMLButtonElement>, index: number) => {\n const back = orientation === \"vertical\" ? \"ArrowUp\" : \"ArrowLeft\";\n const forward = orientation === \"vertical\" ? \"ArrowDown\" : \"ArrowRight\";\n switch (event.key) {\n case back:\n event.preventDefault();\n step(index, -1);\n break;\n case forward:\n event.preventDefault();\n step(index, 1);\n break;\n case \"Home\":\n event.preventDefault();\n edge(\"first\");\n break;\n case \"End\":\n event.preventDefault();\n edge(\"last\");\n break;\n case \" \":\n case \"Enter\":\n event.preventDefault();\n select(items[index]);\n break;\n default:\n break;\n }\n };\n\n const rootProps = {\n role: multiple ? (\"group\" as const) : (\"radiogroup\" as const),\n \"aria-orientation\": multiple ? undefined : orientation,\n \"aria-disabled\": disabled || undefined,\n \"data-orientation\": orientation,\n \"data-disabled\": disabled ? \"\" : undefined\n };\n\n /** Props for the key at `index`, including its own state channel. */\n const keyProps = (option: BankOption, index: number) => {\n const on = selected.includes(option.value);\n return {\n key: option.value,\n type: \"button\" as const,\n ref: (node: HTMLButtonElement | null) => {\n keyRefs.current[index] = node;\n },\n role: multiple ? (\"checkbox\" as const) : (\"radio\" as const),\n \"aria-checked\": on,\n \"aria-label\": option.ariaLabel,\n title: option.ariaLabel,\n disabled: option.disabled || disabled,\n tabIndex: multiple ? 0 : index === tabStop ? 0 : -1,\n \"data-on\": on ? \"\" : undefined,\n onClick: () => select(option),\n onKeyDown: (event: KeyboardEvent<HTMLButtonElement>) => onKeyDown(event, index)\n };\n };\n\n return { selected, select, rootProps, keyProps };\n}\n","import { cn } from \"../lib/cn\";\nimport { AmbientBank } from \"../controls/AmbientBank\";\nimport type { AmbientBankProps } from \"../controls/AmbientBank\";\nimport type { BankOption, BankOrientation } from \"../core/useBank\";\nimport { useDress } from \"../core/kit\";\nimport type { KitLook } from \"../core/kit\";\nimport { groundedKit } from \"../kits/grounded\";\n\nexport type AmbientSelectOption = BankOption;\nexport type AmbientSelectOrientation = BankOrientation;\nexport type AmbientSelectSize = \"sm\" | \"md\" | \"lg\";\n\nexport type AmbientSelectProps = Omit<AmbientBankProps, \"keyParts\" | \"parts\" | \"size\"> & {\n size?: AmbientSelectSize | undefined;\n /** Look options in the active kit's vocabulary. */\n look?: KitLook | undefined;\n};\n\n/**\n * A bank of lamp-lit keys in a shared rail — the hardware idiom for a\n * mode selector, where the state is a lamp rather than a mark.\n *\n * Three physical layers per key, and the ORDER is the whole trick: the key\n * itself is the pocket floor, the lens is a disc lying on it, and the cap\n * is a translucent diffuser over both. The cap is `.amb-mat-glass`, so its\n * backdrop-filter blurs the lens behind it — which is why the lens goes in\n * the `base` frame and the cap in `actuator`, and why swapping them would\n * put out every lamp.\n */\nexport function AmbientSelect({ size = \"md\", look, className, ...rest }: AmbientSelectProps) {\n const { dress } = useDress(\"bank\", { ...look }, groundedKit.bank!);\n return (\n <AmbientBank\n {...rest}\n size={size}\n className={cn(dress.className, className)}\n keyParts={dress.parts}\n />\n );\n}\n","import { useId, useRef } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { ControlStateProvider } from \"../core/context\";\nimport { Frames, useDevPartCheck } from \"../core/frames\";\nimport { sizeProps } from \"../core/types\";\nimport type { ControlAnimate, ControlParts, ControlSize } from \"../core/types\";\nimport { useRotary } from \"../core/useRotary\";\nimport type { UseRotaryOptions } from \"../core/useRotary\";\n\nexport type AmbientRotaryProps = Omit<HTMLAttributes<HTMLDivElement>, \"onChange\" | \"defaultValue\"> &\n UseRotaryOptions & {\n parts?: ControlParts | undefined;\n size?: ControlSize | undefined;\n animate?: ControlAnimate | undefined;\n label?: ReactNode | undefined;\n };\n\n/** A rotary mechanism with no appearance of its own.\n *\n * It owns the value, the three pointer mappings, the sweep, the keyboard\n * contract and the ARIA; what it looks like is entirely the `parts` you\n * give it. There is deliberately no `material` prop: which element a\n * material belongs on is a fact about a particular knob's construction —\n * on the clipped face when it is knurled, on the body when it is not —\n * and a mechanism cannot know that once the body is yours. Presets carry\n * `material`, because a preset knows its own parts. */\nexport function AmbientRotary({\n parts,\n size,\n animate = \"auto\",\n label,\n className,\n value,\n defaultValue,\n min,\n max,\n step,\n detents,\n travel,\n input,\n dragDistance,\n wrap,\n disabled,\n onChange,\n ...rest\n}: AmbientRotaryProps) {\n const labelId = useId();\n const stackRef = useRef<HTMLDivElement>(null);\n const { state, rootProps } = useRotary({\n value,\n defaultValue,\n min,\n max,\n step,\n detents,\n travel,\n input,\n dragDistance,\n wrap,\n disabled,\n onChange\n });\n useDevPartCheck(stackRef, \"AmbientRotary\");\n\n const sized = sizeProps(\"rotary\", size);\n const { style: restStyle, ...restProps } = rest;\n\n const control = (\n <div\n {...restProps}\n {...rootProps}\n aria-labelledby={label ? labelId : rest[\"aria-labelledby\"]}\n data-animate={animate}\n className={cn(\"ambx-control ambx-rotary\", sized.className, className)}\n style={{ ...rootProps.style, ...sized.style, ...restStyle }}\n >\n <ControlStateProvider value={state}>\n <Frames parts={parts} />\n </ControlStateProvider>\n </div>\n );\n\n return (\n <div className=\"ambx-stack\" ref={stackRef}>\n {control}\n {label ? (\n <span id={labelId} className=\"ambx-label\">\n {label}\n </span>\n ) : null}\n </div>\n );\n}\n","import { useCallback, useMemo, useRef, useState } from \"react\";\nimport type { CSSProperties, KeyboardEvent, PointerEvent } from \"react\";\nimport { useControllableValue } from \"./controllable\";\nimport { clamp, commit, denormalise, normalise, valueKeyHandler } from \"./numeric\";\nimport { stateData, stateStyle } from \"./types\";\nimport { isDev } from \"./dev\";\nimport type { ControlState } from \"./types\";\n\n/** How pointer movement becomes value.\n *\n * These are three different mappings, not one with a parameter, and the\n * library was ambiguous about which it implemented: the code did `angle`\n * while knob.md documented `drag`. Naming it makes that drift impossible.\n *\n * - `drag` pointer DISTANCE -> value delta. The v3 default: it is what the\n * docs always described, what most audio software does, and the\n * only one that behaves on touch, where a finger covers the knob.\n * - `angle` pointer POSITION -> absolute angle -> value. Needs a dead zone,\n * and needs a sweep under a full turn to be unambiguous.\n * - `delta` accumulated angular change. The endless-encoder mapping: no\n * ends, no dead zone, and the value may wrap independently of\n * where the pointer happens to be. */\nexport type RotaryInput = \"drag\" | \"angle\" | \"delta\";\n\n/** The pot's travel in degrees clockwise from 12 o'clock. A bare number is\n * a sweep centred on 12 o'clock, so `270` is the default 8-to-4 pot. */\nexport type RotaryTravel = number | { start: number; sweep: number };\n\nexport type UseRotaryOptions = {\n value?: number | undefined;\n defaultValue?: number | undefined;\n min?: number | undefined;\n max?: number | undefined;\n /** Quantises the VALUE. `0` leaves it continuous. */\n step?: number | undefined;\n /** Quantises the TRAVEL: rest positions along the arc. Defaults to the\n * step grid, but the two are independent — an endless encoder can have\n * 24 detents per turn while its value stays continuous. */\n detents?: number | undefined;\n travel?: RotaryTravel | undefined;\n input?: RotaryInput | undefined;\n /** Pixels of drag for one full range, in `drag` mode. */\n dragDistance?: number | undefined;\n /** `delta` mode only: run past the ends and come round again. */\n wrap?: boolean | undefined;\n disabled?: boolean | undefined;\n onChange?: ((next: number) => void) | undefined;\n};\n\nconst DEFAULT_TRAVEL = { start: -135, sweep: 270 };\n\n/** Fold an angle into (-180, 180]. */\nfunction wrapDeg(deg: number): number {\n return ((((deg + 180) % 360) + 360) % 360) - 180;\n}\n\nfunction resolveTravel(travel: RotaryTravel | undefined) {\n if (travel === undefined) return DEFAULT_TRAVEL;\n if (typeof travel === \"number\") return { start: -travel / 2, sweep: travel };\n return travel;\n}\n\nlet warnedFullTurn = false;\n\n/** Pointer capture, but survivable.\n *\n * `setPointerCapture` throws NotFoundError for a pointer id the browser\n * does not currently have down, and is missing outright in jsdom. Neither\n * happens with a real finger, but both happen constantly in tests — and an\n * exception here would abort the handler before the drag ever starts,\n * making the control look broken rather than untestable. */\nexport function capturePointer(target: Element, pointerId: number): void {\n try {\n target.setPointerCapture?.(pointerId);\n } catch {\n /* Without capture the drag still tracks; it just stops at the edge of\n the element instead of following the pointer off it. */\n }\n}\n\nexport function useRotary(options: UseRotaryOptions) {\n const {\n min = 0,\n max = 100,\n step = 1,\n dragDistance = 200,\n wrap = false,\n disabled = false\n } = options;\n\n const { start, sweep } = resolveTravel(options.travel);\n\n /* A full turn cannot be read as an absolute angle: 0 and max land on the\n same screen position, and the dead-zone clamp has no end to snap to.\n Fall back rather than misbehave silently. */\n let input = options.input ?? \"drag\";\n if (input === \"angle\" && Math.abs(sweep) >= 360) {\n if (isDev && !warnedFullTurn) {\n warnedFullTurn = true;\n console.warn(\n `[@ambientcss/components] input=\"angle\" needs a sweep under a full turn ` +\n `(got ${sweep}deg): an absolute angle is ambiguous at 360deg, where the ` +\n `first and last values share a screen position. Falling back to \"drag\".`\n );\n }\n input = \"drag\";\n }\n\n const [value, setValue] = useControllableValue(\n options.value,\n options.defaultValue ?? min,\n options.onChange\n );\n\n /* `dragging` is state because the root publishes it as data-dragging, and\n a REF because the move handler has to gate on it. Reading the state in\n the handler drops every move that fires before React re-renders after\n the press — which is most of them on a fast drag. */\n const [dragging, setDragging] = useState(false);\n const draggingRef = useRef(false);\n const rootRef = useRef<HTMLDivElement | null>(null);\n /* Drag bookkeeping. Deltas are accumulated rather than measured from the\n press point so that toggling the fine-mode modifier mid-drag changes\n the gearing from here on instead of jumping the value. */\n const drag = useRef({ value: 0, clientY: 0, angle: 0, accum: 0 });\n\n const range = max - min;\n const keyStep = step > 0 ? step : range / 100 || 1;\n const percent = clamp(normalise(value, min, max), 0, 1);\n const angle = start + percent * sweep;\n\n const set = useCallback(\n (next: number) => setValue(commit(next, min, max, step)),\n [setValue, min, max, step]\n );\n\n /** Pointer position as an angle in degrees clockwise from 12 o'clock. */\n const pointerAngle = (event: PointerEvent<HTMLElement>): number | null => {\n const rect = rootRef.current?.getBoundingClientRect();\n if (!rect) return null;\n const dx = event.clientX - (rect.left + rect.width / 2);\n const dy = event.clientY - (rect.top + rect.height / 2);\n // atan2 in screen coords reads 0 at 3 o'clock and grows clockwise; +90\n // rotates the origin to 12 o'clock.\n return Math.atan2(dy, dx) * (180 / Math.PI) + 90;\n };\n\n const fromAngle = (event: PointerEvent<HTMLElement>) => {\n const raw = pointerAngle(event);\n if (raw === null) return;\n /* Fold the reading into the half-turn either side of the sweep's own\n midpoint, so a sweep whose end passes 180deg stays reachable. */\n const mid = start + sweep / 2;\n let a = mid + wrapDeg(raw - mid);\n const end = start + sweep;\n if (a < Math.min(start, end) || a > Math.max(start, end)) {\n /* In the dead zone: hold at whichever end is angularly nearer. The\n pre-v3 code chose by which half the value was in, which threw the\n knob to the far end whenever a drag crossed the gap. */\n const toStart = Math.abs(wrapDeg(a - start));\n const toEnd = Math.abs(wrapDeg(a - end));\n a = toStart <= toEnd ? start : end;\n }\n set(denormalise((a - start) / (sweep || 1), min, max));\n };\n\n const fromDrag = (event: PointerEvent<HTMLElement>) => {\n const dy = drag.current.clientY - event.clientY;\n drag.current.clientY = event.clientY;\n drag.current.accum += dy * (event.shiftKey ? 0.25 : 1);\n set(drag.current.value + (drag.current.accum / dragDistance) * range);\n };\n\n const fromDelta = (event: PointerEvent<HTMLElement>) => {\n const raw = pointerAngle(event);\n if (raw === null) return;\n drag.current.accum += wrapDeg(raw - drag.current.angle);\n drag.current.angle = raw;\n const next = drag.current.value + (drag.current.accum / (sweep || 360)) * range;\n set(wrap && range > 0 ? min + (((next - min) % range) + range) % range : next);\n };\n\n const track = (event: PointerEvent<HTMLElement>) => {\n if (input === \"angle\") fromAngle(event);\n else if (input === \"delta\") fromDelta(event);\n else fromDrag(event);\n };\n\n const state: ControlState = useMemo(\n () => ({\n value,\n min,\n max,\n percent,\n angle,\n travelStart: start,\n travelSweep: sweep,\n detents: options.detents ?? (step > 0 && range > 0 ? Math.round(range / step) : 0),\n dragging,\n disabled,\n atMin: value <= min,\n atMax: value >= max\n }),\n [value, min, max, percent, angle, start, sweep, options.detents, step, range, dragging, disabled]\n );\n\n const onKeyDown = valueKeyHandler({ value, min, max, step: keyStep, disabled, onChange: setValue });\n\n const rootProps = {\n ref: rootRef,\n role: \"slider\" as const,\n \"aria-valuemin\": min,\n \"aria-valuemax\": max,\n \"aria-valuenow\": value,\n \"aria-orientation\": \"vertical\" as const,\n \"aria-disabled\": disabled || undefined,\n tabIndex: disabled ? -1 : 0,\n style: stateStyle(state) as CSSProperties,\n ...stateData(state),\n onPointerDown: (event: PointerEvent<HTMLDivElement>) => {\n if (disabled || event.button !== 0) return;\n capturePointer(event.currentTarget, event.pointerId);\n draggingRef.current = true;\n setDragging(true);\n drag.current = {\n value,\n clientY: event.clientY,\n angle: pointerAngle(event) ?? 0,\n accum: 0\n };\n /* Only the absolute mapping jumps to the press point; the relative\n ones would lurch, which is the whole reason to prefer them. */\n if (input === \"angle\") fromAngle(event);\n },\n onPointerMove: (event: PointerEvent<HTMLDivElement>) => {\n if (!draggingRef.current || disabled) return;\n track(event);\n },\n onPointerUp: () => {\n draggingRef.current = false;\n setDragging(false);\n },\n onPointerCancel: () => {\n draggingRef.current = false;\n setDragging(false);\n },\n onKeyDown: (event: KeyboardEvent<HTMLDivElement>) => {\n onKeyDown(event);\n }\n };\n\n return { state, rootProps, setValue: set };\n}\n","/* Value maths shared by every control.\n\n These four functions were previously inlined — identically — in\n AmbientKnob, AmbientSlider and AmbientFader. The keyboard handler below\n was copied three times with the same `pageStep = step * 10`, the same\n Home/End edges and the same snap-then-clamp order. */\n\nexport function clamp(value: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, value));\n}\n\n/** Quantise to the step grid, anchored at `min` rather than at zero so a\n * range like 10..100 step 25 rests on 10/35/60/85 instead of 25/50/75. */\nexport function snap(value: number, min: number, step: number): number {\n if (!(step > 0)) return value;\n return min + Math.round((value - min) / step) * step;\n}\n\n/** Value to its 0-1 position in the range. */\nexport function normalise(value: number, min: number, max: number): number {\n return (value - min) / (max - min || 1);\n}\n\n/** A 0-1 position back to a value. */\nexport function denormalise(t: number, min: number, max: number): number {\n return min + t * (max - min);\n}\n\n/** Snap and clamp in the order every control needs: quantise first, then\n * hold the result inside the range, so a step that does not divide the\n * range still cannot push the value past `max`. */\nexport function commit(value: number, min: number, max: number, step: number): number {\n return clamp(snap(value, min, max === min ? 1 : step), min, max);\n}\n\nexport type ValueKeysOptions = {\n value: number;\n min: number;\n max: number;\n step: number;\n disabled?: boolean;\n /** Swap the direction of the arrow keys along the control's own axis. */\n invert?: boolean;\n onChange: (next: number) => void;\n};\n\n/** The Arrow/Page/Home/End contract, in one place.\n *\n * Both arrow axes act on every control: a knob has no \"left\", and a\n * horizontal slider has no \"up\", but a keyboard user should not have to\n * know which. Page steps are ten of `step`, the figure all three\n * components already used. */\nexport function valueKeyHandler(options: ValueKeysOptions) {\n return (event: { key: string; preventDefault(): void }): boolean => {\n const { value, min, max, step, invert, onChange, disabled } = options;\n if (disabled) return false;\n const dir = invert ? -1 : 1;\n const set = (next: number) => {\n event.preventDefault();\n onChange(commit(next, min, max, step));\n };\n\n switch (event.key) {\n case \"ArrowUp\":\n case \"ArrowRight\":\n set(value + step * dir);\n return true;\n case \"ArrowDown\":\n case \"ArrowLeft\":\n set(value - step * dir);\n return true;\n case \"PageUp\":\n set(value + step * 10 * dir);\n return true;\n case \"PageDown\":\n set(value - step * 10 * dir);\n return true;\n case \"Home\":\n set(min);\n return true;\n case \"End\":\n set(max);\n return true;\n default:\n return false;\n }\n };\n}\n","import { cn } from \"../lib/cn\";\nimport { AmbientRotary } from \"../controls/AmbientRotary\";\nimport type { AmbientRotaryProps } from \"../controls/AmbientRotary\";\nimport { useDress } from \"../core/kit\";\nimport type { KitLook } from \"../core/kit\";\nimport type { AmbientMaterial } from \"../core/material\";\nimport { groundedKit } from \"../kits/grounded\";\n\n/** Printed scale dots on the panel around the knob: the arc's two ends, the\n * full graduated ring, or nothing. */\nexport type AmbientKnobMarkers = \"none\" | \"ends\" | \"full\";\n\n/** The pointer riding the rotating face: a radial bar or an offset dot. */\nexport type AmbientKnobIndicator = \"rectangle\" | \"circle\";\n\nexport type AmbientKnobSize = \"sm\" | \"md\" | \"lg\";\n\nexport type AmbientKnobProps = Omit<AmbientRotaryProps, \"parts\" | \"size\"> & {\n material?: AmbientMaterial | undefined;\n /** Ribbed grip around the rotating body. Off gives a smooth turned body. */\n knurling?: boolean | undefined;\n /** The grip ring's own colour, for a two-tone knob — any CSS colour, read\n * as an albedo, so it still takes the scene's light rather than being\n * painted flat. Unset, the ring is the same material as the cap. */\n knurlColor?: string | undefined;\n markers?: AmbientKnobMarkers | undefined;\n indicator?: AmbientKnobIndicator | undefined;\n size?: AmbientKnobSize | undefined;\n /** Look options in another kit's vocabulary.\n *\n * The five props above are the *grounded* kit's words. A kit that dresses\n * knobs differently has its own, and they arrive here rather than as\n * loose props so the common path stays typed and a misspelt `knurling`\n * is still a compile error. Kits usually ship a preset of their own that\n * types this properly — see `ConsoleKnob`. */\n look?: KitLook | undefined;\n};\n\n/**\n * The rotary preset: `AmbientRotary` wearing whatever the active kit says a\n * knob looks like, and the grounded hardware knob when no kit is set.\n */\nexport function AmbientKnob({\n material,\n knurling,\n knurlColor,\n markers,\n indicator,\n look,\n size = \"md\",\n className,\n travel,\n input,\n animate,\n ...rest\n}: AmbientKnobProps) {\n const { dress, defaults } = useDress(\n \"rotary\",\n { material, knurling, knurlColor, markers, indicator, ...look },\n groundedKit.rotary!\n );\n\n return (\n <AmbientRotary\n {...rest}\n /* Caller wins over kit, kit wins over the mechanism's own default. */\n travel={travel ?? defaults?.travel}\n input={input ?? defaults?.input}\n animate={animate ?? defaults?.animate}\n size={size}\n className={cn(dress.className, className)}\n parts={dress.parts}\n />\n );\n}\n","import { useId, useRef } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { ControlStateProvider } from \"../core/context\";\nimport { Frames, useDevPartCheck } from \"../core/frames\";\nimport { sizeProps } from \"../core/types\";\nimport type { ControlAnimate, ControlParts, ControlSize } from \"../core/types\";\nimport { useTravel } from \"../core/useTravel\";\nimport type { UseTravelOptions } from \"../core/useTravel\";\n\nexport type AmbientTravelProps = Omit<HTMLAttributes<HTMLDivElement>, \"onChange\" | \"defaultValue\"> &\n UseTravelOptions & {\n parts?: ControlParts | undefined;\n size?: ControlSize | undefined;\n animate?: ControlAnimate | undefined;\n label?: ReactNode | undefined;\n };\n\n/** A value on a straight track, with no appearance of its own. */\nexport function AmbientTravel({\n parts,\n size,\n animate = \"auto\",\n label,\n className,\n value,\n defaultValue,\n min,\n max,\n step,\n detents,\n orientation = \"horizontal\",\n invert,\n disabled,\n onChange,\n ...rest\n}: AmbientTravelProps) {\n const labelId = useId();\n const stackRef = useRef<HTMLDivElement>(null);\n const { state, rootProps } = useTravel({\n value,\n defaultValue,\n min,\n max,\n step,\n detents,\n orientation,\n invert,\n disabled,\n onChange\n });\n useDevPartCheck(stackRef, \"AmbientTravel\");\n\n const sized = sizeProps(\"travel\", size);\n const { style: restStyle, ...restProps } = rest;\n\n return (\n <div className=\"ambx-stack\" ref={stackRef}>\n <div\n {...restProps}\n {...rootProps}\n aria-labelledby={label ? labelId : rest[\"aria-labelledby\"]}\n data-animate={animate}\n className={cn(\n \"ambx-control ambx-travel\",\n `ambx-travel-${orientation}`,\n sized.className,\n className\n )}\n style={{ ...rootProps.style, ...sized.style, ...restStyle }}\n >\n <ControlStateProvider value={state}>\n <Frames parts={parts} />\n </ControlStateProvider>\n </div>\n {label ? (\n <span id={labelId} className=\"ambx-label\">\n {label}\n </span>\n ) : null}\n </div>\n );\n}\n","import { useCallback, useMemo, useRef, useState } from \"react\";\nimport type { CSSProperties, KeyboardEvent, PointerEvent } from \"react\";\nimport { useControllableValue } from \"./controllable\";\nimport { clamp, commit, denormalise, normalise, valueKeyHandler } from \"./numeric\";\nimport { capturePointer } from \"./useRotary\";\nimport { stateData, stateStyle } from \"./types\";\nimport type { ControlState } from \"./types\";\n\nexport type TravelOrientation = \"horizontal\" | \"vertical\";\n\nexport type UseTravelOptions = {\n value?: number | undefined;\n defaultValue?: number | undefined;\n min?: number | undefined;\n max?: number | undefined;\n step?: number | undefined;\n detents?: number | undefined;\n orientation?: TravelOrientation | undefined;\n /** Flip which end of the axis is `min`. */\n invert?: boolean | undefined;\n disabled?: boolean | undefined;\n onChange?: ((next: number) => void) | undefined;\n};\n\n/** A value riding a straight track.\n *\n * One mechanism behind both the slider and the fader, which before v3 were\n * the same file twice with X and Y swapped. The only real difference is\n * which axis the pointer reads — and which end is `min`, where the two\n * disagree for a physical reason rather than a stylistic one: a horizontal\n * track runs min-at-the-left, and an upright one runs min-at-the-bottom,\n * because that is how a fader is built. Both are the default here, so\n * neither preset has to ask. */\nexport function useTravel(options: UseTravelOptions) {\n const {\n min = 0,\n max = 100,\n step = 1,\n orientation = \"horizontal\",\n invert = false,\n disabled = false\n } = options;\n\n const [value, setValue] = useControllableValue(\n options.value,\n options.defaultValue ?? min,\n options.onChange\n );\n\n const [dragging, setDragging] = useState(false);\n const draggingRef = useRef(false);\n const rootRef = useRef<HTMLDivElement | null>(null);\n\n const vertical = orientation === \"vertical\";\n const range = max - min;\n const keyStep = step > 0 ? step : range / 100 || 1;\n const percent = clamp(normalise(value, min, max), 0, 1);\n\n const set = useCallback(\n (next: number) => setValue(commit(next, min, max, step)),\n [setValue, min, max, step]\n );\n\n const track = (event: PointerEvent<HTMLElement>) => {\n const rect = rootRef.current?.getBoundingClientRect();\n if (!rect) return;\n // An upright track reads bottom-up: 1 at the top of the box.\n const raw = vertical\n ? 1 - (event.clientY - rect.top) / (rect.height || 1)\n : (event.clientX - rect.left) / (rect.width || 1);\n set(denormalise(clamp(invert ? 1 - raw : raw, 0, 1), min, max));\n };\n\n const state: ControlState = useMemo(\n () => ({\n value,\n min,\n max,\n percent,\n angle: 0,\n travelStart: 0,\n travelSweep: 0,\n detents: options.detents ?? (step > 0 && range > 0 ? Math.round(range / step) : 0),\n dragging,\n disabled,\n atMin: value <= min,\n atMax: value >= max\n }),\n [value, min, max, percent, options.detents, step, range, dragging, disabled]\n );\n\n const onKeyDown = valueKeyHandler({\n value,\n min,\n max,\n step: keyStep,\n disabled,\n invert,\n onChange: setValue\n });\n\n const rootProps = {\n ref: rootRef,\n role: \"slider\" as const,\n \"aria-valuemin\": min,\n \"aria-valuemax\": max,\n \"aria-valuenow\": value,\n \"aria-orientation\": orientation,\n \"aria-disabled\": disabled || undefined,\n tabIndex: disabled ? -1 : 0,\n style: stateStyle(state) as CSSProperties,\n \"data-orientation\": orientation,\n ...stateData(state),\n onPointerDown: (event: PointerEvent<HTMLDivElement>) => {\n if (disabled || event.button !== 0) return;\n capturePointer(event.currentTarget, event.pointerId);\n draggingRef.current = true;\n setDragging(true);\n /* A track is absolute by nature: pressing anywhere on it means \"put\n the thumb here\", which is what a fader does under a finger. */\n track(event);\n },\n onPointerMove: (event: PointerEvent<HTMLDivElement>) => {\n if (!draggingRef.current || disabled) return;\n track(event);\n },\n onPointerUp: () => {\n draggingRef.current = false;\n setDragging(false);\n },\n onPointerCancel: () => {\n draggingRef.current = false;\n setDragging(false);\n },\n onKeyDown: (event: KeyboardEvent<HTMLDivElement>) => {\n onKeyDown(event);\n }\n };\n\n return { state, rootProps, setValue: set };\n}\n","import { cn } from \"../lib/cn\";\nimport { AmbientTravel } from \"../controls/AmbientTravel\";\nimport type { AmbientTravelProps } from \"../controls/AmbientTravel\";\nimport { useDress } from \"../core/kit\";\nimport type { KitLook } from \"../core/kit\";\nimport { groundedKit } from \"../kits/grounded\";\nimport type { AmbientMaterial } from \"../core/material\";\n\nexport type AmbientFaderSize = \"sm\" | \"md\" | \"lg\";\n\nexport type AmbientFaderProps = Omit<AmbientTravelProps, \"parts\" | \"size\" | \"orientation\"> & {\n material?: AmbientMaterial | undefined;\n size?: AmbientFaderSize | undefined;\n /** Look options in the active kit's vocabulary. */\n look?: KitLook | undefined;\n};\n\n/** A pill cap on a stem, riding an upright slot. Min is at the bottom,\n * which `AmbientTravel` already does for a vertical track. */\nexport function AmbientFader({\n material,\n look,\n size = \"md\",\n animate,\n className,\n ...rest\n}: AmbientFaderProps) {\n const { dress, defaults } = useDress(\n \"travel\",\n { material, orientation: \"vertical\", ...look },\n groundedKit.travel!\n );\n return (\n <AmbientTravel\n {...rest}\n orientation=\"vertical\"\n size={size}\n animate={animate ?? defaults?.animate}\n className={cn(dress.className, className)}\n parts={dress.parts}\n />\n );\n}\n","import { cn } from \"../lib/cn\";\nimport { AmbientTravel } from \"../controls/AmbientTravel\";\nimport type { AmbientTravelProps } from \"../controls/AmbientTravel\";\nimport { useDress } from \"../core/kit\";\nimport type { KitLook } from \"../core/kit\";\nimport { groundedKit } from \"../kits/grounded\";\nimport type { AmbientMaterial } from \"../core/material\";\n\nexport type AmbientSliderSize = \"sm\" | \"md\" | \"lg\";\n\nexport type AmbientSliderProps = Omit<AmbientTravelProps, \"parts\" | \"size\" | \"orientation\"> & {\n material?: AmbientMaterial | undefined;\n size?: AmbientSliderSize | undefined;\n /** Look options in the active kit's vocabulary. */\n look?: KitLook | undefined;\n};\n\n/** A domed disc gliding over a shallow concave channel. */\nexport function AmbientSlider({\n material,\n look,\n size = \"md\",\n animate,\n className,\n ...rest\n}: AmbientSliderProps) {\n const { dress, defaults } = useDress(\n \"travel\",\n { material, orientation: \"horizontal\", ...look },\n groundedKit.travel!\n );\n return (\n <AmbientTravel\n {...rest}\n orientation=\"horizontal\"\n size={size}\n animate={animate ?? defaults?.animate}\n className={cn(dress.className, className)}\n parts={dress.parts}\n />\n );\n}\n","import { cn } from \"../lib/cn\";\n\n/* Parts for the `console` kit — a mixer-desk visual language, measured off\n photographs of the real controls. Nothing here is a variant of a grounded\n part: a bar knob and a lit pill track are a different vocabulary, which is\n the reason kits exist rather than another round of boolean props. */\n\n/** The knob's base: a flat face housed in a circular groove.\n *\n * Two elements, because they are two pieces of the panel: the groove is the\n * cut, and the face is the flat disc sitting in it, showing the ring of the\n * cut around itself. Neither carries `.ambient` — the face has no body, so\n * there is no edge to cut and nothing to cast, and every cue that reads as\n * depth here belongs either to the walls of the housing or to the bar\n * standing on the face.\n *\n * It sits in the `base` frame, so it does not turn. A plain disc looks the\n * same at every angle, and leaving it still keeps the scene's light on it\n * untouched — only the bar has to do the work below. */\nexport function ConsoleWell({ className }: { className?: string | undefined }) {\n return (\n <span className={cn(\"amb-console-housing amb-groove\", className)}>\n <span className=\"amb-console-face amb-surface\" />\n </span>\n );\n}\n\n/** The actuator: a cuboid bar lying across the disc on its diameter.\n *\n * Two spans, and the nesting is load-bearing. The bar rides the rotating\n * actuator frame, so a chamfer highlight painted from the inherited light\n * would turn with it and put the lit edge on the wrong side of the screen\n * at half the angles. The fix is to rotate the LIGHT the other way: the\n * outer span captures the scene's light vector, the inner one re-states it\n * in the frame's own turned coordinates, so the bright edge and the drop\n * shadow both stay put on screen while the bar sweeps under them.\n *\n * It has to be two elements because a custom property cannot read itself —\n * `--amb-light-x: calc(var(--amb-light-x) ...)` is a cycle, which resolves\n * to invalid at computed-value time and takes the whole `box-shadow`\n * composite down with it, silently. */\nexport function ConsoleBar({ className }: { className?: string | undefined }) {\n return (\n <span className={cn(\"amb-console-bar\", className)}>\n <span className=\"amb-console-bar-body ambient amb-surface amb-chamfer amb-thickness-2\">\n {/* Printed on the bar near one end, the way the reference prints a\n short black mark at the outer edge of its pointer: with a bar\n that crosses the whole face, this is what says which end reads. */}\n <span className=\"amb-console-indicator\" />\n </span>\n </span>\n );\n}\n\n/** Panel graphics around the knob: the accent centre mark above it, and the\n * −/+ legends at the ends of the travel. Both sit outside the knob's own\n * box, which is what the `panel` frame is for. */\nexport function ConsoleMarks({\n mark = true,\n legend = true,\n className\n}: {\n mark?: boolean | undefined;\n legend?: boolean | undefined;\n className?: string | undefined;\n}) {\n return (\n <span className={cn(\"amb-console-marks\", className)} aria-hidden>\n {mark ? <span className=\"amb-console-mark\" /> : null}\n {legend ? (\n <>\n <span className=\"amb-console-legend amb-console-legend-min\">−</span>\n <span className=\"amb-console-legend amb-console-legend-max\">+</span>\n </>\n ) : null}\n </span>\n );\n}\n\n/** The toggle's track: a pill groove that fills with the accent as the\n * switch travels.\n *\n * A pure-CSS part — it reads `--ambx-percent` off the control root and\n * mixes its own colour from it, so the mechanism does not know this element\n * exists and no React state reaches it. */\nexport function ToggleTrack({ className }: { className?: string | undefined }) {\n return <span className={cn(\"amb-console-track amb-groove\", className)} />;\n}\n\n/** The travelling thumb: an accent disc inside a white ring.\n *\n * Flat on top and deliberately so — no chamfer, no fillet — but still a\n * knob-scale body, so it casts. That pairing is why the classes are spelt\n * out rather than reached through `.amb-fillet-2`: the edge treatments set\n * a thickness of their own, and here the thickness is wanted without the\n * cut that usually comes with it. */\nexport function ToggleThumb({ className }: { className?: string | undefined }) {\n return <span className={cn(\"amb-console-thumb ambient amb-thickness-2\", className)} />;\n}\n","import { cn } from \"../lib/cn\";\nimport { AmbientKnob } from \"../components/AmbientKnob\";\nimport type { AmbientKnobProps } from \"../components/AmbientKnob\";\nimport { AmbientSwitch } from \"../components/AmbientSwitch\";\nimport type { AmbientSwitchProps } from \"../components/AmbientSwitch\";\nimport type { ControlKit, KitDress, KitLook } from \"../core/kit\";\nimport { ConsoleBar, ConsoleMarks, ConsoleWell, ToggleThumb, ToggleTrack } from \"../parts/console\";\n\n/**\n * A mixer-desk visual identity: cuboid bar knobs seated in a circular\n * groove, and pill toggles that light up with the panel accent.\n *\n * It dresses two families and leaves the other three to fall through to\n * `grounded` — which is what a real third-party kit looks like. A kit is not\n * obliged to have an opinion about everything.\n */\n\nfunction rotary(look: KitLook): KitDress {\n const mark = look.mark !== false;\n const legend = look.legend !== false;\n return {\n className: cn(\n \"amb-console-knob\",\n mark && \"amb-console-knob-marked\",\n legend && \"amb-console-knob-legended\"\n ),\n parts: {\n panel: mark || legend ? <ConsoleMarks mark={mark} legend={legend} /> : null,\n base: <ConsoleWell />,\n actuator: <ConsoleBar />\n }\n };\n}\n\nfunction latch(): KitDress {\n return {\n className: \"amb-console-toggle\",\n parts: { base: <ToggleTrack />, actuator: <ToggleThumb /> }\n };\n}\n\nexport const consoleKit: ControlKit = {\n name: \"console\",\n rotary,\n latch,\n /* A visual identity may say how its controls feel to turn. The desk knob\n this is drawn from is an absolute-position pot with a centre detent, so\n it grabs where you press rather than tracking a drag. */\n defaults: {\n rotary: { input: \"angle\", travel: 280 }\n },\n looks: {\n rotary: [\"mark\", \"legend\"],\n latch: []\n }\n};\n\n/* A kit can also ship presets of its own. They are three lines each — the\n shared preset with this kit's look vocabulary typed — and they are how a\n kit gives its own words the same compile-time checking `knurling` gets. */\n\nexport type ConsoleKnobProps = Omit<\n AmbientKnobProps,\n \"look\" | \"material\" | \"knurling\" | \"knurlColor\" | \"markers\" | \"indicator\"\n> & {\n /** The accent centre mark printed above the knob. */\n mark?: boolean | undefined;\n /** The −/+ legends at the ends of the travel. */\n legend?: boolean | undefined;\n};\n\nexport function ConsoleKnob({ mark, legend, ...rest }: ConsoleKnobProps) {\n return <AmbientKnob {...rest} look={{ mark, legend }} />;\n}\n\nexport type ConsoleToggleProps = Omit<AmbientSwitchProps, \"look\">;\n\nexport function ConsoleToggle(props: ConsoleToggleProps) {\n return <AmbientSwitch {...props} />;\n}\n"],"mappings":"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","names":["import_jsx_runtime","import_jsx_runtime","import_react","import_react","import_jsx_runtime","warned","import_react","import_react","import_jsx_runtime","import_react","import_jsx_runtime","import_react","import_jsx_runtime","r","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_react","import_react","import_react","import_jsx_runtime","import_jsx_runtime","import_react","import_react","commit","import_jsx_runtime","bank","import_jsx_runtime","import_react","import_react","travel","import_jsx_runtime","travel","import_jsx_runtime","travel","import_react","import_react","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","rotary","latch"]}
1
+ {"version":3,"sources":["../src/index.ts","../src/components/AmbientProvider.tsx","../src/lib/cn.ts","../src/components/AmbientPanel.tsx","../src/components/AmbientRack.tsx","../src/controls/AmbientPress.tsx","../src/core/context.tsx","../src/core/frames.tsx","../src/core/dev.ts","../src/core/types.ts","../src/core/usePress.ts","../src/core/controllable.ts","../src/core/kit.tsx","../src/parts/knob.tsx","../src/parts/travel.tsx","../src/core/material.ts","../src/parts/press.tsx","../src/parts/latch.tsx","../src/parts/bank.tsx","../src/kits/grounded.tsx","../src/components/AmbientButton.tsx","../src/components/AmbientSwitch.tsx","../src/controls/AmbientLatch.tsx","../src/core/useLatch.ts","../src/controls/AmbientBank.tsx","../src/core/useBank.ts","../src/components/AmbientSelect.tsx","../src/controls/AmbientRotary.tsx","../src/core/useRotary.ts","../src/core/numeric.ts","../src/components/AmbientKnob.tsx","../src/controls/AmbientTravel.tsx","../src/core/useTravel.ts","../src/components/AmbientFader.tsx","../src/components/AmbientSlider.tsx","../src/parts/console.tsx","../src/kits/console.tsx"],"sourcesContent":["export { AmbientProvider } from \"./components/AmbientProvider\";\nexport type { AmbientProviderProps, AmbientTheme } from \"./components/AmbientProvider\";\n\nexport { AmbientPanel } from \"./components/AmbientPanel\";\nexport type { AmbientPanelProps } from \"./components/AmbientPanel\";\n\nexport { AmbientRack } from \"./components/AmbientRack\";\nexport type { AmbientRackProps, AmbientRackGap } from \"./components/AmbientRack\";\n\n/* ------------------------------------------------------------------ *\\\n Presets — a mechanism with a set of parts already chosen. Start here.\n\\* ------------------------------------------------------------------ */\n\nexport { AmbientButton } from \"./components/AmbientButton\";\nexport type {\n AmbientButtonProps,\n AmbientButtonShape,\n AmbientButtonSize\n} from \"./components/AmbientButton\";\n\nexport { AmbientSwitch } from \"./components/AmbientSwitch\";\nexport type { AmbientSwitchProps, AmbientSwitchSize } from \"./components/AmbientSwitch\";\n\nexport { AmbientSelect } from \"./components/AmbientSelect\";\nexport type {\n AmbientSelectProps,\n AmbientSelectOption,\n AmbientSelectSize,\n AmbientSelectOrientation\n} from \"./components/AmbientSelect\";\n\nexport { AmbientKnob } from \"./components/AmbientKnob\";\nexport type {\n AmbientKnobProps,\n AmbientKnobMarkers,\n AmbientKnobIndicator,\n AmbientKnobSize\n} from \"./components/AmbientKnob\";\n\nexport { AmbientFader } from \"./components/AmbientFader\";\nexport type { AmbientFaderProps, AmbientFaderSize } from \"./components/AmbientFader\";\n\nexport { AmbientSlider } from \"./components/AmbientSlider\";\nexport type { AmbientSliderProps, AmbientSliderSize } from \"./components/AmbientSlider\";\n\n/* ------------------------------------------------------------------ *\\\n Mechanisms — kinematics, state and ARIA with no appearance at all.\n Give one a set of parts and it becomes whatever you drew.\n\\* ------------------------------------------------------------------ */\n\nexport { AmbientRotary } from \"./controls/AmbientRotary\";\nexport type { AmbientRotaryProps } from \"./controls/AmbientRotary\";\n\nexport { AmbientTravel } from \"./controls/AmbientTravel\";\nexport type { AmbientTravelProps } from \"./controls/AmbientTravel\";\n\nexport { AmbientPress } from \"./controls/AmbientPress\";\nexport type { AmbientPressProps } from \"./controls/AmbientPress\";\n\nexport { AmbientLatch } from \"./controls/AmbientLatch\";\nexport type { AmbientLatchProps } from \"./controls/AmbientLatch\";\n\nexport { AmbientBank } from \"./controls/AmbientBank\";\nexport type { AmbientBankProps } from \"./controls/AmbientBank\";\n\n/* ------------------------------------------------------------------ *\\\n Hooks — the mechanism without the markup, for a control you render\n yourself from the ground up.\n\\* ------------------------------------------------------------------ */\n\nexport { useRotary } from \"./core/useRotary\";\nexport type { UseRotaryOptions, RotaryInput, RotaryTravel } from \"./core/useRotary\";\n\nexport { useTravel } from \"./core/useTravel\";\nexport type { UseTravelOptions, TravelOrientation } from \"./core/useTravel\";\n\nexport { usePress } from \"./core/usePress\";\nexport type { UsePressOptions, PressMode } from \"./core/usePress\";\n\nexport { useLatch } from \"./core/useLatch\";\nexport type { UseLatchOptions } from \"./core/useLatch\";\n\nexport { useBank } from \"./core/useBank\";\nexport type { UseBankOptions, BankOption, BankOrientation } from \"./core/useBank\";\n\n/* ------------------------------------------------------------------ *\\\n Kits — a named bundle of parts, tokens and presentation defaults that\n dresses every control below it. A kit is a plain object, so publishing\n one is publishing a module. A kit that leaves a family undefined falls\n through to `grounded`.\n\\* ------------------------------------------------------------------ */\n\nexport { AmbientKitProvider, useKit, useDress } from \"./core/kit\";\nexport type {\n ControlKit,\n ControlFamily,\n KitDress,\n KitLook,\n KitDefaults\n} from \"./core/kit\";\n\nexport { groundedKit } from \"./kits/grounded\";\nexport { consoleKit, ConsoleKnob, ConsoleToggle } from \"./kits/console\";\nexport type { ConsoleKnobProps, ConsoleToggleProps } from \"./kits/console\";\n\nexport {\n ConsoleBar,\n ConsoleMarks,\n ConsoleWell,\n ToggleTrack,\n ToggleThumb\n} from \"./parts/console\";\n\n/* ------------------------------------------------------------------ *\\\n The state channel — read the enclosing control from inside a part.\n The custom properties on the control root are canonical; these are a\n typed view of the same values, for parts that need JS.\n\\* ------------------------------------------------------------------ */\n\nexport { useControlState, useBankKey } from \"./core/context\";\nexport type { BankKeyState } from \"./core/context\";\nexport type {\n ControlParts,\n ControlState,\n ControlSize,\n ControlAnimate,\n FrameName\n} from \"./core/types\";\nexport type { AmbientMaterial } from \"./core/material\";\n\n/* ------------------------------------------------------------------ *\\\n Default parts. Nothing privileged about them — each is markup with\n some ambient classes, and a replacement of yours stands on exactly the\n same footing. They live in their own modules so an app that ships only\n its own parts does not pay for these.\n\\* ------------------------------------------------------------------ */\n\nexport { KnobBody, KnurledFace, IndicatorDot, IndicatorBar, ScaleRing } from \"./parts/knob\";\nexport type { ScaleRingProps } from \"./parts/knob\";\nexport { TravelTrack, FaderCap, SliderThumb } from \"./parts/travel\";\nexport { ButtonCap } from \"./parts/press\";\nexport { SwitchTrack, SwitchPill, Led } from \"./parts/latch\";\nexport { KeyLens, KeyCap } from \"./parts/bank\";\n","import type { CSSProperties, PropsWithChildren } from \"react\";\n\nexport type AmbientTheme = {\n lightX?: number;\n lightY?: number;\n keyLight?: number;\n fillLight?: number;\n lightHue?: number;\n lightSaturation?: number;\n highlightColor?: string;\n lumeHue?: number;\n};\n\nexport type AmbientProviderProps = PropsWithChildren<{\n className?: string;\n style?: CSSProperties;\n theme?: AmbientTheme;\n}>;\n\nconst VAR_MAP: Record<string, keyof AmbientTheme> = {\n \"--amb-light-x\": \"lightX\",\n \"--amb-light-y\": \"lightY\",\n \"--amb-key-light-intensity\": \"keyLight\",\n \"--amb-fill-light-intensity\": \"fillLight\",\n \"--amb-light-hue\": \"lightHue\",\n \"--amb-light-saturation\": \"lightSaturation\",\n \"--amb-highlight-color\": \"highlightColor\",\n \"--amb-lume-hue\": \"lumeHue\",\n};\n\nexport function AmbientProvider({ children, className, style, theme }: AmbientProviderProps) {\n const themeVars: Record<string, string> = {};\n for (const [varName, key] of Object.entries(VAR_MAP)) {\n const value = theme?.[key];\n if (value !== undefined) {\n themeVars[varName] = key === \"lightSaturation\" ? `${value}%` : String(value);\n }\n }\n // Derived variables must be re-declared here so they recompute using the\n // overridden input variables on this element rather than inheriting the\n // already-resolved values from :root.\n themeVars[\"--amb-lume\"] = [\n \"color-mix(in oklab,\",\n \"hsl(var(--amb-lume-hue) 100% 74%) calc(clamp(0, (0.5 - var(--amb-key-light-intensity)) / 0.2, 1) * 100%),\",\n \"hsl(var(--amb-light-hue) var(--amb-light-saturation)\",\n \"calc((1 - sign(var(--amb-key-light-intensity) - 0.5)) * 50% + 25%)))\",\n ].join(\" \");\n themeVars[\"--amb-label\"] =\n \"hsl(var(--amb-light-hue) var(--amb-light-saturation) calc((1 - var(--amb-key-light-intensity)) * 60% + 20%))\";\n // --amb-curve-delta deliberately absent: unlike these two it is declared\n // per element in ambient.css, so it already re-resolves against the light\n // overridden here. Re-declaring it would only re-copy the fit.\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\";\nimport type { AmbientMaterial } from \"../core/material\";\n\nexport interface AmbientPanelProps extends HTMLAttributes<HTMLDivElement> {\n material?: AmbientMaterial;\n}\n\n/** A panel is a plain surface, so it can wear any finish directly: it spends\n * neither pseudo-element of its own, which is what the two micro-relief\n * materials need. Their grain paints below the panel's children, and their\n * `overflow: hidden` clips whatever hangs outside it — a control's drop\n * shadow at the very edge included. */\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 `amb-mat-${material}`,\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 { useRef } from \"react\";\nimport type { ButtonHTMLAttributes } from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { ControlStateProvider } from \"../core/context\";\nimport { Frames, useDevPartCheck } from \"../core/frames\";\nimport { sizeProps } from \"../core/types\";\nimport type { ControlParts, ControlSize } from \"../core/types\";\nimport { usePress } from \"../core/usePress\";\nimport type { UsePressOptions } from \"../core/usePress\";\n\nexport type AmbientPressProps = Omit<\n ButtonHTMLAttributes<HTMLButtonElement>,\n \"onChange\" | \"value\" | \"defaultValue\" | \"type\"\n> &\n UsePressOptions & {\n parts?: ControlParts | undefined;\n size?: ControlSize | undefined;\n };\n\n/** A key that sinks under a finger, with no appearance of its own.\n *\n * Its frames are `display: contents` markers rather than boxes, because a\n * button is sized by its cap: the width is `min-width` plus the legend.\n * Wrapping the cap in a positioned frame would collapse the control. */\nexport function AmbientPress({\n parts,\n size,\n className,\n mode,\n value,\n defaultValue,\n onChange,\n onPress,\n repeatDelay,\n repeatInterval,\n disabled,\n children,\n ...rest\n}: AmbientPressProps) {\n const ref = useRef<HTMLButtonElement>(null);\n const { state, rootProps } = usePress({\n mode,\n value,\n defaultValue,\n onChange,\n onPress,\n repeatDelay,\n repeatInterval,\n disabled\n });\n useDevPartCheck(ref, \"AmbientPress\");\n\n const sized = sizeProps(\"press\", size);\n const { style: restStyle, onClick, ...restProps } = rest;\n\n return (\n <button\n {...restProps}\n {...rootProps}\n ref={ref}\n className={cn(\"ambx-control ambx-press\", sized.className, className)}\n style={{ ...rootProps.style, ...sized.style, ...restStyle }}\n onClick={(event) => {\n rootProps.onClick();\n onClick?.(event);\n }}\n >\n <ControlStateProvider value={state}>\n <Frames parts={parts} />\n {children}\n </ControlStateProvider>\n </button>\n );\n}\n","import { createContext, useContext } from \"react\";\nimport type { ControlState } from \"./types\";\nimport type { BankOption } from \"./useBank\";\n\nconst ControlStateContext = createContext<ControlState | null>(null);\n\nexport const ControlStateProvider = ControlStateContext.Provider;\n\n/** Read the enclosing control's state from inside a part.\n *\n * This is the third outlet of the state channel, and the one to reach for\n * last: the custom properties on the control root are canonical, and a\n * part that can be styled from CSS should be. Use this when a part needs\n * the value as a JS number — a readout, a tick ring that has to emit N\n * children, an SVG whose path data depends on the value. */\nexport function useControlState(): ControlState {\n const state = useContext(ControlStateContext);\n if (!state) {\n throw new Error(\n \"useControlState() must be called from inside a control's parts. \" +\n \"Pass the component through `parts` on AmbientRotary, AmbientTravel, \" +\n \"AmbientPress, AmbientLatch or AmbientBank.\"\n );\n }\n return state;\n}\n\n/** A bank key carries more than a number: its legend, its accessible name\n * and its own lamp colour all belong to the option, not to the state. So a\n * key's parts get this alongside `useControlState()`. */\nexport type BankKeyState = { option: BankOption; on: boolean; index: number };\n\nconst BankKeyContext = createContext<BankKeyState | null>(null);\n\nexport const BankKeyProvider = BankKeyContext.Provider;\n\nexport function useBankKey(): BankKeyState {\n const key = useContext(BankKeyContext);\n if (!key) {\n throw new Error(\n \"useBankKey() must be called from inside a bank key's parts. Pass the \" +\n \"component through `keyParts` on AmbientBank.\"\n );\n }\n return key;\n}\n","import { useEffect, useRef } from \"react\";\nimport type { RefObject } from \"react\";\nimport { isDev } from \"./dev\";\nimport { FRAME_ORDER } from \"./types\";\nimport type { ControlParts } from \"./types\";\n\n/** Render the frames a control has parts for, in paint order.\n *\n * Frames are markers by default (`display: contents` in styles.css) and\n * become boxes only where the control has a size of its own — a rotary's\n * rotating face, a travel thumb. That distinction is not cosmetic: a\n * button takes its width from `min-width` plus its cap's legend, so an\n * absolutely-positioned actuator would collapse it to nothing. */\nexport function Frames({ parts }: { parts?: ControlParts | undefined }) {\n if (!parts) return null;\n return (\n <>\n {FRAME_ORDER.map((name) =>\n parts[name] == null ? null : (\n <div key={name} data-frame={name} className={`ambx-frame ambx-frame-${name}`}>\n {parts[name]}\n </div>\n )\n )}\n </>\n );\n}\n\nconst FOCUSABLE =\n \"a[href], button, input, select, textarea, [tabindex], [contenteditable=true],\" +\n \"[role=button], [role=checkbox], [role=radio], [role=slider], [role=switch], [role=link]\";\n\n/** Development-only enforcement of the rule that parts are presentational.\n *\n * The control root owns `role`, `aria-value*`, `tabIndex` and the keyboard\n * handler. A part that smuggles in its own focusable element gives the\n * control two tab stops and, usually, a second conflicting role.\n *\n * Scoped to inside `[data-frame]` subtrees rather than to the whole root,\n * because a bank's key IS a `<button>` that the mechanism renders and the\n * frames sit inside it. Querying from the root would flag every preset we\n * ship. */\nexport function useDevPartCheck(ref: RefObject<HTMLElement | null>, control: string): void {\n const warned = useRef(false);\n /* Mount only, and at most once. A part set is fixed by the code that wrote\n it, so re-querying on every render would buy nothing and cost a DOM walk\n on every frame of a drag. */\n useEffect(() => {\n if (!isDev || warned.current) return;\n const root = ref.current;\n if (!root) return;\n const offenders = root.querySelectorAll(`[data-frame] :is(${FOCUSABLE})`);\n if (offenders.length === 0) return;\n warned.current = true;\n const tags = Array.from(offenders, (node) => `<${node.tagName.toLowerCase()}>`).join(\", \");\n console.warn(\n `[@ambientcss/components] ${control}: a part contains a focusable element ` +\n `(${tags}). Parts are presentational — the control root already owns the ` +\n `role, the tab stop and the keyboard handler, so this creates a second ` +\n `tab stop and usually a conflicting role.`\n );\n }, [ref, control]);\n}\n","declare const process: { env: Record<string, string | undefined> };\n\n/** True outside a production build.\n *\n * Written as a bare `process.env.NODE_ENV` comparison so bundlers replace\n * it textually and drop the guarded code from production output, and\n * wrapped in try/catch so an unbundled ESM consumer — a CDN import with no\n * `process` shim — gets `false` rather than a ReferenceError. */\nexport const isDev: boolean = (() => {\n try {\n return process.env.NODE_ENV !== \"production\";\n } catch {\n return false;\n }\n})();\n","import type { CSSProperties, ReactNode } from \"react\";\n\n/** The four frames every control renders, in paint order.\n *\n * - `panel` static, behind the control, allowed to overflow its box\n * - `base` static, the control's own footprint\n * - `actuator` the moving part: the frame the control transforms\n * - `fixture` static, above the actuator\n *\n * A part dropped into a frame is ordinary markup. The control moves the\n * frame; the part only has to look like something. */\nexport type ControlParts = {\n panel?: ReactNode | undefined;\n base?: ReactNode | undefined;\n actuator?: ReactNode | undefined;\n fixture?: ReactNode | undefined;\n};\n\nexport type FrameName = keyof ControlParts;\n\nexport const FRAME_ORDER: FrameName[] = [\"panel\", \"base\", \"actuator\", \"fixture\"];\n\n/** `\"sm\" | \"md\" | \"lg\"` picks a size from the family's table; any other\n * string is used as a CSS length for `--ambx-size`. */\nexport type ControlSize = \"sm\" | \"md\" | \"lg\" | (string & {});\n\n/** How the actuator moves to a new position.\n *\n * - `follow` 1:1 with the pointer, no transition — right while dragging\n * - `ease` transitions, right for keyboard and click-to-set\n * - `snap` instant, for a detented control that should read as clicking\n *\n * The default is contextual: follow while `data-dragging` is on the root,\n * ease otherwise. That needs no JS — see `.ambx-control` in styles.css. */\nexport type ControlAnimate = \"auto\" | \"follow\" | \"ease\" | \"snap\";\n\n/** What a part can read, via `useControlState()`. The same values are on\n * the control root as custom properties, which are canonical; this is a\n * typed view of them for parts that genuinely need JS. */\nexport type ControlState = {\n /** The raw value. Booleans arrive as 0/1, selections as the index. */\n value: number;\n min: number;\n max: number;\n /** Normalised position, 0-1. */\n percent: number;\n /** Degrees clockwise from 12 o'clock. 0 for non-rotary controls. */\n angle: number;\n /** Sweep origin and extent in degrees. 0 for non-rotary controls. */\n travelStart: number;\n travelSweep: number;\n /** Rest positions along the travel; 0 means continuous. */\n detents: number;\n dragging: boolean;\n disabled: boolean;\n atMin: boolean;\n atMax: boolean;\n};\n\nexport const IDLE_STATE: ControlState = {\n value: 0,\n min: 0,\n max: 1,\n percent: 0,\n angle: 0,\n travelStart: 0,\n travelSweep: 0,\n detents: 0,\n dragging: false,\n disabled: false,\n atMin: true,\n atMax: false\n};\n\n/** The state channel, written onto the control root.\n *\n * Every property is declared here even when a family does not use it,\n * because these inherit: a control nested inside another control's frame\n * would otherwise read its ancestor's angle. `.ambx-control` carries the\n * neutral defaults and this overrides them per instance. */\nexport function stateStyle(state: ControlState): CSSProperties {\n return {\n \"--ambx-value\": state.value,\n \"--ambx-percent\": state.percent,\n \"--ambx-angle\": `${state.angle}deg`,\n \"--ambx-travel-start\": `${state.travelStart}deg`,\n \"--ambx-travel-sweep\": `${state.travelSweep}deg`,\n \"--ambx-detents\": state.detents\n } as CSSProperties;\n}\n\n/** The discrete half of the state channel: conditions a part can style\n * against but cannot detect for itself. */\nexport function stateData(state: ControlState): Record<string, string | undefined> {\n return {\n \"data-dragging\": state.dragging ? \"\" : undefined,\n \"data-disabled\": state.disabled ? \"\" : undefined,\n \"data-at-min\": state.atMin ? \"\" : undefined,\n \"data-at-max\": state.atMax ? \"\" : undefined\n };\n}\n\n/** Resolve `size` into the class suffix and/or the `--ambx-size` override.\n * A named size picks the family's table; a length goes straight through,\n * which is what lets a part scale off one property instead of matching a\n * class it cannot know about. */\nexport function sizeProps(\n family: string,\n size: ControlSize | undefined\n): { className?: string; style?: CSSProperties } {\n if (size === undefined) return {};\n if (size === \"sm\" || size === \"md\" || size === \"lg\") {\n return { className: `ambx-${family}-${size}` };\n }\n return { style: { \"--ambx-size\": size } as CSSProperties };\n}\n","import { useCallback, useEffect, useMemo, useRef, useState } from \"react\";\nimport type { CSSProperties, PointerEvent } from \"react\";\nimport { useControllableValue } from \"./controllable\";\nimport { stateData, stateStyle } from \"./types\";\nimport type { ControlState } from \"./types\";\n\n/** A transport key, a latching mute and an auto-repeating nudge button are\n * the same object with three state machines and identical paint. */\nexport type PressMode = \"momentary\" | \"toggle\" | \"repeat\";\n\nexport type UsePressOptions = {\n mode?: PressMode | undefined;\n /** `toggle` mode only: the pressed-in state. */\n value?: boolean | undefined;\n defaultValue?: boolean | undefined;\n onChange?: ((next: boolean) => void) | undefined;\n /** Fires once per activation, and repeatedly in `repeat` mode. */\n onPress?: (() => void) | undefined;\n /** `repeat` mode: delay before repeating starts, then its interval. */\n repeatDelay?: number | undefined;\n repeatInterval?: number | undefined;\n disabled?: boolean | undefined;\n};\n\nexport function usePress(options: UsePressOptions) {\n const {\n mode = \"momentary\",\n repeatDelay = 400,\n repeatInterval = 60,\n disabled = false\n } = options;\n\n const [on, setOn] = useControllableValue(\n options.value,\n options.defaultValue ?? false,\n options.onChange\n );\n const [held, setHeld] = useState(false);\n\n const onPressRef = useRef(options.onPress);\n onPressRef.current = options.onPress;\n const timers = useRef<{ delay?: ReturnType<typeof setTimeout>; tick?: ReturnType<typeof setInterval> }>(\n {}\n );\n\n const stopRepeat = useCallback(() => {\n if (timers.current.delay) clearTimeout(timers.current.delay);\n if (timers.current.tick) clearInterval(timers.current.tick);\n timers.current = {};\n }, []);\n\n /* A held key that unmounts must not keep firing. */\n useEffect(() => stopRepeat, [stopRepeat]);\n\n const activate = useCallback(() => {\n if (mode === \"toggle\") setOn(!on);\n onPressRef.current?.();\n }, [mode, on, setOn]);\n\n const pressed = mode === \"toggle\" ? on : held;\n\n const state: ControlState = useMemo(\n () => ({\n value: pressed ? 1 : 0,\n min: 0,\n max: 1,\n percent: pressed ? 1 : 0,\n angle: 0,\n travelStart: 0,\n travelSweep: 0,\n detents: 2,\n dragging: held,\n disabled,\n atMin: !pressed,\n atMax: pressed\n }),\n [pressed, held, disabled]\n );\n\n const rootProps = {\n type: \"button\" as const,\n disabled,\n \"aria-pressed\": mode === \"toggle\" ? on : undefined,\n style: stateStyle(state) as CSSProperties,\n \"data-pressed\": pressed ? \"\" : undefined,\n \"data-mode\": mode,\n ...stateData(state),\n onPointerDown: (event: PointerEvent<HTMLButtonElement>) => {\n if (disabled || event.button !== 0) return;\n setHeld(true);\n if (mode !== \"repeat\") return;\n /* Repeat fires immediately, then accelerates into its interval —\n the same shape a keyboard's own auto-repeat has, so a held nudge\n button does not feel like a different kind of control. */\n onPressRef.current?.();\n timers.current.delay = setTimeout(() => {\n timers.current.tick = setInterval(() => onPressRef.current?.(), repeatInterval);\n }, repeatDelay);\n },\n onPointerUp: () => {\n setHeld(false);\n stopRepeat();\n },\n onPointerCancel: () => {\n setHeld(false);\n stopRepeat();\n },\n onPointerLeave: () => {\n setHeld(false);\n stopRepeat();\n },\n onClick: () => {\n /* Repeat already fired on the press; firing again on click would\n double every tap. */\n if (mode !== \"repeat\") activate();\n }\n };\n\n return { state, rootProps, pressed, on, setOn };\n}\n","import { useCallback, useRef, useState } from \"react\";\n\n/** One controlled/uncontrolled convention for every control.\n *\n * Pass `value` to drive it from outside; pass `defaultValue` (or neither)\n * to let the control hold its own. `onChange` fires either way, so a\n * caller can read an uncontrolled control without taking it over.\n *\n * Before v3 this was inconsistent: AmbientSwitch and AmbientSelect took a\n * default, while knob, slider and fader were controlled-only and would\n * sit frozen if you forgot `onChange`. */\nexport function useControllableValue<T>(\n controlled: T | undefined,\n defaultValue: T,\n onChange?: (next: T) => void\n): [T, (next: T) => void] {\n const isControlled = controlled !== undefined;\n const [internal, setInternal] = useState<T>(defaultValue);\n\n /* The setter is called from pointer handlers that run many times per\n drag, so it must not change identity between renders. */\n const onChangeRef = useRef(onChange);\n onChangeRef.current = onChange;\n const controlledRef = useRef(isControlled);\n controlledRef.current = isControlled;\n\n const set = useCallback((next: T) => {\n if (!controlledRef.current) setInternal(next);\n onChangeRef.current?.(next);\n }, []);\n\n return [isControlled ? (controlled as T) : internal, set];\n}\n","import { createContext, useContext } from \"react\";\nimport type { PropsWithChildren } from \"react\";\nimport { isDev } from \"./dev\";\nimport type { ControlParts } from \"./types\";\nimport type { RotaryInput, RotaryTravel } from \"./useRotary\";\nimport type { ControlAnimate } from \"./types\";\n\n/** The five control families a kit can dress. */\nexport type ControlFamily = \"rotary\" | \"travel\" | \"press\" | \"latch\" | \"bank\";\n\n/** What a preset hands its kit: the look options the caller asked for.\n *\n * Deliberately loose. Look props are *kit vocabulary* — `knurling` and\n * `markers` are words the grounded kit made up — so a kit reads the keys it\n * understands and ignores the rest, exactly as a stylesheet that never\n * implemented a class simply does not react to it. See `looks` below for\n * how that stays honest rather than silent. */\nexport type KitLook = Record<string, unknown>;\n\n/** A dressed control: what goes in the frames, and what the root wears.\n *\n * The class comes from the kit rather than the preset because it is part of\n * the look — `.amb-knob` carries the grounded knob's own token table, and a\n * kit that replaces the parts has no use for it. */\nexport type KitDress = {\n parts: ControlParts;\n className?: string | undefined;\n};\n\n/** Presentation defaults a visual identity may legitimately set.\n *\n * Narrow on purpose: a kit says how its controls should *feel* to turn, not\n * what they are worth. Anything touching value, range or handlers stays with\n * the caller. */\nexport type KitDefaults = {\n rotary?: { travel?: RotaryTravel; input?: RotaryInput; animate?: ControlAnimate } | undefined;\n travel?: { animate?: ControlAnimate } | undefined;\n latch?: { animate?: ControlAnimate } | undefined;\n};\n\nexport type ControlKit = {\n name: string;\n rotary?: ((look: KitLook) => KitDress) | undefined;\n travel?: ((look: KitLook) => KitDress) | undefined;\n press?: ((look: KitLook) => KitDress) | undefined;\n latch?: ((look: KitLook) => KitDress) | undefined;\n bank?: ((look: KitLook) => KitDress) | undefined;\n defaults?: KitDefaults | undefined;\n /** Look keys each family honours. Used only to warn in development when a\n * caller passes a prop the active kit is going to drop on the floor —\n * the one real cost of letting look props pass through untyped. */\n looks?: Partial<Record<ControlFamily, readonly string[]>> | undefined;\n};\n\nconst KitContext = createContext<ControlKit | null>(null);\n\n/** Dress every control below this point in `kit`.\n *\n * A kit is a plain object, so shipping one is shipping a module: no\n * registry, no lifecycle, nothing to initialise. A kit that leaves a family\n * undefined falls through to the default, which is what a real third-party\n * kit will do for most of them. */\nexport function AmbientKitProvider({ kit, children }: PropsWithChildren<{ kit: ControlKit }>) {\n return <KitContext.Provider value={kit}>{children}</KitContext.Provider>;\n}\n\nexport function useKit(): ControlKit | null {\n return useContext(KitContext);\n}\n\nconst warned = new Set<string>();\n\n/** Resolve a family's dressing: the active kit if it dresses this family,\n * otherwise the fallback the preset was built around. */\nexport function useDress<F extends ControlFamily>(\n family: F,\n look: KitLook,\n fallback: (look: KitLook) => KitDress\n): { dress: KitDress; defaults: F extends keyof KitDefaults ? KitDefaults[F] : undefined } {\n const kit = useKit();\n const dressed = kit?.[family];\n\n if (isDev && kit && dressed) {\n const honoured = kit.looks?.[family];\n if (honoured) {\n for (const key of Object.keys(look)) {\n if (look[key] === undefined || honoured.includes(key)) continue;\n const id = `${kit.name}:${family}:${key}`;\n if (warned.has(id)) continue;\n warned.add(id);\n console.warn(\n `[@ambientcss/components] the \"${kit.name}\" kit's ${family} does not use ` +\n `\\`${key}\\` — it is a look prop from another kit's vocabulary, so it will ` +\n `have no effect here.`\n );\n }\n }\n }\n\n return {\n dress: (dressed ?? fallback)(look),\n /* Defaults come from the kit that actually dressed the control: a kit\n that falls through to grounded for a family has no say in how that\n family behaves either. */\n defaults: (dressed ? kit?.defaults?.[family as keyof KitDefaults] : undefined) as never\n };\n}\n","import { useId } from \"react\";\nimport type { CSSProperties, ReactNode } from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { useControlState } from \"../core/context\";\nimport type { AmbientMaterial } from \"../core/material\";\n\n/* The knurl: a rim band of straight ribs around the knob's cap, in\n objectBoundingBox units so the clip scales with the component.\n\n The knob it belongs to reads like the turned-and-knurled hardware knob it\n is named for: a smooth chamfered cap on top, and beyond that cap's edge —\n and a step below it — a ring of knurling standing proud of the outline.\n So the clip is an ANNULUS, not a disc: a rippled outer contour punched\n through by a circle at the cap's radius, filled `evenodd`, which leaves\n the cap and its chamfer bands to paint themselves underneath.\n\n The rib section is the referent's (ambient3d/components/knob.py `wall_r`):\n radius falls from the crest by `depth * (0.5 + 0.5cos(N.theta))^sharpness`,\n so ridges are broad and grooves narrow. Sampling that curve beats the old\n four-point trapezoid — at 36 teeth a square wave silhouette reads as gear\n teeth, which is what this replaces.\n\n One knurl for now, kept in a table because the shape is a data question and\n the referent lineup carries broader flutes (14 ribs) we may expose later.\n A second row is not free, though: `teeth` is shadowed by the conic pitch in\n .amb-knob-face (360/teeth) and `band` by that rule's radial stop, so a knurl\n with different numbers needs its shading parameterised out of the stylesheet\n first. Only `depth` and `sharpness` live here alone. */\ntype KnurlSpec = {\n teeth: number; // rib count\n depth: number; // crest-to-root, bounding-box units (the crest is at 0.5)\n sharpness: number; // >1 narrows the groove and broadens the ridge\n band: number; // rim width the ribs occupy, bounding-box units\n};\n\nconst KNURLS: Record<\"standard\", KnurlSpec> = {\n /* 48 ribs — the referent lineup's fine knurl (referents.py knob_cap /\n knob_wheel) rather than the 36 of its coarse one, because a band a tenth\n of the radius wide reads as a machined grip only if the ribs are finer\n than it is; at 36 the same band came out a bottle cap. */\n standard: { teeth: 48, depth: 0.009, sharpness: 1.6, band: 0.05 }\n};\n\n/** The cap's inset: the knurl band's width, so the ribs stand proud of it.\n * One number, two views of the same edge — the clip's inner radius and the\n * body's inset have to agree or the ring floats off its cap. */\nconst KNURL_BAND = KNURLS.standard.band;\n\n/* The clip's hole is a hair tighter than the cap so their antialiased edges\n overlap instead of leaving a hairline of panel between them. */\nconst SEAM = 0.005;\n\n/* Samples per tooth. The curve's extremes both land on samples: the groove\n at the tooth's start, the ridge at its half-pitch. */\nconst STEPS = 6;\n\nfunction knurlPath({ teeth, depth, sharpness, band }: KnurlSpec): string {\n const outer = 0.5;\n const inner = outer - band - SEAM;\n const segs = teeth * STEPS;\n const pts: string[] = [];\n for (let i = 0; i < segs; i++) {\n const t = (i / segs) * Math.PI * 2;\n const r = outer - depth * (0.5 + 0.5 * Math.cos(teeth * t)) ** sharpness;\n pts.push(\n `${(0.5 + r * Math.cos(t)).toFixed(4)} ${(0.5 + r * Math.sin(t)).toFixed(4)}`\n );\n }\n /* Second subpath: the cap-sized hole, two half arcs. Winding is irrelevant —\n the clip fills evenodd. */\n const l = (0.5 - inner).toFixed(4);\n const r = (0.5 + inner).toFixed(4);\n const hole = `M${l} 0.5 A${inner} ${inner} 0 0 0 ${r} 0.5 A${inner} ${inner} 0 0 0 ${l} 0.5 Z`;\n return `M${pts.join(\" L\")} Z ${hole}`;\n}\n\nconst KNURL_PATH = knurlPath(KNURLS.standard);\n\n/** The knob's cap: the smooth chamfered disc that is most of what you see,\n * and the element that carries the drop shadow.\n *\n * `flush` takes the full width, which is what a smooth turned knob wants.\n * The default sits back by the knurl band so a `KnurledFace` can ring it —\n * the same cap either way, and the chamfer the referent cuts on every knob\n * (knob.py's `chamfer=0.35`, regardless of rib count) either way too. */\nexport function KnobBody({\n material,\n flush = false,\n className\n}: {\n material?: AmbientMaterial | undefined;\n flush?: boolean | undefined;\n className?: string | undefined;\n}) {\n return (\n <span\n className={cn(\n \"amb-knob-body ambient amb-thickness-2 amb-surface\",\n material && `amb-mat-${material}`,\n className\n )}\n /* Geometry, not styling: this is the clip's inner radius seen from the\n other side, so it comes from the same constant the path does. */\n style={flush ? undefined : { inset: `${KNURL_BAND * 100}%` }}\n />\n );\n}\n\n/** The rotating knurl: a rim ring of ribs around the cap, clipped to the\n * toothed annulus so the ribs break the outline instead of being painted\n * inside a circle, and shaded per tooth — a lit flank climbing to each\n * ridge, a shaded one falling away — with a contact-occlusion band along\n * its inner edge where the cap overhangs it.\n *\n * The clip is the part's own business — it generates the path, emits its\n * own `<defs>` and references it by a local id. A rotary mechanism has no\n * idea any of this is happening, which is exactly the point: if this part\n * needed help from the control to exist, the split would not be clean. */\nexport function KnurledFace({\n material,\n color,\n className\n}: {\n material?: AmbientMaterial | undefined;\n /** The ribs' own colour, as an albedo. */\n color?: string | undefined;\n className?: string | undefined;\n}) {\n const id = `amb-knurl-${useId().replace(/:/g, \"\")}`;\n return (\n <>\n <svg width={0} height={0} style={{ position: \"absolute\" }} aria-hidden focusable={false}>\n <defs>\n <clipPath id={id} clipPathUnits=\"objectBoundingBox\">\n <path d={KNURL_PATH} clipRule=\"evenodd\" />\n </clipPath>\n </defs>\n </svg>\n <span\n className={cn(\"amb-knob-face\", material && `amb-mat-${material}`, className)}\n style={{\n clipPath: `url(#${id})`,\n /* Not a paint colour: --amb-albedo is the ribs' REFLECTANCE, so a\n dark knurl still takes the scene's exposure, the lamp's cast and\n the rim's own --amb-shade step, and still goes dark when the\n lights do. Inline, so it beats the albedo a micro-relief material\n would otherwise set on this element — an explicit colour wins\n over the finish's own, and the finish keeps its grain. */\n ...(color ? { \"--amb-albedo\": color } : null)\n } as CSSProperties}\n />\n </>\n );\n}\n\n/** The grounded referent's offset indicator dot (knob() dot_frac 0.12,\n * dot_offset 0.68). Put it in the `actuator` frame and it sweeps; put it\n * in `base` and it stays put while everything else turns. */\nexport function IndicatorDot({ className }: { className?: string | undefined }) {\n return <span className={cn(\"amb-knob-indicator-circle\", className)} />;\n}\n\n/** A short radial bar out near the rim, running 0.50R to 0.84R. */\nexport function IndicatorBar({ className }: { className?: string | undefined }) {\n return <span className={cn(\"amb-knob-indicator-rectangle\", className)} />;\n}\n\nexport type ScaleRingProps = {\n /** Dots to print. `2` is the pair the travel starts and stops at. */\n count?: number | undefined;\n className?: string | undefined;\n children?: ReactNode | undefined;\n};\n\n/** Printed scale dots on the panel around a rotary, on the same arc the\n * value sweeps.\n *\n * This is the part that has to read state as JS rather than CSS: the\n * angles come from the control's own travel, and there is no way to emit\n * N children from a stylesheet. It is also the proof that the context\n * outlet works — the dots land on the sweep whatever `travel` is set to,\n * without the ring being told. */\nexport function ScaleRing({ count = 13, className, children }: ScaleRingProps) {\n const { travelStart, travelSweep } = useControlState();\n const divisions = Math.max(1, count - 1);\n const angles =\n count <= 1\n ? [travelStart]\n : Array.from({ length: count }, (_, i) => travelStart + (i / divisions) * travelSweep);\n\n return (\n <span className={cn(\"amb-knob-marker-ring\", className)} aria-hidden>\n {angles.map((angle) => (\n <span\n key={angle}\n className=\"amb-knob-marker\"\n style={{ \"--amb-marker-angle\": `${angle}deg` } as CSSProperties}\n />\n ))}\n {children}\n </span>\n );\n}\n","import { cn } from \"../lib/cn\";\nimport type { AmbientMaterial } from \"../core/material\";\n\n/** The track a thumb rides in.\n *\n * Both grounded referents are grooves with a lume interior — dark in\n * bright light, glowing in low light — but they are cut to different\n * depths: a fader runs in a through-slot, a slider in a shallow concave\n * channel (slider.py, 1mm deep = thickness 0.22). */\nexport function TravelTrack({\n depth = \"slot\",\n className\n}: {\n depth?: \"slot\" | \"channel\" | undefined;\n className?: string | undefined;\n}) {\n return (\n <span\n className={cn(\n \"amb-travel-track amb-groove\",\n depth === \"channel\" && \"amb-travel-track-channel\",\n className\n )}\n />\n );\n}\n\n/** Fader cap: the referent (fader.py) is a pill on a stem — 7mm tall\n * (thickness 1.5) riding 2.2mm above the plate (elevation 0.28) — with a\n * single grip line across the top. */\nexport function FaderCap({\n material,\n className\n}: {\n material?: AmbientMaterial | undefined;\n className?: string | undefined;\n}) {\n return (\n <span\n className={cn(\n \"amb-fader-thumb ambient amb-fillet\",\n material !== \"glass\" && \"amb-surface-concave\",\n material && `amb-mat-${material}`,\n className\n )}\n >\n <span className=\"amb-fader-gripline\" />\n </span>\n );\n}\n\n/** Slider thumb: a domed disc gliding over the channel. */\nexport function SliderThumb({\n material,\n className\n}: {\n material?: AmbientMaterial | undefined;\n className?: string | undefined;\n}) {\n return (\n <span\n className={cn(\n \"amb-slider-thumb ambient amb-fillet\",\n material !== \"glass\" && \"amb-surface-convex\",\n material && `amb-mat-${material}`,\n className\n )}\n />\n );\n}\n","/** The grounded surface finishes from @ambientcss/css.\n *\n * Lives on parts and presets, never on a mechanism: which element a\n * material belongs on is a fact about a particular control's construction,\n * and a mechanism cannot know that once the parts are yours.\n *\n * `brushed`, `brushed-round` and `blasted` are micro-relief materials: they\n * paint their grain into BOTH of the host's pseudo-elements, so a part that\n * already spends one of its own has to give them an inner layer rather than\n * wear them directly. `ButtonCap` is the only part in this package that does.\n *\n * `brushed-round` is the same aluminium as `brushed` with the grain spun\n * round the element's centre, so it belongs on round faces — a knob cap, a\n * round button — where the centre it turns about is a real feature. */\nexport type AmbientMaterial =\n | \"matte\"\n | \"shiny\"\n | \"glass\"\n | \"brushed\"\n | \"brushed-round\"\n | \"blasted\";\n\n/** Whether a finish carries micro-relief, and therefore needs both\n * pseudo-elements of whatever it is put on. */\nexport function isRelief(material: AmbientMaterial | undefined): boolean {\n return material === \"brushed\" || material === \"brushed-round\" || material === \"blasted\";\n}\n","import type { ReactNode } from \"react\";\nimport { cn } from \"../lib/cn\";\nimport type { AmbientMaterial } from \"../core/material\";\nimport { isRelief } from \"../core/material\";\n\n/** The key cap: a chamfered, subtly dished top that sinks on `:active`.\n *\n * The cap is what sizes a press control — its legend sets the width above\n * the well's `min-width` — which is why a press control's frames are\n * `display: contents` markers rather than boxes.\n *\n * The cap spends its own `::after` on the dish, so the two micro-relief\n * materials cannot ride on it: their grain wants both pseudo-elements, and\n * the dish's `background` shorthand and the grain's tile would each silently\n * win half of the other's declarations. They get `.ambx-cap-face` instead —\n * an inner layer under the dish and under the legend, which is the inner\n * layer @ambientcss/css's own note prescribes. The cap itself stays a plain\n * `amb-surface` when relief is down there: the dish's overlay alphas are\n * derived from `--amb-shade` the ordinary way, and since the relief\n * materials carry no `--amb-albedo` of their own any more, that derivation\n * is already correct for them too — no per-material tone correction to\n * apply. */\nexport function ButtonCap({\n material = \"matte\",\n className,\n children\n}: {\n material?: AmbientMaterial | undefined;\n className?: string | undefined;\n children?: ReactNode | undefined;\n}) {\n const relief = isRelief(material);\n return (\n <span\n className={cn(\n \"amb-button-cap ambient amb-chamfer amb-surface amb-heading-3\",\n relief ? undefined : `amb-mat-${material}`,\n className\n )}\n >\n {relief ? (\n <span\n /* `ambient amb-chamfer` on the face, not just on the cap: the\n chamfer is painted as INSET shadows, which belong to the cap's\n own background layer — and the face, being opaque and covering\n it, would hide them. Wearing the cut itself puts the bevel back,\n and puts it back in the material's own tone rather than the\n cap's. */\n className={cn(\"ambx-cap-face ambient amb-chamfer amb-surface\", `amb-mat-${material}`)}\n aria-hidden\n />\n ) : null}\n {children}\n </span>\n );\n}\n","import type { CSSProperties } from \"react\";\nimport { cn } from \"../lib/cn\";\n\n/** The recess the pill slides in (switch.py: a 1.5mm well, thickness 0.33). */\nexport function SwitchTrack({ className }: { className?: string | undefined }) {\n return <span className={cn(\"amb-switch-track amb-groove\", className)} />;\n}\n\n/** The sliding pill, standing 2.6mm above the recess floor. */\nexport function SwitchPill({ className }: { className?: string | undefined }) {\n return (\n <span className={cn(\"amb-switch-pill ambient amb-fillet amb-surface-convex\", className)} />\n );\n}\n\n/** A pinprick indicator lamp. `color` is any CSS colour; unset it takes the\n * scene's own lamp colour, the same `--amb-led-color` a bank reads. */\nexport function Led({\n on = true,\n color,\n className\n}: {\n on?: boolean | undefined;\n color?: string | undefined;\n className?: string | undefined;\n}) {\n return (\n <span\n className={cn(\"amb-led\", !on && \"amb-led-off\", className)}\n style={color ? ({ \"--amb-led-color\": color } as CSSProperties) : undefined}\n />\n );\n}\n","import type { ReactNode } from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { useBankKey } from \"../core/context\";\n\n/** The lamp under a key: a big disc lying on the pocket floor.\n *\n * It has to paint BEFORE the cap, because the cap's `backdrop-filter` is\n * what diffuses it — which is the whole trick, and the reason the lens\n * belongs in the `base` frame and the cap in `actuator`. */\nexport function KeyLens({ className }: { className?: string | undefined }) {\n return <span className={cn(\"amb-select-lens\", className)} />;\n}\n\n/** The translucent diffuser over the lamp, carrying the key's legend.\n *\n * With no children it prints the option's own label, which is why a bank\n * of numerals needs no `renderKey`: the part reads the option it belongs\n * to out of the key context. */\nexport function KeyCap({\n className,\n children\n}: {\n className?: string | undefined;\n children?: ReactNode | undefined;\n}) {\n const { option } = useBankKey();\n return (\n <span className={cn(\"amb-select-cap ambient amb-chamfer amb-mat-glass\", className)}>\n {children ?? option.label ?? option.value}\n </span>\n );\n}\n","import { cn } from \"../lib/cn\";\nimport type { ControlKit, KitDress, KitLook } from \"../core/kit\";\nimport type { AmbientMaterial } from \"../core/material\";\nimport { IndicatorBar, IndicatorDot, KnobBody, KnurledFace, ScaleRing } from \"../parts/knob\";\nimport { FaderCap, SliderThumb, TravelTrack } from \"../parts/travel\";\nimport { ButtonCap } from \"../parts/press\";\nimport { SwitchPill, SwitchTrack } from \"../parts/latch\";\nimport { KeyCap, KeyLens } from \"../parts/bank\";\n\n/* The built-in look, packaged as a kit rather than hardwired into the\n presets. That is the integrity test for the whole idea: if the grounded\n parts needed a private back door the presets could reach and a third party\n could not, the abstraction would be a fiction. They do not — everything\n below is the same `(look) => { parts, className }` a published kit writes. */\n\n/* 12 divisions — 13 dots over the sweep, the pitch measured off the\n reference panel. */\nconst FULL_MARKERS = 13;\n\nfunction rotary(look: KitLook): KitDress {\n const material = look.material as AmbientMaterial | undefined;\n const knurling = look.knurling !== false;\n const knurlColor = look.knurlColor as string | undefined;\n const markers = (look.markers as \"none\" | \"ends\" | \"full\" | undefined) ?? \"none\";\n const indicator = (look.indicator as \"circle\" | \"rectangle\" | undefined) ?? \"circle\";\n\n return {\n /* The full ring reaches past the knob's own box, so its layout clearance\n has to be reserved — and only the kit knows it put a ring there. */\n className: cn(\"amb-knob\", markers === \"full\" && \"amb-knob-markers-full\"),\n parts: {\n panel:\n markers === \"none\" ? null : <ScaleRing count={markers === \"ends\" ? 2 : FULL_MARKERS} />,\n /* `material` goes on every element that paints. The cap always does —\n it is the knob's top face either way — and the knurl ring does too\n when there is one, so a knurled knob's rim and cap are the same\n material rather than the rim being the only thing wearing it.\n\n `knurlColor` is the one thing the ring may hold on its own: a\n two-tone knob — dark grip round a pale cap — is a real piece of\n hardware, and the cap has no matching prop because the cap's colour\n is the control's colour, set the ordinary way with --amb-albedo. */\n base: <KnobBody flush={!knurling} material={material} />,\n actuator: (\n <>\n {knurling ? <KnurledFace material={material} color={knurlColor} /> : null}\n {indicator === \"circle\" ? <IndicatorDot /> : <IndicatorBar />}\n </>\n )\n }\n };\n}\n\nfunction travel(look: KitLook): KitDress {\n const material = look.material as AmbientMaterial | undefined;\n const upright = look.orientation === \"vertical\";\n return {\n className: upright ? \"amb-fader\" : \"amb-slider\",\n parts: {\n base: <TravelTrack depth={upright ? \"slot\" : \"channel\"} />,\n actuator: upright ? <FaderCap material={material} /> : <SliderThumb material={material} />\n }\n };\n}\n\nfunction press(look: KitLook): KitDress {\n const shape = (look.shape as \"pill\" | \"round\" | \"square\" | undefined) ?? \"pill\";\n return {\n className: cn(\n \"amb-button amb-groove\",\n shape === \"round\" && \"amb-button-round\",\n shape === \"square\" && \"amb-button-square\"\n ),\n parts: {\n actuator: (\n <ButtonCap material={(look.material as AmbientMaterial | undefined) ?? \"matte\"}>\n {look.children as React.ReactNode}\n </ButtonCap>\n )\n }\n };\n}\n\nfunction latch(): KitDress {\n return {\n className: \"amb-switch\",\n parts: { base: <SwitchTrack />, actuator: <SwitchPill /> }\n };\n}\n\nfunction bank(): KitDress {\n return {\n className: \"amb-select amb-groove\",\n parts: { base: <KeyLens />, actuator: <KeyCap /> }\n };\n}\n\n/** The Blender-grounded hardware look: the default every preset falls back to. */\nexport const groundedKit: ControlKit = {\n name: \"grounded\",\n rotary,\n travel,\n press,\n latch,\n bank,\n looks: {\n rotary: [\"material\", \"knurling\", \"knurlColor\", \"markers\", \"indicator\"],\n travel: [\"material\", \"orientation\"],\n press: [\"material\", \"shape\", \"children\"],\n latch: [],\n bank: []\n }\n};\n","import { cn } from \"../lib/cn\";\nimport { AmbientPress } from \"../controls/AmbientPress\";\nimport type { AmbientPressProps } from \"../controls/AmbientPress\";\nimport { useDress } from \"../core/kit\";\nimport type { KitLook } from \"../core/kit\";\nimport { groundedKit } from \"../kits/grounded\";\nimport type { AmbientMaterial } from \"../core/material\";\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 type AmbientButtonProps = Omit<AmbientPressProps, \"parts\" | \"size\"> & {\n material?: AmbientMaterial | undefined;\n shape?: AmbientButtonShape | undefined;\n size?: AmbientButtonSize | undefined;\n /** Look options in the active kit's vocabulary. */\n look?: KitLook | undefined;\n};\n\n/** A key cap seated in a clearance well. */\nexport function AmbientButton({\n className,\n children,\n look,\n material = \"matte\",\n shape = \"pill\",\n size = \"md\",\n ...rest\n}: AmbientButtonProps) {\n const { dress } = useDress(\"press\", { material, shape, children, ...look }, groundedKit.press!);\n return (\n <AmbientPress\n {...rest}\n size={size}\n className={cn(dress.className, className)}\n parts={dress.parts}\n />\n );\n}\n","import { useId } from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { AmbientLatch } from \"../controls/AmbientLatch\";\nimport type { AmbientLatchProps } from \"../controls/AmbientLatch\";\nimport { useControllableValue } from \"../core/controllable\";\nimport { useDress } from \"../core/kit\";\nimport type { KitLook } from \"../core/kit\";\nimport { groundedKit } from \"../kits/grounded\";\nimport { Led } from \"../parts/latch\";\n\nexport type AmbientSwitchSize = \"sm\" | \"md\" | \"lg\";\n\nexport type AmbientSwitchProps = Omit<AmbientLatchProps, \"parts\" | \"size\"> & {\n size?: AmbientSwitchSize | undefined;\n /** A lamp above the switch. `true` for the scene's own colour, or any\n * CSS colour string. */\n led?: boolean | string | undefined;\n /** Look options in the active kit's vocabulary. */\n look?: KitLook | undefined;\n};\n\n/** A pill sliding in a dark stadium recess, with an optional lamp above.\n *\n * The lamp is mounted beside the switch rather than inside it: the latch\n * control IS the track, so anything that is neither track nor pill belongs\n * to whatever composes them. That means the preset has to hold the state —\n * the lamp and the pill read the same boolean, and only their common\n * parent can see both.\n */\nexport function AmbientSwitch({\n size = \"md\",\n led,\n label,\n look,\n value,\n defaultValue,\n onChange,\n animate,\n className,\n ...rest\n}: AmbientSwitchProps) {\n const labelId = useId();\n const [on, setOn] = useControllableValue(value, defaultValue ?? false, onChange);\n const { dress, defaults } = useDress(\"latch\", { ...look }, groundedKit.latch!);\n\n const control = (\n <AmbientLatch\n {...rest}\n value={on}\n onChange={setOn}\n size={size}\n animate={animate ?? defaults?.animate}\n aria-labelledby={label ? labelId : rest[\"aria-labelledby\"]}\n className={cn(dress.className, className)}\n parts={dress.parts}\n />\n );\n\n if (!led && !label) return control;\n\n return (\n <div className=\"ambx-stack\">\n {led ? (\n <span className=\"ambx-switch-mount\">\n <Led on={on} {...(typeof led === \"string\" ? { color: led } : null)} />\n {control}\n </span>\n ) : (\n control\n )}\n {label ? (\n <span id={labelId} className=\"ambx-label\">\n {label}\n </span>\n ) : null}\n </div>\n );\n}\n","import { useId, useRef } from \"react\";\nimport type { ButtonHTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { ControlStateProvider } from \"../core/context\";\nimport { Frames, useDevPartCheck } from \"../core/frames\";\nimport { sizeProps } from \"../core/types\";\nimport type { ControlAnimate, ControlParts, ControlSize } from \"../core/types\";\nimport { useLatch } from \"../core/useLatch\";\nimport type { UseLatchOptions } from \"../core/useLatch\";\n\nexport type AmbientLatchProps = Omit<\n ButtonHTMLAttributes<HTMLButtonElement>,\n \"onChange\" | \"value\" | \"defaultValue\" | \"type\"\n> &\n UseLatchOptions & {\n parts?: ControlParts | undefined;\n size?: ControlSize | undefined;\n animate?: ControlAnimate | undefined;\n label?: ReactNode | undefined;\n };\n\n/** A two-position slide, with no appearance of its own. The control IS the\n * track: its actuator is a pill-sized frame that travels across it, which\n * is why anything sitting beside a switch — a lamp, a legend — belongs to\n * whatever composes it rather than to the switch. */\nexport function AmbientLatch({\n parts,\n size,\n animate = \"auto\",\n label,\n className,\n value,\n defaultValue,\n onChange,\n disabled,\n children,\n ...rest\n}: AmbientLatchProps) {\n const labelId = useId();\n const ref = useRef<HTMLButtonElement>(null);\n const { state, rootProps } = useLatch({ value, defaultValue, onChange, disabled });\n useDevPartCheck(ref, \"AmbientLatch\");\n\n const sized = sizeProps(\"latch\", size);\n const { style: restStyle, onClick, ...restProps } = rest;\n\n const control = (\n <button\n {...restProps}\n {...rootProps}\n ref={ref}\n aria-labelledby={label ? labelId : rest[\"aria-labelledby\"]}\n data-animate={animate}\n className={cn(\"ambx-control ambx-latch\", sized.className, className)}\n style={{ ...rootProps.style, ...sized.style, ...restStyle }}\n onClick={(event) => {\n rootProps.onClick();\n onClick?.(event);\n }}\n >\n <ControlStateProvider value={state}>\n <Frames parts={parts} />\n {children}\n </ControlStateProvider>\n </button>\n );\n\n if (!label) return control;\n\n return (\n <div className=\"ambx-stack\">\n {control}\n <span id={labelId} className=\"ambx-label\">\n {label}\n </span>\n </div>\n );\n}\n","import { useMemo } from \"react\";\nimport type { CSSProperties } from \"react\";\nimport { useControllableValue } from \"./controllable\";\nimport { stateData, stateStyle } from \"./types\";\nimport type { ControlState } from \"./types\";\n\nexport type UseLatchOptions = {\n value?: boolean | undefined;\n defaultValue?: boolean | undefined;\n onChange?: ((next: boolean) => void) | undefined;\n disabled?: boolean | undefined;\n};\n\n/** A two-position travel. Kept distinct from Press because its actuator\n * genuinely slides rather than sinking, and because its ARIA is\n * `role=\"switch\"` — a switch is a state, not an action. */\nexport function useLatch(options: UseLatchOptions) {\n const { disabled = false } = options;\n const [on, setOn] = useControllableValue(\n options.value,\n options.defaultValue ?? false,\n options.onChange\n );\n\n const state: ControlState = useMemo(\n () => ({\n value: on ? 1 : 0,\n min: 0,\n max: 1,\n percent: on ? 1 : 0,\n angle: 0,\n travelStart: 0,\n travelSweep: 0,\n detents: 2,\n dragging: false,\n disabled,\n atMin: !on,\n atMax: on\n }),\n [on, disabled]\n );\n\n const rootProps = {\n type: \"button\" as const,\n role: \"switch\" as const,\n \"aria-checked\": on,\n disabled,\n style: stateStyle(state) as CSSProperties,\n ...stateData(state),\n onClick: () => setOn(!on)\n };\n\n return { state, rootProps, on, setOn };\n}\n","import { useId } from \"react\";\nimport type { CSSProperties, HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { BankKeyProvider, ControlStateProvider } from \"../core/context\";\nimport { Frames } from \"../core/frames\";\nimport { sizeProps, stateData, stateStyle } from \"../core/types\";\nimport type { ControlParts, ControlSize, ControlState } from \"../core/types\";\nimport { useBank } from \"../core/useBank\";\nimport type { BankOption, UseBankOptions } from \"../core/useBank\";\n\nexport type AmbientBankProps = Omit<\n HTMLAttributes<HTMLDivElement>,\n \"onChange\" | \"defaultValue\"\n> &\n UseBankOptions & {\n /** Parts applied to every key. The bank's own frames go in `parts`. */\n keyParts?: ControlParts | undefined;\n parts?: ControlParts | undefined;\n size?: ControlSize | undefined;\n /** Lamp colour. Defaults to the scene's `--amb-highlight-color`. */\n color?: string | undefined;\n label?: ReactNode | undefined;\n /** Per-key override, for a bank whose keys are not interchangeable. */\n renderKey?: ((option: BankOption, on: boolean) => ReactNode) | undefined;\n };\n\nfunction keyState(on: boolean, disabled: boolean): ControlState {\n return {\n value: on ? 1 : 0,\n min: 0,\n max: 1,\n percent: on ? 1 : 0,\n angle: 0,\n travelStart: 0,\n travelSweep: 0,\n detents: 2,\n dragging: false,\n disabled,\n atMin: !on,\n atMax: on\n };\n}\n\n/** N keys sharing a selection model, with no appearance of its own.\n *\n * Parts apply per key rather than once, because that is what a bank is.\n * The focusable element is the key `<button>`, which this mechanism\n * renders — your parts go inside it, which is why the presentational-parts\n * rule still holds here. */\nexport function AmbientBank({\n options,\n keyParts,\n parts,\n size,\n color,\n label,\n renderKey,\n className,\n style,\n value,\n defaultValue,\n onChange,\n multiple,\n orientation = \"vertical\",\n disabled = false,\n ...rest\n}: AmbientBankProps) {\n const labelId = useId();\n const { selected, rootProps, keyProps } = useBank({\n options,\n value,\n defaultValue,\n onChange,\n multiple,\n orientation,\n disabled\n });\n\n const sized = sizeProps(\"bank\", size);\n\n const bank = (\n <div\n {...rest}\n {...rootProps}\n aria-labelledby={label ? labelId : rest[\"aria-labelledby\"]}\n className={cn(\n \"ambx-control ambx-bank\",\n `ambx-bank-${orientation}`,\n sized.className,\n className\n )}\n style={{\n ...(color ? ({ \"--amb-led-color\": color } as CSSProperties) : null),\n ...sized.style,\n ...style\n }}\n >\n <Frames parts={parts} />\n {options.map((option, index) => {\n const on = selected.includes(option.value);\n /* Each key publishes its own state channel, exactly as a standalone\n control does. Without this a key's parts would inherit the bank\n root's neutral --ambx-percent and a pure-CSS part could never see\n that its lamp is lit — the one family where \"the properties are\n canonical\" would quietly not be true. */\n const ks = keyState(on, option.disabled || disabled);\n return (\n <button\n key={option.value}\n {...keyProps(option, index)}\n {...stateData(ks)}\n className=\"ambx-key\"\n style={{\n ...(stateStyle(ks) as CSSProperties),\n ...(option.color ? ({ \"--amb-led-color\": option.color } as CSSProperties) : null)\n }}\n >\n <ControlStateProvider value={ks}>\n <BankKeyProvider value={{ option, on, index }}>\n {renderKey ? renderKey(option, on) : <Frames parts={keyParts} />}\n </BankKeyProvider>\n </ControlStateProvider>\n </button>\n );\n })}\n </div>\n );\n\n if (!label) return bank;\n\n return (\n <div className=\"ambx-stack\">\n {bank}\n <span id={labelId} className=\"ambx-label\">\n {label}\n </span>\n </div>\n );\n}\n","import { useCallback, useRef } from \"react\";\nimport type { KeyboardEvent, ReactNode } from \"react\";\nimport { useControllableValue } from \"./controllable\";\n\nexport type BankOption = {\n value: string;\n /** Key legend — a numeral in the referent, but any node works. */\n label?: ReactNode | undefined;\n /** Accessible name, and the hover title. Needed whenever the legend is a\n * glyph or an icon: a key reading \"*\" has no name otherwise. */\n ariaLabel?: string | undefined;\n /** Overrides the bank's lamp colour for this key only. */\n color?: string | undefined;\n disabled?: boolean | undefined;\n};\n\nexport type BankOrientation = \"vertical\" | \"horizontal\";\n\nexport type UseBankOptions = {\n options: BankOption[];\n value?: string | string[] | undefined;\n defaultValue?: string | string[] | undefined;\n onChange?: ((value: string | string[]) => void) | undefined;\n /** Let more than one lamp be lit at a time. */\n multiple?: boolean | undefined;\n orientation?: BankOrientation | undefined;\n disabled?: boolean | undefined;\n};\n\nfunction toArray(value: string | string[] | undefined): string[] {\n if (value === undefined) return [];\n return Array.isArray(value) ? value : [value];\n}\n\n/** N presses sharing a selection model.\n *\n * The roving tabindex, the radiogroup-versus-checkbox-group keyboard\n * difference and the selection-follows-focus rule are the reason this\n * mechanism exists: they are the part nobody should have to re-derive in\n * order to change what a key looks like. */\nexport function useBank(options: UseBankOptions) {\n const { options: items, multiple = false, orientation = \"vertical\", disabled = false } = options;\n\n const [raw, setRaw] = useControllableValue<string | string[]>(\n options.value,\n options.defaultValue ?? (multiple ? [] : \"\"),\n options.onChange\n );\n const selected = toArray(raw);\n const keyRefs = useRef<Array<HTMLButtonElement | null>>([]);\n\n const commit = useCallback(\n (next: string[]) => setRaw(multiple ? next : (next[0] ?? \"\")),\n [setRaw, multiple]\n );\n\n const select = useCallback(\n (option: BankOption | undefined) => {\n if (!option || option.disabled || disabled) return;\n if (!multiple) return commit([option.value]);\n commit(\n selected.includes(option.value)\n ? selected.filter((v) => v !== option.value)\n : [...selected, option.value]\n );\n },\n [commit, multiple, selected, disabled]\n );\n\n const enabled = items.filter((o) => !o.disabled);\n /* Roving tabindex: exactly one key is tab-reachable. The lit one owns the\n stop, so Tab lands where the eye already is; with nothing lit (or in\n multiple mode, where every lamp is independent) the first enabled key\n takes it. */\n const litIndex = items.findIndex((o) => selected.includes(o.value) && !o.disabled);\n const firstEnabled = items.findIndex((o) => !o.disabled);\n const tabStop = multiple ? -1 : litIndex >= 0 ? litIndex : firstEnabled;\n\n const focusAt = (index: number) => keyRefs.current[index]?.focus();\n\n const step = (from: number, delta: number) => {\n if (enabled.length === 0) return;\n let i = from;\n for (let guard = 0; guard < items.length; guard += 1) {\n i = (i + delta + items.length) % items.length;\n if (!items[i]?.disabled) break;\n }\n focusAt(i);\n /* A radio group moves selection with focus (WAI-ARIA radiogroup\n pattern); a checkbox group only moves focus, since each lamp toggles\n on its own. */\n if (!multiple) select(items[i]);\n };\n\n const edge = (which: \"first\" | \"last\") => {\n const i =\n which === \"first\" ? firstEnabled : items.map((o) => !o.disabled).lastIndexOf(true);\n if (i < 0) return;\n focusAt(i);\n if (!multiple) select(items[i]);\n };\n\n const onKeyDown = (event: KeyboardEvent<HTMLButtonElement>, index: number) => {\n const back = orientation === \"vertical\" ? \"ArrowUp\" : \"ArrowLeft\";\n const forward = orientation === \"vertical\" ? \"ArrowDown\" : \"ArrowRight\";\n switch (event.key) {\n case back:\n event.preventDefault();\n step(index, -1);\n break;\n case forward:\n event.preventDefault();\n step(index, 1);\n break;\n case \"Home\":\n event.preventDefault();\n edge(\"first\");\n break;\n case \"End\":\n event.preventDefault();\n edge(\"last\");\n break;\n case \" \":\n case \"Enter\":\n event.preventDefault();\n select(items[index]);\n break;\n default:\n break;\n }\n };\n\n const rootProps = {\n role: multiple ? (\"group\" as const) : (\"radiogroup\" as const),\n \"aria-orientation\": multiple ? undefined : orientation,\n \"aria-disabled\": disabled || undefined,\n \"data-orientation\": orientation,\n \"data-disabled\": disabled ? \"\" : undefined\n };\n\n /** Props for the key at `index`, including its own state channel. */\n const keyProps = (option: BankOption, index: number) => {\n const on = selected.includes(option.value);\n return {\n /* No `key` here on purpose: the caller maps the options, so it owns\n the list key. Spreading one into JSX makes React warn and drops\n the key on release builds. */\n type: \"button\" as const,\n ref: (node: HTMLButtonElement | null) => {\n keyRefs.current[index] = node;\n },\n role: multiple ? (\"checkbox\" as const) : (\"radio\" as const),\n \"aria-checked\": on,\n \"aria-label\": option.ariaLabel,\n title: option.ariaLabel,\n disabled: option.disabled || disabled,\n tabIndex: multiple ? 0 : index === tabStop ? 0 : -1,\n \"data-on\": on ? \"\" : undefined,\n onClick: () => select(option),\n onKeyDown: (event: KeyboardEvent<HTMLButtonElement>) => onKeyDown(event, index)\n };\n };\n\n return { selected, select, rootProps, keyProps };\n}\n","import { cn } from \"../lib/cn\";\nimport { AmbientBank } from \"../controls/AmbientBank\";\nimport type { AmbientBankProps } from \"../controls/AmbientBank\";\nimport type { BankOption, BankOrientation } from \"../core/useBank\";\nimport { useDress } from \"../core/kit\";\nimport type { KitLook } from \"../core/kit\";\nimport { groundedKit } from \"../kits/grounded\";\n\nexport type AmbientSelectOption = BankOption;\nexport type AmbientSelectOrientation = BankOrientation;\nexport type AmbientSelectSize = \"sm\" | \"md\" | \"lg\";\n\nexport type AmbientSelectProps = Omit<AmbientBankProps, \"keyParts\" | \"parts\" | \"size\"> & {\n size?: AmbientSelectSize | undefined;\n /** Look options in the active kit's vocabulary. */\n look?: KitLook | undefined;\n};\n\n/**\n * A bank of lamp-lit keys in a shared rail — the hardware idiom for a\n * mode selector, where the state is a lamp rather than a mark.\n *\n * Three physical layers per key, and the ORDER is the whole trick: the key\n * itself is the pocket floor, the lens is a disc lying on it, and the cap\n * is a translucent diffuser over both. The cap is `.amb-mat-glass`, so its\n * backdrop-filter blurs the lens behind it — which is why the lens goes in\n * the `base` frame and the cap in `actuator`, and why swapping them would\n * put out every lamp.\n */\nexport function AmbientSelect({ size = \"md\", look, className, ...rest }: AmbientSelectProps) {\n const { dress } = useDress(\"bank\", { ...look }, groundedKit.bank!);\n return (\n <AmbientBank\n {...rest}\n size={size}\n className={cn(dress.className, className)}\n keyParts={dress.parts}\n />\n );\n}\n","import { useId, useRef } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { ControlStateProvider } from \"../core/context\";\nimport { Frames, useDevPartCheck } from \"../core/frames\";\nimport { sizeProps } from \"../core/types\";\nimport type { ControlAnimate, ControlParts, ControlSize } from \"../core/types\";\nimport { useRotary } from \"../core/useRotary\";\nimport type { UseRotaryOptions } from \"../core/useRotary\";\n\nexport type AmbientRotaryProps = Omit<HTMLAttributes<HTMLDivElement>, \"onChange\" | \"defaultValue\"> &\n UseRotaryOptions & {\n parts?: ControlParts | undefined;\n size?: ControlSize | undefined;\n animate?: ControlAnimate | undefined;\n label?: ReactNode | undefined;\n };\n\n/** A rotary mechanism with no appearance of its own.\n *\n * It owns the value, the three pointer mappings, the sweep, the keyboard\n * contract and the ARIA; what it looks like is entirely the `parts` you\n * give it. There is deliberately no `material` prop: which element a\n * material belongs on is a fact about a particular knob's construction —\n * on the clipped face when it is knurled, on the body when it is not —\n * and a mechanism cannot know that once the body is yours. Presets carry\n * `material`, because a preset knows its own parts. */\nexport function AmbientRotary({\n parts,\n size,\n animate = \"auto\",\n label,\n className,\n value,\n defaultValue,\n min,\n max,\n step,\n detents,\n travel,\n input,\n dragDistance,\n wrap,\n disabled,\n onChange,\n ...rest\n}: AmbientRotaryProps) {\n const labelId = useId();\n const stackRef = useRef<HTMLDivElement>(null);\n const { state, rootProps } = useRotary({\n value,\n defaultValue,\n min,\n max,\n step,\n detents,\n travel,\n input,\n dragDistance,\n wrap,\n disabled,\n onChange\n });\n useDevPartCheck(stackRef, \"AmbientRotary\");\n\n const sized = sizeProps(\"rotary\", size);\n const { style: restStyle, ...restProps } = rest;\n\n const control = (\n <div\n {...restProps}\n {...rootProps}\n aria-labelledby={label ? labelId : rest[\"aria-labelledby\"]}\n data-animate={animate}\n className={cn(\"ambx-control ambx-rotary\", sized.className, className)}\n style={{ ...rootProps.style, ...sized.style, ...restStyle }}\n >\n <ControlStateProvider value={state}>\n <Frames parts={parts} />\n </ControlStateProvider>\n </div>\n );\n\n return (\n <div className=\"ambx-stack\" ref={stackRef}>\n {control}\n {label ? (\n <span id={labelId} className=\"ambx-label\">\n {label}\n </span>\n ) : null}\n </div>\n );\n}\n","import { useCallback, useMemo, useRef, useState } from \"react\";\nimport type { CSSProperties, KeyboardEvent, PointerEvent } from \"react\";\nimport { useControllableValue } from \"./controllable\";\nimport { clamp, commit, denormalise, normalise, valueKeyHandler } from \"./numeric\";\nimport { stateData, stateStyle } from \"./types\";\nimport { isDev } from \"./dev\";\nimport type { ControlState } from \"./types\";\n\n/** How pointer movement becomes value.\n *\n * These are three different mappings, not one with a parameter, and the\n * library was ambiguous about which it implemented: the code did `angle`\n * while knob.md documented `drag`. Naming it makes that drift impossible.\n *\n * - `drag` pointer DISTANCE -> value delta. The v3 default: it is what the\n * docs always described, what most audio software does, and the\n * only one that behaves on touch, where a finger covers the knob.\n * - `angle` pointer POSITION -> absolute angle -> value. Needs a dead zone,\n * and needs a sweep under a full turn to be unambiguous.\n * - `delta` accumulated angular change. The endless-encoder mapping: no\n * ends, no dead zone, and the value may wrap independently of\n * where the pointer happens to be. */\nexport type RotaryInput = \"drag\" | \"angle\" | \"delta\";\n\n/** The pot's travel in degrees clockwise from 12 o'clock. A bare number is\n * a sweep centred on 12 o'clock, so `270` is the default 8-to-4 pot. */\nexport type RotaryTravel = number | { start: number; sweep: number };\n\nexport type UseRotaryOptions = {\n value?: number | undefined;\n defaultValue?: number | undefined;\n min?: number | undefined;\n max?: number | undefined;\n /** Quantises the VALUE. `0` leaves it continuous. */\n step?: number | undefined;\n /** Quantises the TRAVEL: rest positions along the arc. Defaults to the\n * step grid, but the two are independent — an endless encoder can have\n * 24 detents per turn while its value stays continuous. */\n detents?: number | undefined;\n travel?: RotaryTravel | undefined;\n input?: RotaryInput | undefined;\n /** Pixels of drag for one full range, in `drag` mode. */\n dragDistance?: number | undefined;\n /** `delta` mode only: run past the ends and come round again. */\n wrap?: boolean | undefined;\n disabled?: boolean | undefined;\n onChange?: ((next: number) => void) | undefined;\n};\n\nconst DEFAULT_TRAVEL = { start: -135, sweep: 270 };\n\n/** Fold an angle into (-180, 180]. */\nfunction wrapDeg(deg: number): number {\n return ((((deg + 180) % 360) + 360) % 360) - 180;\n}\n\nfunction resolveTravel(travel: RotaryTravel | undefined) {\n if (travel === undefined) return DEFAULT_TRAVEL;\n if (typeof travel === \"number\") return { start: -travel / 2, sweep: travel };\n return travel;\n}\n\nlet warnedFullTurn = false;\n\n/** Pointer capture, but survivable.\n *\n * `setPointerCapture` throws NotFoundError for a pointer id the browser\n * does not currently have down, and is missing outright in jsdom. Neither\n * happens with a real finger, but both happen constantly in tests — and an\n * exception here would abort the handler before the drag ever starts,\n * making the control look broken rather than untestable. */\nexport function capturePointer(target: Element, pointerId: number): void {\n try {\n target.setPointerCapture?.(pointerId);\n } catch {\n /* Without capture the drag still tracks; it just stops at the edge of\n the element instead of following the pointer off it. */\n }\n}\n\nexport function useRotary(options: UseRotaryOptions) {\n const {\n min = 0,\n max = 100,\n step = 1,\n dragDistance = 200,\n wrap = false,\n disabled = false\n } = options;\n\n const { start, sweep } = resolveTravel(options.travel);\n\n /* A full turn cannot be read as an absolute angle: 0 and max land on the\n same screen position, and the dead-zone clamp has no end to snap to.\n Fall back rather than misbehave silently. */\n let input = options.input ?? \"drag\";\n if (input === \"angle\" && Math.abs(sweep) >= 360) {\n if (isDev && !warnedFullTurn) {\n warnedFullTurn = true;\n console.warn(\n `[@ambientcss/components] input=\"angle\" needs a sweep under a full turn ` +\n `(got ${sweep}deg): an absolute angle is ambiguous at 360deg, where the ` +\n `first and last values share a screen position. Falling back to \"drag\".`\n );\n }\n input = \"drag\";\n }\n\n const [value, setValue] = useControllableValue(\n options.value,\n options.defaultValue ?? min,\n options.onChange\n );\n\n /* `dragging` is state because the root publishes it as data-dragging, and\n a REF because the move handler has to gate on it. Reading the state in\n the handler drops every move that fires before React re-renders after\n the press — which is most of them on a fast drag. */\n const [dragging, setDragging] = useState(false);\n const draggingRef = useRef(false);\n const rootRef = useRef<HTMLDivElement | null>(null);\n /* Drag bookkeeping. Deltas are accumulated rather than measured from the\n press point so that toggling the fine-mode modifier mid-drag changes\n the gearing from here on instead of jumping the value. */\n const drag = useRef({ value: 0, clientY: 0, angle: 0, accum: 0 });\n\n const range = max - min;\n const keyStep = step > 0 ? step : range / 100 || 1;\n const percent = clamp(normalise(value, min, max), 0, 1);\n const angle = start + percent * sweep;\n\n const set = useCallback(\n (next: number) => setValue(commit(next, min, max, step)),\n [setValue, min, max, step]\n );\n\n /** Pointer position as an angle in degrees clockwise from 12 o'clock. */\n const pointerAngle = (event: PointerEvent<HTMLElement>): number | null => {\n const rect = rootRef.current?.getBoundingClientRect();\n if (!rect) return null;\n const dx = event.clientX - (rect.left + rect.width / 2);\n const dy = event.clientY - (rect.top + rect.height / 2);\n // atan2 in screen coords reads 0 at 3 o'clock and grows clockwise; +90\n // rotates the origin to 12 o'clock.\n return Math.atan2(dy, dx) * (180 / Math.PI) + 90;\n };\n\n const fromAngle = (event: PointerEvent<HTMLElement>) => {\n const raw = pointerAngle(event);\n if (raw === null) return;\n /* Fold the reading into the half-turn either side of the sweep's own\n midpoint, so a sweep whose end passes 180deg stays reachable. */\n const mid = start + sweep / 2;\n let a = mid + wrapDeg(raw - mid);\n const end = start + sweep;\n if (a < Math.min(start, end) || a > Math.max(start, end)) {\n /* In the dead zone: hold at whichever end is angularly nearer. The\n pre-v3 code chose by which half the value was in, which threw the\n knob to the far end whenever a drag crossed the gap. */\n const toStart = Math.abs(wrapDeg(a - start));\n const toEnd = Math.abs(wrapDeg(a - end));\n a = toStart <= toEnd ? start : end;\n }\n set(denormalise((a - start) / (sweep || 1), min, max));\n };\n\n const fromDrag = (event: PointerEvent<HTMLElement>) => {\n const dy = drag.current.clientY - event.clientY;\n drag.current.clientY = event.clientY;\n drag.current.accum += dy * (event.shiftKey ? 0.25 : 1);\n set(drag.current.value + (drag.current.accum / dragDistance) * range);\n };\n\n const fromDelta = (event: PointerEvent<HTMLElement>) => {\n const raw = pointerAngle(event);\n if (raw === null) return;\n drag.current.accum += wrapDeg(raw - drag.current.angle);\n drag.current.angle = raw;\n const next = drag.current.value + (drag.current.accum / (sweep || 360)) * range;\n set(wrap && range > 0 ? min + (((next - min) % range) + range) % range : next);\n };\n\n const track = (event: PointerEvent<HTMLElement>) => {\n if (input === \"angle\") fromAngle(event);\n else if (input === \"delta\") fromDelta(event);\n else fromDrag(event);\n };\n\n const state: ControlState = useMemo(\n () => ({\n value,\n min,\n max,\n percent,\n angle,\n travelStart: start,\n travelSweep: sweep,\n detents: options.detents ?? (step > 0 && range > 0 ? Math.round(range / step) : 0),\n dragging,\n disabled,\n atMin: value <= min,\n atMax: value >= max\n }),\n [value, min, max, percent, angle, start, sweep, options.detents, step, range, dragging, disabled]\n );\n\n const onKeyDown = valueKeyHandler({ value, min, max, step: keyStep, disabled, onChange: setValue });\n\n const rootProps = {\n ref: rootRef,\n role: \"slider\" as const,\n \"aria-valuemin\": min,\n \"aria-valuemax\": max,\n \"aria-valuenow\": value,\n \"aria-orientation\": \"vertical\" as const,\n \"aria-disabled\": disabled || undefined,\n tabIndex: disabled ? -1 : 0,\n style: stateStyle(state) as CSSProperties,\n ...stateData(state),\n onPointerDown: (event: PointerEvent<HTMLDivElement>) => {\n if (disabled || event.button !== 0) return;\n capturePointer(event.currentTarget, event.pointerId);\n draggingRef.current = true;\n setDragging(true);\n drag.current = {\n value,\n clientY: event.clientY,\n angle: pointerAngle(event) ?? 0,\n accum: 0\n };\n /* Only the absolute mapping jumps to the press point; the relative\n ones would lurch, which is the whole reason to prefer them. */\n if (input === \"angle\") fromAngle(event);\n },\n onPointerMove: (event: PointerEvent<HTMLDivElement>) => {\n if (!draggingRef.current || disabled) return;\n track(event);\n },\n onPointerUp: () => {\n draggingRef.current = false;\n setDragging(false);\n },\n onPointerCancel: () => {\n draggingRef.current = false;\n setDragging(false);\n },\n onKeyDown: (event: KeyboardEvent<HTMLDivElement>) => {\n onKeyDown(event);\n }\n };\n\n return { state, rootProps, setValue: set };\n}\n","/* Value maths shared by every control.\n\n These four functions were previously inlined — identically — in\n AmbientKnob, AmbientSlider and AmbientFader. The keyboard handler below\n was copied three times with the same `pageStep = step * 10`, the same\n Home/End edges and the same snap-then-clamp order. */\n\nexport function clamp(value: number, min: number, max: number): number {\n return Math.min(max, Math.max(min, value));\n}\n\n/** Quantise to the step grid, anchored at `min` rather than at zero so a\n * range like 10..100 step 25 rests on 10/35/60/85 instead of 25/50/75. */\nexport function snap(value: number, min: number, step: number): number {\n if (!(step > 0)) return value;\n return min + Math.round((value - min) / step) * step;\n}\n\n/** Value to its 0-1 position in the range. */\nexport function normalise(value: number, min: number, max: number): number {\n return (value - min) / (max - min || 1);\n}\n\n/** A 0-1 position back to a value. */\nexport function denormalise(t: number, min: number, max: number): number {\n return min + t * (max - min);\n}\n\n/** Snap and clamp in the order every control needs: quantise first, then\n * hold the result inside the range, so a step that does not divide the\n * range still cannot push the value past `max`. */\nexport function commit(value: number, min: number, max: number, step: number): number {\n return clamp(snap(value, min, max === min ? 1 : step), min, max);\n}\n\nexport type ValueKeysOptions = {\n value: number;\n min: number;\n max: number;\n step: number;\n disabled?: boolean;\n /** Swap the direction of the arrow keys along the control's own axis. */\n invert?: boolean;\n onChange: (next: number) => void;\n};\n\n/** The Arrow/Page/Home/End contract, in one place.\n *\n * Both arrow axes act on every control: a knob has no \"left\", and a\n * horizontal slider has no \"up\", but a keyboard user should not have to\n * know which. Page steps are ten of `step`, the figure all three\n * components already used. */\nexport function valueKeyHandler(options: ValueKeysOptions) {\n return (event: { key: string; preventDefault(): void }): boolean => {\n const { value, min, max, step, invert, onChange, disabled } = options;\n if (disabled) return false;\n const dir = invert ? -1 : 1;\n const set = (next: number) => {\n event.preventDefault();\n onChange(commit(next, min, max, step));\n };\n\n switch (event.key) {\n case \"ArrowUp\":\n case \"ArrowRight\":\n set(value + step * dir);\n return true;\n case \"ArrowDown\":\n case \"ArrowLeft\":\n set(value - step * dir);\n return true;\n case \"PageUp\":\n set(value + step * 10 * dir);\n return true;\n case \"PageDown\":\n set(value - step * 10 * dir);\n return true;\n case \"Home\":\n set(min);\n return true;\n case \"End\":\n set(max);\n return true;\n default:\n return false;\n }\n };\n}\n","import { cn } from \"../lib/cn\";\nimport { AmbientRotary } from \"../controls/AmbientRotary\";\nimport type { AmbientRotaryProps } from \"../controls/AmbientRotary\";\nimport { useDress } from \"../core/kit\";\nimport type { KitLook } from \"../core/kit\";\nimport type { AmbientMaterial } from \"../core/material\";\nimport { groundedKit } from \"../kits/grounded\";\n\n/** Printed scale dots on the panel around the knob: the arc's two ends, the\n * full graduated ring, or nothing. */\nexport type AmbientKnobMarkers = \"none\" | \"ends\" | \"full\";\n\n/** The pointer riding the rotating face: a radial bar or an offset dot. */\nexport type AmbientKnobIndicator = \"rectangle\" | \"circle\";\n\nexport type AmbientKnobSize = \"sm\" | \"md\" | \"lg\";\n\nexport type AmbientKnobProps = Omit<AmbientRotaryProps, \"parts\" | \"size\"> & {\n material?: AmbientMaterial | undefined;\n /** Ribbed grip around the rotating body. Off gives a smooth turned body. */\n knurling?: boolean | undefined;\n /** The grip ring's own colour, for a two-tone knob — any CSS colour, read\n * as an albedo, so it still takes the scene's light rather than being\n * painted flat. Unset, the ring is the same material as the cap. */\n knurlColor?: string | undefined;\n markers?: AmbientKnobMarkers | undefined;\n indicator?: AmbientKnobIndicator | undefined;\n size?: AmbientKnobSize | undefined;\n /** Look options in another kit's vocabulary.\n *\n * The five props above are the *grounded* kit's words. A kit that dresses\n * knobs differently has its own, and they arrive here rather than as\n * loose props so the common path stays typed and a misspelt `knurling`\n * is still a compile error. Kits usually ship a preset of their own that\n * types this properly — see `ConsoleKnob`. */\n look?: KitLook | undefined;\n};\n\n/**\n * The rotary preset: `AmbientRotary` wearing whatever the active kit says a\n * knob looks like, and the grounded hardware knob when no kit is set.\n */\nexport function AmbientKnob({\n material,\n knurling,\n knurlColor,\n markers,\n indicator,\n look,\n size = \"md\",\n className,\n travel,\n input,\n animate,\n ...rest\n}: AmbientKnobProps) {\n const { dress, defaults } = useDress(\n \"rotary\",\n { material, knurling, knurlColor, markers, indicator, ...look },\n groundedKit.rotary!\n );\n\n return (\n <AmbientRotary\n {...rest}\n /* Caller wins over kit, kit wins over the mechanism's own default. */\n travel={travel ?? defaults?.travel}\n input={input ?? defaults?.input}\n animate={animate ?? defaults?.animate}\n size={size}\n className={cn(dress.className, className)}\n parts={dress.parts}\n />\n );\n}\n","import { useId, useRef } from \"react\";\nimport type { HTMLAttributes, ReactNode } from \"react\";\nimport { cn } from \"../lib/cn\";\nimport { ControlStateProvider } from \"../core/context\";\nimport { Frames, useDevPartCheck } from \"../core/frames\";\nimport { sizeProps } from \"../core/types\";\nimport type { ControlAnimate, ControlParts, ControlSize } from \"../core/types\";\nimport { useTravel } from \"../core/useTravel\";\nimport type { UseTravelOptions } from \"../core/useTravel\";\n\nexport type AmbientTravelProps = Omit<HTMLAttributes<HTMLDivElement>, \"onChange\" | \"defaultValue\"> &\n UseTravelOptions & {\n parts?: ControlParts | undefined;\n size?: ControlSize | undefined;\n animate?: ControlAnimate | undefined;\n label?: ReactNode | undefined;\n };\n\n/** A value on a straight track, with no appearance of its own. */\nexport function AmbientTravel({\n parts,\n size,\n animate = \"auto\",\n label,\n className,\n value,\n defaultValue,\n min,\n max,\n step,\n detents,\n orientation = \"horizontal\",\n invert,\n disabled,\n onChange,\n ...rest\n}: AmbientTravelProps) {\n const labelId = useId();\n const stackRef = useRef<HTMLDivElement>(null);\n const { state, rootProps } = useTravel({\n value,\n defaultValue,\n min,\n max,\n step,\n detents,\n orientation,\n invert,\n disabled,\n onChange\n });\n useDevPartCheck(stackRef, \"AmbientTravel\");\n\n const sized = sizeProps(\"travel\", size);\n const { style: restStyle, ...restProps } = rest;\n\n return (\n <div className=\"ambx-stack\" ref={stackRef}>\n <div\n {...restProps}\n {...rootProps}\n aria-labelledby={label ? labelId : rest[\"aria-labelledby\"]}\n data-animate={animate}\n className={cn(\n \"ambx-control ambx-travel\",\n `ambx-travel-${orientation}`,\n sized.className,\n className\n )}\n style={{ ...rootProps.style, ...sized.style, ...restStyle }}\n >\n <ControlStateProvider value={state}>\n <Frames parts={parts} />\n </ControlStateProvider>\n </div>\n {label ? (\n <span id={labelId} className=\"ambx-label\">\n {label}\n </span>\n ) : null}\n </div>\n );\n}\n","import { useCallback, useMemo, useRef, useState } from \"react\";\nimport type { CSSProperties, KeyboardEvent, PointerEvent } from \"react\";\nimport { useControllableValue } from \"./controllable\";\nimport { clamp, commit, denormalise, normalise, valueKeyHandler } from \"./numeric\";\nimport { capturePointer } from \"./useRotary\";\nimport { stateData, stateStyle } from \"./types\";\nimport type { ControlState } from \"./types\";\n\nexport type TravelOrientation = \"horizontal\" | \"vertical\";\n\nexport type UseTravelOptions = {\n value?: number | undefined;\n defaultValue?: number | undefined;\n min?: number | undefined;\n max?: number | undefined;\n step?: number | undefined;\n detents?: number | undefined;\n orientation?: TravelOrientation | undefined;\n /** Flip which end of the axis is `min`. */\n invert?: boolean | undefined;\n disabled?: boolean | undefined;\n onChange?: ((next: number) => void) | undefined;\n};\n\n/** A value riding a straight track.\n *\n * One mechanism behind both the slider and the fader, which before v3 were\n * the same file twice with X and Y swapped. The only real difference is\n * which axis the pointer reads — and which end is `min`, where the two\n * disagree for a physical reason rather than a stylistic one: a horizontal\n * track runs min-at-the-left, and an upright one runs min-at-the-bottom,\n * because that is how a fader is built. Both are the default here, so\n * neither preset has to ask. */\nexport function useTravel(options: UseTravelOptions) {\n const {\n min = 0,\n max = 100,\n step = 1,\n orientation = \"horizontal\",\n invert = false,\n disabled = false\n } = options;\n\n const [value, setValue] = useControllableValue(\n options.value,\n options.defaultValue ?? min,\n options.onChange\n );\n\n const [dragging, setDragging] = useState(false);\n const draggingRef = useRef(false);\n const rootRef = useRef<HTMLDivElement | null>(null);\n\n const vertical = orientation === \"vertical\";\n const range = max - min;\n const keyStep = step > 0 ? step : range / 100 || 1;\n const percent = clamp(normalise(value, min, max), 0, 1);\n\n const set = useCallback(\n (next: number) => setValue(commit(next, min, max, step)),\n [setValue, min, max, step]\n );\n\n const track = (event: PointerEvent<HTMLElement>) => {\n const rect = rootRef.current?.getBoundingClientRect();\n if (!rect) return;\n // An upright track reads bottom-up: 1 at the top of the box.\n const raw = vertical\n ? 1 - (event.clientY - rect.top) / (rect.height || 1)\n : (event.clientX - rect.left) / (rect.width || 1);\n set(denormalise(clamp(invert ? 1 - raw : raw, 0, 1), min, max));\n };\n\n const state: ControlState = useMemo(\n () => ({\n value,\n min,\n max,\n percent,\n angle: 0,\n travelStart: 0,\n travelSweep: 0,\n detents: options.detents ?? (step > 0 && range > 0 ? Math.round(range / step) : 0),\n dragging,\n disabled,\n atMin: value <= min,\n atMax: value >= max\n }),\n [value, min, max, percent, options.detents, step, range, dragging, disabled]\n );\n\n const onKeyDown = valueKeyHandler({\n value,\n min,\n max,\n step: keyStep,\n disabled,\n invert,\n onChange: setValue\n });\n\n const rootProps = {\n ref: rootRef,\n role: \"slider\" as const,\n \"aria-valuemin\": min,\n \"aria-valuemax\": max,\n \"aria-valuenow\": value,\n \"aria-orientation\": orientation,\n \"aria-disabled\": disabled || undefined,\n tabIndex: disabled ? -1 : 0,\n style: stateStyle(state) as CSSProperties,\n \"data-orientation\": orientation,\n ...stateData(state),\n onPointerDown: (event: PointerEvent<HTMLDivElement>) => {\n if (disabled || event.button !== 0) return;\n capturePointer(event.currentTarget, event.pointerId);\n draggingRef.current = true;\n setDragging(true);\n /* A track is absolute by nature: pressing anywhere on it means \"put\n the thumb here\", which is what a fader does under a finger. */\n track(event);\n },\n onPointerMove: (event: PointerEvent<HTMLDivElement>) => {\n if (!draggingRef.current || disabled) return;\n track(event);\n },\n onPointerUp: () => {\n draggingRef.current = false;\n setDragging(false);\n },\n onPointerCancel: () => {\n draggingRef.current = false;\n setDragging(false);\n },\n onKeyDown: (event: KeyboardEvent<HTMLDivElement>) => {\n onKeyDown(event);\n }\n };\n\n return { state, rootProps, setValue: set };\n}\n","import { cn } from \"../lib/cn\";\nimport { AmbientTravel } from \"../controls/AmbientTravel\";\nimport type { AmbientTravelProps } from \"../controls/AmbientTravel\";\nimport { useDress } from \"../core/kit\";\nimport type { KitLook } from \"../core/kit\";\nimport { groundedKit } from \"../kits/grounded\";\nimport type { AmbientMaterial } from \"../core/material\";\n\nexport type AmbientFaderSize = \"sm\" | \"md\" | \"lg\";\n\nexport type AmbientFaderProps = Omit<AmbientTravelProps, \"parts\" | \"size\" | \"orientation\"> & {\n material?: AmbientMaterial | undefined;\n size?: AmbientFaderSize | undefined;\n /** Look options in the active kit's vocabulary. */\n look?: KitLook | undefined;\n};\n\n/** A pill cap on a stem, riding an upright slot. Min is at the bottom,\n * which `AmbientTravel` already does for a vertical track. */\nexport function AmbientFader({\n material,\n look,\n size = \"md\",\n animate,\n className,\n ...rest\n}: AmbientFaderProps) {\n const { dress, defaults } = useDress(\n \"travel\",\n { material, orientation: \"vertical\", ...look },\n groundedKit.travel!\n );\n return (\n <AmbientTravel\n {...rest}\n orientation=\"vertical\"\n size={size}\n animate={animate ?? defaults?.animate}\n className={cn(dress.className, className)}\n parts={dress.parts}\n />\n );\n}\n","import { cn } from \"../lib/cn\";\nimport { AmbientTravel } from \"../controls/AmbientTravel\";\nimport type { AmbientTravelProps } from \"../controls/AmbientTravel\";\nimport { useDress } from \"../core/kit\";\nimport type { KitLook } from \"../core/kit\";\nimport { groundedKit } from \"../kits/grounded\";\nimport type { AmbientMaterial } from \"../core/material\";\n\nexport type AmbientSliderSize = \"sm\" | \"md\" | \"lg\";\n\nexport type AmbientSliderProps = Omit<AmbientTravelProps, \"parts\" | \"size\" | \"orientation\"> & {\n material?: AmbientMaterial | undefined;\n size?: AmbientSliderSize | undefined;\n /** Look options in the active kit's vocabulary. */\n look?: KitLook | undefined;\n};\n\n/** A domed disc gliding over a shallow concave channel. */\nexport function AmbientSlider({\n material,\n look,\n size = \"md\",\n animate,\n className,\n ...rest\n}: AmbientSliderProps) {\n const { dress, defaults } = useDress(\n \"travel\",\n { material, orientation: \"horizontal\", ...look },\n groundedKit.travel!\n );\n return (\n <AmbientTravel\n {...rest}\n orientation=\"horizontal\"\n size={size}\n animate={animate ?? defaults?.animate}\n className={cn(dress.className, className)}\n parts={dress.parts}\n />\n );\n}\n","import { cn } from \"../lib/cn\";\n\n/* Parts for the `console` kit — a mixer-desk visual language, measured off\n photographs of the real controls. Nothing here is a variant of a grounded\n part: a bar knob and a lit pill track are a different vocabulary, which is\n the reason kits exist rather than another round of boolean props. */\n\n/** The knob's base: a flat face housed in a circular groove.\n *\n * Two elements, because they are two pieces of the panel: the groove is the\n * cut, and the face is the flat disc sitting in it, showing the ring of the\n * cut around itself. Neither carries `.ambient` — the face has no body, so\n * there is no edge to cut and nothing to cast, and every cue that reads as\n * depth here belongs either to the walls of the housing or to the bar\n * standing on the face.\n *\n * It sits in the `base` frame, so it does not turn. A plain disc looks the\n * same at every angle, and leaving it still keeps the scene's light on it\n * untouched — only the bar has to do the work below. */\nexport function ConsoleWell({ className }: { className?: string | undefined }) {\n return (\n <span className={cn(\"amb-console-housing amb-groove\", className)}>\n <span className=\"amb-console-face amb-surface\" />\n </span>\n );\n}\n\n/** The actuator: a cuboid bar lying across the disc on its diameter.\n *\n * Two spans, and the nesting is load-bearing. The bar rides the rotating\n * actuator frame, so a chamfer highlight painted from the inherited light\n * would turn with it and put the lit edge on the wrong side of the screen\n * at half the angles. The fix is to rotate the LIGHT the other way: the\n * outer span captures the scene's light vector, the inner one re-states it\n * in the frame's own turned coordinates, so the bright edge and the drop\n * shadow both stay put on screen while the bar sweeps under them.\n *\n * It has to be two elements because a custom property cannot read itself —\n * `--amb-light-x: calc(var(--amb-light-x) ...)` is a cycle, which resolves\n * to invalid at computed-value time and takes the whole `box-shadow`\n * composite down with it, silently. */\nexport function ConsoleBar({ className }: { className?: string | undefined }) {\n return (\n <span className={cn(\"amb-console-bar\", className)}>\n <span className=\"amb-console-bar-body ambient amb-surface amb-chamfer amb-thickness-2\">\n {/* Printed on the bar near one end, the way the reference prints a\n short black mark at the outer edge of its pointer: with a bar\n that crosses the whole face, this is what says which end reads. */}\n <span className=\"amb-console-indicator\" />\n </span>\n </span>\n );\n}\n\n/** Panel graphics around the knob: the centre mark above it, and the\n * −/+ legends at the ends of the travel. Both sit outside the knob's own\n * box, which is what the `panel` frame is for. */\nexport function ConsoleMarks({\n mark = true,\n legend = true,\n className\n}: {\n mark?: boolean | undefined;\n legend?: boolean | undefined;\n className?: string | undefined;\n}) {\n return (\n <span className={cn(\"amb-console-marks\", className)} aria-hidden>\n {mark ? <span className=\"amb-console-mark amb-surface\" /> : null}\n {legend ? (\n <>\n <span className=\"amb-console-legend amb-console-legend-min\">−</span>\n <span className=\"amb-console-legend amb-console-legend-max\">+</span>\n </>\n ) : null}\n </span>\n );\n}\n\n/** The toggle's track: a pill groove that fills with the accent as the\n * switch travels.\n *\n * A pure-CSS part — it reads `--ambx-percent` off the control root and\n * mixes its own colour from it, so the mechanism does not know this element\n * exists and no React state reaches it. */\nexport function ToggleTrack({ className }: { className?: string | undefined }) {\n return <span className={cn(\"amb-console-track amb-groove\", className)} />;\n}\n\n/** The travelling thumb: an albedo disc inside a light ring.\n *\n * Flat on top and deliberately so — no chamfer, no fillet — but still a\n * knob-scale body, so it casts. That pairing is why the classes are spelt\n * out rather than reached through `.amb-fillet-2`: the edge treatments set\n * a thickness of their own, and here the thickness is wanted without the\n * cut that usually comes with it. It wears `amb-surface`, so its colour IS\n * the scene's albedo under the current light rather than a fixed paint —\n * it re-shades when the lamp moves or the intensities change. */\nexport function ToggleThumb({ className }: { className?: string | undefined }) {\n return <span className={cn(\"amb-console-thumb ambient amb-surface amb-thickness-2\", className)} />;\n}\n","import { cn } from \"../lib/cn\";\nimport { AmbientKnob } from \"../components/AmbientKnob\";\nimport type { AmbientKnobProps } from \"../components/AmbientKnob\";\nimport { AmbientSwitch } from \"../components/AmbientSwitch\";\nimport type { AmbientSwitchProps } from \"../components/AmbientSwitch\";\nimport type { ControlKit, KitDress, KitLook } from \"../core/kit\";\nimport { ConsoleBar, ConsoleMarks, ConsoleWell, ToggleThumb, ToggleTrack } from \"../parts/console\";\n\n/**\n * A mixer-desk visual identity: cuboid bar knobs seated in a circular\n * groove, and pill toggles that light up with the panel accent.\n *\n * It dresses two families and leaves the other three to fall through to\n * `grounded` — which is what a real third-party kit looks like. A kit is not\n * obliged to have an opinion about everything.\n */\n\nfunction rotary(look: KitLook): KitDress {\n const mark = look.mark !== false;\n const legend = look.legend !== false;\n return {\n className: cn(\n \"amb-console-knob\",\n mark && \"amb-console-knob-marked\",\n legend && \"amb-console-knob-legended\"\n ),\n parts: {\n panel: mark || legend ? <ConsoleMarks mark={mark} legend={legend} /> : null,\n base: <ConsoleWell />,\n actuator: <ConsoleBar />\n }\n };\n}\n\nfunction latch(): KitDress {\n return {\n className: \"amb-console-toggle\",\n parts: { base: <ToggleTrack />, actuator: <ToggleThumb /> }\n };\n}\n\nexport const consoleKit: ControlKit = {\n name: \"console\",\n rotary,\n latch,\n /* A visual identity may say how its controls feel to turn. The desk knob\n this is drawn from is an absolute-position pot with a centre detent, so\n it grabs where you press rather than tracking a drag. */\n defaults: {\n rotary: { input: \"angle\", travel: 280 }\n },\n looks: {\n rotary: [\"mark\", \"legend\"],\n latch: []\n }\n};\n\n/* A kit can also ship presets of its own. They are three lines each — the\n shared preset with this kit's look vocabulary typed — and they are how a\n kit gives its own words the same compile-time checking `knurling` gets. */\n\nexport type ConsoleKnobProps = Omit<\n AmbientKnobProps,\n \"look\" | \"material\" | \"knurling\" | \"knurlColor\" | \"markers\" | \"indicator\"\n> & {\n /** The accent centre mark printed above the knob. */\n mark?: boolean | undefined;\n /** The −/+ legends at the ends of the travel. */\n legend?: boolean | undefined;\n};\n\nexport function ConsoleKnob({ mark, legend, ...rest }: ConsoleKnobProps) {\n return <AmbientKnob {...rest} look={{ mark, legend }} />;\n}\n\nexport type ConsoleToggleProps = Omit<AmbientSwitchProps, \"look\">;\n\nexport function ConsoleToggle(props: ConsoleToggleProps) {\n return <AmbientSwitch {...props} />;\n}\n"],"mappings":"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","names":["import_jsx_runtime","import_jsx_runtime","import_react","import_react","import_jsx_runtime","warned","import_react","import_react","import_jsx_runtime","import_react","import_jsx_runtime","import_react","import_jsx_runtime","r","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_react","import_react","import_react","import_jsx_runtime","import_jsx_runtime","import_react","import_react","commit","import_jsx_runtime","bank","import_jsx_runtime","import_react","import_react","travel","import_jsx_runtime","travel","import_jsx_runtime","travel","import_react","import_react","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","import_jsx_runtime","rotary","latch"]}