{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "components-carousel",
  "type": "registry:component",
  "title": "Carousel",
  "description": "Discrete slide stepping, a dot per slide, arrow keys",
  "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-primitives.json",
    "https://gpuixui.sudokw.com/gpuix-tokens.json",
    "https://gpuixui.sudokw.com/gpuix-tw.json"
  ],
  "files": [
    {
      "path": "packages/components/src/carousel.tsx",
      "target": "@ui/gpuixui/components/carousel.tsx",
      "type": "registry:component",
      "content": "/** @jsxImportSource @gpuix/react */\nimport type { KeyEvent, Props } from \"@gpuix/react\";\nimport {\n  mergeStyles,\n  resolveStyle,\n  type StateStyle,\n} from \"@gpuix/react/floating\";\nimport { Icon } from \"../icons/index.js\";\nimport {\n  cn,\n  CAROUSEL_INDICATORS,\n  CAROUSEL_ROOT,\n  CAROUSEL_SLIDE,\n  CAROUSEL_TRACK,\n} from \"../tw/index.js\";\nimport * as Arr from \"effect/Array\";\nimport {\n  Children,\n  createContext,\n  useContext,\n  useLayoutEffect,\n  useMemo,\n  useState,\n} from \"react\";\nimport { Button, actionOnColor } from \"./internal/button.js\";\nimport { useControllableState } from \"./internal/controllable.js\";\nimport {\n  activationHandlers,\n  isFirst,\n  isLast,\n  isLeft,\n  isRight,\n} from \"./internal/key.js\";\nimport {\n  assertParts,\n  type PartChildren,\n  type PartComponent,\n  type PartsContract,\n} from \"./internal/parts.js\";\nimport { recipeStyle } from \"./internal/recipe.js\";\nimport { useMoveTiming } from \"./internal/presence.js\";\nimport {\n  controlRing,\n  keyboardRing,\n  targetSize,\n  useTheme,\n} from \"./internal/theme.js\";\n\ninterface CarouselContextValue {\n  readonly active: number;\n  readonly count: number;\n  readonly loop: boolean;\n  readonly step: (delta: 1 | -1) => void;\n  readonly goTo: (index: number) => void;\n}\n\nconst CarouselContext = createContext<CarouselContextValue | undefined>(\n  undefined,\n);\n\nconst SlideIndexContext = createContext<number | undefined>(undefined);\n\nconst useCarousel = (): CarouselContextValue => {\n  const value = useContext(CarouselContext);\n  if (value === undefined) {\n    throw new Error(\"Carousel parts must be used inside Carousel\");\n  }\n  return value;\n};\n\nconst CountContext = createContext<((count: number) => void) | undefined>(\n  undefined,\n);\n\nexport interface CarouselProps extends Omit<Props, \"children\"> {\n  readonly value?: number;\n  readonly defaultValue?: number;\n  readonly onValueChange?: (value: number) => void;\n\n  readonly loop?: boolean;\n\n  readonly label: string;\n\n  readonly className?: string;\n  readonly children?: PartChildren;\n}\n\nexport const Carousel = ({\n  value: valueProp,\n  defaultValue = 0,\n  onValueChange,\n  loop = false,\n  label,\n  className,\n  children,\n  style,\n  onKeyDown,\n  ...rest\n}: CarouselProps) => {\n  const theme = useTheme();\n  const [value, setValue] = useControllableState({\n    value: valueProp,\n    defaultValue,\n    onChange: onValueChange,\n  });\n  const [count, setCount] = useState(0);\n  assertParts(carouselRoot, children);\n\n  const active = count === 0 ? 0 : Math.min(Math.max(value, 0), count - 1);\n\n  const current = Number.isFinite(active) ? active : 0;\n\n  const context = useMemo<CarouselContextValue>(\n    () => ({\n      active: current,\n      count,\n      loop,\n      step: (delta) => {\n        if (count === 0) return;\n        const next = current + delta;\n        const target =\n          next < 0 || next >= count\n            ? loop\n              ? (next + count) % count\n              : Math.min(Math.max(next, 0), count - 1)\n            : next;\n        if (target !== current) setValue(target);\n      },\n      goTo: (index) => {\n        if (count === 0) return;\n        const target = Math.min(Math.max(index, 0), count - 1);\n        if (target !== current) setValue(target);\n      },\n    }),\n    [current, count, loop, setValue],\n  );\n\n  return (\n    <CarouselContext.Provider value={context}>\n      <div\n        {...rest}\n        role=\"group\"\n        aria-label={label}\n        tabIndex={0}\n        onKeyDown={(event: KeyEvent) => {\n          if (isRight(event)) context.step(1);\n          else if (isLeft(event)) context.step(-1);\n          else if (isFirst(event)) context.goTo(0);\n          else if (isLast(event)) context.goTo(count - 1);\n          onKeyDown?.(event);\n        }}\n        style={mergeStyles(\n          mergeStyles(\n            recipeStyle(cn(CAROUSEL_ROOT, className), theme),\n\n            keyboardRing(theme),\n          ),\n          style,\n        )}\n      >\n        <CountContext.Provider value={setCount}>\n          {children}\n        </CountContext.Provider>\n      </div>\n    </CarouselContext.Provider>\n  );\n};\n\nexport interface CarouselTrackProps extends Omit<Props, \"children\"> {\n  readonly className?: string;\n  readonly children?: PartChildren;\n}\n\nexport const CarouselTrack = ({\n  className,\n  children,\n  style,\n  ...rest\n}: CarouselTrackProps) => {\n  const theme = useTheme();\n  const reportCount = useContext(CountContext);\n  const slides = Children.toArray(children);\n  assertParts(carouselTrack, children);\n\n  useLayoutEffect(() => {\n    reportCount?.(slides.length);\n  }, [reportCount, slides.length]);\n\n  return (\n    <div\n      {...rest}\n      style={mergeStyles(\n        recipeStyle(cn(CAROUSEL_TRACK, className), theme),\n        style,\n      )}\n    >\n      {slides.map((slide, index) => (\n        <SlideIndexContext.Provider key={index} value={index}>\n          {slide}\n        </SlideIndexContext.Provider>\n      ))}\n    </div>\n  );\n};\n\nexport interface CarouselSlideProps extends Omit<Props, \"children\" | \"style\"> {\n  readonly className?: string;\n  readonly style?: StateStyle<CarouselSlideState>;\n  readonly children?: PartChildren;\n}\n\nexport interface CarouselSlideState {\n  readonly index: number;\n}\n\nexport const CarouselSlide = ({\n  className,\n  style,\n  children,\n  ...rest\n}: CarouselSlideProps) => {\n  const theme = useTheme();\n  const { active: activeIndex } = useCarousel();\n  const index = useContext(SlideIndexContext) ?? 0;\n\n  if (index !== activeIndex) return null;\n\n  return (\n    <div\n      {...rest}\n      style={mergeStyles(\n        recipeStyle(cn(CAROUSEL_SLIDE, className), theme),\n        resolveStyle(style, { index }),\n      )}\n    >\n      {children}\n    </div>\n  );\n};\n\nexport interface CarouselControlProps extends Omit<Props, \"children\"> {\n  readonly direction: \"previous\" | \"next\";\n\n  readonly label?: string;\n  readonly disabled?: boolean;\n}\n\nconst CONTROL_VARIANT = \"secondary\" as const;\n\nexport const CarouselControl = ({\n  direction,\n  label,\n  disabled = false,\n  ...rest\n}: CarouselControlProps) => {\n  const { active, count, loop, step } = useCarousel();\n  const theme = useTheme();\n  const atEdge = direction === \"next\" ? active >= count - 1 : active <= 0;\n  const name =\n    label ?? (direction === \"next\" ? \"Next slide\" : \"Previous slide\");\n\n  return (\n    <Button\n      {...rest}\n      variant={CONTROL_VARIANT}\n      aria-label={name}\n      disabled={disabled || count === 0 || (atEdge && !loop)}\n      onClick={() => step(direction === \"next\" ? 1 : -1)}\n    >\n      <Icon\n        name={direction === \"next\" ? \"chevron-right\" : \"chevron-left\"}\n        size=\"md\"\n        color={actionOnColor(theme, CONTROL_VARIANT)}\n      />\n    </Button>\n  );\n};\n\nexport interface CarouselIndicatorsProps extends Omit<\n  Props,\n  \"children\" | \"style\"\n> {\n  readonly label?: string;\n\n  readonly className?: string;\n\n  readonly style?: StateStyle<CarouselIndicatorsState>;\n}\n\nexport interface CarouselIndicatorsState {\n  readonly active: number;\n  readonly count: number;\n}\n\nconst DOT_HEIGHT = 6;\nconst DOT_REST_WIDTH = 6;\nconst DOT_ACTIVE_WIDTH = 18;\n\nexport const CarouselIndicators = ({\n  label,\n  className,\n  style,\n  ...rest\n}: CarouselIndicatorsProps) => {\n  const { active, count, goTo } = useCarousel();\n  const theme = useTheme();\n  const move = useMoveTiming(\"fast\");\n\n  if (count === 0) return null;\n\n  return (\n    <div\n      {...rest}\n      role=\"group\"\n      aria-label={label ?? \"Choose a slide\"}\n      style={mergeStyles(\n        recipeStyle(cn(CAROUSEL_INDICATORS, className), theme),\n        resolveStyle(style, { active, count }),\n      )}\n    >\n      {Arr.makeBy(count, (index) => {\n        const selected = index === active;\n        return (\n          <div\n            key={index}\n            role=\"button\"\n            aria-label={`Go to slide ${index + 1}`}\n            aria-selected={selected}\n            tabIndex={selected ? 0 : -1}\n            testId={\n              rest.testId === undefined ? undefined : `${rest.testId}-${index}`\n            }\n            onClick={() => goTo(index)}\n            {...activationHandlers(() => goTo(index))}\n            style={{\n              display: \"flex\",\n              flexDirection: \"row\",\n              alignItems: \"center\",\n              justifyContent: \"center\",\n              width: targetSize.minimum,\n              height: targetSize.minimum,\n              flexShrink: 0,\n              cursor: \"pointer\",\n              ...controlRing(theme),\n            }}\n          >\n            <div\n              motion={{\n                initial: false,\n                animate: {\n                  width: selected ? DOT_ACTIVE_WIDTH : DOT_REST_WIDTH,\n                },\n                transition: move,\n              }}\n              style={{\n                height: DOT_HEIGHT,\n                borderRadius: DOT_HEIGHT / 2,\n\n                pointerEvents: \"none\",\n                backgroundColor: selected\n                  ? theme.colors.primary\n                  : theme.colors.mutedForeground,\n              }}\n            />\n          </div>\n        );\n      })}\n    </div>\n  );\n};\n\nconst carouselParts: ReadonlyArray<PartComponent> = [\n  Carousel,\n  CarouselTrack,\n  CarouselSlide,\n  CarouselControl,\n  CarouselIndicators,\n];\n\nconst carouselRoot: PartsContract = {\n  parent: \"Carousel\",\n  family: carouselParts,\n  accepts: [CarouselTrack, CarouselControl, CarouselIndicators],\n  hint: \"Put CarouselTrack and CarouselControl directly inside Carousel.\",\n};\n\nconst carouselTrack: PartsContract = {\n  parent: \"CarouselTrack\",\n  family: carouselParts,\n  accepts: [CarouselSlide],\n  hint: \"Put CarouselSlide directly inside CarouselTrack.\",\n};\n\nexport const carouselMeta = {\n  name: \"Carousel\",\n  tier: 2,\n  status: \"done\",\n  gpuixSupport: \"partial\",\n  limitations: [\n    \"the track does not travel between slides: the frame sizes itself to the slide on screen, so a travel would lay every slide out in one box and take its height from the tallest slide\",\n    \"the active indicator grows between the 6px dot and the 18px pill on the runtime's clock (`fast`, 160 ms) through the timing table's `standard` phase, because it moves between two resting states rather than arriving; the two inks change with the selection in the same frame, because `motion` interpolates numbers and has no colour\",\n    \"no swipe gesture (no drag host feature) and no scroll snap\",\n    \"no auto-advance or thumbnails in v1\",\n    \"only the slide on screen is mounted, so a slide's local state does not survive a visit (the pinned renderer ignores `display: none`, so a mounted spare slide would paint and keep its tab stops)\",\n  ],\n  docs: \"docs/carousel.mdx\",\n  example: \"examples/carousel.example.tsx\",\n  testFile: \"src/behaviour/carousel.test.tsx\",\n} as const;\n"
    },
    {
      "path": "packages/components/src/internal/button.tsx",
      "target": "@ui/gpuixui/components/internal/button.tsx",
      "type": "registry:component",
      "content": "/** @jsxImportSource @gpuix/react */\nimport type { Props } from \"@gpuix/react\";\nimport type { ReactNode } from \"react\";\nimport {\n  Button as PrimitiveButton,\n  IconButton as PrimitiveIconButton,\n  actionOnColor as primitiveActionOnColor,\n  type ButtonVariant as PrimitiveVariant,\n} from \"../../primitives/button.js\";\nimport { cn } from \"../../tw/index.js\";\nimport * as Schema from \"effect/Schema\";\nimport type { Theme } from \"./theme.js\";\n\nconst ButtonVariants = Schema.Literals([\n  \"primary\",\n  \"secondary\",\n  \"ghost\",\n  \"danger\",\n  \"link\",\n]);\n\nexport type ButtonVariant = typeof ButtonVariants.Type;\n\nexport type ButtonSize = \"sm\" | \"md\" | \"lg\";\n\nexport interface ButtonProps extends Props {\n  readonly variant?: ButtonVariant;\n\n  readonly size?: ButtonSize;\n\n  readonly disabled?: boolean;\n\n  readonly loading?: boolean;\n\n  readonly loadingLabel?: string;\n\n  readonly reducedMotion?: boolean;\n\n  readonly leading?: ReactNode;\n\n  readonly trailing?: ReactNode;\n}\n\nexport interface IconButtonProps extends Props {\n  readonly label: string;\n\n  readonly size?: ButtonSize;\n  readonly disabled?: boolean;\n}\n\ninterface Look {\n  readonly variant: PrimitiveVariant;\n  readonly className: string;\n}\n\nconst LOOKS: Readonly<Record<ButtonVariant, Look>> = {\n  primary: { variant: \"primary\", className: \"\" },\n  secondary: { variant: \"secondary\", className: \"border border-strong\" },\n  ghost: { variant: \"ghost\", className: \"\" },\n  danger: { variant: \"destructive\", className: \"\" },\n\n  link: { variant: \"link\", className: \"underline underline-offset-4\" },\n};\n\nconst lookOf = (variant: unknown): Look =>\n  LOOKS[Schema.is(ButtonVariants)(variant) ? variant : \"secondary\"];\n\nexport const actionOnColor = (theme: Theme, variant: ButtonVariant): string =>\n  primitiveActionOnColor(theme, lookOf(variant).variant);\n\nexport const Button = ({\n  variant = \"secondary\",\n  size = \"md\",\n  disabled = false,\n  onClick,\n  style,\n  \"aria-label\": ariaLabel,\n  ...rest\n}: ButtonProps) => {\n  const look = lookOf(variant);\n  return (\n    <PrimitiveButton\n      {...rest}\n      variant={look.variant}\n      size={size}\n      disabled={disabled}\n      label={ariaLabel}\n      className={cn(look.className)}\n      onActivate={onClick}\n      style={style}\n    />\n  );\n};\n\nexport const IconButton = ({\n  label,\n  size = \"md\",\n  disabled = false,\n  onClick,\n  style,\n  children,\n  ...rest\n}: IconButtonProps) => (\n  <PrimitiveIconButton\n    {...rest}\n    icon={children}\n    variant=\"ghost\"\n    size={size}\n    disabled={disabled}\n    label={label}\n    className=\"text-muted-foreground hover:text-foreground\"\n    onActivate={onClick}\n    style={style}\n  />\n);\n"
    },
    {
      "path": "packages/components/src/internal/controllable.ts",
      "target": "@ui/gpuixui/components/internal/controllable.ts",
      "type": "registry:lib",
      "content": "import { useCallback, useState } from \"react\";\n\nexport type ControllableState<Value> = readonly [Value, (next: Value) => void];\n\nexport interface ControllableStateOptions<Value> {\n  readonly value: Value | undefined;\n\n  readonly defaultValue: Value;\n\n  readonly onChange?: (next: Value) => void;\n}\n\nexport const useControllableState = <Value>({\n  value,\n  defaultValue,\n  onChange,\n}: ControllableStateOptions<Value>): ControllableState<Value> => {\n  const [internal, setInternal] = useState(defaultValue);\n  const controlled = value !== undefined;\n\n  const setValue = useCallback(\n    (next: Value) => {\n      if (!controlled) setInternal(next);\n      if (value !== next) onChange?.(next);\n    },\n    [controlled, value, onChange],\n  );\n\n  return [controlled ? value : internal, setValue];\n};\n"
    },
    {
      "path": "packages/components/src/internal/key.ts",
      "target": "@ui/gpuixui/components/internal/key.ts",
      "type": "registry:lib",
      "content": "import type { EventPayload, KeyEvent, Props } from \"@gpuix/react\";\nimport * as Option from \"effect/Option\";\n\nexport type KeyPhase = \"down\" | \"up\";\n\nexport const isActivation = (event: EventPayload, phase: KeyPhase): boolean => {\n  if (event.isHeld === true) return false;\n  if (event.key === \"enter\") return phase === \"down\";\n  return event.key === \"space\" && phase === \"up\";\n};\n\nexport const swallowsDefault = (\n  event: EventPayload,\n  phase: KeyPhase,\n): boolean => event.key === \"space\" && phase === \"down\";\n\nexport const activationHandlers = (\n  activate: (event: KeyEvent) => void,\n  observe: Pick<Props, \"onKeyDown\" | \"onKeyUp\"> = {},\n): Pick<Props, \"onKeyDown\" | \"onKeyUp\"> => ({\n  onKeyDown: (event: KeyEvent) => {\n    if (swallowsDefault(event, \"down\")) event.preventDefault();\n    if (isActivation(event, \"down\")) activate(event);\n    observe.onKeyDown?.(event);\n  },\n  onKeyUp: (event: KeyEvent) => {\n    if (isActivation(event, \"up\")) activate(event);\n    observe.onKeyUp?.(event);\n  },\n});\n\nexport const isEnter = (event: EventPayload): boolean => event.key === \"enter\";\n\nexport const isDown = (event: EventPayload): boolean =>\n  event.key === \"down\" || (event.key === \"n\" && event.modifiers?.ctrl === true);\n\nexport const isUp = (event: EventPayload): boolean =>\n  event.key === \"up\" || (event.key === \"p\" && event.modifiers?.ctrl === true);\n\nexport const isRight = (event: EventPayload): boolean => event.key === \"right\";\n\nexport const isLeft = (event: EventPayload): boolean => event.key === \"left\";\n\nexport const isFirst = (event: EventPayload): boolean => event.key === \"home\";\n\nexport const isLast = (event: EventPayload): boolean => event.key === \"end\";\n\nexport const isPageUp = (event: EventPayload): boolean =>\n  event.key === \"pageup\";\n\nexport const isPageDown = (event: EventPayload): boolean =>\n  event.key === \"pagedown\";\n\nexport const isDismiss = (event: EventPayload): boolean =>\n  event.key === \"escape\";\n\nexport const isTab = (event: EventPayload): boolean => event.key === \"tab\";\n\nexport const isSelectAll = (event: EventPayload): boolean =>\n  event.key === \"a\" &&\n  (event.modifiers?.cmd === true || event.modifiers?.ctrl === true);\n\nexport const isMenuKey = (event: EventPayload): boolean =>\n  (event.key === \"f10\" && event.modifiers?.shift === true) ||\n  event.key === \"contextmenu\";\n\nexport const axisDirection = (\n  event: EventPayload,\n  orientation: \"horizontal\" | \"vertical\",\n): Option.Option<1 | -1> => {\n  if (event.key === \"right\") return Option.some(1);\n  if (event.key === \"left\") return Option.some(-1);\n  if (orientation === \"vertical\") {\n    if (isDown(event)) return Option.some(1);\n    if (isUp(event)) return Option.some(-1);\n  }\n  return Option.none();\n};\n"
    },
    {
      "path": "packages/components/src/internal/parts.ts",
      "target": "@ui/gpuixui/components/internal/parts.ts",
      "type": "registry:lib",
      "content": "import * as Arr from \"effect/Array\";\nimport * as P from \"effect/Predicate\";\nimport {\n  Children,\n  Fragment,\n  isValidElement,\n  type ReactElement,\n  type ReactNode,\n} from \"react\";\n\nexport type PartComponent = (props: never) => ReactNode;\n\nexport type PartChildren =\n  | ReactElement<unknown>\n  | boolean\n  | null\n  | undefined\n  | ReadonlyArray<PartChildren>;\n\nexport interface PartsContract {\n  readonly parent: string;\n\n  readonly family: ReadonlyArray<PartComponent>;\n\n  readonly accepts: ReadonlyArray<PartComponent>;\n\n  readonly hint?: string;\n}\n\nconst componentName = (type: unknown): string =>\n  P.isString(type)\n    ? type\n    : P.isFunction(type)\n      ? type.name || \"anonymous\"\n      : \"element\";\n\nconst fragmentChildren = (element: ReactElement<unknown>): ReactNode =>\n  hasChildren(element.props) ? element.props.children : undefined;\n\nconst hasChildren = (\n  value: unknown,\n): value is { readonly children?: ReactNode } =>\n  P.isObject(value) && \"children\" in value;\n\nconst leaves = (children: ReactNode): ReadonlyArray<unknown> =>\n  Arr.flatMap(Children.toArray(children), (child) =>\n    isValidElement<unknown>(child) && child.type === Fragment\n      ? leaves(fragmentChildren(child))\n      : [child],\n  );\n\nexport const assertParts = (\n  contract: PartsContract,\n  children: ReactNode,\n): void => {\n  Arr.forEach(leaves(children), (leaf) => {\n    if (!isValidElement(leaf)) return;\n    if (Arr.some(contract.accepts, (part) => part === leaf.type)) return;\n    if (!Arr.some(contract.family, (part) => part === leaf.type)) return;\n\n    throw new Error(\n      `${componentName(leaf.type)} cannot be used inside ${contract.parent}.` +\n        (contract.hint === undefined ? \"\" : ` ${contract.hint}`),\n    );\n  });\n};\n"
    },
    {
      "path": "packages/components/src/internal/presence.tsx",
      "target": "@ui/gpuixui/components/internal/presence.tsx",
      "type": "registry:component",
      "content": "/** @jsxImportSource @gpuix/react */\nimport type { MotionProps } from \"@gpuix/react\";\nimport {\n  delayedTiming,\n  exitWindowMs,\n  fadeFrom,\n  fadeFromAnchor,\n  fadeFromSide,\n  fadeOnly,\n  presenceMotion as motionOfPresence,\n  presenceStyle,\n  transitionWindowMs,\n  type PresenceFrames,\n  type PresenceHitRule,\n  type PresenceSide,\n  type PresenceTiming,\n  type PresenceTransition,\n} from \"../../motion/presence.js\";\nimport {\n  MotionProvider,\n  useMotionPreference,\n  useSurfacePresence,\n  useSurfaceTiming,\n  type MotionProviderProps,\n  type SurfacePresence,\n} from \"../../motion/react/presence.js\";\nimport {\n  motionTiming,\n  type MotionLevel,\n  type MotionPreference,\n} from \"../../motion/timing.js\";\n\nexport { MotionProvider, useMotionPreference, type MotionProviderProps };\n\nexport type SurfaceFrames = PresenceFrames;\n\nexport type SurfaceTiming = PresenceTiming;\n\nexport type PanelSide = PresenceSide;\n\nexport {\n  delayedTiming,\n  exitWindowMs,\n  fadeFrom,\n  fadeFromAnchor,\n  fadeFromSide,\n  fadeOnly,\n  presenceStyle,\n  transitionWindowMs,\n};\nexport type { PresenceHitRule };\n\nexport { useSurfacePresence, useSurfaceTiming, type SurfacePresence };\n\nexport const moveTiming = (\n  level: MotionLevel,\n  preference: MotionPreference,\n): PresenceTransition => motionTiming(level, { phase: \"standard\", preference });\n\nexport const useMoveTiming = (level: MotionLevel): PresenceTransition =>\n  moveTiming(level, useMotionPreference());\n\nexport const presenceMotion = (\n  frames: SurfaceFrames,\n  presence: SurfacePresence,\n  timing: SurfaceTiming = presence.timing,\n): MotionProps => motionOfPresence(frames, presence.present, timing);\n\nexport const PresenceShield = ({ present }: { readonly present: boolean }) =>\n  present ? null : (\n    <div\n      testId=\"presence-shield\"\n      style={{ position: \"absolute\", top: 0, right: 0, bottom: 0, left: 0 }}\n    />\n  );\n\nexport const presenceTabStop = (\n  present: boolean,\n): { readonly tabIndex?: number } => (present ? {} : { tabIndex: -1 });\n"
    },
    {
      "path": "packages/components/src/internal/recipe.ts",
      "target": "@ui/gpuixui/components/internal/recipe.ts",
      "type": "registry:lib",
      "content": "import type { StyleDesc } from \"@gpuix/react\";\nimport { createRecipeCache } from \"../../tw/index.js\";\nimport type { Theme } from \"./theme.js\";\n\nexport const recipeStyle: (recipe: string, theme: Theme) => StyleDesc =\n  createRecipeCache(512);\n"
    },
    {
      "path": "packages/components/src/internal/theme.ts",
      "target": "@ui/gpuixui/components/internal/theme.ts",
      "type": "registry:lib",
      "content": "import type { StyleDesc } from \"@gpuix/react\";\nimport * as Schema from \"effect/Schema\";\nimport {\n  alpha,\n  avatarPixels,\n  avatarSize,\n  brandTextOn,\n  controlFocusRing,\n  controlHeight,\n  controlPaddingX,\n  currentPlatform,\n  darkTheme,\n  disabledAction,\n  disabledOpacity,\n  elevationShadow,\n  filledHover,\n  filledPressed,\n  findHighlight,\n  focusRing,\n  keyboardFocusRing,\n  lightTheme,\n  nativeTextTheme,\n  pointerWash,\n  selectionOn,\n  statusTone,\n  syntaxColors,\n  targetSize,\n  textStyle,\n  type BoxShadow,\n  type ElevationLevel,\n  type FindHighlightSource,\n  type NativeTextFill,\n  type PlatformName,\n  type PointerWashSurface,\n  type StatusTone,\n  type SyntaxColors,\n  type SyntaxRole,\n  type TextRole,\n  type Theme,\n  type ThemeColors,\n} from \"../../tokens/index.js\";\n\nexport {\n  alpha,\n  avatarPixels,\n  avatarSize,\n  controlFocusRing,\n  controlHeight,\n  controlPaddingX,\n  currentPlatform,\n  darkTheme,\n  disabledAction,\n  disabledOpacity,\n  elevationShadow,\n  filledHover,\n  filledPressed,\n  findHighlight,\n  focusRing,\n  keyboardFocusRing,\n  lightTheme,\n  nativeTextTheme,\n  statusTone,\n  syntaxColors,\n  targetSize,\n  textStyle,\n};\nexport type {\n  BoxShadow,\n  ElevationLevel,\n  FindHighlightSource,\n  NativeTextFill,\n  PlatformName,\n  StatusTone,\n  SyntaxColors,\n  SyntaxRole,\n  TextRole,\n  Theme,\n};\nexport { ThemeProvider, useTheme } from \"../../tokens/react.js\";\n\nexport const keyboardRing = (theme: Theme, invalid = false): StyleDesc =>\n  controlFocusRing(theme, { invalid }) ?? {};\n\nexport interface ControlRingState {\n  readonly disabled?: boolean;\n\n  readonly invalid?: boolean;\n}\n\nexport const controlRing = (\n  theme: Theme,\n  state: ControlRingState = {},\n): StyleDesc => controlFocusRing(theme, state) ?? {};\n\nexport const pressWash = (theme: Theme, replaced: PointerWashSurface): string =>\n  pointerWash(theme, \"active\", replaced) ?? theme.colors.active;\n\nexport const selectionWash = (theme: Theme): StyleDesc => ({\n  selectionColor: theme.colors.selection,\n});\n\nexport const keepContent: StyleDesc = { keyboardFocusDim: false };\n\nexport const disabledFade = (\n  disabled: boolean,\n): { readonly opacity: number } | undefined =>\n  disabled ? { opacity: disabledOpacity } : undefined;\n\nconst Tones = Schema.Literals([\"info\", \"success\", \"warning\", \"danger\"]);\n\nexport type Tone = typeof Tones.Type;\n\nexport const toneOf = (value: unknown): Tone =>\n  Schema.is(Tones)(value) ? value : \"info\";\n\nexport interface ToneStyle {\n  readonly fg: string;\n  readonly bg: string;\n  readonly border: string;\n}\n\nconst TOKEN_TONE: Readonly<Record<Tone, StatusTone>> = {\n  info: \"info\",\n  success: \"success\",\n  warning: \"warning\",\n  danger: \"destructive\",\n};\n\nexport const tone = (theme: Theme, value: Tone): ToneStyle => {\n  const { background, border, foreground } = statusTone(\n    theme,\n    TOKEN_TONE[value],\n  );\n  return { bg: background, border, fg: foreground };\n};\n\nconst softRoles: Readonly<Record<Tone, keyof ThemeColors>> = {\n  info: \"infoSoft\",\n  success: \"successSoft\",\n  warning: \"warningSoft\",\n  danger: \"destructiveSoft\",\n};\n\nexport const messageLink = (theme: Theme, value: Tone): string =>\n  brandTextOn(theme, softRoles[value]);\n\nexport const messageSelection = (theme: Theme, value: Tone): string =>\n  selectionOn(theme, softRoles[value]);\n\nexport const toneSurface = (theme: Theme, value: Tone): StyleDesc => {\n  const { bg, border, fg } = tone(theme, value);\n  return {\n    backgroundColor: bg,\n    color: fg,\n    borderWidth: theme.borderWidth.thin,\n    borderColor: border,\n  };\n};\n"
    }
  ],
  "docs": "[Carousel](https://gpuixui.sudokw.com/components/carousel) — 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": "/components/carousel",
    "kind": "component",
    "runtime": "gpuix",
    "registry": "gpuixui"
  }
}