{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "primitives-toggle-group",
  "type": "registry:component",
  "title": "Toggle group",
  "description": "A toolbar of related modes, pressed and unpressed",
  "author": "sudo-kw <https://github.com/sudo-kw>",
  "dependencies": [
    "@gpuix/native@0.11.0",
    "@gpuix/react@0.11.0",
    "effect@4.1.2",
    "react@^19.2.4"
  ],
  "registryDependencies": [
    "https://gpuixui.sudokw.com/gpuix-icons.json",
    "https://gpuixui.sudokw.com/gpuix-motion.json",
    "https://gpuixui.sudokw.com/gpuix-tokens.json",
    "https://gpuixui.sudokw.com/gpuix-tw.json"
  ],
  "files": [
    {
      "path": "packages/primitives/src/components/MessagesProvider.tsx",
      "target": "@ui/gpuixui/primitives/components/MessagesProvider.tsx",
      "type": "registry:component",
      "content": "/** @jsxImportSource @gpuix/react */\nimport {\n  createContext,\n  useContext,\n  type ReactElement,\n  type ReactNode,\n} from \"react\";\nimport {\n  defaultMessages,\n  resolveMessages,\n  type MessagesSource,\n  type PrimitiveMessages,\n} from \"../core/messages.js\";\n\nconst MessagesContext = createContext<PrimitiveMessages>(defaultMessages);\n\nexport interface MessagesProviderProps {\n  readonly messages?: MessagesSource | null;\n  readonly children: ReactNode;\n}\n\nexport const MessagesProvider = ({\n  messages,\n  children,\n}: MessagesProviderProps): ReactElement => {\n  const inherited = useContext(MessagesContext);\n  return (\n    <MessagesContext.Provider value={resolveMessages(messages, inherited)}>\n      {children}\n    </MessagesContext.Provider>\n  );\n};\n\nexport const useMessages = (): PrimitiveMessages => useContext(MessagesContext);\n"
    },
    {
      "path": "packages/primitives/src/components/Spinner.tsx",
      "target": "@ui/gpuixui/primitives/components/Spinner.tsx",
      "type": "registry:component",
      "content": "/** @jsxImportSource @gpuix/react */\nimport type { ReactElement } from \"react\";\nimport type { StyleDesc } from \"@gpuix/react\";\nimport * as Arr from \"effect/Array\";\nimport { useMotionPreference } from \"../../motion/react/presence.js\";\nimport { iconPixels } from \"../../icons/index.js\";\nimport { cn } from \"../../tw/index.js\";\nimport {\n  SPINNER_RING_TICKS,\n  STEP_INTERVAL_MS,\n  spinnerTickStyle,\n  spinnerTicks,\n  type SpinnerAccent,\n} from \"../core/loading.js\";\nimport { accessibleName } from \"../core/a11y.js\";\nimport {\n  busyWord,\n  defaultMessages,\n  type PrimitiveMessages,\n} from \"../core/messages.js\";\nimport { reducedMotionOf, stillFrame } from \"../core/motion.js\";\nimport type { PrimitiveTheme } from \"../core/theme.js\";\nimport { spinnerGroupClass } from \"../recipe/index.js\";\nimport { recipeTw } from \"../recipe/registry.js\";\nimport { mergeStyle, useStep, type ElementHostProps } from \"./internal.js\";\nimport { useMessages } from \"./MessagesProvider.js\";\nimport { useTheme } from \"./ThemeProvider.js\";\n\nexport interface SpinnerProps extends ElementHostProps {\n  readonly size?: keyof PrimitiveTheme[\"iconSize\"] | number;\n\n  readonly accent?: SpinnerAccent;\n\n  readonly label?: string;\n\n  readonly reducedMotion?: boolean;\n  readonly style?: StyleDesc;\n\n  readonly className?: string;\n  readonly testId?: string;\n}\n\nexport const renderSpinner = (\n  {\n    size,\n    accent = \"primary\",\n    label,\n    reducedMotion,\n    style,\n    className,\n    testId,\n    ref,\n    \"aria-id\": controlId,\n    onLayout,\n  }: SpinnerProps,\n  theme: PrimitiveTheme,\n  step: number,\n  messages: PrimitiveMessages = defaultMessages,\n): ReactElement => {\n  const side = iconPixels(size ?? \"md\");\n  const ring = mergeStyle(\n    recipeTw.classesToStyle(cn(spinnerGroupClass, className), theme).style,\n    mergeStyle({ width: side, height: side }, style),\n  );\n\n  const name = accessibleName(label ?? busyWord(messages.loading));\n  return (\n    <div\n      ref={ref}\n      role={name === undefined ? \"presentation\" : \"status\"}\n      aria-label={name}\n      aria-id={controlId}\n      onLayout={onLayout}\n      testId={testId}\n      style={ring}\n    >\n      {Arr.map(\n        spinnerTicks(stillFrame(step, reducedMotion), side),\n        (tick, index) => (\n          <div\n            key={index}\n            style={spinnerTickStyle({ size: side, accent }, tick, theme)}\n          />\n        ),\n      )}\n    </div>\n  );\n};\n\nexport const Spinner = (props: SpinnerProps): ReactElement => {\n  const reducedMotion = reducedMotionOf(\n    props.reducedMotion,\n    useMotionPreference(),\n  );\n  return renderSpinner(\n    { ...props, reducedMotion },\n    useTheme(),\n\n    useStep(SPINNER_RING_TICKS, STEP_INTERVAL_MS, !reducedMotion),\n    useMessages(),\n  );\n};\n"
    },
    {
      "path": "packages/primitives/src/components/Text.tsx",
      "target": "@ui/gpuixui/primitives/components/Text.tsx",
      "type": "registry:component",
      "content": "/** @jsxImportSource @gpuix/react */\nimport type { ReactElement, ReactNode } from \"react\";\nimport type { StyleDesc } from \"@gpuix/react\";\nimport { cn } from \"../../tw/index.js\";\nimport type { TextAlign, TextTone } from \"../core/style.js\";\nimport type { PrimitiveTheme, TextRole } from \"../core/theme.js\";\nimport { textClass } from \"../recipe/index.js\";\nimport { recipeTw } from \"../recipe/registry.js\";\nimport { childrenName, mergeStyle, type ElementHostProps } from \"./internal.js\";\nimport { useTheme } from \"./ThemeProvider.js\";\n\nexport interface TextProps extends ElementHostProps {\n  readonly role?: TextRole;\n\n  readonly tone?: TextTone;\n  readonly align?: TextAlign;\n\n  readonly truncate?: boolean;\n\n  readonly clamp?: number;\n\n  readonly selectable?: boolean;\n  readonly style?: StyleDesc;\n\n  readonly className?: string;\n\n  readonly testId?: string;\n  readonly children?: ReactNode;\n}\n\nconst semanticsOf = (\n  role: TextRole,\n): { readonly role?: string; readonly level?: number } =>\n  role === \"h1\"\n    ? { role: \"heading\", level: 1 }\n    : role === \"h2\"\n      ? { role: \"heading\", level: 2 }\n      : role === \"h3\"\n        ? { role: \"heading\", level: 3 }\n        : role === \"code\" || role === \"codeBlock\"\n          ? { role: \"code\" }\n          : {};\n\nexport const renderText = (\n  {\n    role = \"body\",\n    tone = \"default\",\n    align,\n    truncate,\n    clamp,\n    selectable,\n    style,\n    className,\n    testId,\n    ref,\n    \"aria-id\": controlId,\n    onLayout,\n    children,\n  }: TextProps,\n  theme: PrimitiveTheme,\n): ReactElement => {\n  const resolved = recipeTw.classesToStyle(\n    cn(\n      textClass({ role, tone, align, truncate, clamp, selectable }),\n      className,\n    ),\n    theme,\n  );\n  const semantics = semanticsOf(role);\n  return (\n    <text\n      ref={ref}\n      testId={testId}\n      role={semantics.role}\n      aria-level={semantics.level}\n      aria-id={controlId}\n      aria-label={\n        semantics.role === undefined ? undefined : childrenName(children)\n      }\n      onLayout={onLayout}\n      style={mergeStyle(resolved.style, style)}\n    >\n      {children}\n    </text>\n  );\n};\n\nexport const Text = (props: TextProps): ReactElement =>\n  renderText(props, useTheme());\n"
    },
    {
      "path": "packages/primitives/src/components/ThemeProvider.tsx",
      "target": "@ui/gpuixui/primitives/components/ThemeProvider.tsx",
      "type": "registry:component",
      "content": "/** @jsxImportSource @gpuix/react */\nimport type { ReactElement, ReactNode } from \"react\";\nimport {\n  ThemeProvider as TokensThemeProvider,\n  useTheme as useTokensTheme,\n  useThemePresence,\n} from \"../../tokens/react.js\";\nimport type { MessagesSource } from \"../core/messages.js\";\nimport type { Density, PrimitiveTheme } from \"../core/index.js\";\nimport { withDensity } from \"./internal.js\";\nimport { MessagesProvider } from \"./MessagesProvider.js\";\n\nexport class MissingThemeProviderError extends Error {\n  constructor() {\n    super(\n      \"useTheme() found no <ThemeProvider>. GPUIxUI primitives never fall back \" +\n        \"to a default palette; wrap the tree in <ThemeProvider theme={theme}> \" +\n        \"from this package or from @gpuixui/tokens/react.\",\n    );\n    this.name = \"MissingThemeProviderError\";\n  }\n}\n\nexport interface ThemeProviderProps {\n  readonly theme: PrimitiveTheme;\n\n  readonly density?: Density | null;\n\n  readonly messages?: MessagesSource | null;\n  readonly children: ReactNode;\n}\n\nexport const ThemeProvider = ({\n  theme,\n  density,\n  messages,\n  children,\n}: ThemeProviderProps): ReactElement => (\n  <TokensThemeProvider theme={withDensity(theme, density)}>\n    <MessagesProvider messages={messages}>{children}</MessagesProvider>\n  </TokensThemeProvider>\n);\n\nexport const useTheme = (): PrimitiveTheme => {\n  const theme = useTokensTheme();\n  if (!useThemePresence()) throw new MissingThemeProviderError();\n  return theme;\n};\n"
    },
    {
      "path": "packages/primitives/src/components/Toggle.tsx",
      "target": "@ui/gpuixui/primitives/components/Toggle.tsx",
      "type": "registry:component",
      "content": "/** @jsxImportSource @gpuix/react */\nimport type { ReactElement, ReactNode } from \"react\";\nimport type { EventPayload, KeyEvent } from \"@gpuix/react\";\nimport { resolveStyle, type StateStyle } from \"@gpuix/react/floating\";\nimport { cn } from \"../../tw/index.js\";\nimport { useMotionPreference } from \"../../motion/react/presence.js\";\nimport { accessibleName } from \"../core/a11y.js\";\nimport { controlRing } from \"../core/focus.js\";\nimport { reducedMotionOf } from \"../core/motion.js\";\nimport {\n  decideActivation,\n  isPlainKey,\n  swallowKeyDefault,\n} from \"../core/keyboard.js\";\nimport {\n  busyWord,\n  defaultMessages,\n  pressWord,\n  type PressWords,\n  type PrimitiveMessages,\n} from \"../core/messages.js\";\nimport { controlSize, iconSideOf } from \"../core/theme.js\";\nimport type { ControlSize, PrimitiveTheme } from \"../core/theme.js\";\nimport type { ToggleVariant } from \"../core/variants.js\";\nimport type { ValueState } from \"../core/state.js\";\nimport { toggleClass } from \"../recipe/index.js\";\nimport { toggleSpinnerAccent } from \"../core/variants.js\";\nimport { recipeTw } from \"../recipe/registry.js\";\nimport {\n  childrenName,\n  composeEvent,\n  composePress,\n  mergeStyle,\n  suppressFeedback,\n  useControlState,\n  useFocus,\n  type FieldHostProps,\n  type FocusState,\n  type HelpProps,\n  type InteractionProps,\n  type TooltipTriggerProps,\n} from \"./internal.js\";\nimport { Spinner } from \"./Spinner.js\";\nimport { useMessages } from \"./MessagesProvider.js\";\nimport { useTheme } from \"./ThemeProvider.js\";\n\nexport interface ToggleProps\n  extends InteractionProps, TooltipTriggerProps, FieldHostProps, HelpProps {\n  readonly pressed?: boolean;\n  readonly defaultPressed?: boolean;\n  readonly onPressedChange?: (pressed: boolean) => void;\n\n  readonly variant?: ToggleVariant;\n\n  readonly size?: ControlSize;\n\n  readonly square?: boolean;\n  readonly disabled?: boolean;\n\n  readonly loading?: boolean;\n\n  readonly loadingLabel?: string;\n\n  readonly reducedMotion?: boolean;\n  readonly leading?: ReactNode;\n  readonly trailing?: ReactNode;\n\n  readonly label?: string;\n\n  readonly style?: StateStyle<ToggleState>;\n\n  readonly className?: string;\n  readonly children?: ReactNode;\n  readonly testId?: string;\n}\n\nexport const pressedValueText = (\n  pressed: boolean,\n  words: PressWords = defaultMessages.press,\n): string => pressWord(pressed, words);\n\nexport interface ToggleState {\n  readonly disabled: boolean;\n  readonly focused: boolean;\n  readonly selected: boolean;\n}\n\nexport const renderToggle = (\n  props: ToggleProps,\n  theme: PrimitiveTheme,\n  state: ValueState<boolean>,\n  focus: FocusState,\n  onPressedChange: (pressed: boolean) => void,\n  messages: PrimitiveMessages = defaultMessages,\n): ReactElement => {\n  const { variant = \"default\" } = props;\n  const size = controlSize(props.size);\n  const busy = props.disabled === true || props.loading === true;\n\n  const loadingWord = props.loadingLabel ?? busyWord(messages.loading);\n  const toggle = (): void => {\n    if (busy) return;\n    onPressedChange(!state.current);\n  };\n  const onKey =\n    (phase: \"down\" | \"up\") =>\n    (event: KeyEvent): void => {\n      if (!isPlainKey(event.modifiers)) return;\n      if (swallowKeyDefault(event.key ?? \"\", phase)) event.preventDefault();\n      if (decideActivation(event.key ?? \"\", phase, event.isHeld === true))\n        toggle();\n    };\n  const resolved = recipeTw.classesToStyle(\n    cn(\n      toggleClass(variant, state.current, size, { square: props.square }),\n      props.className,\n    ),\n    theme,\n  );\n  let style = resolved.style;\n  if (props.disabled === true) {\n    style = suppressFeedback(mergeStyle(style, resolved.disabled));\n  }\n  style = mergeStyle(style, controlRing(theme, { disabled: props.disabled }));\n  style = mergeStyle(\n    style,\n    resolveStyle(props.style, {\n      disabled: busy,\n      focused: focus.focused,\n      selected: state.current,\n    }),\n  );\n  return (\n    <div\n      ref={props.ref}\n      role=\"button\"\n      aria-label={accessibleName(props.label) ?? childrenName(props.children)}\n      aria-description={\n        props.loading === true\n          ? accessibleName(loadingWord)\n          : (accessibleName(props.description) ??\n            accessibleName(props[\"aria-description\"]))\n      }\n      aria-id={props[\"aria-id\"]}\n      aria-valuetext={pressedValueText(state.current, messages.press)}\n      tabIndex={props.disabled === true ? undefined : 0}\n      testId={props.testId}\n      onLayout={props.onLayout}\n      onClick={composePress(busy, props.onClick, toggle)}\n      onMouseEnter={props.onMouseEnter}\n      onMouseLeave={props.onMouseLeave}\n      onKeyDown={composeEvent<KeyEvent>(props.onKeyDown, onKey(\"down\"))}\n      onKeyUp={composeEvent<KeyEvent>(props.onKeyUp, onKey(\"up\"))}\n      onFocus={composeEvent<EventPayload>(props.onFocus, focus.onFocus)}\n      onBlur={composeEvent<EventPayload>(props.onBlur, focus.onBlur)}\n      style={style}\n    >\n      {props.loading === true ? (\n        <Spinner\n          size={iconSideOf(theme, \"sm\")}\n          accent={toggleSpinnerAccent(state.current, props.disabled === true)}\n          label={loadingWord}\n          reducedMotion={props.reducedMotion}\n        />\n      ) : (\n        props.leading\n      )}\n      {props.children}\n      {props.trailing}\n    </div>\n  );\n};\n\nexport const Toggle = (props: ToggleProps): ReactElement => {\n  const theme = useTheme();\n  const messages = useMessages();\n  const focus = useFocus();\n  const state = useControlState(\n    props.pressed,\n    props.defaultPressed ?? false,\n    props.onPressedChange,\n  );\n\n  const reducedMotion = reducedMotionOf(\n    props.reducedMotion,\n    useMotionPreference(),\n  );\n  return renderToggle(\n    { ...props, reducedMotion },\n    theme,\n    state.value,\n    focus,\n    state.set,\n    messages,\n  );\n};\n"
    },
    {
      "path": "packages/primitives/src/components/ToggleGroup.tsx",
      "target": "@ui/gpuixui/primitives/components/ToggleGroup.tsx",
      "type": "registry:component",
      "content": "/** @jsxImportSource @gpuix/react */\nimport type { ReactElement, ReactNode } from \"react\";\nimport * as Arr from \"effect/Array\";\nimport * as Option from \"effect/Option\";\nimport * as P from \"effect/Predicate\";\nimport type { EventPayload, KeyEvent } from \"@gpuix/react\";\nimport { resolveStyle, type StateStyle } from \"@gpuix/react/floating\";\nimport { cn } from \"../../tw/index.js\";\nimport { accessibleName } from \"../core/a11y.js\";\nimport { controlRing } from \"../core/focus.js\";\nimport {\n  decideAbsolute,\n  decideActivation,\n  decideMove,\n  isPlainKey,\n  orientationOf,\n  swallowKeyDefault,\n} from \"../core/keyboard.js\";\nimport { rovingIndex } from \"../core/roving.js\";\nimport { defaultMessages, type PrimitiveMessages } from \"../core/messages.js\";\nimport { toggleSelection } from \"../core/selection.js\";\nimport { controlSize } from \"../core/theme.js\";\nimport type { ControlSize, PrimitiveTheme } from \"../core/theme.js\";\nimport type { ToggleVariant } from \"../core/variants.js\";\nimport { stackClass, toggleClass } from \"../recipe/index.js\";\nimport { recipeTw } from \"../recipe/registry.js\";\nimport { pressedValueText } from \"./Toggle.js\";\nimport {\n  focusedOption,\n  groupOptions,\n  optionBody,\n  optionDisabled,\n  optionHelp,\n  optionItems,\n  optionName,\n  useRovingFocus,\n  useTypeAhead,\n  type GroupFocus,\n  type GroupHandlers,\n  type GroupItemProps,\n  type GroupKeys,\n  type GroupOption,\n} from \"./group.js\";\nimport {\n  composeEvent,\n  composePress,\n  mergeRefs,\n  mergeStyle,\n  suppressFeedback,\n  useControlState,\n  type FieldHostProps,\n  type HelpProps,\n  type InteractionProps,\n} from \"./internal.js\";\nimport { useMessages } from \"./MessagesProvider.js\";\nimport { useTheme } from \"./ThemeProvider.js\";\n\nexport const TOGGLE_GROUP_MODES = [\"single\", \"multiple\"] as const;\nexport type ToggleGroupMode = (typeof TOGGLE_GROUP_MODES)[number];\n\nexport type ToggleGroupOption = GroupOption;\n\nexport type ToggleGroupItemProps = GroupItemProps;\n\nexport const ToggleGroupItem = (_props: ToggleGroupItemProps): null => null;\n\nexport const toggleGroupItems = (props: {\n  readonly options?: ReadonlyArray<ToggleGroupOption>;\n  readonly children?: ReactNode;\n}): ReadonlyArray<ToggleGroupOption> =>\n  props.options === undefined || props.options === null\n    ? optionItems(props.children, ToggleGroupItem)\n    : groupOptions(props.options);\n\nexport const toggleGroupValues = (value: unknown): ReadonlyArray<string> =>\n  P.isString(value)\n    ? value === \"\"\n      ? []\n      : [value]\n    : Arr.isArray(value)\n      ? Arr.filter(value, P.isString)\n      : [];\n\nconst storedSelection = (\n  value: unknown,\n): Option.Option<ReadonlyArray<string>> =>\n  P.isString(value) || Arr.isArray(value)\n    ? Option.some(toggleGroupValues(value))\n    : Option.none();\n\nexport function toggleGroupValue(\n  mode: \"single\",\n  values: ReadonlyArray<string>,\n): string;\nexport function toggleGroupValue(\n  mode: \"multiple\",\n  values: ReadonlyArray<string>,\n): ReadonlyArray<string>;\nexport function toggleGroupValue(\n  mode: ToggleGroupMode,\n  values: ReadonlyArray<string>,\n): string | ReadonlyArray<string> {\n  return mode === \"single\" ? (values[0] ?? \"\") : values;\n}\n\ninterface ToggleGroupBase extends InteractionProps, FieldHostProps, HelpProps {\n  readonly options?: ReadonlyArray<ToggleGroupOption>;\n\n  readonly children?: ReactNode;\n\n  readonly orientation?: \"vertical\" | \"horizontal\";\n\n  readonly variant?: ToggleVariant;\n\n  readonly size?: ControlSize;\n\n  readonly square?: boolean;\n\n  readonly disabled?: boolean;\n\n  readonly label?: string;\n\n  readonly style?: StateStyle<ToggleGroupState>;\n\n  readonly itemStyle?: StateStyle<ToggleItemState>;\n\n  readonly className?: string;\n\n  readonly testId?: string;\n\n  readonly itemTestId?: (value: string) => string;\n}\n\nexport interface SingleToggleGroupProps extends ToggleGroupBase {\n  readonly type: \"single\";\n\n  readonly value?: string;\n  readonly defaultValue?: string;\n  readonly onValueChange?: (next: string) => void;\n}\n\nexport interface MultipleToggleGroupProps extends ToggleGroupBase {\n  readonly type?: \"multiple\";\n\n  readonly value?: ReadonlyArray<string>;\n  readonly defaultValue?: ReadonlyArray<string>;\n  readonly onValueChange?: (next: ReadonlyArray<string>) => void;\n}\n\nexport type ToggleGroupProps =\n  | SingleToggleGroupProps\n  | MultipleToggleGroupProps;\n\nexport interface ToggleGroupState {\n  readonly disabled: boolean;\n\n  readonly focused: boolean;\n}\n\nexport interface ToggleItemState {\n  readonly disabled: boolean;\n  readonly focused: boolean;\n  readonly pressed: boolean;\n}\n\nexport interface ToggleGroupHandlers extends GroupHandlers, GroupKeys {\n  readonly onToggle: (value: string) => void;\n}\n\nexport const renderToggleGroup = (\n  props: ToggleGroupProps,\n  theme: PrimitiveTheme,\n  values: ReadonlyArray<string>,\n  preferredIndex: Option.Option<number>,\n  focus: GroupFocus,\n  handlers: ToggleGroupHandlers,\n  messages: PrimitiveMessages = defaultMessages,\n): ReactElement => {\n  const { variant = \"default\", square = false } = props;\n\n  const orientation = orientationOf(props.orientation, \"horizontal\");\n  const size = controlSize(props.size);\n  const options = toggleGroupItems(props);\n  const count = Arr.length(options);\n  const isDisabled = optionDisabled(options, props.disabled);\n\n  const focused = focusedOption(count, focus.focusedIndex);\n\n  const activeIndex = rovingIndex(count, preferredIndex, isDisabled);\n  const toggle = (index: number): void => {\n    const option = options[index];\n    if (option === undefined || isDisabled(index)) return;\n    handlers.onToggle(option.value);\n  };\n  const focusMove = (index: number): true => {\n    handlers.onFocusMove(index);\n    return true;\n  };\n  const move = (key: string): boolean =>\n    Option.match(activeIndex, {\n      onNone: () => false,\n      onSome: (index) =>\n        Option.match(decideMove(index, count, key, orientation, isDisabled), {\n          onNone: () => false,\n          onSome: focusMove,\n        }),\n    });\n  const jump = (key: string): boolean =>\n    Option.match(decideAbsolute(count, key, isDisabled), {\n      onNone: () => false,\n      onSome: focusMove,\n    });\n  const activate = (): void => {\n    Option.match(activeIndex, { onNone: () => {}, onSome: toggle });\n  };\n  const onKeyDown = (event: KeyEvent): void => {\n    if (!isPlainKey(event.modifiers)) return;\n    const key = event.key ?? \"\";\n    if (swallowKeyDefault(key, \"down\")) event.preventDefault();\n    if (move(key) || jump(key)) return;\n\n    const typed = Option.flatMap(\n      Option.all([Option.fromNullishOr(handlers.typeAhead), activeIndex]),\n      ([match, from]) => match(from, key),\n    );\n    if (Option.match(typed, { onNone: () => false, onSome: focusMove })) return;\n    if (decideActivation(key, \"down\", event.isHeld === true)) activate();\n  };\n\n  const onKeyUp = (event: KeyEvent): void => {\n    if (!isPlainKey(event.modifiers)) return;\n    if (decideActivation(event.key ?? \"\", \"up\", false)) activate();\n  };\n  const group = mergeStyle(\n    recipeTw.classesToStyle(\n      cn(\n        stackClass({\n          direction: orientation === \"horizontal\" ? \"row\" : \"column\",\n          gap: \"xs\",\n        }),\n        props.className,\n      ),\n      theme,\n    ).style,\n    resolveStyle(props.style, {\n      disabled: props.disabled === true,\n      focused: Option.isSome(focused),\n    }),\n  );\n  return (\n    <div\n      role=\"group\"\n      aria-label={accessibleName(props.label)}\n      aria-description={accessibleName(props.description)}\n      testId={props.testId}\n      onKeyDown={composeEvent<KeyEvent>(props.onKeyDown, onKeyDown)}\n      onKeyUp={composeEvent<KeyEvent>(props.onKeyUp, onKeyUp)}\n      style={group}\n    >\n      {Arr.map(options, (option, index) => {\n        const disabled = isDisabled(index);\n        const pressed = Arr.contains(values, option.value);\n        const resolved = recipeTw.classesToStyle(\n          toggleClass(variant, pressed, size, { square }),\n          theme,\n        );\n        let style = resolved.style;\n        if (disabled) {\n          style = suppressFeedback(mergeStyle(style, resolved.disabled));\n        }\n        style = mergeStyle(style, controlRing(theme, { disabled }));\n        style = mergeStyle(\n          style,\n          resolveStyle(props.itemStyle, {\n            disabled,\n            focused: Option.contains(focused, index),\n            pressed,\n          }),\n        );\n\n        const addressed = Option.contains(activeIndex, index);\n        const register = handlers.registerItem(index);\n        return (\n          <div\n            key={option.value}\n            ref={addressed ? mergeRefs(register, props.ref) : register}\n            role=\"button\"\n            aria-label={optionName(option)}\n            aria-description={optionHelp(option)}\n            aria-id={addressed ? props[\"aria-id\"] : undefined}\n            aria-valuetext={pressedValueText(pressed, messages.press)}\n            testId={props.itemTestId?.(option.value)}\n            tabIndex={\n              disabled\n                ? undefined\n                : Option.contains(activeIndex, index)\n                  ? 0\n                  : -1\n            }\n            onLayout={addressed ? props.onLayout : undefined}\n            onClick={composePress(disabled, props.onClick, () => {\n              toggle(index);\n            })}\n            onFocus={composeEvent<EventPayload>(props.onFocus, () =>\n              focus.onFocus(index),\n            )}\n            onBlur={composeEvent<EventPayload>(props.onBlur, () =>\n              focus.onBlur(index),\n            )}\n            style={style}\n          >\n            {optionBody(option, disabled, theme)}\n          </div>\n        );\n      })}\n    </div>\n  );\n};\n\nexport const ToggleGroup = (props: ToggleGroupProps): ReactElement => {\n  const theme = useTheme();\n  const messages = useMessages();\n  const focus = useRovingFocus();\n  const mode = props.type ?? \"multiple\";\n\n  const notify = (next: ReadonlyArray<string>): void => {\n    if (props.type === \"single\")\n      props.onValueChange?.(toggleGroupValue(\"single\", next));\n    else props.onValueChange?.(toggleGroupValue(\"multiple\", next));\n  };\n  const selected = useControlState<ReadonlyArray<string>>(\n    Option.getOrUndefined(storedSelection(props.value)),\n    Option.getOrElse(storedSelection(props.defaultValue), () => []),\n    notify,\n  );\n  const options = toggleGroupItems(props);\n  const typeAhead = useTypeAhead(\n    options,\n    optionDisabled(options, props.disabled),\n  );\n  const preferred: Option.Option<number> = Option.firstSomeOf([\n    focus.focusedIndex,\n    Arr.findFirstIndex(options, (option) =>\n      Arr.contains(selected.value.current, option.value),\n    ),\n  ]);\n  return renderToggleGroup(\n    props,\n    theme,\n    selected.value.current,\n    preferred,\n    focus,\n    {\n      onToggle: (value) =>\n        selected.set(toggleSelection(mode, selected.value.current, value)),\n      onFocusMove: focus.onFocusMove,\n      registerItem: focus.registerItem,\n      typeAhead,\n    },\n    messages,\n  );\n};\n"
    },
    {
      "path": "packages/primitives/src/components/group.tsx",
      "target": "@ui/gpuixui/primitives/components/group.tsx",
      "type": "registry:component",
      "content": "/** @jsxImportSource @gpuix/react */\nimport {\n  Children,\n  Fragment,\n  isValidElement,\n  useEffect,\n  useRef,\n  useState,\n  type ComponentType,\n  type ReactElement,\n  type ReactNode,\n} from \"react\";\nimport * as Arr from \"effect/Array\";\nimport * as Option from \"effect/Option\";\nimport * as P from \"effect/Predicate\";\nimport { useGpuix } from \"@gpuix/react\";\nimport type { PublicInstance, StyleDesc } from \"@gpuix/react\";\nimport { targetSize } from \"../../tokens/index.js\";\nimport { accessibleName, visibleCopy } from \"../core/a11y.js\";\nimport { controlRing } from \"../core/focus.js\";\nimport { storedList, storedText } from \"../core/stored.js\";\nimport {\n  decideTypeAhead,\n  isTypeAheadKey,\n  TYPE_AHEAD_RESET_MS,\n} from \"../core/keyboard.js\";\nimport type { PrimitiveTheme } from \"../core/theme.js\";\nimport { recipeTw } from \"../recipe/registry.js\";\nimport { mergeStyle } from \"./internal.js\";\nimport { Text } from \"./Text.js\";\n\nexport interface GroupOption {\n  readonly value: string;\n  readonly label: string;\n  readonly description?: string;\n  readonly disabled?: boolean;\n\n  readonly content?: ReactNode;\n}\n\nexport interface GroupItemProps {\n  readonly value: string;\n\n  readonly label: string;\n  readonly description?: string;\n  readonly disabled?: boolean;\n\n  readonly children?: ReactNode;\n}\n\nexport const optionItems = <Props extends GroupItemProps>(\n  children: ReactNode,\n  Item: ComponentType<Props>,\n): ReadonlyArray<GroupOption> =>\n  Arr.flatMap(Children.toArray(children), (child) => {\n    if (!isValidElement<Props>(child)) return [];\n    if (child.type === Fragment) return optionItems(child.props.children, Item);\n    if (child.type !== Item) return [];\n    return [\n      {\n        value: child.props.value,\n        label: child.props.label,\n        description: child.props.description,\n        disabled: child.props.disabled,\n        content: child.props.children,\n      },\n    ];\n  });\n\nconst storedContent = (value: unknown): ReactNode | undefined =>\n  isValidElement(value) || P.isString(value) || P.isNumber(value)\n    ? value\n    : undefined;\n\nconst storedOption = (entry: unknown): Option.Option<GroupOption> => {\n  if (!P.isObject(entry)) return Option.none();\n  const value = storedText(entry[\"value\"]);\n  if (value === undefined) return Option.none();\n  const description = storedText(entry[\"description\"]);\n  const content = storedContent(entry[\"content\"]);\n  return Option.some({\n    value,\n\n    label: storedText(entry[\"label\"]) ?? \"\",\n    disabled: entry[\"disabled\"] === true,\n    ...(description === undefined ? {} : { description }),\n    ...(content === undefined ? {} : { content }),\n  });\n};\n\nexport const groupOptions = (value: unknown): ReadonlyArray<GroupOption> =>\n  storedList(value, storedOption);\n\nexport const optionName = (option: GroupOption): string | undefined =>\n  accessibleName(option.label);\n\nexport const optionHelp = (option: GroupOption): string | undefined =>\n  accessibleName(option.description);\n\nexport const optionBody = (\n  option: GroupOption,\n  disabled: boolean,\n  theme: PrimitiveTheme,\n): ReactElement => {\n  const caption = visibleCopy(option.description);\n  return (\n    <div\n      style={\n        recipeTw.classesToStyle(\"flex flex-row items-center gap-sm\", theme)\n          .style\n      }\n    >\n      {option.content === undefined ? (\n        <>\n          <Text role=\"label\" tone={disabled ? \"muted\" : \"default\"}>\n            {option.label}\n          </Text>\n          {caption === undefined ? null : (\n            <Text role=\"caption\" tone=\"muted\">\n              {caption}\n            </Text>\n          )}\n        </>\n      ) : (\n        option.content\n      )}\n    </div>\n  );\n};\n\nexport const optionRowClass = (disabled: boolean): string =>\n  `flex flex-row items-center gap-sm ${disabled ? \"cursor-not-allowed\" : \"cursor-pointer\"}`;\n\nexport const optionRowStyle = (\n  state: { readonly disabled: boolean; readonly invalid?: boolean },\n  theme: PrimitiveTheme,\n): StyleDesc =>\n  mergeStyle(\n    mergeStyle(\n      recipeTw.classesToStyle(optionRowClass(state.disabled), theme).style,\n      controlRing(theme, {\n        disabled: state.disabled,\n        invalid: state.invalid,\n      }),\n    ),\n    { minHeight: targetSize.minimum },\n  );\n\nexport interface GroupFocus {\n  readonly focusedIndex: Option.Option<number>;\n  readonly onFocus: (index: number) => void;\n\n  readonly onBlur: (index: number) => void;\n}\n\nexport interface GroupHandlers {\n  readonly onFocusMove: (index: number) => void;\n\n  readonly registerItem: (\n    index: number,\n  ) => (instance: PublicInstance | null) => void;\n}\n\nexport type TypeAhead = (from: number, key: string) => Option.Option<number>;\n\nexport interface GroupKeys {\n  readonly typeAhead?: TypeAhead;\n}\n\nexport const optionDisabled =\n  (\n    options: ReadonlyArray<GroupOption>,\n    groupDisabled: boolean | undefined,\n  ): ((index: number) => boolean) =>\n  (index) =>\n    groupDisabled === true || options[index]?.disabled === true;\n\nexport const focusedOption = (\n  count: number,\n  focused: Option.Option<number>,\n): Option.Option<number> =>\n  Option.filter(focused, (index) => index >= 0 && index < count);\n\nexport const useTypeAhead = (\n  options: ReadonlyArray<GroupOption>,\n  isDisabled: (index: number) => boolean,\n): TypeAhead => {\n  const buffer = useRef(\"\");\n\n  const reset = useRef<Option.Option<ReturnType<typeof setTimeout>>>(\n    Option.none(),\n  );\n  const cancel = (): void =>\n    Option.match(reset.current, {\n      onNone: () => {},\n      onSome: clearTimeout,\n    });\n  useEffect(\n    () => () => {\n      cancel();\n    },\n    [],\n  );\n  return (from, key) => {\n    if (!isTypeAheadKey(key)) return Option.none();\n    buffer.current = `${buffer.current}${key}`;\n    cancel();\n    reset.current = Option.some(\n      setTimeout(() => {\n        buffer.current = \"\";\n      }, TYPE_AHEAD_RESET_MS),\n    );\n    return decideTypeAhead(\n      Arr.map(options, (option) => option.label),\n      from,\n      buffer.current,\n      isDisabled,\n    );\n  };\n};\n\nexport interface RovingFocus extends GroupFocus, GroupHandlers {}\n\nexport const useRovingFocus = (): RovingFocus => {\n  const { renderer } = useGpuix();\n  const [focusedIndex, setFocusedIndex] = useState<Option.Option<number>>(\n    Option.none(),\n  );\n  const ids = useRef<Map<number, number>>(new Map());\n  return {\n    focusedIndex,\n    onFocus: (index) => setFocusedIndex(Option.some(index)),\n    onBlur: (index) =>\n      setFocusedIndex((current) =>\n        Option.filter(current, (focused) => focused !== index),\n      ),\n    registerItem: (index) => (instance) => {\n      if (instance === null) ids.current.delete(index);\n      else ids.current.set(index, instance.id);\n    },\n    onFocusMove: (index) =>\n      Option.match(\n        Option.all({\n          id: Option.fromNullishOr(ids.current.get(index)),\n          target: Option.fromNullishOr(renderer),\n        }),\n        {\n          onNone: () => {},\n\n          onSome: ({ id, target }) => {\n            target.focusElement?.(id);\n            setFocusedIndex(Option.some(index));\n          },\n        },\n      ),\n  };\n};\n"
    },
    {
      "path": "packages/primitives/src/components/internal.ts",
      "target": "@ui/gpuixui/primitives/components/internal.ts",
      "type": "registry:lib",
      "content": "import {\n  Children,\n  createContext,\n  useEffect,\n  useState,\n  type ReactNode,\n  type Ref,\n} from \"react\";\nimport * as Arr from \"effect/Array\";\nimport * as Option from \"effect/Option\";\nimport type {\n  EventPayload,\n  KeyEvent,\n  Props,\n  PublicInstance,\n  StyleDesc,\n} from \"@gpuix/react\";\nimport {\n  initValueState,\n  setValue,\n  withValue,\n  type ValueState,\n} from \"../core/state.js\";\nimport type { Density, PrimitiveTheme } from \"../core/theme.js\";\n\nexport const childrenName = (children: ReactNode): string | undefined => {\n  const text = Children.toArray(children)\n    .filter(\n      (child): child is string | number =>\n        typeof child === \"string\" || typeof child === \"number\",\n    )\n    .join(\" \")\n    .trim();\n  return text === \"\" ? undefined : text;\n};\n\nexport const mergeStyle = (\n  base: StyleDesc,\n  override: StyleDesc | undefined,\n): StyleDesc => (override === undefined ? base : { ...base, ...override });\n\nexport interface InteractionProps {\n  readonly onClick?: (event: EventPayload) => void;\n  readonly onKeyDown?: (event: KeyEvent) => void;\n  readonly onKeyUp?: (event: KeyEvent) => void;\n  readonly onFocus?: (event: EventPayload) => void;\n  readonly onBlur?: (event: EventPayload) => void;\n}\n\nexport interface ElementHostProps {\n  readonly ref?: Ref<PublicInstance>;\n\n  readonly \"aria-id\"?: string;\n\n  readonly onLayout?: (event: EventPayload) => void;\n}\n\nexport type FieldHostProps = ElementHostProps;\n\nexport interface HelpProps {\n  readonly description?: string;\n}\n\nexport const mergeRefs = <Instance>(\n  ...refs: ReadonlyArray<Ref<Instance> | undefined>\n): ((instance: Instance | null) => void) => {\n  return (instance) => {\n    Arr.forEach(refs, (ref) => {\n      if (ref === undefined || ref === null) return;\n      if (typeof ref === \"function\") ref(instance);\n      else ref.current = instance;\n    });\n  };\n};\n\nexport const AttachedGroup = createContext(false);\n\nexport type ActionHostProps = Omit<\n  Props,\n  | \"key\"\n  | \"children\"\n  | \"style\"\n  | \"role\"\n  | \"tabIndex\"\n  | \"aria-label\"\n  | \"aria-description\"\n  | \"motion\"\n  | \"testId\"\n  | \"onClick\"\n  | \"onKeyDown\"\n  | \"onKeyUp\"\n  | \"onFocus\"\n  | \"onBlur\"\n  | \"onMouseEnter\"\n  | \"onMouseLeave\"\n>;\n\nexport interface TooltipTriggerProps {\n  readonly onMouseEnter?: (event: EventPayload) => void;\n  readonly onMouseLeave?: (event: EventPayload) => void;\n  readonly \"aria-description\"?: string;\n}\n\nexport const composeEvent = <Event>(\n  caller: ((event: Event) => void) | undefined,\n  internal: ((event: Event) => void) | undefined,\n): ((event: Event) => void) | undefined =>\n  caller === undefined\n    ? internal\n    : internal === undefined\n      ? caller\n      : (event) => {\n          caller(event);\n          internal(event);\n        };\n\nexport const composePress = (\n  blocked: boolean,\n  caller: ((event: EventPayload) => void) | undefined,\n  action: (event: EventPayload) => void,\n): ((event: EventPayload) => void) | undefined =>\n  blocked\n    ? undefined\n    : (event) => {\n        caller?.(event);\n        action(event);\n      };\n\nexport const suppressFeedback = (style: StyleDesc): StyleDesc => ({\n  ...style,\n  hover: { backgroundColor: style.backgroundColor },\n  active: { backgroundColor: style.backgroundColor },\n});\n\nexport const suppressSelectionFeedback = (style: StyleDesc): StyleDesc => ({\n  ...style,\n  hover: {\n    backgroundColor: style.backgroundColor,\n    borderColor: style.borderColor,\n  },\n  active: {},\n});\n\nexport const decorative = (style: StyleDesc): StyleDesc =>\n  mergeStyle(style, { pointerEvents: \"none\" });\n\nexport const withDensity = (\n  theme: PrimitiveTheme,\n  density: Density | null | undefined,\n): PrimitiveTheme =>\n  density === null || density === undefined ? theme : { ...theme, density };\n\nexport interface FocusState {\n  readonly focused: boolean;\n  readonly onFocus: () => void;\n  readonly onBlur: () => void;\n}\n\nexport const useFocus = (): FocusState => {\n  const [focused, setFocused] = useState(false);\n  return {\n    focused,\n    onFocus: () => setFocused(true),\n    onBlur: () => setFocused(false),\n  };\n};\n\nexport interface CheckedChangeProps {\n  readonly onCheckedChange?: (next: boolean) => void;\n\n  readonly onChange?: (next: boolean) => void;\n}\n\nexport const checkedChange = (\n  props: CheckedChangeProps,\n): ((next: boolean) => void) | undefined =>\n  props.onCheckedChange ?? props.onChange;\n\nexport interface ValueChangeProps<Value> {\n  readonly onValueChange?: (next: Value) => void;\n\n  readonly onChange?: (next: Value) => void;\n}\n\nexport const valueChange = <Value>(\n  props: ValueChangeProps<Value>,\n): ((next: Value) => void) | undefined => props.onValueChange ?? props.onChange;\n\nexport interface ControlState<Value> {\n  readonly value: ValueState<Value>;\n  readonly set: (next: Value) => void;\n}\n\nexport const useControlState = <Value>(\n  value: Value | undefined,\n  defaultValue: Value,\n  onChange: ((next: Value) => void) | undefined,\n): ControlState<Value> => {\n  const [state, setState] = useState(() =>\n    initValueState(Option.fromNullishOr(value), defaultValue),\n  );\n  const current = withValue(state, Option.fromNullishOr(value));\n  return {\n    value: current,\n    set: (next) => {\n      const applied = setValue(current, next);\n      setState(applied.state);\n      if (applied.notify) onChange?.(next);\n    },\n  };\n};\n\nexport const useStep = (\n  steps: number,\n  intervalMs: number,\n  running = true,\n): number => {\n  const [step, setStep] = useState(0);\n  useEffect(() => {\n    if (!running) return undefined;\n    const id = setInterval(\n      () => setStep((current) => (current + 1) % steps),\n      intervalMs,\n    );\n    return () => clearInterval(id);\n  }, [steps, intervalMs, running]);\n  return step;\n};\n"
    },
    {
      "path": "packages/primitives/src/core/a11y.ts",
      "target": "@ui/gpuixui/primitives/core/a11y.ts",
      "type": "registry:lib",
      "content": "import * as Option from \"effect/Option\";\nimport * as Str from \"effect/String\";\n\nexport const accessibleName = (label: string | undefined): string | undefined =>\n  Option.getOrUndefined(\n    Option.filter(\n      Option.map(Option.fromNullishOr(label), Str.trim),\n      Str.isNonEmpty,\n    ),\n  );\n\nexport const visibleCopy = (text: string | undefined): string | undefined =>\n  accessibleName(text) === undefined ? undefined : text;\n\nexport const captionCopy = <Child>(\n  children: Child | undefined,\n  label: string | undefined,\n): Child | string | undefined =>\n  typeof children === \"string\"\n    ? (visibleCopy(children) ?? visibleCopy(label))\n    : (children ?? visibleCopy(label));\n\nexport const spokenText = (\n  words: Option.Option<string>,\n  fallback: string,\n): string =>\n  Option.getOrElse(\n    Option.flatMap(words, (word) => Option.fromNullishOr(accessibleName(word))),\n    () => fallback,\n  );\n\nexport const spokenSentence = (answer: string, fallback: string): string =>\n  spokenText(Option.fromNullishOr(answer), fallback);\n\nexport const spokenWord = (\n  word: string | undefined,\n  fallback: string,\n): string => spokenText(Option.fromNullishOr(word), fallback);\n\nexport const fieldHelp = (\n  props: { readonly description?: string; readonly placeholder?: string },\n  value: string,\n): string | undefined =>\n  Option.match(Option.fromNullishOr(accessibleName(props.description)), {\n    onSome: (help) => help,\n    onNone: () =>\n      value.length === 0 ? accessibleName(props.placeholder) : undefined,\n  });\n"
    },
    {
      "path": "packages/primitives/src/core/focus.ts",
      "target": "@ui/gpuixui/primitives/core/focus.ts",
      "type": "registry:lib",
      "content": "import type { StyleDesc } from \"@gpuix/react\";\nimport { controlFocusRing } from \"../../tokens/index.js\";\nimport type { PrimitiveTheme } from \"./theme.js\";\n\nexport const keyboardRing = (\n  theme: PrimitiveTheme,\n  invalid?: boolean,\n): StyleDesc => controlFocusRing(theme, { invalid }) ?? {};\n\nexport const keepContent: StyleDesc = { keyboardFocusDim: false };\n\nexport interface RingState {\n  readonly disabled?: boolean;\n  readonly invalid?: boolean;\n}\n\nexport const controlRing = (\n  theme: PrimitiveTheme,\n  state: RingState = {},\n): StyleDesc => controlFocusRing(theme, state) ?? {};\n"
    },
    {
      "path": "packages/primitives/src/core/index.ts",
      "target": "@ui/gpuixui/primitives/core/index.ts",
      "type": "registry:lib",
      "content": "export { alpha } from \"../../tokens/index.js\";\nexport {\n  accessibleName,\n  fieldHelp,\n  spokenSentence,\n  spokenText,\n  spokenWord,\n  visibleCopy,\n} from \"./a11y.js\";\n\nexport {\n  busyWord,\n  defaultMessages,\n  indeterminateWord,\n  pressWord,\n  rangeThumbNames,\n  resolveMessages,\n  selectionWord,\n  starWord,\n} from \"./messages.js\";\nexport type {\n  LoadingWords,\n  MessagesSource,\n  PressWords,\n  PrimitiveMessages,\n  RangeEndWords,\n  SelectionWords,\n  StarWords,\n} from \"./messages.js\";\n\nexport {\n  decideAbsolute,\n  decideActivation,\n  decideMove,\n  decidePage,\n  decideToggle,\n  decideTypeAhead,\n  ENTER_KEY,\n  isOrientation,\n  isPlainKey,\n  isTypeAheadKey,\n  orientationOf,\n  SPACE_KEY,\n  TYPE_AHEAD_RESET_MS,\n} from \"./keyboard.js\";\nexport type { KeyChord, KeyName, KeyPhase, Orientation } from \"./keyboard.js\";\n\nexport { initValueState, setValue, withValue } from \"./state.js\";\nexport type { ControlMode, ValueState } from \"./state.js\";\n\nexport { rovingIndex } from \"./roving.js\";\n\nexport { SCROLL_END, scrollTarget } from \"./scroll.js\";\nexport type { ScrollMetrics, ScrollOffset } from \"./scroll.js\";\n\nexport {\n  clampNumeric,\n  decideNumberKey,\n  displayNumber,\n  expandedNumber,\n  formatNumber,\n  normalizeNumberRange,\n  numberDisplay,\n  parseNumberText,\n  parseNumericText,\n  SCRUB_PIXELS_PER_STEP,\n  scrubNumber,\n  SHIFT_SCRUB_SCALE,\n  stepNumber,\n} from \"./number.js\";\nexport type { NumberRange, ParseValue } from \"./number.js\";\n\nexport {\n  clampRating,\n  decideRating,\n  pointerRating,\n  ratingTabStop,\n  starCount,\n  starFill,\n  starState,\n} from \"./rating.js\";\nexport type { StarBox, StarState } from \"./rating.js\";\n\nexport {\n  applyOtpInput,\n  DEFAULT_OTP_LENGTH,\n  decideOtpKey,\n  normalizeOtp,\n  otpCellCount,\n  otpCells,\n  otpEmptiedCell,\n  otpLength,\n} from \"./otp.js\";\nexport type { OtpEdit } from \"./otp.js\";\n\nexport {\n  storedList,\n  storedNumber,\n  storedText,\n  storedTextList,\n} from \"./stored.js\";\n\nexport {\n  clampValue,\n  decideValueKey,\n  fractionValue,\n  moveSpanEnd,\n  nearestEnd,\n  normalizeRange,\n  normalizeSpan,\n  pointerValue,\n  spanFrom,\n  stepValue,\n  storedRange,\n  valueFraction,\n  valueStep,\n  verticalPointerValue,\n} from \"./value.js\";\nexport type {\n  StoredRange,\n  TrackBox,\n  ValueRange,\n  ValueSpan,\n  VerticalTrackBox,\n} from \"./value.js\";\n\nexport {\n  boxStyle,\n  gridStyle,\n  isStackDirection,\n  stackDirection,\n  stackStyle,\n  STACK_ALIGNS,\n  STACK_DIRECTIONS,\n  STACK_JUSTIFIES,\n} from \"./layout.js\";\nexport type {\n  BoxSpec,\n  GridSpec,\n  StackAlign,\n  StackDirection,\n  StackJustify,\n  StackSpec,\n} from \"./layout.js\";\n\nexport {\n  isSelectionAccent,\n  radioDotStyle,\n  SELECTION_ACCENTS,\n  SELECTION_STATES,\n  selectionAccentOf,\n  selectionBoxStyle,\n  selectionMarkColor,\n  switchThumbStyle,\n  switchTrackStyle,\n  toggleSelection,\n} from \"./selection.js\";\nexport type {\n  SelectionAccent,\n  SelectionSpec,\n  SelectionState,\n  SwitchPaintTheme,\n} from \"./selection.js\";\n\nexport {\n  indeterminateFillStyle,\n  indeterminateLeadStyle,\n  indeterminateOffset,\n  progressAnimates,\n  PULSE_INTERVAL_MS,\n  PULSE_STEPS,\n  pulseOpacity,\n  skeletonSize,\n  isSpinnerAccent,\n  skeletonStyle,\n  SPINNER_ACCENTS,\n  SPINNER_ARC_TICKS,\n  SPINNER_FADE_FLOOR,\n  SPINNER_RING_TICKS,\n  SPINNER_SEGMENTS,\n  spinnerAccentOf,\n  spinnerTickStyle,\n  spinnerTicks,\n  STEP_INTERVAL_MS,\n} from \"./loading.js\";\nexport type {\n  SkeletonSpec,\n  SpinnerAccent,\n  SpinnerSpec,\n  SpinnerTick,\n} from \"./loading.js\";\n\nexport { controlRing, keyboardRing, keepContent } from \"./focus.js\";\nexport type { RingState } from \"./focus.js\";\n\nexport { pressWash, primaryButton } from \"./pointer.js\";\n\nexport {\n  BORDER_STYLES,\n  controlFocusStyle,\n  controlStyle,\n  fieldTextStyle,\n  nativeTextFills,\n  nativeTextTheme,\n  numberInputStyle,\n  numberStepperColumnStyle,\n  numberStepperStyle,\n  otpCellStyle,\n  otpGroupStyle,\n  isProgressSize,\n  isProgressTone,\n  isTextAlign,\n  isTextTone,\n  progressFillStyle,\n  progressPercent,\n  progressSizeOf,\n  progressToneOf,\n  progressTrackStyle,\n  PROGRESS_SIZES,\n  ratingStarColor,\n  ratingStarStyle,\n  ratingPartialCellStyle,\n  ratingPartialStyle,\n  PROGRESS_TONES,\n  ruleStyle,\n  SCROLL_AXES,\n  isScrollAxis,\n  scrollAxis,\n  scrollStyle,\n  sliderFillStyle,\n  sliderInset,\n  sliderRailStyle,\n  SLIDER_ORIENTATIONS,\n  sliderThumbStyle,\n  sliderTrackStyle,\n  surfaceStyle,\n  SURFACE_TONES,\n  textAlignOf,\n  textAlignValue,\n  textStyle,\n  TEXT_ALIGNMENTS,\n  textToneOf,\n  TEXT_TONES,\n  toneColor,\n} from \"./style.js\";\nexport type {\n  BorderStyle,\n  ControlSpec,\n  ControlVariant,\n  NativeTextFill,\n  NativeTextTheme,\n  OtpCellSpec,\n  ProgressSize,\n  ProgressSpec,\n  ProgressTone,\n  RatingStarSpec,\n  RuleSpec,\n  ScrollAxis,\n  ScrollSpec,\n  SliderOrientation,\n  SliderSpec,\n  SurfaceSpec,\n  SurfaceTone,\n  TextAlign,\n  TextSpec,\n  TextTone,\n} from \"./style.js\";\n\nexport {\n  actionOnColor,\n  buttonVariants,\n  buttonVariantOf,\n  BUTTON_VARIANTS,\n  fieldVariant,\n  hasPointerFeedback,\n  isButtonVariant,\n  isToggleVariant,\n  TOGGLE_VARIANTS,\n  toggleVariantOf,\n  toggleVariants,\n  variantKey,\n  variantTable,\n} from \"./variants.js\";\nexport type { ButtonVariant, ToggleVariant } from \"./variants.js\";\n\nexport {\n  borderWidthOf,\n  colorRole,\n  colorsOf,\n  controlHeightOf,\n  controlPaddingOf,\n  controlSize,\n  elevationLevel,\n  familyOf,\n  iconSideOf,\n  iconStepValue,\n  isIconStep,\n  isRadiusStep,\n  isSpaceStep,\n  isTextRole,\n  radiusStep,\n  radiusValue,\n  rowHeightOf,\n  spaceStep,\n  spaceValue,\n  typeOf,\n} from \"./theme.js\";\n\nexport type {\n  BorderWidth,\n  BorderWidthSource,\n  ColorRef,\n  ColorSource,\n  ControlSize,\n  Density,\n  DensityName,\n  DensitySource,\n  Elevation,\n  ElevationLevel,\n  FontWeight,\n  IconSizeSource,\n  PrimitiveTheme,\n  Radius,\n  RadiusSource,\n  RadiusStep,\n  Spacing,\n  SpaceSource,\n  SpaceStep,\n  TextRole,\n  TextStyle,\n  ThemeColors,\n  ThemeIconSize,\n  ThemeMode,\n  ThemeShadow,\n  TypeSource,\n  Typography,\n} from \"./theme.js\";\n"
    },
    {
      "path": "packages/primitives/src/core/keyboard.ts",
      "target": "@ui/gpuixui/primitives/core/keyboard.ts",
      "type": "registry:lib",
      "content": "import * as Arr from \"effect/Array\";\nimport * as Option from \"effect/Option\";\nimport * as P from \"effect/Predicate\";\nimport * as R from \"effect/Record\";\nimport * as Str from \"effect/String\";\n\nexport type KeyName = string;\n\nexport type KeyPhase = \"down\" | \"up\";\n\nexport const ENTER_KEY = \"enter\";\nexport const SPACE_KEY = \"space\";\n\nexport const swallowKeyDefault = (key: KeyName, phase: KeyPhase): boolean =>\n  key === SPACE_KEY && phase === \"down\";\n\nexport interface KeyChord {\n  readonly shift?: boolean;\n  readonly ctrl?: boolean;\n  readonly alt?: boolean;\n  readonly cmd?: boolean;\n}\n\nexport const isPlainKey = (chord: KeyChord | undefined): boolean =>\n  chord?.ctrl !== true && chord?.alt !== true && chord?.cmd !== true;\n\nexport const decideActivation = (\n  key: KeyName,\n  phase: KeyPhase,\n  held: boolean,\n): boolean => {\n  if (held) return false;\n  if (key === ENTER_KEY) return phase === \"down\";\n  if (key === SPACE_KEY) return phase === \"up\";\n  return false;\n};\n\nexport const decideToggle = (current: boolean): boolean => !current;\n\nconst ARROW_KEYS = {\n  vertical: { forward: \"down\", backward: \"up\" },\n  horizontal: { forward: \"right\", backward: \"left\" },\n} as const;\n\nexport type Orientation = keyof typeof ARROW_KEYS;\n\nconst ORIENTATION_NAMES: ReadonlyArray<string> = R.keys(ARROW_KEYS);\n\nexport const isOrientation = (value: unknown): value is Orientation =>\n  P.isString(value) && Arr.contains(ORIENTATION_NAMES, value);\n\nexport const orientationOf = (\n  value: unknown,\n  fallback: Orientation,\n): Orientation => (isOrientation(value) ? value : fallback);\n\nexport const decideMove = (\n  index: number,\n  count: number,\n  key: KeyName,\n  orientation: Orientation,\n  isDisabled: (index: number) => boolean = () => false,\n): Option.Option<number> => {\n  if (count <= 1 || !isOrientation(orientation)) return Option.none();\n  const { forward, backward } = ARROW_KEYS[orientation];\n  if (key !== forward && key !== backward) return Option.none();\n  const step = key === forward ? 1 : -1;\n  const candidates = Arr.map(\n    Arr.range(1, count - 1),\n    (offset) => (((index + step * offset) % count) + count) % count,\n  );\n  return Arr.findFirst(candidates, (candidate) => !isDisabled(candidate));\n};\n\nexport const decideAbsolute = (\n  count: number,\n  key: KeyName,\n  isDisabled: (index: number) => boolean = () => false,\n): Option.Option<number> => {\n  if (count <= 0) return Option.none();\n  const indexes = Arr.range(0, count - 1);\n  if (key === \"home\")\n    return Arr.findFirst(indexes, (index) => !isDisabled(index));\n  if (key === \"end\")\n    return Arr.findFirst(Arr.reverse(indexes), (index) => !isDisabled(index));\n  return Option.none();\n};\n\nexport const decidePage = (\n  index: number,\n  count: number,\n  key: KeyName,\n  pageSize: number,\n): Option.Option<number> => {\n  if (count <= 0 || pageSize <= 0) return Option.none();\n  if (key !== \"pageup\" && key !== \"pagedown\") return Option.none();\n  const target = key === \"pagedown\" ? index + pageSize : index - pageSize;\n  return Option.some(Math.max(0, Math.min(count - 1, target)));\n};\n\nexport const TYPE_AHEAD_RESET_MS = 500;\n\nexport const isTypeAheadKey = (key: KeyName): boolean => key.length === 1;\n\nexport const decideTypeAhead = (\n  labels: ReadonlyArray<string>,\n  from: number,\n  buffer: string,\n  isDisabled: (index: number) => boolean = () => false,\n): Option.Option<number> => {\n  const count = labels.length;\n  if (count <= 0 || buffer.length === 0) return Option.none();\n  const search = (wanted: string): Option.Option<number> => {\n    const order = Arr.map(\n      Arr.range(1, count),\n      (offset) => (((from + offset) % count) + count) % count,\n    );\n    return Arr.findFirst(\n      order,\n      (index) =>\n        !isDisabled(index) &&\n        Str.startsWith(wanted)(Str.toLowerCase(labels[index] ?? \"\")),\n    );\n  };\n  const wanted = Str.toLowerCase(buffer);\n  return Option.match(search(wanted), {\n    onSome: Option.some,\n    onNone: () =>\n      wanted.length > 1 ? search(Str.takeRight(1)(wanted)) : Option.none(),\n  });\n};\n"
    },
    {
      "path": "packages/primitives/src/core/layout.ts",
      "target": "@ui/gpuixui/primitives/core/layout.ts",
      "type": "registry:lib",
      "content": "import type { StyleDesc } from \"@gpuix/react\";\nimport * as Arr from \"effect/Array\";\nimport * as Option from \"effect/Option\";\nimport * as P from \"effect/Predicate\";\nimport { storedNumber } from \"./stored.js\";\nimport { spaceValue, type PrimitiveTheme, type SpaceStep } from \"./theme.js\";\nimport { surfaceStyle, type SurfaceSpec } from \"./style.js\";\n\nexport const STACK_DIRECTIONS = [\"row\", \"column\"] as const;\nexport type StackDirection = (typeof STACK_DIRECTIONS)[number];\n\nexport const isStackDirection = (value: unknown): value is StackDirection =>\n  P.isString(value) && Arr.contains(STACK_DIRECTIONS, value);\n\nexport const stackDirection = (value: unknown): StackDirection =>\n  isStackDirection(value) ? value : \"column\";\n\nexport const STACK_ALIGNS = [\n  \"start\",\n  \"center\",\n  \"end\",\n  \"stretch\",\n  \"baseline\",\n] as const;\nexport type StackAlign = (typeof STACK_ALIGNS)[number];\n\nexport const STACK_JUSTIFIES = [\n  \"start\",\n  \"center\",\n  \"end\",\n  \"between\",\n  \"around\",\n] as const;\nexport type StackJustify = (typeof STACK_JUSTIFIES)[number];\n\nconst alignToFlex: Record<StackAlign, string> = {\n  start: \"flex-start\",\n  center: \"center\",\n  end: \"flex-end\",\n  stretch: \"stretch\",\n  baseline: \"baseline\",\n};\n\nconst justifyToFlex: Record<StackJustify, string> = {\n  start: \"flex-start\",\n  center: \"center\",\n  end: \"flex-end\",\n  between: \"space-between\",\n  around: \"space-around\",\n};\n\nexport interface StackSpec {\n  readonly direction: StackDirection;\n\n  readonly gap?: SpaceStep;\n  readonly align?: StackAlign;\n  readonly justify?: StackJustify;\n  readonly wrap?: boolean;\n\n  readonly grow?: boolean;\n  readonly fullWidth?: boolean;\n  readonly fullHeight?: boolean;\n}\n\nexport const stackStyle = (\n  spec: StackSpec,\n  theme: PrimitiveTheme,\n): StyleDesc => {\n  const style: StyleDesc = {\n    display: \"flex\",\n    flexDirection: stackDirection(spec.direction),\n  };\n  if (spec.gap !== undefined) style.gap = spaceValue(theme, spec.gap);\n  if (spec.align !== undefined) style.alignItems = alignToFlex[spec.align];\n  if (spec.justify !== undefined)\n    style.justifyContent = justifyToFlex[spec.justify];\n  if (spec.wrap === true) style.flexWrap = \"wrap\";\n  if (spec.grow === true) style.flexGrow = 1;\n  if (spec.fullWidth === true) style.width = \"100%\";\n  if (spec.fullHeight === true) style.height = \"100%\";\n  return style;\n};\n\nexport interface GridSpec {\n  readonly columns: number;\n  readonly rows?: number;\n  readonly gap?: SpaceStep;\n  readonly grow?: boolean;\n}\n\nexport const trackCount = (count: number): number =>\n  Number.isFinite(count) ? Math.max(1, Math.floor(count)) : 1;\n\nexport interface FieldRows {\n  readonly minRows?: number;\n  readonly maxRows?: number;\n}\n\nconst rowCount = (count: unknown): Option.Option<number> =>\n  Option.map(storedNumber(count), trackCount);\n\nexport const fieldRows = (minRows: unknown, maxRows: unknown): FieldRows => {\n  const floor = rowCount(minRows);\n  const cap = rowCount(maxRows);\n  const raised = Option.match(Option.all([floor, cap]), {\n    onNone: () => cap,\n    onSome: ([floorRows, capRows]) => Option.some(Math.max(capRows, floorRows)),\n  });\n  return {\n    minRows: Option.getOrUndefined(floor),\n    maxRows: Option.getOrUndefined(raised),\n  };\n};\n\nexport const gridStyle = (spec: GridSpec, theme: PrimitiveTheme): StyleDesc => {\n  const style: StyleDesc = {\n    display: \"grid\",\n    gridTemplateColumns: trackCount(spec.columns),\n  };\n  if (spec.rows !== undefined) {\n    style.gridTemplateRows = trackCount(spec.rows);\n  }\n  if (spec.gap !== undefined) style.gap = spaceValue(theme, spec.gap);\n  if (spec.grow === true) style.flexGrow = 1;\n  return style;\n};\n\nexport interface BoxSpec extends SurfaceSpec {\n  readonly grow?: boolean;\n\n  readonly shrink?: boolean;\n  readonly fullWidth?: boolean;\n  readonly fullHeight?: boolean;\n}\n\nexport const boxStyle = (spec: BoxSpec, theme: PrimitiveTheme): StyleDesc => {\n  const style: StyleDesc = {\n    ...surfaceStyle(spec, theme),\n    flexShrink: spec.shrink === true ? 1 : 0,\n  };\n  if (spec.grow === true) style.flexGrow = 1;\n  if (spec.fullWidth === true) style.width = \"100%\";\n  if (spec.fullHeight === true) style.height = \"100%\";\n  return style;\n};\n"
    },
    {
      "path": "packages/primitives/src/core/loading.ts",
      "target": "@ui/gpuixui/primitives/core/loading.ts",
      "type": "registry:lib",
      "content": "import * as Arr from \"effect/Array\";\nimport * as Option from \"effect/Option\";\nimport type { StyleDesc } from \"@gpuix/react\";\nimport { motionLevels } from \"../../motion/timing.js\";\nimport { visibleCopy } from \"./a11y.js\";\nimport type { PrimitiveTheme, RadiusStep } from \"./theme.js\";\nimport { colorRole, radiusStep, radiusValue, typeOf } from \"./theme.js\";\n\nexport const PULSE_STEPS = 2;\n\nexport const SPINNER_SEGMENTS = 8;\n\nexport const SPINNER_RING_TICKS = 12;\n\nexport const SPINNER_ARC_TICKS = 7;\n\nexport const STEP_INTERVAL_MS = motionLevels.step;\n\nexport const PULSE_INTERVAL_MS = 700;\n\nexport const SPINNER_FADE_FLOOR = 0.2;\n\nexport interface SkeletonSpec {\n  readonly width?: number | string;\n  readonly height?: number | string;\n\n  readonly radius?: RadiusStep;\n\n  readonly circle?: boolean;\n}\n\nconst paintableSide = (\n  side: number | string | undefined,\n): number | string | undefined =>\n  typeof side === \"number\"\n    ? Number.isFinite(side) && side > 0\n      ? side\n      : undefined\n    : visibleCopy(side);\n\nexport const skeletonSize = (\n  spec: SkeletonSpec,\n  theme: PrimitiveTheme,\n): { readonly width: number | string; readonly height: number | string } => {\n  const width = paintableSide(spec.width);\n  const height = paintableSide(spec.height);\n  const line = typeOf(theme, \"body\").lineHeight;\n  if (spec.circle !== true) {\n    return {\n      width: width ?? \"100%\",\n      height: height ?? line,\n    };\n  }\n  if (width !== undefined && height !== undefined) {\n    return { width, height };\n  }\n  const side = width ?? height ?? line;\n  return { width: side, height: side };\n};\n\nexport const skeletonStyle = (\n  spec: SkeletonSpec,\n  theme: PrimitiveTheme,\n): StyleDesc => ({\n  ...skeletonSize(spec, theme),\n  flexShrink: 0,\n  borderRadius:\n    spec.circle === true\n      ? radiusValue(theme, \"full\")\n      : radiusValue(theme, radiusStep(spec.radius) ?? \"sm\"),\n  backgroundColor: colorRole(theme, \"skeleton\"),\n});\n\nexport const pulseOpacity = (step: number, dim = 0.6, full = 1): number =>\n  step % PULSE_STEPS === 0 ? full : dim;\n\nexport const SPINNER_ACCENTS = [\n  \"primary\",\n  \"destructive\",\n  \"muted\",\n  \"on-primary\",\n  \"on-secondary\",\n  \"on-destructive\",\n  \"on-accent\",\n  \"on-disabled\",\n] as const;\nexport type SpinnerAccent = (typeof SPINNER_ACCENTS)[number];\n\nconst ACCENT_NAMES: ReadonlyArray<string> = SPINNER_ACCENTS;\n\nexport const isSpinnerAccent = (value: unknown): value is SpinnerAccent =>\n  typeof value === \"string\" && Arr.contains(ACCENT_NAMES, value);\n\nexport const spinnerAccentOf = (value: unknown): SpinnerAccent =>\n  isSpinnerAccent(value) ? value : \"primary\";\n\nexport interface SpinnerSpec {\n  readonly size: number;\n  readonly accent: SpinnerAccent;\n}\n\nexport interface SpinnerTick {\n  readonly index: number;\n\n  readonly active: boolean;\n  readonly opacity: number;\n\n  readonly x: number;\n  readonly y: number;\n\n  readonly side: number;\n}\n\nexport const spinnerTicks = (\n  step: number,\n  size: number,\n  count = SPINNER_RING_TICKS,\n  arc = SPINNER_ARC_TICKS,\n): ReadonlyArray<SpinnerTick> => {\n  const ring = Math.max(\n    2,\n    Math.trunc(Number.isFinite(count) ? count : SPINNER_RING_TICKS),\n  );\n  const lit = Math.min(\n    ring,\n    Math.max(1, Math.trunc(Number.isFinite(arc) ? arc : SPINNER_ARC_TICKS)),\n  );\n  const side = Number.isFinite(size) && size > 0 ? size : 16;\n  const tick = Math.max(1.5, side / 6);\n  const radius = (side - tick) / 2;\n  const head = ((Math.trunc(step) % ring) + ring) % ring;\n  return Arr.map(Arr.range(0, ring - 1), (index) => {\n    const distance = (head - index + ring) % ring;\n    const angle = -Math.PI / 2 + (index / ring) * Math.PI * 2;\n    const centre = side / 2;\n\n    const edge = side - tick;\n    const x = Math.min(\n      edge,\n      Math.max(0, centre + radius * Math.cos(angle) - tick / 2),\n    );\n    const y = Math.min(\n      edge,\n      Math.max(0, centre + radius * Math.sin(angle) - tick / 2),\n    );\n    const opacity =\n      distance >= lit\n        ? 0\n        : distance === lit - 1\n          ? SPINNER_FADE_FLOOR\n          : 1 - (distance / Math.max(1, lit - 1)) * (1 - SPINNER_FADE_FLOOR);\n    return {\n      index,\n      active: distance === 0,\n      opacity,\n      side: tick,\n      x,\n      y,\n    };\n  });\n};\n\nconst ACCENT_COLOR: Readonly<\n  Record<SpinnerAccent, (theme: PrimitiveTheme) => string | undefined>\n> = {\n  primary: (theme) => colorRole(theme, \"primary\"),\n  destructive: (theme) => colorRole(theme, \"destructive\"),\n  muted: (theme) => colorRole(theme, \"mutedForeground\"),\n  \"on-primary\": (theme) => colorRole(theme, \"primaryForeground\"),\n  \"on-secondary\": (theme) => colorRole(theme, \"secondaryForeground\"),\n  \"on-destructive\": (theme) => colorRole(theme, \"destructiveForeground\"),\n  \"on-accent\": (theme) => colorRole(theme, \"accentForeground\"),\n  \"on-disabled\": (theme) => colorRole(theme, \"disabledForeground\"),\n};\n\nconst accentColor = (\n  accent: SpinnerAccent,\n  theme: PrimitiveTheme,\n): string | undefined => ACCENT_COLOR[spinnerAccentOf(accent)](theme);\n\nexport const spinnerTickStyle = (\n  spec: SpinnerSpec,\n  tick: SpinnerTick,\n  theme: PrimitiveTheme,\n): StyleDesc => ({\n  position: \"absolute\",\n  left: tick.x,\n  top: tick.y,\n  width: tick.side,\n  height: tick.side,\n  flexShrink: 0,\n  borderRadius: radiusValue(theme, \"full\"),\n  opacity: tick.opacity,\n  backgroundColor: accentColor(spec.accent, theme),\n});\n\nexport const indeterminateOffset = (step: number, segment = 40): number => {\n  const travel = Math.max(0, 100 - segment);\n  const phase =\n    ((step % SPINNER_SEGMENTS) + SPINNER_SEGMENTS) % SPINNER_SEGMENTS;\n  return (phase / SPINNER_SEGMENTS) * travel;\n};\n\nexport const progressAnimates = (value: Option.Option<number>): boolean =>\n  Option.isNone(value);\n\nexport const indeterminateFillStyle = (\n  segment: number,\n  color: string,\n  theme: PrimitiveTheme,\n): StyleDesc => ({\n  width: `${segment}%`,\n  height: \"100%\",\n  borderRadius: radiusValue(theme, \"full\"),\n  backgroundColor: color,\n});\n\nexport const indeterminateLeadStyle = (offset: number): StyleDesc => ({\n  width: `${offset}%`,\n  flexShrink: 0,\n});\n"
    },
    {
      "path": "packages/primitives/src/core/messages.ts",
      "target": "@ui/gpuixui/primitives/core/messages.ts",
      "type": "registry:lib",
      "content": "import * as P from \"effect/Predicate\";\nimport { accessibleName, spokenSentence, spokenWord } from \"./a11y.js\";\nimport type { StarState } from \"./rating.js\";\nimport type { SelectionState } from \"./selection.js\";\n\nexport interface SelectionWords {\n  readonly checked: string;\n  readonly unchecked: string;\n  readonly mixed: string;\n}\n\nexport interface PressWords {\n  readonly pressed: string;\n  readonly notPressed: string;\n}\n\nexport interface StarWords {\n  readonly checked: string;\n  readonly half: string;\n  readonly unchecked: string;\n}\n\nexport interface LoadingWords {\n  readonly busy: string;\n  readonly indeterminate: string;\n}\n\nexport type RangeEndWords = (label: string, end: \"start\" | \"end\") => string;\n\nexport interface PrimitiveMessages {\n  readonly selection: SelectionWords;\n  readonly press: PressWords;\n  readonly star: StarWords;\n\n  readonly starName: (index: number, max: number) => string;\n\n  readonly scrollRegion: string;\n\n  readonly codeDigit: (index: number, label: string | undefined) => string;\n\n  readonly loading: LoadingWords;\n\n  readonly rangeEnd: RangeEndWords;\n}\n\nexport const defaultMessages: PrimitiveMessages = {\n  selection: { checked: \"checked\", unchecked: \"unchecked\", mixed: \"mixed\" },\n  press: { pressed: \"pressed\", notPressed: \"not pressed\" },\n  star: { checked: \"checked\", half: \"half\", unchecked: \"unchecked\" },\n  starName: (index, max) => `${index} of ${max}`,\n  scrollRegion: \"Scroll region\",\n  codeDigit: (index, label) => `${label ?? \"Code\"} digit ${index + 1}`,\n  loading: { busy: \"Loading\", indeterminate: \"loading\" },\n  rangeEnd: (label, end) =>\n    `${label} ${end === \"start\" ? \"minimum\" : \"maximum\"}`,\n};\n\nconst spokenEnd = (\n  label: string,\n  end: RangeEndWords,\n  side: \"start\" | \"end\",\n): string =>\n  spokenSentence(end(label, side), defaultMessages.rangeEnd(label, side));\n\nexport const rangeThumbNames = (\n  label: string | undefined,\n  end: RangeEndWords = defaultMessages.rangeEnd,\n): readonly [string | undefined, string | undefined] => {\n  const name = accessibleName(label);\n  return name === undefined\n    ? [undefined, undefined]\n    : [spokenEnd(name, end, \"start\"), spokenEnd(name, end, \"end\")];\n};\n\ntype Stored<T> = T extends (...args: never[]) => unknown\n  ? unknown\n  : T extends object\n    ? { readonly [K in keyof T]?: Stored<T[K]> } | null\n    : unknown;\n\nexport type MessagesSource = {\n  readonly [K in keyof PrimitiveMessages]?: Stored<PrimitiveMessages[K]>;\n};\n\nconst row = (stored: unknown, inherited: string): string =>\n  P.isString(stored) ? stored : inherited;\n\nconst isSentence = <A>(value: unknown): value is A => P.isFunction(value);\n\nconst sentence = <A>(stored: unknown, inherited: A): A =>\n  isSentence<A>(stored) ? stored : inherited;\n\nconst selectionRows = (\n  stored: Stored<SelectionWords> | undefined,\n  inherited: SelectionWords,\n): SelectionWords => ({\n  checked: row(stored?.checked, inherited.checked),\n  unchecked: row(stored?.unchecked, inherited.unchecked),\n  mixed: row(stored?.mixed, inherited.mixed),\n});\n\nconst pressRows = (\n  stored: Stored<PressWords> | undefined,\n  inherited: PressWords,\n): PressWords => ({\n  pressed: row(stored?.pressed, inherited.pressed),\n  notPressed: row(stored?.notPressed, inherited.notPressed),\n});\n\nconst starRows = (\n  stored: Stored<StarWords> | undefined,\n  inherited: StarWords,\n): StarWords => ({\n  checked: row(stored?.checked, inherited.checked),\n  half: row(stored?.half, inherited.half),\n  unchecked: row(stored?.unchecked, inherited.unchecked),\n});\n\nconst loadingRows = (\n  stored: Stored<LoadingWords> | undefined,\n  inherited: LoadingWords,\n): LoadingWords => ({\n  busy: row(stored?.busy, inherited.busy),\n  indeterminate: row(stored?.indeterminate, inherited.indeterminate),\n});\n\nexport const resolveMessages = (\n  messages?: MessagesSource | null,\n  inherited: PrimitiveMessages = defaultMessages,\n): PrimitiveMessages =>\n  messages === undefined || messages === null\n    ? inherited\n    : {\n        selection: selectionRows(messages.selection, inherited.selection),\n        press: pressRows(messages.press, inherited.press),\n        star: starRows(messages.star, inherited.star),\n        starName: sentence(messages.starName, inherited.starName),\n        scrollRegion: row(messages.scrollRegion, inherited.scrollRegion),\n        codeDigit: sentence(messages.codeDigit, inherited.codeDigit),\n        loading: loadingRows(messages.loading, inherited.loading),\n        rangeEnd: sentence(messages.rangeEnd, inherited.rangeEnd),\n      };\n\nexport const selectionWord = (\n  state: SelectionState,\n  words: SelectionWords = defaultMessages.selection,\n): string =>\n  state === \"indeterminate\"\n    ? spokenWord(words.mixed, defaultMessages.selection.mixed)\n    : state === \"checked\"\n      ? spokenWord(words.checked, defaultMessages.selection.checked)\n      : spokenWord(words.unchecked, defaultMessages.selection.unchecked);\n\nexport const pressWord = (\n  pressed: boolean,\n  words: PressWords = defaultMessages.press,\n): string =>\n  pressed\n    ? spokenWord(words.pressed, defaultMessages.press.pressed)\n    : spokenWord(words.notPressed, defaultMessages.press.notPressed);\n\nexport const starWord = (\n  state: StarState,\n  words: StarWords = defaultMessages.star,\n): string =>\n  state === \"checked\"\n    ? spokenWord(words.checked, defaultMessages.star.checked)\n    : state === \"half\"\n      ? spokenWord(words.half, defaultMessages.star.half)\n      : spokenWord(words.unchecked, defaultMessages.star.unchecked);\n\nexport const busyWord = (\n  words: LoadingWords = defaultMessages.loading,\n): string => spokenWord(words.busy, defaultMessages.loading.busy);\n\nexport const indeterminateWord = (\n  words: LoadingWords = defaultMessages.loading,\n): string =>\n  spokenWord(words.indeterminate, defaultMessages.loading.indeterminate);\n"
    },
    {
      "path": "packages/primitives/src/core/motion.ts",
      "target": "@ui/gpuixui/primitives/core/motion.ts",
      "type": "registry:lib",
      "content": "import type { MotionTransition } from \"@gpuix/react\";\n\nexport { reducedMotionOf } from \"../../motion/timing.js\";\n\nexport const stillFrame = (step: number, reducedMotion?: boolean): number =>\n  reducedMotion === true ? 0 : step;\n\nexport const stillTransition = (\n  transition: MotionTransition,\n  reducedMotion?: boolean,\n): MotionTransition => (reducedMotion === true ? { duration: 0 } : transition);\n"
    },
    {
      "path": "packages/primitives/src/core/number.ts",
      "target": "@ui/gpuixui/primitives/core/number.ts",
      "type": "registry:lib",
      "content": "import * as Option from \"effect/Option\";\nimport * as Str from \"effect/String\";\nimport { visibleCopy } from \"./a11y.js\";\nimport { storedNumber } from \"./stored.js\";\n\nexport interface NumberRange {\n  readonly min?: number;\n  readonly max?: number;\n  readonly step: number;\n}\n\nconst NUMERIC = /^[+-]?(?:\\d+(?:\\.\\d*)?|\\.\\d+)(?:e[+-]?\\d+)?$/i;\n\nexport const parseNumericText = (text: string): Option.Option<number> => {\n  const trimmed = text.trim();\n  if (!NUMERIC.test(trimmed)) return Option.none();\n  const value = Number(trimmed);\n  return Number.isFinite(value) ? Option.some(value) : Option.none();\n};\n\nexport type ParseValue = (text: string) => Option.Option<number>;\n\nexport const parseNumberText = (\n  text: string,\n  parseValue?: ParseValue,\n): Option.Option<number> => {\n  if (!Str.isNonEmpty(Str.trim(text))) return Option.none();\n  const own: Option.Option<number> =\n    parseValue === undefined\n      ? Option.none()\n      : Option.filter(parseValue(text), Number.isFinite);\n  return Option.isSome(own) ? own : parseNumericText(text);\n};\n\nexport const normalizeNumberRange = (range: NumberRange): NumberRange => {\n  const min = Number.isFinite(range.min) ? range.min : undefined;\n  const max = Number.isFinite(range.max) ? range.max : undefined;\n  return min !== undefined && max !== undefined && min > max\n    ? { min: max, max: min, step: range.step }\n    : { min, max, step: range.step };\n};\n\nconst numericBounds = (\n  range: NumberRange,\n): { readonly min: number | undefined; readonly max: number | undefined } => {\n  const { min, max } = normalizeNumberRange(range);\n  return { min, max };\n};\n\nconst paintable = (\n  value: number,\n  min: number | undefined,\n  max: number | undefined,\n): number => (Number.isFinite(value) ? value : (min ?? max ?? 0));\n\nexport const clampNumeric = (value: number, range: NumberRange): number => {\n  const { min, max } = numericBounds(range);\n  const finite = paintable(value, min, max);\n  const aboveMin = min === undefined ? finite : Math.max(min, finite);\n  return max === undefined ? aboveMin : Math.min(max, aboveMin);\n};\n\nconst NEGATIVE_ZERO = /^-0(?:\\.0+)?$/;\n\nconst plainFixed = (text: string, decimals: number): string => {\n  const [mantissa = \"0\", exponentText = \"0\"] = text.split(/e/i);\n  const negative = Str.startsWith(\"-\")(mantissa);\n  const unsigned = negative ? Str.slice(1)(mantissa) : mantissa;\n  const [whole = \"0\", fraction = \"\"] = unsigned.split(\".\");\n  const shift = Number(exponentText) - Str.length(fraction);\n  const digits = `${whole}${fraction}${Str.repeat(Math.max(0, shift))(\"0\")}`;\n  const point = decimals > 0 ? `.${Str.repeat(decimals)(\"0\")}` : \"\";\n  return `${negative ? \"-\" : \"\"}${digits}${point}`;\n};\n\nexport const formatNumber = (value: number, precision = 0): string => {\n  const decimals = Math.min(20, Math.max(0, Math.trunc(precision)));\n  const fixed = value.toFixed(decimals);\n  const text = Str.includes(\"e\")(fixed) ? plainFixed(fixed, decimals) : fixed;\n  return NEGATIVE_ZERO.test(text) ? Str.slice(1)(text) : text;\n};\n\nconst writtenDecimals = (value: number): number => {\n  const [mantissa = \"\", exponentText] = Str.split(/e/i)(String(value));\n  const exponent = exponentText === undefined ? 0 : Number(exponentText);\n  const [, fraction = \"\"] = Str.split(\".\")(mantissa);\n  return Math.max(0, Str.length(fraction) - exponent);\n};\n\nconst decimalsOf = (value: number): number =>\n  Math.min(15, writtenDecimals(value));\n\nexport const expandedNumber = (value: number): string => {\n  const text = String(value);\n  if (!Str.includes(\"e\")(text)) return text;\n  const [mantissa = \"0\", exponentText = \"0\"] = Str.split(/e/i)(text);\n  const negative = Str.startsWith(\"-\")(mantissa);\n  const unsigned = negative ? Str.slice(1)(mantissa) : mantissa;\n  const [whole = \"0\", fraction = \"\"] = Str.split(\".\")(unsigned);\n  const digits = `${whole}${fraction}`;\n  const point = Str.length(whole) + Number(exponentText);\n  const body =\n    point <= 0\n      ? `0.${Str.repeat(-point)(\"0\")}${digits}`\n      : point >= Str.length(digits)\n        ? `${digits}${Str.repeat(point - Str.length(digits))(\"0\")}`\n        : `${Str.slice(0, point)(digits)}.${Str.slice(point)(digits)}`;\n  return `${negative ? \"-\" : \"\"}${body}`;\n};\n\nconst precisionOf = (precision: unknown): Option.Option<number> =>\n  Option.filter(storedNumber(precision), Number.isFinite);\n\nexport const displayNumber = (value: number, precision?: unknown): string =>\n  Option.match(precisionOf(precision), {\n    onNone: () => expandedNumber(value),\n    onSome: (decimals) => formatNumber(value, decimals),\n  });\n\nexport const numberDisplay = (\n  value: number,\n  precision: unknown,\n  formatValue?: (value: number) => string,\n): string =>\n  visibleCopy(formatValue?.(value)) ?? displayNumber(value, precision);\n\nexport const stepNumber = (\n  value: number,\n  range: NumberRange,\n  steps: number,\n): number => {\n  const step = Number.isFinite(range.step) && range.step > 0 ? range.step : 1;\n\n  const from = clampNumeric(value, range);\n  const scale = 10 ** Math.max(decimalsOf(step), decimalsOf(from));\n  const moved = Math.round((from + steps * step) * scale) / scale;\n  return clampNumeric(moved, range);\n};\n\nexport const SCRUB_PIXELS_PER_STEP = 4;\n\nexport const SHIFT_SCRUB_SCALE = 10;\n\nexport const scrubNumber = (\n  start: number,\n  travel: number,\n  range: NumberRange,\n  pixelsPerStep = SCRUB_PIXELS_PER_STEP,\n  stepScale = 1,\n): number => {\n  if (!Number.isFinite(travel)) return start;\n  const scale =\n    Number.isFinite(pixelsPerStep) && pixelsPerStep > 0\n      ? pixelsPerStep\n      : SCRUB_PIXELS_PER_STEP;\n  const multiplier =\n    Number.isFinite(stepScale) && stepScale > 0 ? stepScale : 1;\n  const steps =\n    Math.sign(travel) * Math.round(Math.abs(travel) / scale) * multiplier;\n  return stepNumber(start, range, steps);\n};\n\nconst ARROW_STEPS: Readonly<Record<string, number>> = {\n  up: 1,\n  down: -1,\n};\n\nexport const decideNumberKey = (\n  value: number,\n  range: NumberRange,\n  key: string,\n  pageSteps = 10,\n): Option.Option<number> => {\n  const { min, max } = normalizeNumberRange(range);\n  if (key === \"home\")\n    return min === undefined ? Option.none() : Option.some(min);\n  if (key === \"end\")\n    return max === undefined ? Option.none() : Option.some(max);\n  const steps =\n    key === \"pageup\"\n      ? pageSteps\n      : key === \"pagedown\"\n        ? -pageSteps\n        : ARROW_STEPS[key];\n  return steps === undefined\n    ? Option.none()\n    : Option.some(stepNumber(value, range, steps));\n};\n\nexport interface NumberDraft {\n  readonly text: Option.Option<string>;\n  readonly incoming: Option.Option<number>;\n  readonly touched: boolean;\n}\n\nexport const initNumberDraft = (\n  incoming: Option.Option<number>,\n  hasValue: boolean,\n): NumberDraft => ({\n  text: Option.none(),\n  incoming,\n  touched: hasValue || Option.isSome(incoming),\n});\n\nexport const numberDraftText = (\n  draft: NumberDraft,\n  current: number,\n  display: (value: number) => string,\n): string =>\n  Option.match(draft.text, {\n    onSome: (text) => text,\n    onNone: () => (draft.touched ? display(current) : \"\"),\n  });\n\nexport const withNumberDraftText = (\n  draft: NumberDraft,\n  text: string,\n): NumberDraft => ({ ...draft, text: Option.some(text) });\n\nexport const withNumberDraftValue = (draft: NumberDraft): NumberDraft => ({\n  ...draft,\n  touched: true,\n});\n\nexport const commitNumberDraft = (draft: NumberDraft): NumberDraft => ({\n  ...draft,\n  text: Option.none(),\n});\n\nconst meansValue = (\n  text: string,\n  range: NumberRange,\n  parseValue?: ParseValue,\n): Option.Option<number> =>\n  Option.map(parseNumberText(text, parseValue), (parsed) =>\n    clampNumeric(parsed, range),\n  );\n\nexport const syncNumberDraft = (\n  draft: NumberDraft,\n  incoming: Option.Option<number>,\n  range: NumberRange,\n  parseValue?: ParseValue,\n): Option.Option<NumberDraft> => {\n  if (Option.isNone(incoming)) return Option.none();\n  const value = incoming.value;\n\n  if (Object.is(Option.getOrUndefined(draft.incoming), value))\n    return Option.none();\n  const kept = Option.match(draft.text, {\n    onSome: (text) =>\n      Option.match(meansValue(text, range, parseValue), {\n        onNone: () => false,\n        onSome: (meant) => meant === value,\n      }),\n    onNone: () => false,\n  });\n  return Option.some({\n    text: kept ? draft.text : Option.none(),\n    incoming: Option.some(value),\n    touched: true,\n  });\n};\n"
    },
    {
      "path": "packages/primitives/src/core/otp.ts",
      "target": "@ui/gpuixui/primitives/core/otp.ts",
      "type": "registry:lib",
      "content": "import * as Arr from \"effect/Array\";\nimport * as Option from \"effect/Option\";\nimport * as Str from \"effect/String\";\nimport { storedNumber, storedText } from \"./stored.js\";\n\nexport const otpLength = (length: number): number =>\n  Math.max(1, Math.trunc(Number.isFinite(length) ? length : 1));\n\nexport const DEFAULT_OTP_LENGTH = 6;\n\nexport const otpCellCount = (length: unknown): number =>\n  Option.match(storedNumber(length), {\n    onNone: () => DEFAULT_OTP_LENGTH,\n    onSome: otpLength,\n  });\n\nexport const normalizeOtp = (value: unknown, length: number): string =>\n  Str.takeLeft(otpLength(length))(\n    Str.replace(/[^0-9A-Za-z]/g, \"\")(storedText(value) ?? \"\"),\n  );\n\nexport interface OtpEdit {\n  readonly value: string;\n  readonly focus: number;\n}\n\nexport const otpCells = (\n  value: unknown,\n  length: number,\n): ReadonlyArray<string> => {\n  const limit = otpLength(length);\n  const chars = Arr.fromIterable(normalizeOtp(value, limit));\n  return Arr.makeBy(limit, (index) =>\n    Option.getOrElse(Arr.get(chars, index), () => \"\"),\n  );\n};\n\nconst indexOf = (index: number, length: number): number =>\n  Math.min(\n    otpLength(length) - 1,\n    Math.max(0, Number.isFinite(index) ? Math.trunc(index) : 0),\n  );\n\nconst join = (cells: ReadonlyArray<string>): string => Arr.join(cells, \"\");\n\nconst withCell = (\n  cells: ReadonlyArray<string>,\n  index: number,\n  char: string,\n): ReadonlyArray<string> =>\n  Arr.map(cells, (cell, at) => (at === index ? char : cell));\n\nexport const applyOtpInput = (\n  current: unknown,\n  index: number,\n  text: string,\n  length: number,\n): OtpEdit => {\n  const limit = otpLength(length);\n  const cells = otpCells(current, limit);\n  const start = Math.min(indexOf(index, limit), Str.length(join(cells)));\n\n  const cell = Option.getOrElse(Arr.get(cells, start), () => \"\");\n  const edited =\n    cell !== \"\" &&\n    Str.length(text) > Str.length(cell) &&\n    Str.startsWith(cell)(text)\n      ? Str.slice(Str.length(cell))(text)\n      : text;\n  const typed = normalizeOtp(edited, limit);\n\n  if (typed === \"\")\n    return { value: join(withCell(cells, start, \"\")), focus: start };\n\n  if (Str.length(typed) === 1) {\n    return {\n      value: join(withCell(cells, start, typed)),\n      focus: Math.min(limit - 1, start + 1),\n    };\n  }\n\n  const inserted = Arr.fromIterable(typed);\n  const next = Arr.map(cells, (cell, at) =>\n    at >= start && at - start < Arr.length(inserted)\n      ? Option.getOrElse(Arr.get(inserted, at - start), () => cell)\n      : cell,\n  );\n  return {\n    value: join(next),\n    focus: Math.min(limit - 1, start + Arr.length(inserted)),\n  };\n};\n\nexport const otpEmptiedCell = (\n  before: unknown,\n  after: unknown,\n  index: number,\n  length: number,\n): boolean => {\n  const limit = otpLength(length);\n  const at = indexOf(index, limit);\n  const cell = (value: unknown): string =>\n    Option.getOrElse(Arr.get(otpCells(value, limit), at), () => \"\");\n  return cell(before) !== \"\" && cell(after) === \"\";\n};\n\nexport const decideOtpKey = (\n  current: unknown,\n  index: number,\n  key: string,\n  length: number,\n): Option.Option<OtpEdit> => {\n  const limit = otpLength(length);\n  const cells = otpCells(current, limit);\n  const at = indexOf(index, limit);\n  const value = join(cells);\n  const moveTo = (target: number): Option.Option<OtpEdit> =>\n    target === at ? Option.none() : Option.some({ value, focus: target });\n\n  if (key === \"left\") return moveTo(Math.max(0, at - 1));\n  if (key === \"right\") return moveTo(Math.min(limit - 1, at + 1));\n  if (key === \"home\") return moveTo(0);\n  if (key === \"end\") return moveTo(limit - 1);\n  if (key !== \"backspace\") return Option.none();\n\n  const filled = Option.getOrElse(Arr.get(cells, at), () => \"\") !== \"\";\n  if (filled || at === 0) return Option.none();\n  return Option.some({\n    value: join(withCell(cells, at - 1, \"\")),\n    focus: at - 1,\n  });\n};\n"
    },
    {
      "path": "packages/primitives/src/core/pointer.ts",
      "target": "@ui/gpuixui/primitives/core/pointer.ts",
      "type": "registry:lib",
      "content": "import { pointerWash } from \"../../tokens/index.js\";\nimport { colorRole, type PaintSource } from \"./theme.js\";\n\nexport const pressWash = (theme: PaintSource): string | undefined =>\n  pointerWash(theme, \"active\", \"hover\") ?? colorRole(theme, \"active\");\n\nexport const primaryButton = (event: { readonly button?: number }): boolean =>\n  event.button === undefined || event.button === 0;\n"
    },
    {
      "path": "packages/primitives/src/core/rating.ts",
      "target": "@ui/gpuixui/primitives/core/rating.ts",
      "type": "registry:lib",
      "content": "import * as Option from \"effect/Option\";\n\nexport type StarState = \"checked\" | \"half\" | \"unchecked\";\n\nexport interface StarBox {\n  readonly x: number;\n  readonly width: number;\n}\n\nexport const starCount = (max: unknown): number =>\n  typeof max === \"number\" && Number.isFinite(max)\n    ? Math.max(1, Math.trunc(max))\n    : 1;\n\nconst snapRating = (value: number, half: boolean): number =>\n  half ? Math.round(value * 2) / 2 : Math.trunc(value);\n\nexport const clampRating = (\n  value: number,\n  max: number,\n  half = false,\n): number => {\n  if (!Number.isFinite(value)) return 0;\n  return Math.min(starCount(max), Math.max(0, snapRating(value, half)));\n};\n\nexport const starFill = (index: number, value: number): number =>\n  Math.min(1, Math.max(0, value - (index - 1)));\n\nexport const starState = (index: number, value: number): StarState => {\n  const fill = starFill(index, value);\n  return fill >= 1 ? \"checked\" : fill > 0 ? \"half\" : \"unchecked\";\n};\n\nconst ARROW_STEPS: Readonly<Record<string, number>> = {\n  right: 1,\n  up: 1,\n  left: -1,\n  down: -1,\n};\n\nexport const decideRating = (\n  value: number,\n  max: number,\n  key: string,\n  half = false,\n): Option.Option<number> => {\n  const limit = starCount(max);\n  const place = half ? 0.5 : 1;\n  if (key === \"home\") return Option.some(place);\n  if (key === \"end\") return Option.some(limit);\n  if (key === \"delete\" || key === \"backspace\") return Option.some(0);\n  const step = ARROW_STEPS[key];\n  if (step === undefined) return Option.none();\n  const current = clampRating(value, limit, half);\n  const lower = current === 0 ? 0 : place;\n  return Option.some(\n    Math.min(\n      limit,\n      Math.max(lower, clampRating(current + step * place, limit, half)),\n    ),\n  );\n};\n\nexport const ratingTabStop = (\n  value: number,\n  max: number,\n  half = false,\n): number => {\n  const current = clampRating(value, max, half);\n  return current === 0 ? 1 : Math.min(starCount(max), Math.ceil(current));\n};\n\nexport const pointerRating = (\n  star: number,\n  x: Option.Option<number>,\n  box: Option.Option<StarBox>,\n  half = false,\n): number => {\n  if (!half) return star;\n  return Option.match(x, {\n    onNone: () => star,\n    onSome: (pointer) =>\n      Option.match(box, {\n        onNone: () => star,\n        onSome: (target) =>\n          target.width > 0 && (pointer - target.x) / target.width < 0.5\n            ? Math.max(0.5, star - 0.5)\n            : star,\n      }),\n  });\n};\n"
    },
    {
      "path": "packages/primitives/src/core/roving.ts",
      "target": "@ui/gpuixui/primitives/core/roving.ts",
      "type": "registry:lib",
      "content": "import * as Arr from \"effect/Array\";\nimport * as Option from \"effect/Option\";\n\nexport const rovingIndex = (\n  count: number,\n  preferred: Option.Option<number>,\n  isDisabled: (index: number) => boolean,\n): Option.Option<number> => {\n  if (count <= 0) return Option.none();\n  const usable = (index: number): boolean =>\n    index >= 0 && index < count && !isDisabled(index);\n  return Option.match(Option.filter(preferred, usable), {\n    onSome: Option.some,\n    onNone: () => Arr.findFirst(Arr.range(0, count - 1), usable),\n  });\n};\n"
    },
    {
      "path": "packages/primitives/src/core/scroll.ts",
      "target": "@ui/gpuixui/primitives/core/scroll.ts",
      "type": "registry:lib",
      "content": "import { Match } from \"effect\";\nimport * as Option from \"effect/Option\";\nimport * as R from \"effect/Record\";\nimport { scrollAxis, type ScrollAxis } from \"./style.js\";\n\nexport interface ScrollOffset {\n  readonly x: number;\n  readonly y: number;\n}\n\nexport interface ScrollMetrics {\n  readonly line: number;\n\n  readonly page: { readonly width: number; readonly height: number };\n}\n\nexport interface ScrollRect {\n  readonly x: number;\n  readonly y: number;\n  readonly width: number;\n  readonly height: number;\n}\n\nexport const SCROLL_END = -1e7;\n\ninterface Move {\n  readonly x: -1 | 0 | 1;\n\n  readonly y: -1 | 0 | 1;\n  readonly size: \"line\" | \"page\" | \"end\" | \"start\";\n}\n\nconst MOVES: Record<string, Move> = {\n  up: { x: 0, y: 1, size: \"line\" },\n  down: { x: 0, y: -1, size: \"line\" },\n  pageup: { x: 0, y: 1, size: \"page\" },\n  pagedown: { x: 0, y: -1, size: \"page\" },\n  left: { x: 1, y: 0, size: \"line\" },\n  right: { x: -1, y: 0, size: \"line\" },\n  home: { x: 0, y: 0, size: \"start\" },\n  end: { x: -1, y: -1, size: \"end\" },\n};\n\nconst scrolls = (axis: ScrollAxis, side: \"x\" | \"y\"): boolean =>\n  axis === \"both\" || axis === (side === \"x\" ? \"horizontal\" : \"vertical\");\n\nconst pageAxis = (axis: ScrollAxis): Option.Option<\"x\" | \"y\"> =>\n  scrolls(axis, \"y\")\n    ? Option.some(\"y\")\n    : scrolls(axis, \"x\")\n      ? Option.some(\"x\")\n      : Option.none();\n\nconst next = (\n  current: number,\n  move: Move,\n  side: \"x\" | \"y\",\n  metrics: ScrollMetrics,\n): number => {\n  const direction =\n    move.size === \"page\" ? move.y : side === \"x\" ? move.x : move.y;\n  return Match.value(move.size).pipe(\n    Match.when(\"end\", () => SCROLL_END),\n    Match.when(\"start\", () => 0),\n    Match.when(\"page\", () =>\n      Math.min(\n        0,\n        current +\n          direction * (side === \"x\" ? metrics.page.width : metrics.page.height),\n      ),\n    ),\n    Match.when(\"line\", () => Math.min(0, current + direction * metrics.line)),\n    Match.exhaustive,\n  );\n};\n\nexport const scrollTarget = (\n  key: string,\n  axis: unknown,\n  current: ScrollOffset,\n  metrics: ScrollMetrics,\n): Option.Option<ScrollOffset> => {\n  const resolved = scrollAxis(axis);\n  return Option.flatMap(R.get(MOVES, key), (move) => {\n    const paged = move.size === \"page\" ? pageAxis(resolved) : Option.none();\n\n    const takes = (side: \"x\" | \"y\"): boolean =>\n      scrolls(resolved, side) &&\n      Match.value(move.size).pipe(\n        Match.when(\"start\", () => true),\n        Match.when(\"end\", () => true),\n        Match.when(\"page\", () => Option.contains(paged, side)),\n        Match.when(\"line\", () => (side === \"x\" ? move.x !== 0 : move.y !== 0)),\n        Match.exhaustive,\n      );\n    return takes(\"x\") || takes(\"y\")\n      ? Option.some({\n          x: takes(\"x\") ? next(current.x, move, \"x\", metrics) : current.x,\n          y: takes(\"y\") ? next(current.y, move, \"y\", metrics) : current.y,\n        })\n      : Option.none();\n  });\n};\n\nconst outside = (\n  row: ScrollRect,\n  viewport: ScrollRect,\n): { readonly above: number; readonly below: number } => ({\n  above: row.y - viewport.y,\n  below: row.y + row.height - (viewport.y + viewport.height),\n});\n\nexport const revealScroll = (\n  row: ScrollRect,\n  viewport: ScrollRect,\n  current: ScrollOffset,\n): Option.Option<ScrollOffset> => {\n  const { above, below } = outside(row, viewport);\n  const shift =\n    row.height > viewport.height\n      ? above\n      : above < 0\n        ? above\n        : below > 0\n          ? below\n          : 0;\n  return shift === 0\n    ? Option.none()\n    : Option.some({ x: current.x, y: current.y - shift });\n};\n"
    },
    {
      "path": "packages/primitives/src/core/selection.ts",
      "target": "@ui/gpuixui/primitives/core/selection.ts",
      "type": "registry:lib",
      "content": "import * as Arr from \"effect/Array\";\nimport * as Option from \"effect/Option\";\nimport * as P from \"effect/Predicate\";\nimport * as Schema from \"effect/Schema\";\nimport * as Str from \"effect/String\";\nimport { pipe } from \"effect\";\nimport type { StyleDesc } from \"@gpuix/react\";\nimport {\n  disabledOpacity,\n  elevationShadow,\n  filledHover,\n  filledPressed,\n  switchMetricsAt,\n  targetInset,\n  targetSize,\n} from \"../../tokens/index.js\";\nimport type { SwitchColors } from \"../../tokens/index.js\";\nimport {\n  iconSideOf,\n  borderWidthOf,\n  colorRole,\n  radiusValue,\n  spaceValue,\n} from \"./theme.js\";\nimport type { ControlSize, PrimitiveTheme } from \"./theme.js\";\nimport { pressWash } from \"./pointer.js\";\n\ntype SwitchSlot = \"on\" | \"off\" | \"knob\" | \"knobOff\" | \"edge\";\n\nconst DeclaredSwitch = Schema.Record(Schema.String, Schema.Unknown);\ntype DeclaredSwitch = typeof DeclaredSwitch.Type;\n\nconst decodeDeclaredSwitch = Schema.decodeUnknownOption(DeclaredSwitch);\n\nexport type SwitchPaintTheme = Omit<PrimitiveTheme, \"switch\"> & {\n  readonly switch?: unknown;\n};\n\nconst declaredPaint = (source: SwitchPaintTheme): Option.Option<SwitchColors> =>\n  Option.flatMap(Option.fromNullishOr(source.switch), (table) =>\n    Option.flatMap(decodeDeclaredSwitch(table), (paint) =>\n      Option.map(\n        Option.all({\n          on: declaredColour(paint, \"on\"),\n          off: declaredColour(paint, \"off\"),\n          knob: declaredColour(paint, \"knob\"),\n        }),\n        (slots) => {\n          const edge = Option.getOrUndefined(declaredColour(paint, \"edge\"));\n          const knobOff = Option.getOrUndefined(\n            declaredColour(paint, \"knobOff\"),\n          );\n          return {\n            ...slots,\n            ...(edge === undefined ? {} : { edge }),\n            ...(knobOff === undefined ? {} : { knobOff }),\n          };\n        },\n      ),\n    ),\n  );\n\nconst switchTheme = (source: SwitchPaintTheme): PrimitiveTheme => ({\n  ...source,\n  switch: Option.getOrUndefined(declaredPaint(source)),\n});\n\nconst declaredColour = (\n  paint: DeclaredSwitch,\n  slot: SwitchSlot,\n): Option.Option<string> =>\n  pipe(\n    Option.fromNullishOr(paint[slot]),\n    Option.filter(P.isString),\n    Option.filter(Str.isNonEmpty),\n  );\n\nexport const SELECTION_STATES = [\n  \"unchecked\",\n  \"checked\",\n  \"indeterminate\",\n] as const;\nexport type SelectionState = (typeof SELECTION_STATES)[number];\n\nexport const SELECTION_ACCENTS = [\"primary\", \"destructive\"] as const;\nexport type SelectionAccent = (typeof SELECTION_ACCENTS)[number];\n\nconst ACCENT_NAMES: ReadonlyArray<string> = SELECTION_ACCENTS;\n\nexport const isSelectionAccent = (value: unknown): value is SelectionAccent =>\n  typeof value === \"string\" && Arr.contains(ACCENT_NAMES, value);\n\nexport const selectionAccentOf = (value: unknown): SelectionAccent =>\n  isSelectionAccent(value) ? value : \"primary\";\n\nexport interface SelectionSpec {\n  readonly state: SelectionState;\n  readonly size: ControlSize;\n  readonly accent: SelectionAccent;\n\n  readonly shape?: \"square\" | \"circle\";\n  readonly invalid?: boolean;\n  readonly disabled?: boolean;\n}\n\nconst filled = (spec: SelectionSpec): boolean => spec.state !== \"unchecked\";\n\nconst accentRole = (\n  spec: SelectionSpec,\n  theme: PrimitiveTheme,\n): {\n  readonly background: string | undefined;\n  readonly foreground: string | undefined;\n} =>\n  spec.accent === \"destructive\"\n    ? {\n        background: colorRole(theme, \"destructive\"),\n        foreground: colorRole(theme, \"destructiveForeground\"),\n      }\n    : {\n        background: colorRole(theme, \"primary\"),\n        foreground: colorRole(theme, \"primaryForeground\"),\n      };\n\nexport const selectionMarkColor = (\n  spec: SelectionSpec,\n  theme: PrimitiveTheme,\n): string | undefined =>\n  filled(spec)\n    ? accentRole(spec, theme).foreground\n    : spec.invalid === true\n      ? colorRole(theme, \"destructive\")\n      : colorRole(theme, \"mutedForeground\");\n\nconst feedbackFill = (\n  spec: SelectionSpec,\n  theme: PrimitiveTheme,\n  phase: \"hover\" | \"press\",\n): StyleDesc => ({\n  backgroundColor:\n    phase === \"hover\"\n      ? filledHover(theme, selectionAccentOf(spec.accent))\n      : filledPressed(theme, selectionAccentOf(spec.accent)),\n  borderColor: \"transparent\",\n});\n\nexport const selectionBoxStyle = (\n  spec: SelectionSpec,\n  theme: PrimitiveTheme,\n): StyleDesc => {\n  const side = iconSideOf(theme, spec.size);\n  const role = accentRole(spec, theme);\n  const emptyBorder =\n    spec.invalid === true\n      ? colorRole(theme, \"destructive\")\n      : colorRole(theme, \"borderStrong\");\n  const style: StyleDesc = {\n    display: \"flex\",\n    alignItems: \"center\",\n    justifyContent: \"center\",\n    width: side,\n    height: side,\n    flexShrink: 0,\n    borderRadius:\n      spec.shape === \"circle\"\n        ? radiusValue(theme, \"full\")\n        : radiusValue(theme, \"sm\"),\n    borderWidth: borderWidthOf(theme, \"thin\"),\n    borderColor: filled(spec) ? role.background : emptyBorder,\n    backgroundColor: filled(spec) ? role.background : undefined,\n    color: selectionMarkColor(spec, theme),\n    cursor: spec.disabled === true ? \"not-allowed\" : \"pointer\",\n    hover: filled(spec)\n      ? feedbackFill(spec, theme, \"hover\")\n      : { backgroundColor: colorRole(theme, \"hover\") },\n    active: filled(spec)\n      ? feedbackFill(spec, theme, \"press\")\n      : { backgroundColor: pressWash(theme) },\n  };\n  if (spec.disabled === true) {\n    style.opacity = disabledOpacity;\n\n    style.hover = {\n      backgroundColor: filled(spec) ? role.background : undefined,\n      borderColor: filled(spec) ? role.background : emptyBorder,\n    };\n    style.active = {};\n  }\n  return style;\n};\n\nexport const switchThumbInset = (\n  spec: SelectionSpec,\n  source: SwitchPaintTheme,\n): number => switchBox(spec.size, source).inset;\n\nexport interface SwitchBox {\n  readonly width: number;\n\n  readonly height: number;\n\n  readonly knob: number;\n\n  readonly inset: number;\n\n  readonly border: number;\n}\n\nexport const switchBox = (\n  size: ControlSize,\n  source: SwitchPaintTheme,\n): SwitchBox => {\n  const theme = switchTheme(source);\n\n  const metrics = Option.getOrUndefined(\n    Option.fromNullishOr(theme.switchMetrics),\n  );\n  if (theme.switch !== undefined && metrics !== undefined) {\n    return switchMetricsAt(metrics, size);\n  }\n  const iconSide = iconSideOf(theme, size);\n  const inset = spaceValue(theme, \"2xs\");\n  return {\n    width: Math.round(iconSide * 1.75),\n    height: iconSide,\n    knob: iconSide - inset * 2,\n    inset,\n    border: borderWidthOf(theme, \"thin\"),\n  };\n};\n\nexport const selectionTargetStyle = (\n  spec: SelectionSpec,\n  theme: PrimitiveTheme,\n): StyleDesc => {\n  const side = iconSideOf(theme, spec.size);\n  const inset = targetInset(side);\n  return {\n    display: \"flex\",\n    alignItems: \"center\",\n    justifyContent: \"center\",\n    width: side + inset * 2,\n    height: side + inset * 2,\n    flexShrink: 0,\n    cursor: spec.disabled === true ? \"not-allowed\" : \"pointer\",\n  };\n};\n\nexport const switchTargetStyle = (spec: SelectionSpec): StyleDesc => ({\n  display: \"flex\",\n  alignItems: \"center\",\n  justifyContent: \"center\",\n  minHeight: targetSize.minimum,\n  flexShrink: 0,\n  cursor: spec.disabled === true ? \"not-allowed\" : \"pointer\",\n});\n\nexport const switchThumbTravel = (\n  spec: SelectionSpec,\n  theme: SwitchPaintTheme,\n): number => {\n  const box = switchBox(spec.size, theme);\n  return box.width - box.knob - box.inset * 2;\n};\n\nexport const switchThumbOffset = (\n  spec: SelectionSpec,\n  theme: SwitchPaintTheme,\n): number => {\n  const box = switchBox(spec.size, theme);\n  const rest = box.inset - box.border;\n  return rest + (filled(spec) ? switchThumbTravel(spec, theme) : 0);\n};\n\nconst switchFill = (\n  spec: SelectionSpec,\n  theme: PrimitiveTheme,\n): string | undefined =>\n  theme.switch === undefined\n    ? undefined\n    : filled(spec)\n      ? theme.switch.on\n      : spec.invalid === true\n        ? colorRole(theme, \"destructive\")\n        : theme.switch.off;\n\nexport const switchTrackPaint = (\n  spec: SelectionSpec,\n  source: SwitchPaintTheme,\n): StyleDesc | undefined => {\n  const theme = switchTheme(source);\n  const fill = switchFill(spec, theme);\n  if (fill === undefined) return undefined;\n  const edge = filled(spec)\n    ? fill\n    : spec.invalid === true\n      ? colorRole(theme, \"destructive\")\n      : (theme.switch?.edge ?? fill);\n  const box = switchBox(spec.size, source);\n  return {\n    backgroundColor: fill,\n    borderColor: edge,\n\n    boxShadow:\n      !filled(spec) && box.border === 0 && theme.switch?.edge !== undefined\n        ? {\n            offsetX: 0,\n            offsetY: 0,\n            blurRadius: 0,\n            spreadRadius: 1,\n            color: edge ?? fill,\n          }\n        : undefined,\n    hover: { backgroundColor: fill, borderColor: edge },\n    active: { backgroundColor: fill, borderColor: edge },\n  };\n};\n\nexport const switchThumbPaint = (\n  spec: SelectionSpec,\n  source: SwitchPaintTheme,\n): StyleDesc | undefined => {\n  const theme = switchTheme(source);\n  return theme.switch === undefined\n    ? undefined\n    : {\n        backgroundColor: filled(spec)\n          ? theme.switch.knob\n          : (theme.switch.knobOff ?? theme.switch.knob),\n        boxShadow: elevationShadow(theme, \"sm\"),\n      };\n};\n\nexport const switchTrackStyle = (\n  spec: SelectionSpec,\n  source: SwitchPaintTheme,\n): StyleDesc => {\n  const theme = switchTheme(source);\n  const box = switchBox(spec.size, source);\n  const role = accentRole(spec, theme);\n  const emptyBorder =\n    spec.invalid === true\n      ? colorRole(theme, \"destructive\")\n      : colorRole(theme, \"borderStrong\");\n  const paint = switchTrackPaint(spec, source);\n  const fill =\n    paint?.backgroundColor ??\n    (filled(spec) ? role.background : colorRole(theme, \"muted\"));\n  const edge =\n    paint?.borderColor ?? (filled(spec) ? role.background : emptyBorder);\n  const style: StyleDesc = {\n    display: \"flex\",\n    flexDirection: \"row\",\n    alignItems: \"center\",\n    position: \"relative\",\n    width: box.width,\n    height: box.height,\n    flexShrink: 0,\n    borderRadius: radiusValue(theme, \"full\"),\n    borderWidth: box.border,\n    borderColor: edge,\n    backgroundColor: fill,\n    boxShadow: paint?.boxShadow,\n    cursor: spec.disabled === true ? \"not-allowed\" : \"pointer\",\n    hover:\n      paint?.hover ??\n      (filled(spec)\n        ? feedbackFill(spec, theme, \"hover\")\n        : { backgroundColor: colorRole(theme, \"hover\") }),\n    active:\n      paint?.active ??\n      (filled(spec)\n        ? feedbackFill(spec, theme, \"press\")\n        : { backgroundColor: pressWash(theme) }),\n  };\n  if (spec.disabled === true) {\n    style.opacity = disabledOpacity;\n    style.hover = { backgroundColor: fill, borderColor: edge };\n    style.active = {};\n  }\n  return style;\n};\n\nexport const switchThumbStyle = (\n  spec: SelectionSpec,\n  source: SwitchPaintTheme,\n): StyleDesc => {\n  const theme = switchTheme(source);\n  const paint = switchThumbPaint(spec, source);\n  const box = switchBox(spec.size, source);\n  return {\n    position: \"absolute\",\n\n    top: (box.height - box.border * 2 - box.knob) / 2,\n    left: switchThumbOffset(spec, source),\n    width: box.knob,\n    height: box.knob,\n    flexShrink: 0,\n    borderRadius: radiusValue(theme, \"full\"),\n    pointerEvents: \"none\",\n    backgroundColor:\n      paint?.backgroundColor ??\n      (filled(spec)\n        ? accentRole(spec, theme).foreground\n        : colorRole(theme, \"foreground\")),\n    boxShadow: paint?.boxShadow,\n  };\n};\n\nexport const radioDotStyle = (\n  spec: SelectionSpec,\n  theme: PrimitiveTheme,\n): StyleDesc => {\n  const side = Math.round(iconSideOf(theme, spec.size) / 2);\n  return {\n    width: side,\n    height: side,\n    flexShrink: 0,\n    borderRadius: radiusValue(theme, \"full\"),\n    backgroundColor: selectionMarkColor(spec, theme),\n  };\n};\n\nexport const toggleSelection = (\n  mode: \"single\" | \"multiple\",\n  current: ReadonlyArray<string>,\n  value: string,\n): ReadonlyArray<string> =>\n  mode === \"single\"\n    ? Arr.contains(current, value)\n      ? []\n      : [value]\n    : Arr.contains(current, value)\n      ? Arr.filter(current, (item) => item !== value)\n      : [...current, value];\n"
    },
    {
      "path": "packages/primitives/src/core/state.ts",
      "target": "@ui/gpuixui/primitives/core/state.ts",
      "type": "registry:lib",
      "content": "import * as Option from \"effect/Option\";\n\nexport type ControlMode = \"controlled\" | \"uncontrolled\";\n\nexport interface ValueState<Value> {\n  readonly mode: ControlMode;\n\n  readonly current: Value;\n\n  readonly internal: Value;\n}\n\nexport const initValueState = <Value>(\n  value: Option.Option<Value>,\n  defaultValue: Value,\n): ValueState<Value> => ({\n  mode: Option.isSome(value) ? \"controlled\" : \"uncontrolled\",\n  current: Option.getOrElse(value, () => defaultValue),\n  internal: defaultValue,\n});\n\nexport const setValue = <Value>(\n  state: ValueState<Value>,\n  next: Value,\n): { readonly state: ValueState<Value>; readonly notify: boolean } => {\n  const notify = !Object.is(state.current, next);\n  if (state.mode === \"controlled\") {\n    return {\n      state: { mode: state.mode, current: next, internal: state.internal },\n      notify,\n    };\n  }\n  return {\n    state: { mode: state.mode, current: next, internal: next },\n    notify,\n  };\n};\n\nexport const withValue = <Value>(\n  state: ValueState<Value>,\n  value: Option.Option<Value>,\n): ValueState<Value> =>\n  Option.match(value, {\n    onSome: (incoming) => ({\n      mode: \"controlled\",\n      current: incoming,\n      internal: state.internal,\n    }),\n    onNone: () => state,\n  });\n"
    },
    {
      "path": "packages/primitives/src/core/stored.ts",
      "target": "@ui/gpuixui/primitives/core/stored.ts",
      "type": "registry:lib",
      "content": "import * as Arr from \"effect/Array\";\nimport * as Option from \"effect/Option\";\nimport * as P from \"effect/Predicate\";\n\nexport const storedText = (value: unknown): string | undefined =>\n  P.isString(value) ? value : undefined;\n\nexport const storedList = <A>(\n  value: unknown,\n  read: (entry: unknown) => Option.Option<A>,\n): ReadonlyArray<A> =>\n  Arr.isArray(value) ? Arr.getSomes(Arr.map(value, read)) : [];\n\nexport const storedTextList = (\n  value: unknown,\n): Option.Option<ReadonlyArray<string>> =>\n  Arr.isArray(value)\n    ? Option.some(Arr.filter(value, P.isString))\n    : Option.none();\n\nexport const storedNumber = (value: unknown): Option.Option<number> =>\n  typeof value === \"number\" ? Option.some(value) : Option.none();\n"
    },
    {
      "path": "packages/primitives/src/core/style.ts",
      "target": "@ui/gpuixui/primitives/core/style.ts",
      "type": "registry:lib",
      "content": "import type { StyleDesc } from \"@gpuix/react\";\nimport {\n  brandText,\n  disabledAction,\n  disabledOpacity,\n  elevationShadow,\n  targetSize,\n  type FilledAction,\n} from \"../../tokens/index.js\";\nimport * as Arr from \"effect/Array\";\nimport * as Option from \"effect/Option\";\nimport * as P from \"effect/Predicate\";\nimport type {\n  ColorRef,\n  ControlSize,\n  ElevationLevel,\n  PrimitiveTheme,\n  RadiusStep,\n  SpaceStep,\n  TextRole,\n} from \"./theme.js\";\nimport { controlRing } from \"./focus.js\";\nimport { type Orientation, orientationOf } from \"./keyboard.js\";\nimport { pressWash } from \"./pointer.js\";\nimport {\n  borderWidthOf,\n  colorRole,\n  controlHeightOf,\n  controlPaddingOf,\n  familyOf,\n  iconSideOf,\n  radiusStep,\n  radiusValue,\n  spaceValue,\n  typeOf,\n} from \"./theme.js\";\nimport { fieldVariant } from \"./variants.js\";\n\ntype Paint = ColorRef | undefined;\n\nconst paint = (ref: Paint, theme: PrimitiveTheme): string | undefined =>\n  Option.getOrUndefined(\n    Option.map(Option.fromNullishOr(ref), (colorRef) => colorRef(theme)),\n  );\n\nexport interface ControlVariant {\n  readonly background: Paint;\n  readonly foreground: ColorRef;\n  readonly border: Paint;\n\n  readonly filledAction?: FilledAction;\n\n  readonly hover: (theme: PrimitiveTheme) => StyleDesc;\n  readonly active: (theme: PrimitiveTheme) => StyleDesc;\n}\n\nconst CONTROL_GAP: SpaceStep = \"sm\";\n\nexport interface ControlSpec {\n  readonly variant: ControlVariant;\n  readonly size: ControlSize;\n\n  readonly square?: boolean;\n  readonly fullWidth?: boolean;\n  readonly disabled?: boolean;\n\n  readonly invalid?: boolean;\n}\n\nexport const controlStyle = (\n  spec: ControlSpec,\n  theme: PrimitiveTheme,\n): StyleDesc => {\n  const { variant, size } = spec;\n  const height = controlHeightOf(theme, size);\n  const padding = controlPaddingOf(theme, size);\n  const label = typeOf(theme, \"label\");\n  const rest = paint(variant.background, theme);\n  const border =\n    spec.invalid === true\n      ? colorRole(theme, \"destructive\")\n      : paint(variant.border, theme);\n\n  const style: StyleDesc = {\n    display: \"flex\",\n    flexDirection: \"row\",\n    alignItems: \"center\",\n    justifyContent: \"center\",\n    gap: spaceValue(theme, CONTROL_GAP),\n    height,\n    borderRadius: radiusValue(theme, \"md\"),\n    fontSize: label.fontSize,\n    lineHeight: label.lineHeight,\n    fontWeight: label.fontWeight,\n    backgroundColor: rest,\n    color: paint(variant.foreground, theme),\n    borderWidth:\n      variant.border === undefined ? 0 : borderWidthOf(theme, \"thin\"),\n    borderColor: border,\n    paddingLeft: padding,\n    paddingRight: padding,\n    cursor: spec.disabled === true ? \"not-allowed\" : \"pointer\",\n  };\n\n  if (spec.disabled === true) {\n    const pair =\n      variant.filledAction === undefined ? undefined : disabledAction(theme);\n    if (pair === undefined) {\n      style.opacity = disabledOpacity;\n    } else {\n      style.backgroundColor = pair.backgroundColor;\n      style.color = pair.color;\n    }\n    style.hover = { backgroundColor: style.backgroundColor };\n    style.active = { backgroundColor: style.backgroundColor };\n  } else {\n    if (theme.interaction !== \"appkit\") style.hover = variant.hover(theme);\n    style.active = variant.active(theme);\n  }\n  if (spec.square === true) {\n    style.width = height;\n    style.paddingLeft = 0;\n    style.paddingRight = 0;\n  }\n  if (spec.fullWidth === true) style.width = \"100%\";\n  return style;\n};\n\nexport const controlFocusStyle = (\n  spec: ControlSpec,\n  theme: PrimitiveTheme,\n): StyleDesc =>\n  controlRing(theme, { disabled: spec.disabled, invalid: spec.invalid });\n\nexport const fieldTextStyle = (theme: PrimitiveTheme): StyleDesc => {\n  const body = typeOf(theme, \"body\");\n  return {\n    justifyContent: \"flex-start\",\n    fontSize: body.fontSize,\n    lineHeight: body.lineHeight,\n    fontWeight: body.fontWeight,\n    cursor: \"text\",\n    userSelect: \"text\",\n    selectionColor: colorRole(theme, \"selection\"),\n  };\n};\n\nexport {\n  nativeTextFills,\n  nativeTextTheme,\n  type NativeTextFill,\n  type NativeTextTheme,\n} from \"../../tokens/index.js\";\n\nexport const TEXT_TONES = [\n  \"default\",\n  \"muted\",\n  \"primary\",\n  \"destructive\",\n  \"inherit\",\n] as const;\n\nexport type TextTone = (typeof TEXT_TONES)[number];\n\nconst TEXT_TONE_NAMES: ReadonlyArray<string> = TEXT_TONES;\n\nexport const isTextTone = (value: unknown): value is TextTone =>\n  typeof value === \"string\" && Arr.contains(TEXT_TONE_NAMES, value);\n\nexport const textToneOf = (value: unknown): TextTone =>\n  isTextTone(value) ? value : \"default\";\n\nconst tones: Record<TextTone, Paint> = {\n  default: (theme) => colorRole(theme, \"foreground\"),\n  muted: (theme) => colorRole(theme, \"mutedForeground\"),\n\n  primary: brandText,\n\n  destructive: (theme) => colorRole(theme, \"destructiveSoftForeground\"),\n\n  inherit: undefined,\n};\n\nexport const toneColor = (\n  theme: PrimitiveTheme,\n  tone: TextTone,\n): string | undefined => paint(tones[textToneOf(tone)], theme);\n\nexport const TEXT_ALIGNMENTS = [\"start\", \"center\", \"end\"] as const;\nexport type TextAlign = (typeof TEXT_ALIGNMENTS)[number];\n\nconst ALIGN_VALUES: Readonly<Record<TextAlign, \"left\" | \"center\" | \"right\">> = {\n  start: \"left\",\n  center: \"center\",\n  end: \"right\",\n};\n\nexport const textAlignValue = (align: TextAlign): \"left\" | \"center\" | \"right\" =>\n  ALIGN_VALUES[align];\n\nexport const isTextAlign = (align: unknown): align is TextAlign =>\n  P.isString(align) && Arr.contains(TEXT_ALIGNMENTS, align);\n\nexport const textAlignOf = (align: unknown): TextAlign | undefined =>\n  isTextAlign(align) ? align : undefined;\n\nexport interface TextSpec {\n  readonly role: TextRole;\n  readonly tone: TextTone;\n  readonly align?: TextAlign;\n  readonly truncate?: boolean;\n\n  readonly clamp?: number;\n\n  readonly selectable?: boolean;\n}\n\nconst MONO_ROLES: ReadonlyArray<TextRole> = [\"code\", \"codeBlock\"];\n\nexport const clampLines = (clamp: unknown): number =>\n  typeof clamp === \"number\" && Number.isFinite(clamp)\n    ? Math.max(1, Math.floor(clamp))\n    : 1;\n\nexport const lineClampOf = (clamp: unknown): number | undefined =>\n  Option.match(Option.fromNullishOr(clamp), {\n    onNone: () => undefined,\n    onSome: (count) => clampLines(count),\n  });\n\nexport const textStyle = (spec: TextSpec, theme: PrimitiveTheme): StyleDesc => {\n  const role = typeOf(theme, spec.role);\n  const style: StyleDesc = {\n    fontSize: role.fontSize,\n    lineHeight: role.lineHeight,\n    fontWeight: role.fontWeight,\n    fontFamily: Arr.contains(MONO_ROLES, spec.role)\n      ? familyOf(theme, \"mono\")\n      : familyOf(theme, \"sans\"),\n    color: toneColor(theme, spec.tone),\n    userSelect: spec.selectable === true ? \"text\" : \"none\",\n  };\n  const align = textAlignOf(spec.align);\n  if (align !== undefined) style.textAlign = textAlignValue(align);\n\n  if (spec.selectable === true)\n    style.selectionColor = colorRole(theme, \"selection\");\n  if (spec.truncate === true) {\n    style.whiteSpace = \"nowrap\";\n    style.textOverflow = \"ellipsis\";\n  }\n  const clamp = lineClampOf(spec.clamp);\n  if (clamp !== undefined) {\n    style.whiteSpace = \"normal\";\n    style.height = role.lineHeight * clamp;\n    style.overflow = \"hidden\";\n  }\n  return style;\n};\n\nexport const SURFACE_TONES = [\n  \"none\",\n  \"background\",\n  \"card\",\n  \"popover\",\n  \"muted\",\n  \"accent\",\n  \"selected\",\n  \"skeleton\",\n] as const;\n\nexport type SurfaceTone = (typeof SURFACE_TONES)[number];\n\nconst surfaces: Record<SurfaceTone, Paint> = {\n  none: undefined,\n  background: (theme) => colorRole(theme, \"background\"),\n  card: (theme) => colorRole(theme, \"card\"),\n  popover: (theme) => colorRole(theme, \"popover\"),\n  muted: (theme) => colorRole(theme, \"muted\"),\n  accent: (theme) => colorRole(theme, \"accent\"),\n  selected: (theme) => colorRole(theme, \"selected\"),\n  skeleton: (theme) => colorRole(theme, \"skeleton\"),\n};\n\nexport const BORDER_STYLES = [\"solid\", \"dashed\"] as const;\nexport type BorderStyle = (typeof BORDER_STYLES)[number];\n\nexport interface SurfaceSpec {\n  readonly tone: SurfaceTone;\n\n  readonly padding?: SpaceStep;\n\n  readonly paddingX?: SpaceStep;\n\n  readonly paddingY?: SpaceStep;\n  readonly radius?: RadiusStep;\n  readonly border?: boolean;\n\n  readonly borderStyle?: BorderStyle;\n\n  readonly aspectRatio?: number;\n  readonly elevation?: ElevationLevel;\n}\n\nexport interface PaddingSides {\n  readonly top?: SpaceStep;\n  readonly right?: SpaceStep;\n  readonly bottom?: SpaceStep;\n  readonly left?: SpaceStep;\n}\n\nexport const paddingSides = ({\n  padding,\n  paddingX,\n  paddingY,\n}: Pick<SurfaceSpec, \"padding\" | \"paddingX\" | \"paddingY\">): PaddingSides =>\n  paddingX === undefined && paddingY === undefined\n    ? { top: padding, right: padding, bottom: padding, left: padding }\n    : {\n        top: paddingY ?? padding,\n        right: paddingX ?? padding,\n        bottom: paddingY ?? padding,\n        left: paddingX ?? padding,\n      };\n\nexport const paintableAspectRatio = (\n  aspectRatio: number | undefined,\n): number | undefined =>\n  aspectRatio !== undefined && Number.isFinite(aspectRatio) && aspectRatio > 0\n    ? aspectRatio\n    : undefined;\n\nexport const surfaceStyle = (\n  spec: SurfaceSpec,\n  theme: PrimitiveTheme,\n): StyleDesc => {\n  const style: StyleDesc = {\n    display: \"flex\",\n    flexDirection: \"column\",\n    backgroundColor: paint(surfaces[spec.tone], theme),\n  };\n  const sides = paddingSides(spec);\n  if (spec.paddingX === undefined && spec.paddingY === undefined) {\n    if (sides.top !== undefined) style.padding = spaceValue(theme, sides.top);\n  } else {\n    if (sides.top !== undefined)\n      style.paddingTop = spaceValue(theme, sides.top);\n    if (sides.right !== undefined)\n      style.paddingRight = spaceValue(theme, sides.right);\n    if (sides.bottom !== undefined)\n      style.paddingBottom = spaceValue(theme, sides.bottom);\n    if (sides.left !== undefined)\n      style.paddingLeft = spaceValue(theme, sides.left);\n  }\n  const corner = radiusStep(spec.radius);\n  if (corner !== undefined) style.borderRadius = radiusValue(theme, corner);\n  if (spec.border === true) {\n    style.borderWidth = borderWidthOf(theme, \"thin\");\n    style.borderColor = colorRole(theme, \"border\");\n    if (spec.borderStyle === \"dashed\") style.borderStyle = \"dashed\";\n  }\n  Option.map(\n    Option.fromNullishOr(paintableAspectRatio(spec.aspectRatio)),\n    (ratio) => {\n      style.aspectRatio = ratio;\n    },\n  );\n  if (spec.elevation !== undefined) {\n    Option.map(\n      Option.fromNullishOr(elevationShadow(theme, spec.elevation)),\n      (shadow) => {\n        style.boxShadow = shadow;\n      },\n    );\n  }\n  return style;\n};\n\nexport interface RuleSpec {\n  readonly orientation: Orientation;\n\n  readonly inset?: SpaceStep;\n}\n\nexport const ruleStyle = (spec: RuleSpec, theme: PrimitiveTheme): StyleDesc => {\n  const inset = spec.inset === undefined ? 0 : spaceValue(theme, spec.inset);\n  return orientationOf(spec.orientation, \"horizontal\") === \"horizontal\"\n    ? {\n        height: borderWidthOf(theme, \"thin\"),\n        flexShrink: 0,\n        backgroundColor: colorRole(theme, \"border\"),\n        marginLeft: inset,\n        marginRight: inset,\n      }\n    : {\n        width: borderWidthOf(theme, \"thin\"),\n        flexShrink: 0,\n        backgroundColor: colorRole(theme, \"border\"),\n        marginTop: inset,\n        marginBottom: inset,\n      };\n};\n\nexport const SCROLL_AXES = [\"vertical\", \"horizontal\", \"both\"] as const;\n\nexport type ScrollAxis = (typeof SCROLL_AXES)[number];\n\nconst SCROLL_AXIS_NAMES: ReadonlyArray<string> = SCROLL_AXES;\n\nexport const isScrollAxis = (value: unknown): value is ScrollAxis =>\n  P.isString(value) && Arr.contains(SCROLL_AXIS_NAMES, value);\n\nexport const scrollAxis = (value: unknown): ScrollAxis =>\n  isScrollAxis(value) ? value : \"vertical\";\n\nexport interface ScrollSpec {\n  readonly axis: ScrollAxis;\n}\n\nexport const scrollStyle = (spec: ScrollSpec): StyleDesc => {\n  const axis = scrollAxis(spec.axis);\n  return {\n    overflowY: axis === \"horizontal\" ? \"hidden\" : \"scroll\",\n    overflowX: axis === \"vertical\" ? \"hidden\" : \"scroll\",\n  };\n};\n\nexport const progressPercent = (value: unknown): number =>\n  typeof value === \"number\" && !Number.isNaN(value)\n    ? Math.min(100, Math.max(0, value))\n    : 0;\n\nexport const PROGRESS_TONES = [\n  \"primary\",\n  \"success\",\n  \"destructive\",\n  \"muted\",\n] as const;\n\nexport type ProgressTone = (typeof PROGRESS_TONES)[number];\n\nconst PROGRESS_TONE_NAMES: ReadonlyArray<string> = PROGRESS_TONES;\n\nconst progressTones: Record<ProgressTone, ColorRef> = {\n  primary: brandText,\n  success: (theme) => colorRole(theme, \"success\"),\n  destructive: (theme) => colorRole(theme, \"destructive\"),\n  muted: (theme) => colorRole(theme, \"mutedForeground\"),\n};\n\nexport const PROGRESS_SIZES = [\"sm\", \"md\"] as const;\nexport type ProgressSize = (typeof PROGRESS_SIZES)[number];\n\nconst PROGRESS_SIZE_NAMES: ReadonlyArray<string> = PROGRESS_SIZES;\n\nexport const isProgressSize = (value: unknown): value is ProgressSize =>\n  typeof value === \"string\" && Arr.contains(PROGRESS_SIZE_NAMES, value);\n\nexport const progressSizeOf = (value: unknown): ProgressSize =>\n  isProgressSize(value) ? value : \"md\";\n\nexport const isProgressTone = (value: unknown): value is ProgressTone =>\n  typeof value === \"string\" && Arr.contains(PROGRESS_TONE_NAMES, value);\n\nexport const progressToneOf = (value: unknown): ProgressTone =>\n  isProgressTone(value) ? value : \"primary\";\n\nexport interface ProgressSpec {\n  readonly value?: number;\n  readonly tone: ProgressTone;\n  readonly size: ProgressSize;\n}\n\nconst PROGRESS_HEIGHT: Record<ProgressSize, SpaceStep> = {\n  sm: \"xs\",\n  md: \"sm\",\n};\n\nexport const progressTrackStyle = (\n  spec: ProgressSpec,\n  theme: PrimitiveTheme,\n): StyleDesc => ({\n  display: \"flex\",\n  flexDirection: \"row\",\n  width: \"100%\",\n  height: spaceValue(theme, PROGRESS_HEIGHT[progressSizeOf(spec.size)]),\n  borderRadius: radiusValue(theme, \"full\"),\n  backgroundColor: colorRole(theme, \"muted\"),\n  overflow: \"hidden\",\n});\n\nexport const progressFillStyle = (\n  spec: ProgressSpec,\n  theme: PrimitiveTheme,\n): StyleDesc => ({\n  height: \"100%\",\n  width: `${progressPercent(spec.value ?? 0)}%`,\n  borderRadius: radiusValue(theme, \"full\"),\n  backgroundColor: paint(progressTones[progressToneOf(spec.tone)], theme),\n});\n\nexport const SLIDER_ORIENTATIONS = [\"horizontal\", \"vertical\"] as const;\nexport type SliderOrientation = (typeof SLIDER_ORIENTATIONS)[number];\n\nexport interface SliderSpec {\n  readonly size: ControlSize;\n  readonly invalid?: boolean;\n  readonly disabled?: boolean;\n\n  readonly orientation?: SliderOrientation;\n}\n\nconst isVertical = (spec: Pick<SliderSpec, \"orientation\">): boolean =>\n  spec.orientation === \"vertical\";\n\nexport const sliderInset = (size: ControlSize, theme: PrimitiveTheme): number =>\n  Math.round(iconSideOf(theme, size) / 2);\n\nexport const sliderTrackStyle = (\n  spec: SliderSpec,\n  theme: PrimitiveTheme,\n): StyleDesc => {\n  const inset = sliderInset(spec.size, theme);\n  const control = controlHeightOf(theme, spec.size);\n  const style: StyleDesc = isVertical(spec)\n    ? {\n        display: \"flex\",\n        flexDirection: \"column\",\n        alignItems: \"center\",\n        width: control,\n        height: \"100%\",\n        paddingTop: inset,\n        paddingBottom: inset,\n      }\n    : {\n        display: \"flex\",\n        flexDirection: \"row\",\n        alignItems: \"center\",\n        width: \"100%\",\n        height: control,\n        paddingLeft: inset,\n        paddingRight: inset,\n      };\n  style.cursor = spec.disabled === true ? \"not-allowed\" : \"pointer\";\n  if (spec.disabled === true) style.opacity = disabledOpacity;\n  return style;\n};\n\nexport const sliderRailStyle = (\n  spec: SliderSpec,\n  theme: PrimitiveTheme,\n): StyleDesc =>\n  isVertical(spec)\n    ? {\n        width: spaceValue(theme, \"xs\"),\n        height: \"100%\",\n        borderRadius: radiusValue(theme, \"full\"),\n        backgroundColor: colorRole(theme, \"muted\"),\n        display: \"flex\",\n\n        flexDirection: \"column\",\n        justifyContent: \"flex-end\",\n        alignItems: \"center\",\n        pointerEvents: \"none\",\n      }\n    : {\n        width: \"100%\",\n        height: spaceValue(theme, \"xs\"),\n        borderRadius: radiusValue(theme, \"full\"),\n        backgroundColor: colorRole(theme, \"muted\"),\n        display: \"flex\",\n        flexDirection: \"row\",\n        alignItems: \"center\",\n        pointerEvents: \"none\",\n      };\n\nexport const sliderFillStyle = (\n  fraction: number,\n  spec: SliderSpec,\n  theme: PrimitiveTheme,\n): StyleDesc => {\n  const share = `${(Number.isFinite(fraction) ? Math.min(1, Math.max(0, fraction)) : 0) * 100}%`;\n  const style: StyleDesc = isVertical(spec)\n    ? { width: \"100%\", height: share }\n    : { width: share, height: \"100%\" };\n  style.flexShrink = 0;\n  style.borderRadius = radiusValue(theme, \"full\");\n  style.backgroundColor =\n    spec.invalid === true\n      ? colorRole(theme, \"destructive\")\n      : colorRole(theme, \"primary\");\n  style.pointerEvents = \"none\";\n  return style;\n};\n\nexport const sliderThumbStyle = (\n  spec: SliderSpec,\n  theme: PrimitiveTheme,\n): StyleDesc => {\n  const side = iconSideOf(theme, spec.size);\n  const half = Math.round(side / 2);\n  const style: StyleDesc = {\n    width: side,\n    height: side,\n    flexShrink: 0,\n    borderRadius: radiusValue(theme, \"full\"),\n    backgroundColor: colorRole(theme, \"input\"),\n    borderWidth: borderWidthOf(theme, \"strong\"),\n    borderColor:\n      spec.invalid === true\n        ? colorRole(theme, \"destructive\")\n        : colorRole(theme, \"primary\"),\n    ...(isVertical(spec)\n      ? { marginTop: -half, marginBottom: -half }\n      : { marginLeft: -half, marginRight: -half }),\n    pointerEvents: \"none\",\n  };\n  return style;\n};\n\nexport const numberInputStyle = (): StyleDesc => ({\n  flexGrow: 1,\n  height: \"100%\",\n  minWidth: 0,\n  paddingLeft: 0,\n  paddingRight: 0,\n  borderWidth: 0,\n});\n\nexport const numberStepperColumnStyle = (theme: PrimitiveTheme): StyleDesc => ({\n  display: \"flex\",\n  flexDirection: \"column\",\n  width: iconSideOf(theme, \"md\") + spaceValue(theme, \"sm\"),\n  height: \"100%\",\n  flexShrink: 0,\n});\n\nexport const numberStepperStyle = (\n  spec: { readonly disabled?: boolean },\n  theme: PrimitiveTheme,\n): StyleDesc => {\n  const style: StyleDesc = {\n    display: \"flex\",\n    alignItems: \"center\",\n    justifyContent: \"center\",\n    flexGrow: 1,\n    borderRadius: radiusValue(theme, \"sm\"),\n    cursor: spec.disabled === true ? \"not-allowed\" : \"pointer\",\n  };\n  if (spec.disabled !== true) {\n    style.hover = { backgroundColor: colorRole(theme, \"hover\") };\n\n    style.active = { backgroundColor: pressWash(theme) };\n  }\n  return style;\n};\n\nexport interface RatingStarSpec {\n  readonly size: ControlSize;\n  readonly disabled?: boolean;\n  readonly readOnly?: boolean;\n}\n\nexport const ratingStarStyle = (\n  spec: RatingStarSpec,\n  theme: PrimitiveTheme,\n): StyleDesc => {\n  const interactive = spec.disabled !== true && spec.readOnly !== true;\n  const style: StyleDesc = {\n    position: \"relative\",\n    display: \"flex\",\n    alignItems: \"center\",\n    justifyContent: \"center\",\n    padding: spaceValue(theme, \"2xs\"),\n    minWidth: targetSize.minimum,\n    minHeight: targetSize.minimum,\n    borderRadius: radiusValue(theme, \"full\"),\n    cursor: interactive ? \"pointer\" : \"not-allowed\",\n  };\n  if (spec.disabled === true) style.opacity = disabledOpacity;\n  return style;\n};\n\nexport const ratingPartialStyle = (fill: number): StyleDesc => ({\n  position: \"absolute\",\n  top: 0,\n  bottom: 0,\n  left: 0,\n  width: `${Math.min(1, Math.max(0, fill)) * 100}%`,\n  overflow: \"hidden\",\n  pointerEvents: \"none\",\n});\n\nexport const ratingPartialCellStyle = (theme: PrimitiveTheme): StyleDesc => ({\n  position: \"absolute\",\n  top: 0,\n  bottom: 0,\n  left: 0,\n  display: \"flex\",\n  alignItems: \"center\",\n  justifyContent: \"center\",\n  padding: spaceValue(theme, \"2xs\"),\n  minWidth: targetSize.minimum,\n});\n\nexport const ratingStarColor = (\n  filled: boolean,\n  theme: PrimitiveTheme,\n  invalid?: boolean,\n): string | undefined =>\n  filled\n    ? invalid === true\n      ? colorRole(theme, \"destructive\")\n      : colorRole(theme, \"primary\")\n    : colorRole(theme, \"mutedForeground\");\n\nexport const otpGroupStyle = (theme: PrimitiveTheme): StyleDesc => ({\n  display: \"flex\",\n  flexDirection: \"row\",\n  alignItems: \"center\",\n  gap: spaceValue(theme, \"sm\"),\n});\n\nexport interface OtpCellSpec {\n  readonly size: ControlSize;\n  readonly invalid?: boolean;\n  readonly disabled?: boolean;\n}\n\nexport const otpCellStyle = (\n  spec: OtpCellSpec,\n  theme: PrimitiveTheme,\n): StyleDesc => {\n  const control = controlStyle(\n    {\n      variant: fieldVariant,\n      size: spec.size,\n      square: true,\n      invalid: spec.invalid,\n      disabled: spec.disabled,\n    },\n    theme,\n  );\n  const body = typeOf(theme, \"body\");\n  return {\n    ...control,\n    justifyContent: \"center\",\n    textAlign: \"center\",\n    fontSize: body.fontSize,\n    lineHeight: body.lineHeight,\n    fontWeight: body.fontWeight,\n    cursor: spec.disabled === true ? \"not-allowed\" : \"text\",\n  };\n};\n"
    },
    {
      "path": "packages/primitives/src/core/theme.ts",
      "target": "@ui/gpuixui/primitives/core/theme.ts",
      "type": "registry:lib",
      "content": "import {\n  borderWidth as libraryBorderWidth,\n  defaultDensity as libraryDensity,\n  iconSize as libraryIconSize,\n  isControlSize,\n  isElevationLevel,\n  isTextRole,\n  radius as libraryRadius,\n  spacing as librarySpacing,\n  themeColors,\n  typography as libraryTypography,\n  type ControlSize,\n  type ElevationLevel,\n  type ThemeColors,\n  type ThemeContrast,\n} from \"../../tokens/index.js\";\nimport type {\n  BorderWidth,\n  Density,\n  IconSize,\n  Radius,\n  Spacing,\n  TextRole,\n  TextStyle,\n} from \"../../tokens/index.js\";\nimport * as Arr from \"effect/Array\";\nimport * as Option from \"effect/Option\";\nimport * as P from \"effect/Predicate\";\nimport * as R from \"effect/Record\";\n\nexport { isTextRole };\n\nexport type {\n  BoxShadow as ThemeShadow,\n  BorderWidth,\n  ControlSize,\n  Density,\n  DensityName,\n  Elevation,\n  ElevationLevel,\n  FontWeight,\n  IconSize as ThemeIconSize,\n  Radius,\n  Spacing,\n  TextStyle,\n  TextRole,\n  Theme as PrimitiveTheme,\n  ThemeColors,\n  ThemeMode,\n  Typography,\n} from \"../../tokens/index.js\";\n\nexport const controlSize = (size: unknown): ControlSize =>\n  isControlSize(size) ? size : \"md\";\n\nexport const elevationLevel = (level: unknown): ElevationLevel | undefined =>\n  Option.match(Option.fromNullishOr(level), {\n    onNone: () => undefined,\n    onSome: (value) => (isElevationLevel(value) ? value : \"md\"),\n  });\n\nexport type SpaceStep = keyof Spacing;\n\nexport type RadiusStep = keyof Radius;\n\nexport interface SpaceSource {\n  readonly spacing?: Spacing | null;\n}\n\nexport const isSpaceStep = (\n  theme: SpaceSource,\n  step: unknown,\n): step is SpaceStep => {\n  const scale = theme.spacing;\n  if (scale === undefined || scale === null || !P.isString(step)) return false;\n  return Arr.some(R.keys(scale), (name) => name === step);\n};\n\nexport const spaceStep = (\n  theme: SpaceSource,\n  step: unknown,\n): SpaceStep | undefined => (isSpaceStep(theme, step) ? step : undefined);\n\nexport const scaleValue = <Step extends string>(\n  scale: Readonly<Partial<Record<Step, number>>> | null | undefined,\n  library: Readonly<Record<Step, number>>,\n  step: Step,\n): number => {\n  const value = scale === null || scale === undefined ? undefined : scale[step];\n  return P.isNumber(value) && Number.isFinite(value) ? value : library[step];\n};\n\nexport const spaceValue = (theme: SpaceSource, step: SpaceStep): number =>\n  scaleValue(theme.spacing, librarySpacing, step);\n\nexport interface RadiusSource {\n  readonly radius?: Radius | null;\n}\n\nexport const radiusValue = (theme: RadiusSource, step: RadiusStep): number =>\n  scaleValue(theme.radius, libraryRadius, step);\n\nconst RADIUS_STEPS: ReadonlyArray<string> = R.keys(libraryRadius);\n\nexport const isRadiusStep = (step: unknown): step is RadiusStep =>\n  P.isString(step) && Arr.contains(RADIUS_STEPS, step);\n\nexport const radiusStep = (step: unknown): RadiusStep | undefined =>\n  isRadiusStep(step) ? step : undefined;\n\nexport interface BorderWidthSource {\n  readonly borderWidth?: Partial<BorderWidth> | null;\n}\n\nexport const borderWidthOf = (\n  theme: BorderWidthSource,\n  step: keyof BorderWidth,\n): number => scaleValue(theme.borderWidth, libraryBorderWidth, step);\n\nexport interface DensitySource {\n  readonly density?: Density | null;\n}\n\nexport const controlHeightOf = (\n  theme: DensitySource,\n  size: ControlSize,\n): number =>\n  scaleValue(\n    theme.density?.controlHeight,\n    libraryDensity.controlHeight,\n    controlSize(size),\n  );\n\nexport const controlPaddingOf = (\n  theme: DensitySource,\n  size: ControlSize,\n): number =>\n  scaleValue(\n    theme.density?.controlPaddingX,\n    libraryDensity.controlPaddingX,\n    controlSize(size),\n  );\n\nexport const rowHeightOf = (theme: DensitySource): number => {\n  const height = theme.density?.rowHeight;\n  return P.isNumber(height) && Number.isFinite(height)\n    ? height\n    : libraryDensity.rowHeight;\n};\n\nexport interface IconSizeSource {\n  readonly iconSize?: IconSize | null;\n}\n\nexport const iconSideOf = (theme: IconSizeSource, size: ControlSize): number =>\n  scaleValue(theme.iconSize, libraryIconSize, controlSize(size));\n\nconst ICON_STEPS: ReadonlyArray<string> = R.keys(libraryIconSize);\n\nexport const isIconStep = (step: unknown): step is keyof IconSize =>\n  P.isString(step) && Arr.contains(ICON_STEPS, step);\n\nexport const iconStepValue = (theme: IconSizeSource, step: unknown): number =>\n  scaleValue(theme.iconSize, libraryIconSize, isIconStep(step) ? step : \"md\");\n\nexport interface TypeSource {\n  readonly typography?: {\n    readonly sans?: string | null;\n    readonly mono?: string | null;\n  } & Partial<Record<TextRole, TextStyle | null>>;\n}\n\nconst isTextStyle = (value: unknown): value is TextStyle =>\n  typeof value === \"object\" &&\n  value !== null &&\n  \"fontSize\" in value &&\n  \"lineHeight\" in value &&\n  \"fontWeight\" in value &&\n  P.isNumber(value.fontSize) &&\n  P.isNumber(value.lineHeight) &&\n  P.isNumber(value.fontWeight);\n\nexport const typeOf = (theme: TypeSource, role: unknown): TextStyle => {\n  const name = isTextRole(role) ? role : \"body\";\n  const style: unknown = theme.typography?.[name];\n  return isTextStyle(style) ? style : libraryTypography[name];\n};\n\nexport const familyOf = (\n  theme: TypeSource,\n  family: \"sans\" | \"mono\",\n): string => {\n  const name: unknown = theme.typography?.[family];\n  return P.isString(name) && name !== \"\" ? name : libraryTypography[family];\n};\n\nexport interface ColorSource {\n  readonly colors?: Partial<ThemeColors>;\n}\n\nexport type PaintSource = ColorSource & {\n  readonly contrast?: ThemeContrast;\n};\n\nexport const colorsOf = (theme: ColorSource): Partial<ThemeColors> =>\n  themeColors(theme);\n\nexport const colorRole = (\n  theme: ColorSource,\n  role: keyof ThemeColors,\n): string | undefined => colorsOf(theme)[role];\n\nexport type ColorRef = (theme: PaintSource) => string | undefined;\n"
    },
    {
      "path": "packages/primitives/src/core/value.ts",
      "target": "@ui/gpuixui/primitives/core/value.ts",
      "type": "registry:lib",
      "content": "import * as Option from \"effect/Option\";\nimport { storedNumber } from \"./stored.js\";\n\nexport interface ValueRange {\n  readonly min: number;\n  readonly max: number;\n  readonly step: number;\n}\n\nexport interface TrackBox {\n  readonly x: number;\n  readonly width: number;\n}\n\nexport interface VerticalTrackBox {\n  readonly y: number;\n  readonly height: number;\n}\n\nexport interface ValueSpan {\n  readonly start: number;\n  readonly end: number;\n}\n\nconst finiteOr = (value: number, fallback: number): number =>\n  Number.isFinite(value) ? value : fallback;\n\nexport const normalizeRange = (range: ValueRange): ValueRange => {\n  const min = finiteOr(range.min, 0);\n  const max = finiteOr(range.max, min + 1);\n  const step = finiteOr(range.step, 0) > 0 ? Math.abs(range.step) : 0;\n  return min <= max ? { min, max, step } : { min: max, max: min, step };\n};\n\nexport interface StoredRange {\n  readonly min?: unknown;\n  readonly max?: unknown;\n  readonly step?: unknown;\n}\n\nexport const storedRange = (\n  bounds: StoredRange,\n  defaults: ValueRange,\n): ValueRange =>\n  normalizeRange({\n    min: Option.getOrElse(storedNumber(bounds.min), () => defaults.min),\n    max: Option.getOrElse(storedNumber(bounds.max), () => defaults.max),\n    step: Option.getOrElse(storedNumber(bounds.step), () => defaults.step),\n  });\n\nconst cleanStep = (value: number): number =>\n  Number.parseFloat(value.toPrecision(15));\n\nexport const clampValue = (value: number, range: ValueRange): number => {\n  const { min, max, step } = normalizeRange(range);\n  if (!Number.isFinite(value)) return min;\n  const clamped = Math.min(max, Math.max(min, value));\n  if (step === 0) return clamped;\n  if (clamped >= max) return max;\n  const snapped = min + Math.round((clamped - min) / step) * step;\n  return Math.min(max, Math.max(min, cleanStep(snapped)));\n};\n\nexport const valueFraction = (value: number, range: ValueRange): number => {\n  const { min, max } = normalizeRange(range);\n  const span = max - min;\n  if (span <= 0) return 0;\n  return (clampValue(value, range) - min) / span;\n};\n\nexport const fractionValue = (fraction: number, range: ValueRange): number => {\n  const { min, max } = normalizeRange(range);\n  const bounded = Number.isFinite(fraction)\n    ? Math.min(1, Math.max(0, fraction))\n    : 0;\n  return clampValue(min + bounded * (max - min), range);\n};\n\nexport const valueStep = (range: ValueRange): number => {\n  const { min, max, step } = normalizeRange(range);\n  if (step > 0) return step;\n  const span = max - min;\n  return span > 0 ? span / 100 : 1;\n};\n\nexport const stepValue = (\n  value: number,\n  range: ValueRange,\n  steps: number,\n): number => {\n  const normalized = normalizeRange(range);\n  const base = clampValue(value, normalized);\n  if (steps === 0) return base;\n  if (normalized.step === 0)\n    return clampValue(base + steps * valueStep(normalized), normalized);\n  const offset = (base - normalized.min) / normalized.step;\n  const nearest = Math.round(offset);\n\n  const index =\n    Math.abs(offset - nearest) < 1e-9\n      ? nearest\n      : steps > 0\n        ? Math.floor(offset)\n        : Math.ceil(offset);\n  return clampValue(\n    normalized.min + (index + steps) * normalized.step,\n    normalized,\n  );\n};\n\nconst ARROW_STEPS: Readonly<Record<string, number>> = {\n  left: -1,\n  down: -1,\n  right: 1,\n  up: 1,\n};\n\nexport const decideValueKey = (\n  value: number,\n  range: ValueRange,\n  key: string,\n  pageSteps = 10,\n): Option.Option<number> => {\n  const normalized = normalizeRange(range);\n  if (key === \"home\") return Option.some(normalized.min);\n  if (key === \"end\") return Option.some(normalized.max);\n  const steps =\n    key === \"pageup\"\n      ? pageSteps\n      : key === \"pagedown\"\n        ? -pageSteps\n        : ARROW_STEPS[key];\n  return steps === undefined\n    ? Option.none()\n    : Option.some(stepValue(value, normalized, steps));\n};\n\nexport const pointerValue = (\n  x: number,\n  box: TrackBox,\n  range: ValueRange,\n  inset = 0,\n): number => {\n  const span = box.width - 2 * inset;\n  if (!Number.isFinite(x) || span <= 0) return normalizeRange(range).min;\n  return fractionValue((x - box.x - inset) / span, range);\n};\n\nexport const verticalPointerValue = (\n  y: number,\n  box: VerticalTrackBox,\n  range: ValueRange,\n  inset = 0,\n): number => {\n  const span = box.height - 2 * inset;\n  if (!Number.isFinite(y) || span <= 0) return normalizeRange(range).min;\n  return fractionValue(1 - (y - box.y - inset) / span, range);\n};\n\nexport const normalizeSpan = (\n  span: ValueSpan,\n  range: ValueRange,\n): ValueSpan => {\n  const start = clampValue(span.start, range);\n  const end = clampValue(span.end, range);\n  return start <= end ? { start, end } : { start: end, end: start };\n};\n\nexport const nearestEnd = (value: number, span: ValueSpan): \"start\" | \"end\" => {\n  if (value <= span.start) return \"start\";\n  if (value >= span.end) return \"end\";\n  return value - span.start <= span.end - value ? \"start\" : \"end\";\n};\n\nexport const spanFrom = (\n  point: number,\n  value: number,\n  range: ValueRange,\n): ValueSpan => {\n  const pinned = clampValue(point, range);\n  const moved = clampValue(value, range);\n  return moved >= pinned\n    ? { start: pinned, end: moved }\n    : { start: moved, end: pinned };\n};\n\nexport const moveSpanEnd = (\n  span: ValueSpan,\n  end: \"start\" | \"end\",\n  value: number,\n  range: ValueRange,\n): ValueSpan => {\n  const current = normalizeSpan(span, range);\n  return end === \"start\"\n    ? {\n        start: Math.min(clampValue(value, range), current.end),\n        end: current.end,\n      }\n    : {\n        start: current.start,\n        end: Math.max(clampValue(value, range), current.start),\n      };\n};\n"
    },
    {
      "path": "packages/primitives/src/core/variants.ts",
      "target": "@ui/gpuixui/primitives/core/variants.ts",
      "type": "registry:lib",
      "content": "import * as Arr from \"effect/Array\";\nimport type { StyleDesc } from \"@gpuix/react\";\nimport {\n  brandText,\n  filledHover,\n  filledPressed,\n  type FilledAction,\n} from \"../../tokens/index.js\";\nimport type { SpinnerAccent } from \"./loading.js\";\nimport { pressWash } from \"./pointer.js\";\nimport { colorRole, type PaintSource, type PrimitiveTheme } from \"./theme.js\";\nimport type { ControlVariant } from \"./style.js\";\n\nexport const BUTTON_VARIANTS = [\n  \"primary\",\n  \"secondary\",\n  \"outline\",\n  \"ghost\",\n  \"destructive\",\n  \"link\",\n] as const;\n\nexport type ButtonVariant = (typeof BUTTON_VARIANTS)[number];\n\nconst VARIANT_NAMES: ReadonlyArray<string> = BUTTON_VARIANTS;\n\nexport const isButtonVariant = (value: unknown): value is ButtonVariant =>\n  typeof value === \"string\" && Arr.contains(VARIANT_NAMES, value);\n\nexport const buttonVariantOf = (value: unknown): ButtonVariant =>\n  isButtonVariant(value) ? value : \"primary\";\n\nconst filled = (\n  action: FilledAction,\n): Pick<ControlVariant, \"hover\" | \"active\" | \"filledAction\"> => ({\n  filledAction: action,\n  hover: (theme) => ({ backgroundColor: filledHover(theme, action) }),\n  active: (theme) => ({ backgroundColor: filledPressed(theme, action) }),\n});\n\nconst primary: ControlVariant = {\n  background: (theme) => colorRole(theme, \"primary\"),\n  foreground: (theme) => colorRole(theme, \"primaryForeground\"),\n  border: undefined,\n  ...filled(\"primary\"),\n};\n\nconst secondary: ControlVariant = {\n  background: (theme) => colorRole(theme, \"secondary\"),\n  foreground: (theme) => colorRole(theme, \"secondaryForeground\"),\n  border: (theme) => colorRole(theme, \"borderStrong\"),\n  ...filled(\"secondary\"),\n};\n\nconst washed: Pick<ControlVariant, \"hover\" | \"active\"> = {\n  hover: (theme) => ({ backgroundColor: colorRole(theme, \"hover\") }),\n  active: (theme) => ({ backgroundColor: pressWash(theme) }),\n};\n\nconst outline: ControlVariant = {\n  background: undefined,\n  foreground: (theme) => colorRole(theme, \"foreground\"),\n  border: (theme) => colorRole(theme, \"borderStrong\"),\n  ...washed,\n};\n\nconst ghost: ControlVariant = {\n  background: undefined,\n  foreground: (theme) => colorRole(theme, \"foreground\"),\n  border: undefined,\n  ...washed,\n};\n\nconst destructive: ControlVariant = {\n  background: (theme) => colorRole(theme, \"destructive\"),\n  foreground: (theme) => colorRole(theme, \"destructiveForeground\"),\n  border: undefined,\n  ...filled(\"destructive\"),\n};\n\nconst link: ControlVariant = {\n  background: undefined,\n\n  foreground: brandText,\n  border: undefined,\n  hover: (theme) => ({\n    backgroundColor: colorRole(theme, \"hover\"),\n    textDecoration: \"underline\",\n  }),\n  active: (theme) => ({ backgroundColor: pressWash(theme) }),\n};\n\nexport const buttonVariants: Record<ButtonVariant, ControlVariant> = {\n  primary,\n  secondary,\n  outline,\n  ghost,\n  destructive,\n  link,\n};\n\nexport function actionOnColor(\n  theme: PrimitiveTheme,\n  variant: ButtonVariant,\n): string;\nexport function actionOnColor(\n  theme: PaintSource,\n  variant: ButtonVariant,\n): string | undefined;\nexport function actionOnColor(\n  theme: PaintSource,\n  variant: ButtonVariant,\n): string | undefined {\n  return buttonVariants[buttonVariantOf(variant)].foreground(theme);\n}\n\nconst FILLED_SPINNER_ACCENT: Readonly<\n  Partial<Record<ButtonVariant, SpinnerAccent>>\n> = {\n  primary: \"on-primary\",\n  secondary: \"on-secondary\",\n  destructive: \"on-destructive\",\n};\n\nexport const variantSpinnerAccent = (\n  variant: ButtonVariant,\n  disabled = false,\n): SpinnerAccent => {\n  const name = buttonVariantOf(variant);\n  return disabled && paintsFilledSurface(name)\n    ? \"on-disabled\"\n    : (FILLED_SPINNER_ACCENT[name] ?? \"primary\");\n};\n\nexport const toggleSpinnerAccent = (\n  pressed: boolean,\n  disabled = false,\n): SpinnerAccent => {\n  if (pressed) return disabled ? \"on-disabled\" : \"on-accent\";\n  return \"primary\";\n};\n\nexport const paintsFilledSurface = (variant: ButtonVariant): boolean =>\n  buttonVariants[buttonVariantOf(variant)].filledAction !== undefined;\n\nexport const fieldVariant: ControlVariant = {\n  background: (theme) => colorRole(theme, \"input\"),\n  foreground: (theme) => colorRole(theme, \"inputForeground\"),\n  border: (theme) => colorRole(theme, \"border\"),\n  hover: (theme) => ({ borderColor: colorRole(theme, \"borderStrong\") }),\n  active: (theme) => ({ borderColor: colorRole(theme, \"ring\") }),\n};\n\nexport const variantTable: ReadonlyArray<{\n  readonly name: ButtonVariant;\n  readonly variant: ControlVariant;\n  readonly description: string;\n}> = [\n  { name: \"primary\", variant: primary, description: \"The brand action.\" },\n  { name: \"secondary\", variant: secondary, description: \"Filled, neutral.\" },\n  { name: \"outline\", variant: outline, description: \"Border only.\" },\n  { name: \"ghost\", variant: ghost, description: \"No chrome at rest.\" },\n  {\n    name: \"destructive\",\n    variant: destructive,\n    description: \"Deletes, revokes, disconnects.\",\n  },\n  { name: \"link\", variant: link, description: \"A text action.\" },\n];\n\nexport const TOGGLE_VARIANTS = [\"default\", \"outline\"] as const;\n\nexport type ToggleVariant = (typeof TOGGLE_VARIANTS)[number];\n\nconst TOGGLE_NAMES: ReadonlyArray<string> = TOGGLE_VARIANTS;\n\nexport const isToggleVariant = (value: unknown): value is ToggleVariant =>\n  typeof value === \"string\" && Arr.contains(TOGGLE_NAMES, value);\n\nexport const toggleVariantOf = (value: unknown): ToggleVariant =>\n  isToggleVariant(value) ? value : \"default\";\n\nconst toggleRest: ControlVariant = {\n  background: undefined,\n  foreground: (theme) => colorRole(theme, \"foreground\"),\n  border: undefined,\n  ...washed,\n};\n\nconst toggleOutlineRest: ControlVariant = {\n  background: undefined,\n  foreground: (theme) => colorRole(theme, \"foreground\"),\n  border: (theme) => colorRole(theme, \"borderStrong\"),\n  ...washed,\n};\n\nconst togglePressedBase = (\n  border: ControlVariant[\"border\"],\n): ControlVariant => ({\n  background: (theme) => colorRole(theme, \"accent\"),\n  foreground: (theme) => colorRole(theme, \"accentForeground\"),\n  border,\n\n  hover: (theme) => ({ backgroundColor: filledHover(theme, \"accent\") }),\n  active: (theme) => ({ backgroundColor: filledPressed(theme, \"accent\") }),\n});\n\nexport const toggleVariants: Readonly<\n  Record<\n    ToggleVariant,\n    { readonly rest: ControlVariant; readonly pressed: ControlVariant }\n  >\n> = {\n  default: {\n    rest: toggleRest,\n    pressed: togglePressedBase(undefined),\n  },\n  outline: {\n    rest: toggleOutlineRest,\n    pressed: togglePressedBase((theme) => colorRole(theme, \"borderStrong\")),\n  },\n};\n\nexport const variantKey = (\n  variant: ControlVariant,\n  theme: PrimitiveTheme,\n): string =>\n  [\n    variant.background === undefined ? \"none\" : variant.background(theme),\n    variant.foreground(theme),\n    variant.border === undefined ? \"none\" : variant.border(theme),\n  ].join(\"/\");\n\nexport const hasPointerFeedback = (\n  variant: ControlVariant,\n  theme: PrimitiveTheme,\n): boolean => {\n  const feedback = (style: StyleDesc): boolean =>\n    style.backgroundColor !== undefined || style.borderColor !== undefined;\n  return feedback(variant.hover(theme)) && feedback(variant.active(theme));\n};\n"
    },
    {
      "path": "packages/primitives/src/recipe/index.ts",
      "target": "@ui/gpuixui/primitives/recipe/index.ts",
      "type": "registry:lib",
      "content": "import type { ControlSize, TextRole } from \"../../tokens/index.js\";\nimport { cn } from \"../../tw/index.js\";\nimport { elevationLevel, isTextRole, radiusStep } from \"../core/theme.js\";\nimport { stackDirection, trackCount } from \"../core/layout.js\";\nimport type {\n  BoxSpec,\n  GridSpec,\n  StackAlign,\n  StackJustify,\n  StackSpec,\n} from \"../core/layout.js\";\nimport type { SelectionAccent, SelectionState } from \"../core/selection.js\";\nimport {\n  lineClampOf,\n  paintableAspectRatio,\n  paddingSides,\n  progressSizeOf,\n  progressToneOf,\n  scrollAxis,\n  textAlignOf,\n  textToneOf,\n} from \"../core/style.js\";\nimport type {\n  ProgressSize,\n  ProgressTone,\n  SliderOrientation,\n  SurfaceTone,\n  TextAlign,\n  TextTone,\n} from \"../core/style.js\";\nimport type { ElevationLevel, RadiusStep, SpaceStep } from \"../core/theme.js\";\nimport { type Orientation, orientationOf } from \"../core/keyboard.js\";\nimport { selectionAccentOf } from \"../core/selection.js\";\nimport {\n  buttonVariantOf,\n  paintsFilledSurface,\n  toggleVariantOf,\n} from \"../core/variants.js\";\nimport type { ButtonVariant, ToggleVariant } from \"../core/variants.js\";\n\nconst BUTTON_BASE =\n  \"flex flex-row items-center justify-center gap-sm rounded-md type-label cursor-pointer disabled:cursor-not-allowed\";\n\nconst FILLED_DISABLED =\n  \"disabled:bg-disabled disabled:text-disabled-foreground\";\nconst UNFILLED_DISABLED = \"disabled:opacity-50\";\n\nconst BUTTON_VARIANT: Readonly<Record<ButtonVariant, string>> = {\n  primary:\n    \"bg-primary text-primary-foreground border-0 hover:fill-primary active:fill-primary-pressed\",\n  secondary:\n    \"bg-secondary text-secondary-foreground border border-strong hover:fill-secondary active:fill-secondary-pressed\",\n  outline:\n    \"text-foreground border border-strong hover:bg-hover active:bg-active\",\n  ghost: \"text-foreground border-0 hover:bg-hover active:bg-active\",\n  destructive:\n    \"bg-destructive text-destructive-foreground border-0 hover:fill-destructive active:fill-destructive-pressed\",\n  link: \"text-brand border-0 hover:bg-hover hover:underline active:bg-active\",\n};\n\nconst BUTTON_SIZE: Readonly<Record<ControlSize, string>> = {\n  sm: \"h-sm px-sm\",\n  md: \"h-md px-md\",\n  lg: \"h-lg px-lg\",\n};\n\nconst BUTTON_SQUARE: Readonly<Record<ControlSize, string>> = {\n  sm: \"size-sm px-0\",\n  md: \"size-md px-0\",\n  lg: \"size-lg px-0\",\n};\n\nexport interface ButtonRecipeOptions {\n  readonly square?: boolean;\n  readonly fullWidth?: boolean;\n}\n\nexport const buttonClass = (\n  variant: ButtonVariant,\n  size: ControlSize,\n  options: ButtonRecipeOptions = {},\n): string => {\n  const name = buttonVariantOf(variant);\n  return cn(\n    BUTTON_BASE,\n    BUTTON_VARIANT[name],\n    paintsFilledSurface(name) ? FILLED_DISABLED : UNFILLED_DISABLED,\n    options.square === true ? BUTTON_SQUARE[size] : BUTTON_SIZE[size],\n    options.fullWidth === true && \"w-full\",\n  );\n};\n\nconst FIELD_BASE =\n  \"flex flex-row items-center justify-start gap-sm rounded-md type-body cursor-text select-text bg-input text-input-foreground border border-border hover:border-border-strong active:border-ring disabled:opacity-50 disabled:cursor-not-allowed\";\n\nconst FIELD_INVALID = \"aria-invalid:border-destructive\";\n\nexport interface FieldRecipeOptions {\n  readonly size: ControlSize;\n  readonly fullWidth?: boolean;\n  readonly invalid?: boolean;\n}\n\nexport const fieldClass = (options: FieldRecipeOptions): string =>\n  cn(\n    FIELD_BASE,\n    BUTTON_SIZE[options.size],\n    options.invalid === true && FIELD_INVALID,\n    options.fullWidth === true && \"w-full\",\n  );\n\nconst ROLE_CLASS: Readonly<Record<TextRole, string>> = {\n  display: \"display\",\n  h1: \"h1\",\n  h2: \"h2\",\n  h3: \"h3\",\n  body: \"body\",\n  bodyStrong: \"body-strong\",\n  label: \"label\",\n  caption: \"caption\",\n  code: \"code\",\n  codeBlock: \"code-block\",\n};\n\nconst TONE_CLASS: Readonly<Record<TextTone, string | undefined>> = {\n  default: \"text-foreground\",\n  muted: \"text-muted-foreground\",\n\n  primary: \"text-brand\",\n\n  destructive: \"text-destructiveSoftForeground\",\n  inherit: undefined,\n};\n\nconst ALIGN_CLASS: Readonly<Record<TextAlign, string>> = {\n  start: \"text-start\",\n  center: \"text-center\",\n  end: \"text-end\",\n};\n\nconst MONO_ROLES: ReadonlyArray<TextRole> = [\"code\", \"codeBlock\"];\n\nconst familyOf = (role: TextRole): string =>\n  MONO_ROLES.includes(role) ? \"font-mono\" : \"font-sans\";\n\nexport interface TextRecipeOptions {\n  readonly role: TextRole;\n  readonly tone: TextTone;\n  readonly align?: TextAlign;\n  readonly truncate?: boolean;\n  readonly clamp?: number;\n  readonly selectable?: boolean;\n}\n\nexport const textClass = (options: TextRecipeOptions): string => {\n  const role = isTextRole(options.role) ? options.role : \"body\";\n  const align = textAlignOf(options.align);\n  const clamp = lineClampOf(options.clamp);\n  return cn(\n    `type-${ROLE_CLASS[role]}`,\n    familyOf(role),\n    TONE_CLASS[textToneOf(options.tone)],\n    align === undefined ? undefined : ALIGN_CLASS[align],\n    options.selectable === true ? \"select-text\" : \"select-none\",\n    options.truncate === true && \"whitespace-nowrap text-ellipsis\",\n\n    clamp === undefined ? undefined : `clamp-${ROLE_CLASS[role]}-${clamp}`,\n  );\n};\n\nconst ALIGN_TO_CLASS: Readonly<Record<StackAlign, string>> = {\n  start: \"items-start\",\n  center: \"items-center\",\n  end: \"items-end\",\n  stretch: \"items-stretch\",\n  baseline: \"items-baseline\",\n};\n\nconst JUSTIFY_TO_CLASS: Readonly<Record<StackJustify, string>> = {\n  start: \"justify-start\",\n  center: \"justify-center\",\n  end: \"justify-end\",\n  between: \"justify-between\",\n  around: \"justify-around\",\n};\n\nconst directionClass = (direction: unknown): string =>\n  stackDirection(direction) === \"row\" ? \"flex-row\" : \"flex-col\";\n\nexport const stackClass = (spec: StackSpec): string =>\n  cn(\n    \"flex\",\n    directionClass(spec.direction),\n    spec.gap === undefined ? undefined : `gap-${spec.gap}`,\n    spec.align === undefined ? undefined : ALIGN_TO_CLASS[spec.align],\n    spec.justify === undefined ? undefined : JUSTIFY_TO_CLASS[spec.justify],\n    spec.wrap === true && \"flex-wrap\",\n    spec.grow === true && \"flex-grow\",\n    spec.fullWidth === true && \"w-full\",\n    spec.fullHeight === true && \"h-full\",\n  );\n\nexport const gridClass = (spec: GridSpec): string =>\n  cn(\n    \"grid\",\n    `grid-cols-${trackCount(spec.columns)}`,\n    spec.rows === undefined ? undefined : `grid-rows-${trackCount(spec.rows)}`,\n    spec.gap === undefined ? undefined : `gap-${spec.gap}`,\n    spec.grow === true && \"flex-grow\",\n  );\n\nconst SURFACE_BG: Readonly<Record<SurfaceTone, string | undefined>> = {\n  none: undefined,\n  background: \"bg-background\",\n  card: \"bg-card\",\n  popover: \"bg-popover\",\n  muted: \"bg-muted\",\n  accent: \"bg-accent\",\n  selected: \"bg-selected\",\n  skeleton: \"bg-skeleton\",\n};\n\nconst ELEVATION_SHADOW: Readonly<Record<ElevationLevel, string | undefined>> = {\n  sm: \"shadow-sm\",\n  md: \"shadow-md\",\n  lg: \"shadow-lg\",\n  overlay: undefined,\n};\n\nconst elevationClass = (level: unknown): string | undefined => {\n  const resolved = elevationLevel(level);\n  return resolved === undefined ? undefined : ELEVATION_SHADOW[resolved];\n};\n\nconst boxPaddingClass = (spec: BoxSpec): string | undefined => {\n  const sides = paddingSides(spec);\n  if (spec.paddingX === undefined && spec.paddingY === undefined) {\n    return sides.top === undefined ? undefined : `p-${sides.top}`;\n  }\n  return cn(\n    sides.top === undefined ? undefined : `pt-${sides.top}`,\n    sides.right === undefined ? undefined : `pr-${sides.right}`,\n    sides.bottom === undefined ? undefined : `pb-${sides.bottom}`,\n    sides.left === undefined ? undefined : `pl-${sides.left}`,\n  );\n};\n\nexport const boxClass = (spec: BoxSpec): string => {\n  const corner = radiusStep(spec.radius);\n  return cn(\n    \"flex flex-col\",\n    SURFACE_BG[spec.tone],\n    boxPaddingClass(spec),\n    corner === undefined ? undefined : `rounded-${corner}`,\n    spec.border === true && \"border border-border\",\n    spec.border === true && spec.borderStyle === \"dashed\" && \"border-dashed\",\n    paintableAspectRatio(spec.aspectRatio) === undefined\n      ? undefined\n      : `aspect-ratio-${spec.aspectRatio}`,\n    elevationClass(spec.elevation),\n    spec.shrink === true ? \"shrink-1\" : \"shrink-0\",\n    spec.grow === true && \"flex-grow\",\n    spec.fullWidth === true && \"w-full\",\n    spec.fullHeight === true && \"h-full\",\n  );\n};\n\nconst TOGGLE_PAINT: Readonly<\n  Record<ToggleVariant, { readonly rest: string; readonly pressed: string }>\n> = {\n  default: {\n    rest: \"text-foreground border-0 hover:bg-hover active:bg-active\",\n    pressed:\n      \"bg-accent text-accent-foreground border-0 hover:fill-accent active:fill-accent-pressed\",\n  },\n  outline: {\n    rest: \"text-foreground border border-strong hover:bg-hover active:bg-active\",\n    pressed:\n      \"bg-accent text-accent-foreground border border-strong hover:fill-accent active:fill-accent-pressed\",\n  },\n};\n\nexport const toggleClass = (\n  variant: ToggleVariant,\n  pressed: boolean,\n  size: ControlSize,\n  options: ButtonRecipeOptions = {},\n): string =>\n  cn(\n    BUTTON_BASE,\n    TOGGLE_PAINT[toggleVariantOf(variant)][pressed ? \"pressed\" : \"rest\"],\n\n    pressed ? FILLED_DISABLED : UNFILLED_DISABLED,\n    options.square === true ? BUTTON_SQUARE[size] : BUTTON_SIZE[size],\n  );\n\nexport const separatorClass = (\n  orientation: Orientation,\n  inset?: SpaceStep,\n): string => {\n  const step = inset ?? \"0\";\n  return orientationOf(orientation, \"horizontal\") === \"horizontal\"\n    ? cn(\"h-px shrink-0 bg-border\", `ml-${step}`, `mr-${step}`)\n    : cn(\"w-px shrink-0 bg-border\", `mt-${step}`, `mb-${step}`);\n};\n\nexport const separatorGroupClass = \"flex flex-row items-center gap-sm\";\n\nexport const scrollClass = (axis: unknown): string => {\n  const resolved = scrollAxis(axis);\n  return resolved === \"horizontal\"\n    ? \"overflow-y-hidden overflow-x-scroll\"\n    : resolved === \"vertical\"\n      ? \"overflow-y-scroll overflow-x-hidden\"\n      : \"overflow-y-scroll overflow-x-scroll\";\n};\n\nexport const scrollFrameClass = (spec: {\n  readonly padding?: SpaceStep;\n  readonly radius?: RadiusStep;\n  readonly border?: boolean;\n}): string => {\n  const corner = radiusStep(spec.radius);\n  return cn(\n    \"flex flex-col overflow-hidden\",\n    spec.padding === undefined ? undefined : `p-${spec.padding}`,\n    corner === undefined ? undefined : `rounded-${corner}`,\n    spec.border === true && \"border border-border\",\n  );\n};\n\nexport const buttonGroupClass = (\n  mode: \"attached\" | \"separated\",\n  gap: SpaceStep,\n  orientation: \"horizontal\" | \"vertical\",\n): string =>\n  cn(\n    \"flex\",\n    orientation === \"vertical\"\n      ? \"flex-col items-stretch\"\n      : \"flex-row items-center\",\n    mode === \"attached\" ? \"gap-0 rounded-md overflow-hidden\" : `gap-${gap}`,\n  );\n\nconst FIELD_SQUARE_BASE =\n  \"flex flex-row items-center justify-center gap-sm rounded-md type-body text-center bg-input text-input-foreground border border-border cursor-text hover:border-border-strong active:border-ring disabled:opacity-50 disabled:cursor-not-allowed\";\n\nexport const fieldSquareClass = (options: {\n  readonly size: ControlSize;\n  readonly invalid?: boolean;\n}): string =>\n  cn(\n    FIELD_SQUARE_BASE,\n    `size-${options.size}`,\n    \"px-0\",\n    options.invalid === true && FIELD_INVALID,\n  );\n\nexport const otpGroupClass = \"flex flex-row items-center gap-sm\";\n\nexport const ratingStarClass = (options: {\n  readonly disabled?: boolean;\n  readonly readOnly?: boolean;\n}): string => {\n  const interactive = options.disabled !== true && options.readOnly !== true;\n  return cn(\n    \"relative flex items-center justify-center p-2xs rounded-full min-target\",\n    interactive ? \"cursor-pointer\" : \"cursor-not-allowed\",\n    options.disabled === true && \"disabled:opacity-50\",\n  );\n};\n\nexport const ratingGroupClass = \"flex flex-row items-center gap-2xs\";\n\nexport const tooltipClass =\n  \"flex flex-col bg-popover text-popover-foreground rounded-sm border border-border pl-sm pr-sm pt-xs pb-xs type-size-caption whitespace-nowrap\";\n\nconst SELECT_TRIGGER_BASE =\n  \"flex flex-row items-center justify-between gap-sm rounded-md type-label bg-input text-input-foreground border border-border cursor-pointer hover:border-border-strong active:border-ring disabled:opacity-50 disabled:cursor-not-allowed\";\n\nexport const selectTriggerClass = (options: {\n  readonly size: ControlSize;\n  readonly invalid?: boolean;\n  readonly fullWidth?: boolean;\n}): string =>\n  cn(\n    SELECT_TRIGGER_BASE,\n    BUTTON_SIZE[options.size],\n    options.invalid === true && FIELD_INVALID,\n    options.fullWidth === true && \"w-full\",\n  );\n\nexport const selectContentClass =\n  \"flex flex-col bg-popover rounded-md border border-border p-xs gap-2xs min-w-full shadow-lg\";\n\nexport const selectItemRowClass =\n  \"flex flex-row items-center justify-between w-full\";\n\nexport const selectLabelClass =\n  \"flex flex-row items-center pl-sm pr-sm py-2xs type-size-caption text-muted-foreground\";\n\nexport const selectSeparatorClass = \"h-px w-full bg-border\";\n\nexport interface SelectItemPaint {\n  readonly selected: boolean;\n  readonly highlighted: boolean;\n  readonly disabled: boolean;\n}\n\nexport const selectItemClass = (state: SelectItemPaint): string =>\n  cn(\n    \"flex flex-row items-center h-sm pl-sm pr-sm rounded-sm type-size-label\",\n    state.disabled === true\n      ? \"text-disabled-foreground cursor-not-allowed\"\n      : \"text-popover-foreground cursor-pointer\",\n    state.disabled === true\n      ? undefined\n      : state.selected === true\n        ? \"bg-selected\"\n        : state.highlighted === true\n          ? \"bg-hover\"\n          : undefined,\n  );\n\nexport const numberFieldClass = (options: FieldRecipeOptions): string =>\n  cn(fieldClass(options), \"pr-0\");\n\nexport const numberStepperColumnClass =\n  \"flex flex-col h-full shrink-0 w-stepper-column\";\n\nexport const numberStepperClass = (disabled: boolean): string =>\n  cn(\n    \"flex items-center justify-center flex-grow rounded-sm\",\n    disabled\n      ? \"cursor-not-allowed\"\n      : \"cursor-pointer hover:bg-hover active:bg-active\",\n  );\n\nexport const numberInputClass = \"flex-grow h-full min-w-0 px-0 border-0\";\n\nconst SELECTION_ROLE: Readonly<\n  Record<SelectionAccent, { readonly bg: string; readonly fg: string }>\n> = {\n  primary: { bg: \"primary\", fg: \"primary-foreground\" },\n  destructive: { bg: \"destructive\", fg: \"destructive-foreground\" },\n};\n\nexport interface SelectionRecipeInput {\n  readonly size: ControlSize;\n  readonly accent: SelectionAccent;\n  readonly state: SelectionState;\n  readonly shape?: \"square\" | \"circle\";\n  readonly invalid?: boolean;\n}\n\nexport const selectionBoxClass = ({\n  size,\n  accent,\n  state,\n  shape = \"square\",\n  invalid,\n}: SelectionRecipeInput): string => {\n  const filled = state !== \"unchecked\";\n  const { bg, fg } = SELECTION_ROLE[selectionAccentOf(accent)];\n  return cn(\n    \"flex items-center justify-center shrink-0 border cursor-pointer\",\n    `size-icon-${size}`,\n    shape === \"circle\" ? \"rounded-full\" : \"rounded-sm\",\n    \"disabled:opacity-50 disabled:cursor-not-allowed\",\n    filled\n      ? cn(\n          `bg-${bg} border-${bg} text-${fg}`,\n\n          `hover:fill-${bg} hover:border-transparent active:fill-${bg}-pressed active:border-transparent`,\n        )\n      : cn(\n          invalid === true ? \"border-destructive\" : \"border-strong\",\n          invalid === true ? \"text-destructive\" : \"text-muted-foreground\",\n          \"hover:bg-hover active:bg-active\",\n        ),\n  );\n};\n\nexport const radioDotClass = ({\n  size,\n  accent,\n  state,\n  invalid,\n}: SelectionRecipeInput): string => {\n  const filled = state !== \"unchecked\";\n  return cn(\n    \"shrink-0 rounded-full\",\n    `size-dot-${size}`,\n    filled\n      ? `bg-${SELECTION_ROLE[selectionAccentOf(accent)].fg}`\n      : invalid === true\n        ? \"bg-destructive\"\n        : \"bg-muted-foreground\",\n  );\n};\n\nexport const switchTrackClass = ({\n  size,\n  accent,\n  state,\n  invalid,\n}: SelectionRecipeInput): string => {\n  const filled = state !== \"unchecked\";\n  const { bg } = SELECTION_ROLE[selectionAccentOf(accent)];\n  return cn(\n    \"relative flex flex-row items-center shrink-0 rounded-full border cursor-pointer\",\n    `switch-track-${size}`,\n    \"disabled:opacity-50 disabled:cursor-not-allowed\",\n    filled\n      ? cn(\n          `bg-${bg} border-${bg}`,\n\n          `hover:fill-${bg} hover:border-transparent active:fill-${bg}-pressed active:border-transparent`,\n        )\n      : cn(\n          \"bg-muted\",\n          invalid === true ? \"border-destructive\" : \"border-strong\",\n          \"hover:bg-hover active:bg-active\",\n        ),\n  );\n};\n\nexport const switchThumbClass = ({\n  size,\n  accent,\n  state,\n}: SelectionRecipeInput): string => {\n  const filled = state !== \"unchecked\";\n  return cn(\n    \"absolute shrink-0 rounded-full pointer-events-none\",\n    `switch-thumb-${size}`,\n    `size-thumb-${size}`,\n    filled ? `switch-thumb-on-${size}` : undefined,\n    filled\n      ? `bg-${SELECTION_ROLE[selectionAccentOf(accent)].fg}`\n      : \"bg-foreground\",\n  );\n};\n\nexport const sliderTrackClass = (\n  size: ControlSize,\n  orientation: SliderOrientation = \"horizontal\",\n): string =>\n  orientation === \"vertical\"\n    ? cn(\n        \"flex flex-col items-center h-full cursor-pointer\",\n        `w-control-${size}`,\n        `py-inset-${size}`,\n        \"disabled:opacity-50 disabled:cursor-not-allowed\",\n      )\n    : cn(\n        \"flex flex-row items-center w-full cursor-pointer\",\n        `h-${size}`,\n        `px-inset-${size}`,\n        \"disabled:opacity-50 disabled:cursor-not-allowed\",\n      );\n\nexport const sliderRailClass = (\n  orientation: SliderOrientation = \"horizontal\",\n): string =>\n  orientation === \"vertical\"\n    ? \"h-full w-space-xs rounded-full bg-muted flex flex-col justify-end items-center pointer-events-none\"\n    : \"w-full h-space-xs rounded-full bg-muted flex flex-row items-center pointer-events-none\";\n\nexport const sliderFillClass = (\n  invalid: boolean,\n  orientation: SliderOrientation = \"horizontal\",\n): string =>\n  cn(\n    \"shrink-0 rounded-full pointer-events-none\",\n    orientation === \"vertical\" ? \"w-full\" : \"h-full\",\n    invalid ? \"bg-destructive\" : \"bg-primary\",\n  );\n\nexport const sliderThumbClass = (\n  size: ControlSize,\n  invalid: boolean,\n  orientation: SliderOrientation = \"horizontal\",\n): string =>\n  cn(\n    orientation === \"vertical\"\n      ? `slider-thumb-v-${size}`\n      : `slider-thumb-${size}`,\n    \"shrink-0 rounded-full bg-input pointer-events-none\",\n    invalid ? \"border-destructive\" : \"border-primary\",\n  );\n\nconst PROGRESS_HEIGHT_STEP: Readonly<Record<ProgressSize, SpaceStep>> = {\n  sm: \"xs\",\n  md: \"sm\",\n};\n\nexport const progressTrackClass = (size: ProgressSize): string =>\n  `flex flex-row w-full h-space-${PROGRESS_HEIGHT_STEP[progressSizeOf(size)]} rounded-full bg-muted overflow-hidden`;\n\nconst PROGRESS_TONE_CLASS: Readonly<Record<ProgressTone, string>> = {\n  primary: \"bg-primary\",\n  success: \"bg-success\",\n  destructive: \"bg-destructive\",\n  muted: \"bg-muted-foreground\",\n};\n\nexport const progressFillClass = (tone: ProgressTone): string =>\n  cn(\"h-full rounded-full\", PROGRESS_TONE_CLASS[progressToneOf(tone)]);\n\nexport const progressBufferClass = (tone: ProgressTone): string =>\n  cn(\n    \"h-full shrink-0\",\n    progressToneOf(tone) === \"muted\"\n      ? \"bg-border-strong\"\n      : \"bg-muted-foreground\",\n  );\n\nexport const spinnerGroupClass = \"relative shrink-0\";\n\nexport const skeletonClass = (spec: {\n  readonly circle?: boolean;\n  readonly radius?: RadiusStep;\n}): string =>\n  cn(\n    \"shrink-0 bg-skeleton\",\n\n    spec.circle === true\n      ? \"rounded-full\"\n      : `rounded-${radiusStep(spec.radius) ?? \"sm\"}`,\n  );\n"
    },
    {
      "path": "packages/primitives/src/recipe/registry.ts",
      "target": "@ui/gpuixui/primitives/recipe/registry.ts",
      "type": "registry:lib",
      "content": "import type { StyleDesc } from \"@gpuix/react\";\nimport type { ControlSize, FilledRole, TextRole, Theme } from \"../../tokens/index.js\";\nimport {\n  brandText,\n  filledHover,\n  filledPressed,\n  targetSize,\n} from \"../../tokens/index.js\";\nimport { createTw, type TwCompiler } from \"../../tw/index.js\";\nimport { pipe } from \"effect\";\nimport * as Option from \"effect/Option\";\nimport * as Str from \"effect/String\";\nimport { switchBox, switchThumbOffset } from \"../core/selection.js\";\nimport { pressWash } from \"../core/pointer.js\";\nimport { paintableAspectRatio, textAlignValue } from \"../core/style.js\";\nimport type { RadiusStep, SpaceStep } from \"../core/theme.js\";\nimport {\n  borderWidthOf,\n  colorRole,\n  controlHeightOf,\n  controlPaddingOf,\n  familyOf,\n  iconSideOf,\n  radiusValue,\n  typeOf,\n  spaceValue,\n} from \"../core/theme.js\";\n\nconst SPACING_STEP: Readonly<Partial<Record<string, SpaceStep>>> = {\n  \"2xs\": \"2xs\",\n  xs: \"xs\",\n  sm: \"sm\",\n  md: \"md\",\n  lg: \"lg\",\n  xl: \"xl\",\n  \"2xl\": \"2xl\",\n  \"3xl\": \"3xl\",\n  \"4xl\": \"4xl\",\n  \"5xl\": \"5xl\",\n};\n\nconst RADIUS_STEP: Readonly<Partial<Record<string, RadiusStep>>> = {\n  none: \"none\",\n  sm: \"sm\",\n  md: \"md\",\n  lg: \"lg\",\n  xl: \"xl\",\n  full: \"full\",\n};\n\nconst CONTROL_SIZE: Readonly<Partial<Record<string, ControlSize>>> = {\n  sm: \"sm\",\n  md: \"md\",\n  lg: \"lg\",\n};\n\nconst TEXT_ROLE: Readonly<Partial<Record<string, TextRole>>> = {\n  display: \"display\",\n  h1: \"h1\",\n  h2: \"h2\",\n  h3: \"h3\",\n  body: \"body\",\n  \"body-strong\": \"bodyStrong\",\n  label: \"label\",\n  caption: \"caption\",\n  code: \"code\",\n  \"code-block\": \"codeBlock\",\n};\n\nconst spacingStep = (value: string | undefined): SpaceStep | undefined =>\n  value === undefined ? undefined : SPACING_STEP[value];\n\nconst controlSize = (value: string | undefined): ControlSize | undefined =>\n  value === undefined ? undefined : CONTROL_SIZE[value];\n\nconst iconSide = (\n  theme: Theme,\n  value: string | undefined,\n): number | undefined => {\n  const size = controlSize(value);\n  return size === undefined ? undefined : iconSideOf(theme, size);\n};\n\nconst halfIconSide = (\n  theme: Theme,\n  value: string | undefined,\n): number | undefined => {\n  const side = iconSide(theme, value);\n  return side === undefined ? undefined : Math.round(side / 2);\n};\n\nconst roleType = (\n  theme: Theme,\n  role: TextRole,\n): Pick<StyleDesc, \"fontSize\" | \"lineHeight\" | \"fontWeight\"> => {\n  const type = typeOf(theme, role);\n  return {\n    fontSize: type.fontSize,\n    lineHeight: type.lineHeight,\n    fontWeight: type.fontWeight,\n  };\n};\n\nconst roleSize = (\n  theme: Theme,\n  role: TextRole,\n): Pick<StyleDesc, \"fontSize\" | \"lineHeight\"> => {\n  const type = typeOf(theme, role);\n  return { fontSize: type.fontSize, lineHeight: type.lineHeight };\n};\n\nconst CLAMP_TOKEN = /^(.+)-(\\d+)$/;\n\nconst clampStyle = (\n  theme: Theme,\n  value: string | undefined,\n): StyleDesc | undefined => {\n  const token = pipe(\n    Option.fromNullishOr(value),\n    Option.flatMap(Str.match(CLAMP_TOKEN)),\n  );\n  if (Option.isNone(token)) return undefined;\n  const [, key = \"\", count = \"0\"] = token.value;\n  const role = TEXT_ROLE[key];\n  return role === undefined\n    ? undefined\n    : {\n        whiteSpace: \"normal\",\n        overflow: \"hidden\",\n        height: typeOf(theme, role).lineHeight * Math.max(1, Number(count)),\n      };\n};\n\nconst filledFill = (\n  theme: Theme,\n  role: FilledRole,\n  value: string | undefined,\n): StyleDesc | undefined =>\n  value === undefined\n    ? { backgroundColor: filledHover(theme, role) }\n    : value === \"pressed\"\n      ? { backgroundColor: filledPressed(theme, role) }\n      : undefined;\n\nconst compiler = createTw({\n  utilities: {\n    \"flex-row\": () => ({ flexDirection: \"row\" }),\n    \"justify-start\": () => ({ justifyContent: \"flex-start\" }),\n    \"justify-end\": () => ({ justifyContent: \"flex-end\" }),\n    \"justify-around\": () => ({ justifyContent: \"space-around\" }),\n    \"items-end\": () => ({ alignItems: \"flex-end\" }),\n    \"items-stretch\": () => ({ alignItems: \"stretch\" }),\n    \"items-baseline\": () => ({ alignItems: \"baseline\" }),\n    \"flex-wrap\": () => ({ flexWrap: \"wrap\" }),\n    \"flex-grow\": () => ({ flexGrow: 1 }),\n    \"cursor-text\": () => ({ cursor: \"text\" }),\n\n    \"select-text\": (theme) => ({\n      userSelect: \"text\",\n      selectionColor: colorRole(theme, \"selection\"),\n    }),\n\n    \"text-start\": () => ({ textAlign: textAlignValue(\"start\") }),\n    \"text-end\": () => ({ textAlign: textAlignValue(\"end\") }),\n    \"text-ellipsis\": () => ({ textOverflow: \"ellipsis\" }),\n    \"font-sans\": (theme) => ({ fontFamily: familyOf(theme, \"sans\") }),\n    \"font-mono\": (theme) => ({ fontFamily: familyOf(theme, \"mono\") }),\n    \"h-px\": (theme) => ({ height: borderWidthOf(theme, \"thin\") }),\n    \"w-px\": (theme) => ({ width: borderWidthOf(theme, \"thin\") }),\n\n    \"border-dashed\": () => ({ borderStyle: \"dashed\" }),\n\n    \"aspect-ratio\": (_theme, value) => {\n      const ratio = paintableAspectRatio(\n        value === undefined ? undefined : Number(value),\n      );\n      return ratio === undefined ? undefined : { aspectRatio: ratio };\n    },\n    \"shrink-1\": () => ({ flexShrink: 1 }),\n    \"min-w-full\": () => ({ minWidth: \"100%\" }),\n    \"overflow-x-hidden\": () => ({ overflowX: \"hidden\" }),\n    \"overflow-x-scroll\": () => ({ overflowX: \"scroll\" }),\n    \"overflow-y-hidden\": () => ({ overflowY: \"hidden\" }),\n    \"overflow-y-scroll\": () => ({ overflowY: \"scroll\" }),\n\n    \"text-brand\": (theme) => ({ color: brandText(theme) }),\n\n    \"bg-active\": (theme) => ({ backgroundColor: pressWash(theme) }),\n\n    \"fill-primary\": (theme, value) => filledFill(theme, \"primary\", value),\n    \"fill-secondary\": (theme, value) => filledFill(theme, \"secondary\", value),\n    \"fill-destructive\": (theme, value) =>\n      filledFill(theme, \"destructive\", value),\n\n    \"fill-accent\": (theme, value) => filledFill(theme, \"accent\", value),\n    \"ml-0\": () => ({ marginLeft: 0 }),\n    \"mr-0\": () => ({ marginRight: 0 }),\n    \"mt-0\": () => ({ marginTop: 0 }),\n    \"mb-0\": () => ({ marginBottom: 0 }),\n\n    gap: (theme, value) => {\n      const step = spacingStep(value);\n      return step === undefined ? undefined : { gap: spaceValue(theme, step) };\n    },\n    p: (theme, value) => {\n      const step = spacingStep(value);\n      return step === undefined\n        ? undefined\n        : { padding: spaceValue(theme, step) };\n    },\n    pl: (theme, value) => {\n      const step = spacingStep(value);\n      return step === undefined\n        ? undefined\n        : { paddingLeft: spaceValue(theme, step) };\n    },\n    pr: (theme, value) => {\n      const step = spacingStep(value);\n      return step === undefined\n        ? undefined\n        : { paddingRight: spaceValue(theme, step) };\n    },\n    pt: (theme, value) => {\n      const step = spacingStep(value);\n      return step === undefined\n        ? undefined\n        : { paddingTop: spaceValue(theme, step) };\n    },\n    pb: (theme, value) => {\n      const step = spacingStep(value);\n      return step === undefined\n        ? undefined\n        : { paddingBottom: spaceValue(theme, step) };\n    },\n    ml: (theme, value) => {\n      const step = spacingStep(value);\n      return step === undefined\n        ? undefined\n        : { marginLeft: spaceValue(theme, step) };\n    },\n    mr: (theme, value) => {\n      const step = spacingStep(value);\n      return step === undefined\n        ? undefined\n        : { marginRight: spaceValue(theme, step) };\n    },\n    mt: (theme, value) => {\n      const step = spacingStep(value);\n      return step === undefined\n        ? undefined\n        : { marginTop: spaceValue(theme, step) };\n    },\n    mb: (theme, value) => {\n      const step = spacingStep(value);\n      return step === undefined\n        ? undefined\n        : { marginBottom: spaceValue(theme, step) };\n    },\n    top: (theme, value) => {\n      const step = spacingStep(value);\n      return step === undefined ? undefined : { top: spaceValue(theme, step) };\n    },\n    left: (theme, value) => {\n      const step = spacingStep(value);\n      return step === undefined ? undefined : { left: spaceValue(theme, step) };\n    },\n    h: (theme, value) => {\n      const size = value === undefined ? undefined : CONTROL_SIZE[value];\n      return size === undefined\n        ? undefined\n        : { height: controlHeightOf(theme, size) };\n    },\n    px: (theme, value) => {\n      const size = value === undefined ? undefined : CONTROL_SIZE[value];\n      const padding =\n        size === undefined ? undefined : controlPaddingOf(theme, size);\n      return padding === undefined\n        ? undefined\n        : { paddingLeft: padding, paddingRight: padding };\n    },\n    size: (theme, value) => {\n      const size = value === undefined ? undefined : CONTROL_SIZE[value];\n      const side =\n        size === undefined ? undefined : controlHeightOf(theme, size);\n      return side === undefined ? undefined : { width: side, height: side };\n    },\n    rounded: (theme, value) => {\n      const step = value === undefined ? undefined : RADIUS_STEP[value];\n      return step === undefined\n        ? undefined\n        : { borderRadius: radiusValue(theme, step) };\n    },\n    type: (theme, value) => {\n      const role = value === undefined ? undefined : TEXT_ROLE[value];\n      return role === undefined ? undefined : roleType(theme, role);\n    },\n    \"type-size\": (theme, value) => {\n      const role = value === undefined ? undefined : TEXT_ROLE[value];\n      return role === undefined ? undefined : roleSize(theme, role);\n    },\n\n    clamp: clampStyle,\n\n    \"size-icon\": (theme, value) => iconSide(theme, value),\n    \"size-dot\": (theme, value) => halfIconSide(theme, value),\n\n    \"size-thumb\": (theme, value) => {\n      const size = controlSize(value);\n      return size === undefined ? undefined : switchBox(size, theme).knob;\n    },\n    \"switch-track\": (theme, value) => {\n      const size = controlSize(value);\n      if (size === undefined) return undefined;\n      const box = switchBox(size, theme);\n      return { width: box.width, height: box.height, borderWidth: box.border };\n    },\n    \"switch-thumb\": (theme, value) => {\n      const size = controlSize(value);\n      if (size === undefined) return undefined;\n      const box = switchBox(size, theme);\n      return {\n        top: (box.height - box.border * 2 - box.knob) / 2,\n        left: switchThumbOffset(\n          { state: \"unchecked\", size, accent: \"primary\" },\n          theme,\n        ),\n      };\n    },\n    \"switch-thumb-on\": (theme, value) => {\n      const size = controlSize(value);\n      return size === undefined\n        ? undefined\n        : {\n            left: switchThumbOffset(\n              { state: \"checked\", size, accent: \"primary\" },\n              theme,\n            ),\n          };\n    },\n    \"slider-thumb\": (theme, value) => {\n      const side = iconSide(theme, value);\n      if (side === undefined) return undefined;\n      const half = Math.round(side / 2);\n      return {\n        width: side,\n        height: side,\n        marginLeft: -half,\n        marginRight: -half,\n        borderWidth: borderWidthOf(theme, \"strong\"),\n      };\n    },\n\n    \"slider-thumb-v\": (theme, value) => {\n      const side = iconSide(theme, value);\n      if (side === undefined) return undefined;\n      const half = Math.round(side / 2);\n      return {\n        width: side,\n        height: side,\n        marginTop: -half,\n        marginBottom: -half,\n        borderWidth: borderWidthOf(theme, \"strong\"),\n      };\n    },\n    \"px-inset\": (theme, value) => {\n      const half = halfIconSide(theme, value);\n      return half === undefined\n        ? undefined\n        : { paddingLeft: half, paddingRight: half };\n    },\n    \"py-inset\": (theme, value) => {\n      const half = halfIconSide(theme, value);\n      return half === undefined\n        ? undefined\n        : { paddingTop: half, paddingBottom: half };\n    },\n\n    \"w-control\": (theme, value) => {\n      const size = controlSize(value);\n      return size === undefined\n        ? undefined\n        : { width: controlHeightOf(theme, size) };\n    },\n    \"w-stepper-column\": (theme) => ({\n      width: iconSideOf(theme, \"md\") + spaceValue(theme, \"sm\"),\n    }),\n\n    \"min-target\": () => ({\n      minWidth: targetSize.minimum,\n      minHeight: targetSize.minimum,\n    }),\n    \"h-space\": (theme, value) => {\n      const step = spacingStep(value);\n      return step === undefined\n        ? undefined\n        : { height: spaceValue(theme, step) };\n    },\n    \"w-space\": (theme, value) => {\n      const step = spacingStep(value);\n      return step === undefined\n        ? undefined\n        : { width: spaceValue(theme, step) };\n    },\n  },\n});\n\nexport const recipeTw: TwCompiler = {\n  ...compiler,\n  classesToStyle: (className, theme, state) => {\n    const result = compiler.classesToStyle(className, theme, state);\n    if (theme.interaction !== \"appkit\") return result;\n    const { hover: _pointer, ...style } = result.style;\n    return { ...result, style };\n  },\n};\n"
    },
    {
      "path": "packages/primitives/src/toggle-group.ts",
      "target": "@ui/gpuixui/primitives/toggle-group.ts",
      "type": "registry:lib",
      "content": "export {\n  ToggleGroup,\n  ToggleGroupItem,\n  toggleGroupValue,\n  toggleGroupValues,\n} from \"./components/ToggleGroup.js\";\nexport type {\n  MultipleToggleGroupProps,\n  SingleToggleGroupProps,\n  ToggleGroupItemProps,\n  ToggleGroupMode,\n  ToggleGroupOption,\n  ToggleGroupProps,\n  ToggleGroupState,\n  ToggleItemState,\n} from \"./components/ToggleGroup.js\";\n"
    }
  ],
  "docs": "[Toggle group](https://gpuixui.sudokw.com/primitives/toggle-group) — These are GPUix native components: the files render through GPUix's reconciler against `@gpuix/react`, not the DOM, and need the per-platform `@gpuix/native` binding. The CLI installs the `@gpuixui/*` runtime the components import as registry items, so the copied tree resolves on its own; wrap it in `ThemeProvider` before it renders.",
  "meta": {
    "url": "/primitives/toggle-group",
    "kind": "component",
    "runtime": "gpuix",
    "registry": "gpuixui"
  }
}