{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "cart-item",
  "title": "Cart Item",
  "description": "A compound cart line with product details, availability, quantity, price, and removal.",
  "dependencies": [
    "class-variance-authority",
    "lucide-react"
  ],
  "registryDependencies": [
    "button",
    "https://uaiblocks.dev/r/uai-theme.json",
    "https://uaiblocks.dev/r/uai-utils.json",
    "https://uaiblocks.dev/r/quantity-picker.json"
  ],
  "files": [
    {
      "path": "src/registry/uai/components/cart-item.tsx",
      "content": "\"use client\";\n\nimport { cva } from \"class-variance-authority\";\nimport { LoaderCircle, Trash2 } from \"lucide-react\";\nimport { type ComponentProps, createContext, type ReactNode, useContext, useId } from \"react\";\n\nimport { Button } from \"@/components/ui/button\";\nimport { cn } from \"@/lib/uai-utils\";\n\nexport const CART_ITEM_VARIANTS = [\"card\", \"plain\", \"compact\"] as const;\nexport const CART_ITEM_AVAILABILITY_TONES = [\"available\", \"low\", \"unavailable\"] as const;\n\nexport type CartItemVariant = (typeof CART_ITEM_VARIANTS)[number];\nexport type CartItemAvailabilityTone = (typeof CART_ITEM_AVAILABILITY_TONES)[number];\n\nexport type CartItemProps = ComponentProps<\"article\"> & {\n  variant?: CartItemVariant;\n};\n\n// The line dims and stops taking input while its remove action is in flight.\nconst cartItemVariants = cva(\n  \"grid w-full items-start border-border/60 text-foreground transition-opacity duration-200 ease-out has-[[data-slot=cart-item-remove][aria-busy=true]]:pointer-events-none has-[[data-slot=cart-item-remove][aria-busy=true]]:opacity-55 motion-reduce:transition-none\",\n  {\n    variants: {\n      variant: {\n        card: \"grid-cols-[96px_minmax(0,1fr)] gap-4 rounded-[14px] border bg-card p-4 max-[420px]:grid-cols-[76px_minmax(0,1fr)]\",\n        plain:\n          \"grid-cols-[88px_minmax(0,1fr)] gap-4 rounded-none border-b bg-transparent pb-4.5 max-[420px]:grid-cols-[76px_minmax(0,1fr)]\",\n        compact:\n          \"grid-cols-[72px_minmax(0,1fr)] gap-3 rounded-xl border bg-card p-3 max-[420px]:grid-cols-[68px_minmax(0,1fr)]\",\n      },\n    },\n  },\n);\n\nfunction cartItemChrome(variant: CartItemVariant) {\n  const compact = variant === \"compact\";\n\n  return {\n    mediaClass: compact ? \"rounded-lg\" : \"rounded-[10px]\",\n    titleClass: compact ? \"text-[13px]/[18px]\" : \"text-sm/5\",\n    descriptionClass: compact ? \"mt-0.5 text-[11.5px]/4\" : \"mt-0.5 text-[12.5px]/[18px]\",\n    priceClass: compact ? \"text-[13px]/[18px]\" : \"text-sm/5\",\n    optionsClass: compact ? \"mt-2 gap-1\" : \"mt-2.5 gap-1.5\",\n    optionClass: compact ? \"h-5 px-1.5 text-[11px]\" : \"h-5.5 px-2 text-[11.5px]\",\n    availabilityClass: compact ? \"mt-2 px-1.5 text-[11px]/4\" : \"mt-2.5 px-2 text-[11.5px]/4\",\n    actionsClass: compact ? \"mt-3 gap-2.5\" : \"mt-4 gap-3\",\n    removeClass: compact\n      ? \"h-7 px-2.5 text-[12px] has-[>svg]:px-2.5\"\n      : \"h-8 px-3 text-[12.5px] has-[>svg]:px-3\",\n  };\n}\n\ntype CartItemContextValue = {\n  titleId: string;\n  chrome: ReturnType<typeof cartItemChrome>;\n};\n\nconst CartItemContext = createContext<CartItemContextValue | null>(null);\n\nfunction useCartItem(name: string) {\n  const context = useContext(CartItemContext);\n  if (!context) throw new Error(`${name} must be used within CartItem`);\n  return context;\n}\n\nexport function CartItem({\n  variant = \"card\",\n  children,\n  className,\n  \"aria-labelledby\": ariaLabelledby,\n  ...props\n}: CartItemProps) {\n  const titleId = useId();\n  const chrome = cartItemChrome(variant);\n\n  return (\n    <CartItemContext.Provider value={{ titleId, chrome }}>\n      <article\n        data-slot=\"cart-item\"\n        data-variant={variant}\n        className={cn(cartItemVariants({ variant }), className)}\n        {...props}\n        aria-labelledby={ariaLabelledby ?? titleId}\n      >\n        {children}\n      </article>\n    </CartItemContext.Provider>\n  );\n}\n\nexport type CartItemMediaProps = ComponentProps<\"div\">;\n\nexport function CartItemMedia({ children, className, ...props }: CartItemMediaProps) {\n  const context = useCartItem(\"CartItemMedia\");\n\n  return (\n    <div\n      data-slot=\"cart-item-media\"\n      className={cn(\n        \"relative aspect-square min-w-0 overflow-hidden bg-muted after:pointer-events-none after:absolute after:inset-0 after:rounded-[inherit] after:shadow-[inset_0_0_0_1px_color-mix(in_oklab,var(--foreground)_8%,transparent)] after:content-[''] [&>img]:size-full [&>img]:object-cover\",\n        context.chrome.mediaClass,\n        className,\n      )}\n      {...props}\n    >\n      {children}\n    </div>\n  );\n}\n\nexport type CartItemContentProps = ComponentProps<\"div\">;\n\nexport function CartItemContent({ children, className, ...props }: CartItemContentProps) {\n  useCartItem(\"CartItemContent\");\n\n  return (\n    <div data-slot=\"cart-item-content\" className={cn(\"min-w-0\", className)} {...props}>\n      {children}\n    </div>\n  );\n}\n\nexport type CartItemHeaderProps = ComponentProps<\"header\">;\n\nexport function CartItemHeader({ children, className, ...props }: CartItemHeaderProps) {\n  useCartItem(\"CartItemHeader\");\n\n  return (\n    <header\n      data-slot=\"cart-item-header\"\n      className={cn(\"flex min-w-0 items-start justify-between gap-3\", className)}\n      {...props}\n    >\n      {children}\n    </header>\n  );\n}\n\nexport type CartItemTitleProps = ComponentProps<\"h2\">;\n\nexport function CartItemTitle({ children, className, ...props }: CartItemTitleProps) {\n  const context = useCartItem(\"CartItemTitle\");\n\n  return (\n    <h2\n      data-slot=\"cart-item-title\"\n      className={cn(\n        \"font-medium tracking-[-0.01em] wrap-anywhere\",\n        context.chrome.titleClass,\n        className,\n      )}\n      {...props}\n      id={context.titleId}\n    >\n      {children}\n    </h2>\n  );\n}\n\nexport type CartItemDescriptionProps = ComponentProps<\"p\">;\n\nexport function CartItemDescription({ children, className, ...props }: CartItemDescriptionProps) {\n  const context = useCartItem(\"CartItemDescription\");\n\n  return (\n    <p\n      data-slot=\"cart-item-description\"\n      className={cn(\n        \"text-muted-foreground wrap-anywhere\",\n        context.chrome.descriptionClass,\n        className,\n      )}\n      {...props}\n    >\n      {children}\n    </p>\n  );\n}\n\nexport type CartItemPriceProps = ComponentProps<\"p\">;\n\nexport function CartItemPrice({ children, className, ...props }: CartItemPriceProps) {\n  const context = useCartItem(\"CartItemPrice\");\n\n  return (\n    <p\n      data-slot=\"cart-item-price\"\n      className={cn(\n        \"shrink-0 text-right font-medium tracking-[-0.01em] tabular-nums\",\n        context.chrome.priceClass,\n        className,\n      )}\n      {...props}\n    >\n      {children}\n    </p>\n  );\n}\n\nexport type CartItemOptionsProps = ComponentProps<\"dl\">;\n\nexport function CartItemOptions({ children, className, ...props }: CartItemOptionsProps) {\n  const context = useCartItem(\"CartItemOptions\");\n\n  return (\n    <dl\n      data-slot=\"cart-item-options\"\n      className={cn(\"flex min-w-0 flex-wrap leading-4\", context.chrome.optionsClass, className)}\n      {...props}\n    >\n      {children}\n    </dl>\n  );\n}\n\nexport type CartItemOptionProps = ComponentProps<\"div\"> & {\n  label: ReactNode;\n};\n\nexport function CartItemOption({ label, children, className, ...props }: CartItemOptionProps) {\n  const context = useCartItem(\"CartItemOption\");\n\n  return (\n    <div\n      data-slot=\"cart-item-option\"\n      className={cn(\n        \"inline-flex min-w-0 items-center gap-1 rounded-[6px] bg-muted\",\n        context.chrome.optionClass,\n        className,\n      )}\n      {...props}\n    >\n      <dt className=\"text-subtle-foreground\">{label}</dt>\n      <dd className=\"min-w-0 font-medium text-foreground wrap-anywhere\">{children}</dd>\n    </div>\n  );\n}\n\nexport type CartItemAvailabilityProps = ComponentProps<\"p\"> & {\n  tone?: CartItemAvailabilityTone;\n};\n\nconst availabilityToneClass: Record<CartItemAvailabilityTone, string> = {\n  available: \"bg-success/14 text-success-ink\",\n  low: \"bg-warning/14 text-warning-ink\",\n  unavailable: \"bg-destructive/14 text-destructive-ink\",\n};\n\nexport function CartItemAvailability({\n  tone = \"available\",\n  children,\n  className,\n  ...props\n}: CartItemAvailabilityProps) {\n  const context = useCartItem(\"CartItemAvailability\");\n\n  return (\n    <p\n      data-slot=\"cart-item-availability\"\n      className={cn(\n        \"flex w-fit max-w-full items-center gap-1.5 rounded-full py-0.5 font-medium wrap-anywhere before:size-1.5 before:shrink-0 before:rounded-full before:bg-current before:content-['']\",\n        context.chrome.availabilityClass,\n        availabilityToneClass[tone],\n        className,\n      )}\n      {...props}\n    >\n      {children}\n    </p>\n  );\n}\n\nexport type CartItemActionsProps = ComponentProps<\"footer\">;\n\nexport function CartItemActions({ children, className, ...props }: CartItemActionsProps) {\n  const context = useCartItem(\"CartItemActions\");\n\n  return (\n    <footer\n      data-slot=\"cart-item-actions\"\n      className={cn(\n        \"flex min-w-0 flex-wrap items-center justify-between\",\n        context.chrome.actionsClass,\n        className,\n      )}\n      {...props}\n    >\n      {children}\n    </footer>\n  );\n}\n\nexport type CartItemRemoveProps = ComponentProps<\"button\"> & {\n  removing?: boolean;\n  removingLabel?: ReactNode;\n};\n\nexport function CartItemRemove({\n  removing = false,\n  removingLabel = \"Removing…\",\n  children = \"Remove\",\n  className,\n  disabled,\n  type = \"button\",\n  ...props\n}: CartItemRemoveProps) {\n  const context = useCartItem(\"CartItemRemove\");\n\n  return (\n    <Button\n      data-slot=\"cart-item-remove\"\n      variant=\"ghost\"\n      size=\"sm\"\n      type={type}\n      className={cn(\n        \"inline-flex shrink-0 items-center justify-center gap-1.5 rounded-full font-medium text-muted-foreground transition-[scale,color,background-color] duration-140 ease-out-quint hover:bg-destructive/12 hover:text-destructive-ink focus-visible:ring-0 focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring focus-visible:outline-solid active:scale-[0.97] disabled:pointer-events-none disabled:opacity-60 motion-reduce:transition-none motion-reduce:active:scale-100 dark:hover:bg-destructive/12\",\n        context.chrome.removeClass,\n        className,\n      )}\n      {...props}\n      disabled={disabled || removing}\n      aria-busy={removing || undefined}\n    >\n      {removing ? (\n        <LoaderCircle\n          className=\"size-3.5 animate-spin motion-reduce:animate-none\"\n          aria-hidden=\"true\"\n        />\n      ) : (\n        <Trash2 className=\"size-3.5\" strokeWidth={1.75} aria-hidden=\"true\" />\n      )}\n      <span>{removing ? removingLabel : children}</span>\n    </Button>\n  );\n}\n",
      "type": "registry:ui",
      "target": "@ui/uai/cart-item.tsx"
    }
  ],
  "categories": [
    "commerce",
    "data-display"
  ],
  "type": "registry:ui"
}