{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "tabs",
  "title": "tabs",
  "dependencies": [
    "@radix-ui/react-tabs",
    "class-variance-authority@^0.7"
  ],
  "registryDependencies": [
    "@dwellir/dwellir-theme",
    "@dwellir/utils"
  ],
  "files": [
    {
      "path": "components/ui/tabs.tsx",
      "content": "'use client';\n\nimport * as TabsPrimitive from '@radix-ui/react-tabs';\nimport { cva, type VariantProps } from 'class-variance-authority';\nimport {\n  type ComponentProps,\n  createContext,\n  useCallback,\n  useContext,\n  useEffect,\n  useRef,\n} from 'react';\nimport { cn } from '@/lib/utils';\n\n/*\n * The orientation sets the arrow keys: Left and Right for a row of tabs, Up\n * and Down for a column. A vertical root places the list beside its panels.\n */\nfunction Tabs({\n  className,\n  orientation = 'horizontal',\n  ...props\n}: ComponentProps<typeof TabsPrimitive.Root>) {\n  return (\n    <TabsPrimitive.Root\n      data-slot=\"tabs\"\n      data-orientation={orientation}\n      orientation={orientation}\n      className={cn('group/tabs flex gap-6 data-[orientation=horizontal]:flex-col', className)}\n      {...props}\n    />\n  );\n}\n\nconst tabsListVariants = cva('', {\n  variants: {\n    variant: {\n      /* A track with the control corner (in tab-tabs-list-variants); the active tab nests inside it. */\n      default:\n        'tab-tabs-list-variants inline-flex w-fit group-data-[orientation=vertical]/tabs:flex-col',\n      /*\n       * Long labels: on phones the tabs share the full width, with the icon\n       * over the label. From md up it is the default track.\n       */\n      stretch:\n        'tab-tabs-list-variants tab-stretch-2 w-full group-data-[orientation=vertical]/tabs:flex-col md:w-fit',\n      /*\n       * A column of rich rows beside a preview, such as products. No track of\n       * its own: place it in a card. The active row is a block of the ground colour.\n       */\n      stack: 'flex w-full flex-col items-stretch gap-1',\n      /*\n       * Tabs on a rule, as in an app's page header: the active tab is underlined.\n       * One row that scrolls sideways. Each tab draws its piece of the rule and\n       * the list's background (tab-line-rule) draws the rest: it scrolls with the\n       * tabs and takes no room, so tabs given flex-1 share the full row.\n       */\n      line: 'scrollbar-none tab-line-rule flex overflow-x-auto overscroll-x-contain group-data-[orientation=vertical]/tabs:flex-col group-data-[orientation=vertical]/tabs:bg-none',\n    },\n  },\n  defaultVariants: { variant: 'default' },\n});\n\nconst tabsTriggerVariants = cva('', {\n  variants: {\n    variant: {\n      default:\n        'ui-tab tab-default text-sm group-data-[orientation=vertical]/tabs:w-full group-data-[orientation=vertical]/tabs:justify-start',\n      /* The track's corner less its inset, so the corners nest. */\n      stretch:\n        'ui-tab tab-stretch text-sm leading-tight group-data-[orientation=vertical]/tabs:w-full group-data-[orientation=vertical]/tabs:justify-start',\n      stack: 'ui-tab tab-stack text-sm',\n      line: 'tab-line text-sm leading-none group-data-[orientation=horizontal]/tabs:border-b-border group-data-[orientation=vertical]/tabs:w-full group-data-[orientation=vertical]/tabs:justify-start',\n    },\n    /* The active line tab's colour, when the tabs stand for states such as errors. */\n    tone: {\n      default: '',\n      accent: '',\n      destructive: '',\n      warning: '',\n    },\n  },\n  compoundVariants: [\n    { variant: 'line', tone: 'default', class: 'data-[state=active]:border-b-primary' },\n    {\n      variant: 'line',\n      tone: 'accent',\n      class: 'data-[state=active]:border-b-primary data-[state=active]:text-accent-ink',\n    },\n    {\n      variant: 'line',\n      tone: 'destructive',\n      class: 'data-[state=active]:border-b-destructive data-[state=active]:text-destructive',\n    },\n    {\n      variant: 'line',\n      tone: 'warning',\n      class: 'data-[state=active]:border-b-warning-ink data-[state=active]:text-warning-ink',\n    },\n  ],\n  defaultVariants: { variant: 'default', tone: 'default' },\n});\n\ntype Variant = VariantProps<typeof tabsListVariants>['variant'];\n\nconst VariantContext = createContext<Variant>('default');\n\n/*\n * Scrolls a list sideways until its active tab shows: on mount, and whenever\n * a tab's state changes, by a click, the arrow keys or a new value.\n */\nfunction useActiveTabInView(enabled: boolean) {\n  const ref = useRef<HTMLDivElement | null>(null);\n  useEffect(() => {\n    const list = ref.current;\n    if (!enabled || !list) return;\n    const reveal = () => {\n      const tab = list.querySelector('[role=tab][data-state=active]');\n      if (!tab) return;\n      const box = list.getBoundingClientRect();\n      const rect = tab.getBoundingClientRect();\n      if (rect.left < box.left) list.scrollLeft -= box.left - rect.left;\n      else if (rect.right > box.right) list.scrollLeft += rect.right - box.right;\n    };\n    reveal();\n    const observer = new MutationObserver(reveal);\n    observer.observe(list, { subtree: true, attributeFilter: ['data-state'] });\n    return () => observer.disconnect();\n  }, [enabled]);\n  return ref;\n}\n\nfunction TabsList({\n  className,\n  variant,\n  children,\n  ref,\n  ...props\n}: ComponentProps<typeof TabsPrimitive.List> & VariantProps<typeof tabsListVariants>) {\n  const listRef = useActiveTabInView(variant === 'line');\n  // Returning a cleanup tells React 19 not to call the ref with null, so the\n  // cleanup must do that, or run the cleanup the caller's own callback returned.\n  const setRef = useCallback(\n    (node: HTMLDivElement | null) => {\n      listRef.current = node;\n      const cleanup = typeof ref === 'function' ? ref(node) : undefined;\n      if (ref && typeof ref === 'object') ref.current = node;\n      return () => {\n        listRef.current = null;\n        if (typeof cleanup === 'function') cleanup();\n        else if (typeof ref === 'function') ref(null);\n        else if (ref) ref.current = null;\n      };\n    },\n    [listRef, ref],\n  );\n  return (\n    <TabsPrimitive.List\n      ref={setRef}\n      data-slot=\"tabs-list\"\n      data-variant={variant ?? 'default'}\n      className={cn(tabsListVariants({ variant }), className)}\n      {...props}\n    >\n      <VariantContext.Provider value={variant}>{children}</VariantContext.Provider>\n    </TabsPrimitive.List>\n  );\n}\n\n/*\n * Radix focuses a tab by script on a mouse press, so the browser takes the\n * click for keyboard use and shows the ring. A pressed tab carries data-pointer\n * until it blurs, and the ring stays off for it. Arrow keys move the ring on.\n */\nfunction TabsTrigger({\n  className,\n  tone,\n  onPointerDown,\n  onBlur,\n  ...props\n}: ComponentProps<typeof TabsPrimitive.Trigger> &\n  Pick<VariantProps<typeof tabsTriggerVariants>, 'tone'>) {\n  const variant = useContext(VariantContext);\n  return (\n    <TabsPrimitive.Trigger\n      data-slot=\"tabs-trigger\"\n      className={cn(tabsTriggerVariants({ variant, tone }), className)}\n      onPointerDown={(event) => {\n        onPointerDown?.(event);\n        event.currentTarget.dataset.pointer = '';\n      }}\n      onBlur={(event) => {\n        onBlur?.(event);\n        delete event.currentTarget.dataset.pointer;\n      }}\n      {...props}\n    />\n  );\n}\n\nfunction TabsContent({ className, ...props }: ComponentProps<typeof TabsPrimitive.Content>) {\n  return (\n    <TabsPrimitive.Content\n      data-slot=\"tabs-content\"\n      className={cn('tab-content', className)}\n      {...props}\n    />\n  );\n}\n\nexport { Tabs, TabsContent, TabsList, TabsTrigger };\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui"
}