{"$schema":"https:\/\/ui.particle.academy\/schema\/registry-item.json","name":"tabs","type":"registry:ui","title":"Tabs","description":"Tabs from react-fancy","package":"react-fancy","dependencies":[],"registryDependencies":[],"files":[{"path":"components\/fancy\/tabs\/Tabs.context.ts","content":"import { createContext, useContext } from \"react\";\r\nimport type { TabsContextValue } from \".\/Tabs.types\";\r\n\r\nexport const TabsContext = createContext<TabsContextValue | null>(null);\r\n\r\nexport function useTabs(): TabsContextValue {\r\n  const ctx = useContext(TabsContext);\r\n  if (!ctx) {\r\n    throw new Error(\"Tabs compound components must be used within <Tabs>\");\r\n  }\r\n  return ctx;\r\n}\r\n","type":"registry:ui","target":"components\/fancy\/tabs\/Tabs.context.ts"},{"path":"components\/fancy\/tabs\/Tabs.tsx","content":"import { useMemo } from \"react\";\r\nimport { cn } from \"..\/..\/utils\/cn\";\r\nimport { useControllableState } from \"..\/..\/hooks\/use-controllable-state\";\r\nimport { TabsContext } from \".\/Tabs.context\";\r\nimport { TabsList } from \".\/TabsList\";\r\nimport { TabsTab } from \".\/TabsTab\";\r\nimport { TabsPanels } from \".\/TabsPanels\";\r\nimport { TabsPanel } from \".\/TabsPanel\";\r\nimport type { TabsProps } from \".\/Tabs.types\";\r\n\r\nfunction TabsRoot({\r\n  children,\r\n  defaultTab = \"\",\r\n  activeTab: controlledTab,\r\n  onTabChange,\r\n  variant = \"underline\",\r\n  className,\r\n}: TabsProps) {\r\n  const [activeTab, setActiveTab] = useControllableState(\r\n    controlledTab,\r\n    defaultTab,\r\n    onTabChange,\r\n  );\r\n\r\n  const ctx = useMemo(\r\n    () => ({ activeTab, setActiveTab, variant }),\r\n    [activeTab, setActiveTab, variant],\r\n  );\r\n\r\n  return (\r\n    <TabsContext.Provider value={ctx}>\r\n      <div data-react-fancy-tabs=\"\" className={cn(className)}>{children}<\/div>\r\n    <\/TabsContext.Provider>\r\n  );\r\n}\r\n\r\nexport const Tabs = Object.assign(TabsRoot, {\r\n  List: TabsList,\r\n  Tab: TabsTab,\r\n  Panels: TabsPanels,\r\n  Panel: TabsPanel,\r\n});\r\n","type":"registry:ui","target":"components\/fancy\/tabs\/Tabs.tsx"},{"path":"components\/fancy\/tabs\/Tabs.types.ts","content":"import type { ButtonHTMLAttributes, ReactNode } from \"react\";\r\n\r\nexport type TabsVariant = \"underline\" | \"pills\" | \"boxed\";\r\n\r\nexport interface TabsContextValue {\r\n  activeTab: string;\r\n  setActiveTab: (tab: string) => void;\r\n  variant: TabsVariant;\r\n}\r\n\r\nexport interface TabsProps {\r\n  children: ReactNode;\r\n  defaultTab?: string;\r\n  activeTab?: string;\r\n  onTabChange?: (tab: string) => void;\r\n  variant?: TabsVariant;\r\n  className?: string;\r\n}\r\n\r\nexport interface TabsListProps {\r\n  children: ReactNode;\r\n  className?: string;\r\n}\r\n\r\nexport interface TabsTabProps extends Omit<ButtonHTMLAttributes<HTMLButtonElement>, \"value\"> {\r\n  children: ReactNode;\r\n  value: string;\r\n  disabled?: boolean;\r\n  className?: string;\r\n}\r\n\r\nexport interface TabsPanelsProps {\r\n  children: ReactNode;\r\n  className?: string;\r\n}\r\n\r\nexport interface TabsPanelProps {\r\n  children: ReactNode;\r\n  value: string;\r\n  className?: string;\r\n}\r\n","type":"registry:ui","target":"components\/fancy\/tabs\/Tabs.types.ts"},{"path":"components\/fancy\/tabs\/TabsList.tsx","content":"import { useCallback, useRef } from \"react\";\r\nimport { cn } from \"..\/..\/utils\/cn\";\r\nimport { useTabs } from \".\/Tabs.context\";\r\nimport type { TabsListProps } from \".\/Tabs.types\";\r\n\r\nexport function TabsList({ children, className }: TabsListProps) {\r\n  const { variant } = useTabs();\r\n  const listRef = useRef<HTMLDivElement>(null);\r\n\r\n  const handleKeyDown = useCallback((e: React.KeyboardEvent) => {\r\n    const buttons = listRef.current?.querySelectorAll<HTMLButtonElement>(\r\n      '[role=\"tab\"]:not([disabled])',\r\n    );\r\n    if (!buttons?.length) return;\r\n\r\n    const items = Array.from(buttons);\r\n    const currentIndex = items.indexOf(document.activeElement as HTMLButtonElement);\r\n\r\n    if (e.key === \"ArrowRight\" || e.key === \"ArrowDown\") {\r\n      e.preventDefault();\r\n      const next = currentIndex < items.length - 1 ? currentIndex + 1 : 0;\r\n      items[next].focus();\r\n      items[next].click();\r\n    } else if (e.key === \"ArrowLeft\" || e.key === \"ArrowUp\") {\r\n      e.preventDefault();\r\n      const prev = currentIndex > 0 ? currentIndex - 1 : items.length - 1;\r\n      items[prev].focus();\r\n      items[prev].click();\r\n    }\r\n  }, []);\r\n\r\n  return (\r\n    <div\r\n      data-react-fancy-tabs-list=\"\"\r\n      ref={listRef}\r\n      role=\"tablist\"\r\n      onKeyDown={handleKeyDown}\r\n      className={cn(\r\n        \"flex\",\r\n        variant === \"underline\" && \"gap-0 border-b border-zinc-200 dark:border-zinc-700\",\r\n        variant === \"pills\" && \"gap-0 rounded-lg bg-zinc-100 p-1 dark:bg-zinc-800\",\r\n        variant === \"boxed\" &&\r\n          \"gap-0 rounded-lg bg-zinc-100 p-1 dark:bg-zinc-800\",\r\n        className,\r\n      )}\r\n    >\r\n      {children}\r\n    <\/div>\r\n  );\r\n}\r\n\r\nTabsList.displayName = \"TabsList\";\r\n","type":"registry:ui","target":"components\/fancy\/tabs\/TabsList.tsx"},{"path":"components\/fancy\/tabs\/TabsPanel.tsx","content":"import { cn } from \"..\/..\/utils\/cn\";\r\nimport { useTabs } from \".\/Tabs.context\";\r\nimport type { TabsPanelProps } from \".\/Tabs.types\";\r\n\r\nexport function TabsPanel({ children, value, className }: TabsPanelProps) {\r\n  const { activeTab } = useTabs();\r\n\r\n  if (activeTab !== value) return null;\r\n\r\n  return (\r\n    <div data-react-fancy-tabs-panel=\"\" role=\"tabpanel\" className={cn(\"fancy-fade-in\", className)}>\r\n      {children}\r\n    <\/div>\r\n  );\r\n}\r\n\r\nTabsPanel.displayName = \"TabsPanel\";\r\n","type":"registry:ui","target":"components\/fancy\/tabs\/TabsPanel.tsx"},{"path":"components\/fancy\/tabs\/TabsPanels.tsx","content":"import { cn } from \"..\/..\/utils\/cn\";\r\nimport type { TabsPanelsProps } from \".\/Tabs.types\";\r\n\r\nexport function TabsPanels({ children, className }: TabsPanelsProps) {\r\n  return <div data-react-fancy-tabs-panels=\"\" className={cn(\"mt-4\", className)}>{children}<\/div>;\r\n}\r\n\r\nTabsPanels.displayName = \"TabsPanels\";\r\n","type":"registry:ui","target":"components\/fancy\/tabs\/TabsPanels.tsx"},{"path":"components\/fancy\/tabs\/TabsTab.tsx","content":"import { cn } from \"..\/..\/utils\/cn\";\r\nimport { useTabs } from \".\/Tabs.context\";\r\nimport type { TabsTabProps } from \".\/Tabs.types\";\r\n\r\nexport function TabsTab({\r\n  children,\r\n  value,\r\n  disabled = false,\r\n  className,\r\n  onClick,\r\n  ...rest\r\n}: TabsTabProps) {\r\n  const { activeTab, setActiveTab, variant } = useTabs();\r\n  const isActive = activeTab === value;\r\n\r\n  return (\r\n    <button\r\n      data-react-fancy-tabs-tab=\"\"\r\n      type=\"button\"\r\n      role=\"tab\"\r\n      disabled={disabled}\r\n      aria-selected={isActive}\r\n      tabIndex={isActive ? 0 : -1}\r\n      onClick={(e) => { if (!disabled) setActiveTab(value); onClick?.(e); }}\r\n      {...rest}\r\n      className={cn(\r\n        \"text-sm font-medium transition-colors\",\r\n        disabled && \"cursor-not-allowed opacity-50\",\r\n        variant === \"underline\" && [\r\n          \"border-b-2 px-4 py-2.5\",\r\n          isActive\r\n            ? \"border-zinc-900 text-zinc-900 dark:border-white dark:text-white\"\r\n            : \"border-transparent text-zinc-500 hover:border-zinc-300 hover:text-zinc-700 dark:text-zinc-400 dark:hover:text-zinc-300\",\r\n        ],\r\n        variant === \"pills\" && [\r\n          \"rounded-md px-4 py-1.5\",\r\n          isActive\r\n            ? \"bg-white text-zinc-900 shadow-sm dark:bg-zinc-900 dark:text-white\"\r\n            : \"text-zinc-500 dark:text-zinc-400\",\r\n        ],\r\n        variant === \"boxed\" && [\r\n          \"flex-1 rounded-md px-4 py-1.5\",\r\n          isActive\r\n            ? \"bg-white text-zinc-900 shadow-sm dark:bg-zinc-900 dark:text-white\"\r\n            : \"text-zinc-500 dark:text-zinc-400\",\r\n        ],\r\n        className,\r\n      )}\r\n    >\r\n      {children}\r\n    <\/button>\r\n  );\r\n}\r\n\r\nTabsTab.displayName = \"TabsTab\";\r\n","type":"registry:ui","target":"components\/fancy\/tabs\/TabsTab.tsx"},{"path":"components\/fancy\/tabs\/index.ts","content":"export { Tabs } from \".\/Tabs\";\r\nexport { useTabs } from \".\/Tabs.context\";\r\nexport type {\r\n  TabsProps,\r\n  TabsListProps,\r\n  TabsTabProps,\r\n  TabsPanelsProps,\r\n  TabsPanelProps,\r\n  TabsVariant,\r\n  TabsContextValue,\r\n} from \".\/Tabs.types\";\r\n","type":"registry:ui","target":"components\/fancy\/tabs\/index.ts"}]}