{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "tabs",
  "type": "registry:ui",
  "title": "Tabs",
  "description": "A set of layered sections with the same height of content—known as tab panels—that are displayed one at a time.",
  "dependencies": [
    "motion"
  ],
  "registryDependencies": [
    "https://animate-ui.com/r/motion-highlight"
  ],
  "files": [
    {
      "path": "registry/components/tabs/index.tsx",
      "content": "'use client';\n\nimport * as React from 'react';\nimport { motion, type Transition, type HTMLMotionProps } from 'motion/react';\n\nimport { cn } from '@/lib/utils';\nimport {\n  MotionHighlight,\n  MotionHighlightItem,\n} from '@/components/animate-ui/effects/motion-highlight';\n\ntype TabsContextType<T extends string> = {\n  activeValue: T;\n  handleValueChange: (value: T) => void;\n  registerTrigger: (value: T, node: HTMLElement | null) => void;\n};\n\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nconst TabsContext = React.createContext<TabsContextType<any> | undefined>(\n  undefined,\n);\n\nfunction useTabs<T extends string = string>(): TabsContextType<T> {\n  const context = React.useContext(TabsContext);\n  if (!context) {\n    throw new Error('useTabs must be used within a TabsProvider');\n  }\n  return context;\n}\n\ntype BaseTabsProps = React.ComponentProps<'div'> & {\n  children: React.ReactNode;\n};\n\ntype UnControlledTabsProps<T extends string = string> = BaseTabsProps & {\n  defaultValue?: T;\n  value?: never;\n  onValueChange?: never;\n};\n\ntype ControlledTabsProps<T extends string = string> = BaseTabsProps & {\n  value: T;\n  onValueChange?: (value: T) => void;\n  defaultValue?: never;\n};\n\ntype TabsProps<T extends string = string> =\n  | UnControlledTabsProps<T>\n  | ControlledTabsProps<T>;\n\nfunction Tabs<T extends string = string>({\n  defaultValue,\n  value,\n  onValueChange,\n  children,\n  className,\n  ...props\n}: TabsProps<T>) {\n  const [activeValue, setActiveValue] = React.useState<T | undefined>(\n    defaultValue ?? undefined,\n  );\n  const triggersRef = React.useRef(new Map<string, HTMLElement>());\n  const initialSet = React.useRef(false);\n  const isControlled = value !== undefined;\n\n  React.useEffect(() => {\n    if (\n      !isControlled &&\n      activeValue === undefined &&\n      triggersRef.current.size > 0 &&\n      !initialSet.current\n    ) {\n      const firstTab = Array.from(triggersRef.current.keys())[0];\n      setActiveValue(firstTab as T);\n      initialSet.current = true;\n    }\n  }, [activeValue, isControlled]);\n\n  const registerTrigger = (value: string, node: HTMLElement | null) => {\n    if (node) {\n      triggersRef.current.set(value, node);\n      if (!isControlled && activeValue === undefined && !initialSet.current) {\n        setActiveValue(value as T);\n        initialSet.current = true;\n      }\n    } else {\n      triggersRef.current.delete(value);\n    }\n  };\n\n  const handleValueChange = (val: T) => {\n    if (!isControlled) setActiveValue(val);\n    else onValueChange?.(val);\n  };\n\n  return (\n    <TabsContext.Provider\n      value={{\n        activeValue: (value ?? activeValue)!,\n        handleValueChange,\n        registerTrigger,\n      }}\n    >\n      <div\n        data-slot=\"tabs\"\n        className={cn('flex flex-col gap-2', className)}\n        {...props}\n      >\n        {children}\n      </div>\n    </TabsContext.Provider>\n  );\n}\n\ntype TabsListProps = React.ComponentProps<'div'> & {\n  children: React.ReactNode;\n  activeClassName?: string;\n  transition?: Transition;\n};\n\nfunction TabsList({\n  children,\n  className,\n  activeClassName,\n  transition = {\n    type: 'spring',\n    stiffness: 200,\n    damping: 25,\n  },\n  ...props\n}: TabsListProps) {\n  const { activeValue } = useTabs();\n\n  return (\n    <MotionHighlight\n      controlledItems\n      className={cn('rounded-sm bg-background shadow-sm', activeClassName)}\n      value={activeValue}\n      transition={transition}\n    >\n      <div\n        role=\"tablist\"\n        data-slot=\"tabs-list\"\n        className={cn(\n          'bg-muted text-muted-foreground inline-flex h-10 w-fit items-center justify-center rounded-lg p-[4px]',\n          className,\n        )}\n        {...props}\n      >\n        {children}\n      </div>\n    </MotionHighlight>\n  );\n}\n\ntype TabsTriggerProps = HTMLMotionProps<'button'> & {\n  value: string;\n  children: React.ReactNode;\n};\n\nfunction TabsTrigger({\n  ref,\n  value,\n  children,\n  className,\n  ...props\n}: TabsTriggerProps) {\n  const { activeValue, handleValueChange, registerTrigger } = useTabs();\n\n  const localRef = React.useRef<HTMLButtonElement | null>(null);\n  React.useImperativeHandle(ref, () => localRef.current as HTMLButtonElement);\n\n  React.useEffect(() => {\n    registerTrigger(value, localRef.current);\n    return () => registerTrigger(value, null);\n  }, [value, registerTrigger]);\n\n  return (\n    <MotionHighlightItem value={value} className=\"size-full\">\n      <motion.button\n        ref={localRef}\n        data-slot=\"tabs-trigger\"\n        role=\"tab\"\n        whileTap={{ scale: 0.95 }}\n        onClick={() => handleValueChange(value)}\n        data-state={activeValue === value ? 'active' : 'inactive'}\n        className={cn(\n          'inline-flex cursor-pointer items-center size-full justify-center whitespace-nowrap rounded-sm px-2 py-1 text-sm font-medium ring-offset-background transition-transform focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 data-[state=active]:text-foreground z-[1]',\n          className,\n        )}\n        {...props}\n      >\n        {children}\n      </motion.button>\n    </MotionHighlightItem>\n  );\n}\n\ntype TabsContentsProps = React.ComponentProps<'div'> & {\n  children: React.ReactNode;\n  transition?: Transition;\n};\n\nfunction TabsContents({\n  children,\n  className,\n  transition = {\n    type: 'spring',\n    stiffness: 300,\n    damping: 30,\n    bounce: 0,\n    restDelta: 0.01,\n  },\n  ...props\n}: TabsContentsProps) {\n  const { activeValue } = useTabs();\n  const childrenArray = React.Children.toArray(children);\n  const activeIndex = childrenArray.findIndex(\n    (child): child is React.ReactElement<{ value: string }> =>\n      React.isValidElement(child) &&\n      typeof child.props === 'object' &&\n      child.props !== null &&\n      'value' in child.props &&\n      child.props.value === activeValue,\n  );\n\n  return (\n    <div\n      data-slot=\"tabs-contents\"\n      className={cn('overflow-hidden', className)}\n      {...props}\n    >\n      <motion.div\n        className=\"flex -mx-2\"\n        animate={{ x: activeIndex * -100 + '%' }}\n        transition={transition}\n      >\n        {childrenArray.map((child, index) => (\n          <div key={index} className=\"w-full shrink-0 px-2\">\n            {child}\n          </div>\n        ))}\n      </motion.div>\n    </div>\n  );\n}\n\ntype TabsContentProps = HTMLMotionProps<'div'> & {\n  value: string;\n  children: React.ReactNode;\n};\n\nfunction TabsContent({\n  children,\n  value,\n  className,\n  ...props\n}: TabsContentProps) {\n  const { activeValue } = useTabs();\n  const isActive = activeValue === value;\n  return (\n    <motion.div\n      role=\"tabpanel\"\n      data-slot=\"tabs-content\"\n      className={cn('overflow-hidden', className)}\n      initial={{ filter: 'blur(0px)' }}\n      animate={{ filter: isActive ? 'blur(0px)' : 'blur(4px)' }}\n      exit={{ filter: 'blur(0px)' }}\n      transition={{ type: 'spring', stiffness: 200, damping: 25 }}\n      {...props}\n    >\n      {children}\n    </motion.div>\n  );\n}\n\nexport {\n  Tabs,\n  TabsList,\n  TabsTrigger,\n  TabsContents,\n  TabsContent,\n  useTabs,\n  type TabsContextType,\n  type TabsProps,\n  type TabsListProps,\n  type TabsTriggerProps,\n  type TabsContentsProps,\n  type TabsContentProps,\n};\n",
      "type": "registry:ui",
      "target": "components/animate-ui/components/tabs.tsx"
    }
  ]
}