{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "ios-mail-tabs",
  "type": "registry:block",
  "title": "iOS Mail Tabs",
  "description": "A set of animated, iOS-inspired mail tabs for React apps. Switch between tabs like Primary, Transactions, Updates, Promotions, and All Mail with smooth transitions. Great for email clients or any UI needing visually distinct, interactive tab navigation.",
  "dependencies": [
    "motion",
    "lucide-react"
  ],
  "files": [
    {
      "path": "registry/new-york/ios-mail-tabs/ios-mail-tabs.tsx",
      "content": "import { cn } from \"@/lib/utils\";\nimport { LucideIcon } from \"lucide-react\";\nimport { AnimatePresence, motion } from \"motion/react\";\nimport * as React from \"react\";\n\n// Context for managing selected tab\ninterface IosMailTabsContextProps {\n  value: string;\n  setValue: (value: string) => void;\n}\nconst IosMailTabsContext = React.createContext<\n  IosMailTabsContextProps | undefined\n>(undefined);\n\n/**\n * Custom hook to access IosMailTabs context.\n * Throws if used outside of <IosMailTabs>.\n * @example\n * const { value, setValue } = useIosMailTabs();\n */\nexport function useIosMailTabs(): IosMailTabsContextProps {\n  const ctx = React.useContext(IosMailTabsContext);\n  if (!ctx) throw new Error(\"useIosMailTabs must be used within <IosMailTabs>\");\n  return ctx;\n}\n\n/**\n * Root component for iOS-style tabs.\n * @example\n * <IosMailTabs defaultValue=\"primary\">\n *   <IosMailTabsList>\n *     <IosMailTabsTrigger value=\"primary\" icon={UserRoundIcon} className=\"bg-sky-600 text-white\">\n *       Primary\n *     </IosMailTabsTrigger>\n *   </IosMailTabsList>\n *   <IosMailTabsContent value=\"primary\">Primary content</IosMailTabsContent>\n * </IosMailTabs>\n */\nexport function IosMailTabs({\n  defaultValue,\n  value: controlledValue,\n  onValueChange,\n  children,\n  className,\n}: {\n  defaultValue?: string;\n  value?: string;\n  onValueChange?: (value: string) => void;\n  children: React.ReactNode;\n  className?: string;\n}) {\n  const [uncontrolledValue, setUncontrolledValue] = React.useState(\n    defaultValue ?? \"\",\n  );\n  const isControlled = controlledValue !== undefined;\n  const value = isControlled ? controlledValue : uncontrolledValue;\n  const setValue = React.useCallback(\n    (v: string) => {\n      if (!isControlled) setUncontrolledValue(v);\n      onValueChange?.(v);\n    },\n    [isControlled, onValueChange],\n  );\n\n  return (\n    <IosMailTabsContext.Provider value={{ value, setValue }}>\n      <div className={cn(\"flex flex-col gap-2\", className)}>{children}</div>\n    </IosMailTabsContext.Provider>\n  );\n}\n\n/**\n * List container for iOS-style tab triggers.\n * @example\n * <IosMailTabsList>\n *   <IosMailTabsTrigger value=\"primary\" icon={UserRoundIcon} className=\"bg-sky-600 text-white\">\n *     Primary\n *   </IosMailTabsTrigger>\n * </IosMailTabsList>\n */\nexport function IosMailTabsList({\n  children,\n  className,\n}: {\n  children: React.ReactNode;\n  className?: string;\n}) {\n  return (\n    <div\n      className={cn(\n        \"flex flex-row items-center justify-center gap-1.5\",\n        className,\n      )}\n    >\n      {children}\n    </div>\n  );\n}\n\n/**\n * Trigger button for iOS-style tab. Accepts an icon prop and label as children. Consumer controls color via className.\n * @example\n * <IosMailTabsTrigger value=\"primary\" icon={UserRoundIcon} className=\"bg-sky-600 text-white\">\n *   Primary\n * </IosMailTabsTrigger>\n */\nexport function IosMailTabsTrigger({\n  value: triggerValue,\n  icon: Icon,\n  children,\n  className,\n}: {\n  value: string;\n  icon: LucideIcon;\n  children: React.ReactNode;\n  className?: string;\n}) {\n  const { value, setValue } = useIosMailTabs();\n  const isSelected = value === triggerValue;\n\n  return (\n    <motion.button\n      type=\"button\"\n      initial={false}\n      animate={{\n        paddingLeft: isSelected ? \"32px\" : \"16px\",\n        paddingRight: isSelected ? \"32px\" : \"16px\",\n      }}\n      className={cn(\n        \"flex h-9 flex-row items-center overflow-hidden rounded-[11px] transition-colors duration-300\",\n        className,\n        !isSelected && \"bg-muted text-muted-foreground\",\n      )}\n      onClick={() => setValue(triggerValue)}\n      aria-pressed={isSelected}\n      tabIndex={0}\n    >\n      <Icon className=\"size-4\" />\n      <AnimatePresence initial={false}>\n        {isSelected && (\n          <motion.span\n            key={triggerValue}\n            className=\"flex items-center gap-2 font-medium whitespace-nowrap\"\n            initial={{ opacity: 0, width: 0, marginLeft: 0 }}\n            animate={{ opacity: 1, width: \"auto\", marginLeft: 8 }}\n            exit={{ opacity: 0, width: 0, marginLeft: 0 }}\n          >\n            {children}\n          </motion.span>\n        )}\n      </AnimatePresence>\n    </motion.button>\n  );\n}\n\n/**\n * Content for a specific tab. Only renders if the tab is selected.\n * @example\n * <IosMailTabsContent value=\"primary\">Primary content</IosMailTabsContent>\n */\nexport function IosMailTabsContent({\n  value: contentValue,\n  children,\n  className,\n}: {\n  value: string;\n  children: React.ReactNode;\n  className?: string;\n}) {\n  const { value } = useIosMailTabs();\n  if (value !== contentValue) return null;\n  return <div className={className}>{children}</div>;\n}\n",
      "type": "registry:component"
    }
  ]
}