{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "tabs",
  "title": "Tabs",
  "description": "A tabbed interface with default, primary, and line variants.",
  "dependencies": [
    "@base-ui/react",
    "class-variance-authority"
  ],
  "registryDependencies": [
    "https://ui.ask.mir-ai.it/r/utils.json"
  ],
  "files": [
    {
      "path": "src/registry/ask-ui/components/ui/tabs/tabs.tsx",
      "content": "import { Tabs as TabsPrimitive } from \"@base-ui/react/tabs\";\nimport { cva, type VariantProps } from \"class-variance-authority\";\n\nimport { cn } from \"@/registry/ask-ui/lib/utils\";\n\nfunction Tabs({\n  className,\n  orientation = \"horizontal\",\n  ...props\n}: TabsPrimitive.Root.Props) {\n  return (\n    <TabsPrimitive.Root\n      data-slot=\"tabs\"\n      data-orientation={orientation}\n      className={cn(\n        \"group/tabs flex gap-2 data-horizontal:flex-col\",\n        className\n      )}\n      {...props}\n    />\n  );\n}\n\nconst tabsListVariants = cva(\n  \"group/tabs-list inline-flex w-fit items-center justify-center rounded-lg p-[3px] text-muted-foreground group-data-horizontal/tabs:h-9 group-data-vertical/tabs:h-fit group-data-vertical/tabs:flex-col\",\n  {\n    variants: {\n      variant: {\n        // `bg-secondary`, not `bg-muted`: Figma's updated frame\n        // (2658:8587) uses --color/secondary (#f4f4f5) for the track,\n        // which maps to our --secondary token (ask-neutral-100, L≈0.967) —\n        // --muted (ask-neutral-50, L≈0.985) is visibly whiter than the hex.\n        default: \"bg-secondary\",\n        // Figma \"Primary\" type: same track, but the active pill fills\n        // solid brand-red instead of white (see TabsTrigger below).\n        primary: \"bg-secondary\",\n        // Keeps the same track background as default/primary — only the\n        // active tab's own styling (underline instead of a pill, see\n        // TabsTrigger) sets `line` apart.\n        line: \"gap-1 bg-secondary\",\n        // `ghost`: same active-tab pill as `default` (border + shadow),\n        // just without the track's own background — the tabs-list\n        // container itself stays fully transparent.\n        ghost: \"bg-transparent\",\n      },\n    },\n    defaultVariants: {\n      variant: \"default\",\n    },\n  }\n);\n\nfunction TabsList({\n  className,\n  variant = \"default\",\n  ...props\n}: TabsPrimitive.List.Props & VariantProps<typeof tabsListVariants>) {\n  return (\n    <TabsPrimitive.List\n      data-slot=\"tabs-list\"\n      data-variant={variant}\n      className={cn(tabsListVariants({ variant }), className)}\n      {...props}\n    />\n  );\n}\n\nfunction TabsTrigger({ className, ...props }: TabsPrimitive.Tab.Props) {\n  return (\n    <TabsPrimitive.Tab\n      data-slot=\"tabs-trigger\"\n      className={cn(\n        // `cursor-not-allowed`, not `pointer-events-none`: base-ui's own\n        // click/pointer handlers already bail out when disabled, so\n        // pointer-events-none here would only stop the cursor from ever\n        // showing \"not-allowed\" (a disabled element is skipped during\n        // hit-testing, so its own cursor style is never applied).\n        //\n        // `not-data-active:hover:text-foreground`, not a bare `hover:`: an\n        // unconditional hover rule has the same specificity as the\n        // `primary` variant's `data-active:text-primary-foreground` (both\n        // single-class selectors), so on an active+hovered primary tab\n        // either could win the cascade — and did, painting near-black text\n        // on the solid red background. Scoping hover to inactive tabs only\n        // removes the conflict for every variant, not just primary.\n        \"relative inline-flex h-[calc(100%-1px)] flex-1 items-center justify-center gap-1.5 rounded-md border border-transparent px-2 py-1 text-sm font-medium whitespace-nowrap text-foreground/60 transition-all group-data-vertical/tabs:w-full group-data-vertical/tabs:justify-start not-data-active:hover:text-foreground focus-visible:border-ring focus-visible:ring-[3px] focus-visible:ring-ring/50 focus-visible:outline-1 focus-visible:outline-ring disabled:cursor-not-allowed disabled:opacity-50 has-data-[icon=inline-end]:pr-1.5 has-data-[icon=inline-start]:pl-1.5 aria-disabled:cursor-not-allowed aria-disabled:opacity-50 dark:text-muted-foreground dark:not-data-active:hover:text-foreground group-data-[variant=default]/tabs-list:data-active:shadow-sm group-data-[variant=primary]/tabs-list:data-active:shadow-sm group-data-[variant=ghost]/tabs-list:data-active:shadow-sm group-data-[variant=line]/tabs-list:data-active:shadow-none [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4\",\n        \"group-data-[variant=line]/tabs-list:bg-transparent group-data-[variant=line]/tabs-list:data-active:bg-transparent dark:group-data-[variant=line]/tabs-list:data-active:border-transparent dark:group-data-[variant=line]/tabs-list:data-active:bg-transparent\",\n        // Scoped to default/primary/ghost, not a bare `data-active:border-border`:\n        // Figma's active pill (2658:8587) shows a real border\n        // (--color/border, #e4e4e7 — our --border token exactly) in the\n        // default/light state too, not just the `dark:` fallback stock\n        // had — but `line`'s active tab has no border in any mode (its\n        // own override below only resets it in `dark:`, so an unscoped\n        // rule here would've leaked a border onto it in light mode).\n        // `ghost` reuses the same bordered-pill treatment as `default` —\n        // it only drops the tabs-list track's own background (see\n        // tabsListVariants), the active tab itself looks identical.\n        \"group-data-[variant=default]/tabs-list:data-active:border-border group-data-[variant=primary]/tabs-list:data-active:border-border group-data-[variant=ghost]/tabs-list:data-active:border-border data-active:bg-background data-active:text-foreground dark:data-active:border-input dark:data-active:bg-input/30 dark:data-active:text-foreground\",\n        // Figma \"Primary\" type: active tab fills solid brand-red instead of\n        // the default white pill.\n        \"group-data-[variant=primary]/tabs-list:data-active:border-transparent group-data-[variant=primary]/tabs-list:data-active:bg-primary group-data-[variant=primary]/tabs-list:data-active:text-primary-foreground dark:group-data-[variant=primary]/tabs-list:data-active:bg-primary\",\n        // `after:bg-primary`, not `-foreground`: the underline only ever\n        // renders for `line` (opacity stays 0 for every other variant), and\n        // brand-red better matches an accent indicator than near-black.\n        // Vertical orientation puts it on the left edge, not the right —\n        // that's the leading edge for a vertical tab list read top-to-bottom.\n        \"after:absolute after:bg-primary after:opacity-0 after:transition-opacity group-data-horizontal/tabs:after:inset-x-0 group-data-horizontal/tabs:after:bottom-[-5px] group-data-horizontal/tabs:after:h-0.5 group-data-vertical/tabs:after:inset-y-0 group-data-vertical/tabs:after:-left-1 group-data-vertical/tabs:after:w-0.5 group-data-[variant=line]/tabs-list:data-active:after:opacity-100\",\n        className\n      )}\n      {...props}\n    />\n  );\n}\n\nfunction TabsContent({ className, ...props }: TabsPrimitive.Panel.Props) {\n  return (\n    <TabsPrimitive.Panel\n      data-slot=\"tabs-content\"\n      className={cn(\"flex-1 text-sm outline-none\", className)}\n      {...props}\n    />\n  );\n}\n\nexport { Tabs, TabsList, TabsTrigger, TabsContent };\n",
      "type": "registry:ui"
    }
  ],
  "type": "registry:ui"
}