{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "tabs-styled",
  "title": "Tabs essentials",
  "description": "Styled tabs: the essentials set. 5 decorative tabs variations (UnderlineTabs, PillTabs, SegmentedTabs, BoxedTabs, IconTabs) on the ai2 token system, powered by framer-motion, reduced-motion aware and sized sm to xl. Part of the free styled layer.",
  "dependencies": [
    "motion@^12.42.2",
    "lucide-react@^1.23.0"
  ],
  "registryDependencies": [
    "@ai2/tokens"
  ],
  "files": [
    {
      "path": "registry/ai2/styled/tabs-styled.tsx",
      "content": "\"use client\"\r\n\r\nimport * as React from \"react\"\r\nimport { Activity, LayoutGrid, Settings, User } from \"lucide-react\"\r\nimport { motion, useReducedMotion } from \"motion/react\"\r\n\r\nimport { cn } from \"@/lib/utils\"\r\n\r\n/* Tabs family: 5 decorative tab strips. Only the TAB LIST is rendered (no panel).\n   role=\"tablist\" + role=\"tab\"/aria-selected, a roving tabIndex, and the selection\n   moves with ArrowLeft/Right. Color comes ONLY from tokens. The sliding indicator\n   flows with a framer-motion `layoutId`; it switches instantly under reduced-motion.\n   Controlled (value) or uncontrolled (defaultValue). */\r\n\r\nexport type StyledSize = \"sm\" | \"md\" | \"lg\" | \"xl\"\r\n\r\ntype TabItem = { value: string; label: React.ReactNode }\r\n\r\ntype TabsProps = {\r\n  className?: string\r\n  size?: StyledSize\r\n  tabs?: TabItem[]\r\n  value?: string\r\n  defaultValue?: string\r\n  onValueChange?: (v: string) => void\r\n}\r\n\r\nconst DEFAULT_TABS: TabItem[] = [\r\n  { value: \"overview\", label: \"Overview\" },\r\n  { value: \"activity\", label: \"Activity\" },\r\n  { value: \"settings\", label: \"Settings\" },\r\n]\r\n\r\nconst ICON_TABS: TabItem[] = [\r\n  { value: \"overview\", label: <><LayoutGrid /> Overview</> },\r\n  { value: \"activity\", label: <><Activity /> Activity</> },\r\n  { value: \"account\", label: <><User /> Account</> },\r\n  { value: \"settings\", label: <><Settings /> Settings</> },\r\n]\r\n\r\nconst sizeTab: Record<StyledSize, string> = {\r\n  sm: \"h-8 px-3 text-xs\",\r\n  md: \"h-9 px-4 text-sm\",\r\n  lg: \"h-10 px-5 text-sm\",\r\n  xl: \"h-11 px-6 text-base\",\r\n}\r\n\r\nconst tabBase =\r\n  \"relative z-10 inline-flex select-none items-center justify-center gap-2 whitespace-nowrap font-medium outline-none transition-colors focus-visible:ring-[3px] focus-visible:ring-ring/50 [&_svg]:size-4 [&_svg]:shrink-0 [&_i]:text-base [&_i]:leading-none\"\r\n\r\nfunction useTabsState({ tabs, value, defaultValue, onValueChange }: TabsProps, fallback: TabItem[]) {\r\n  const list = React.useMemo(() => (tabs && tabs.length ? tabs : fallback), [tabs, fallback])\r\n  const [internal, setInternal] = React.useState<string>(() => defaultValue ?? list[0]?.value ?? \"\")\r\n  const active = value ?? internal\r\n  const refs = React.useRef<(HTMLButtonElement | null)[]>([])\r\n  const select = React.useCallback(\r\n    (v: string) => {\r\n      if (value === undefined) setInternal(v)\r\n      onValueChange?.(v)\r\n    },\r\n    [value, onValueChange]\r\n  )\r\n  const onKeyDown = (e: React.KeyboardEvent) => {\r\n    if (e.key !== \"ArrowLeft\" && e.key !== \"ArrowRight\") return\r\n    e.preventDefault()\r\n    const idx = list.findIndex((t) => t.value === active)\r\n    const dir = e.key === \"ArrowRight\" ? 1 : -1\r\n    const ni = (idx + dir + list.length) % list.length\r\n    select(list[ni].value)\r\n    refs.current[ni]?.focus()\r\n  }\r\n  return { list, active, select, refs, onKeyDown }\r\n}\r\n\r\nfunction useSlide() {\r\n  const reduce = useReducedMotion()\r\n  return reduce ? { duration: 0 } : ({ type: \"spring\", stiffness: 420, damping: 34 } as const)\r\n}\r\n\r\n/* Underline: a token line slides under the active tab. */\r\nexport function UnderlineTabs({ className, size = \"md\", ...rest }: TabsProps) {\r\n  const { list, active, select, refs, onKeyDown } = useTabsState(rest, DEFAULT_TABS)\r\n  const id = React.useId()\r\n  const transition = useSlide()\r\n  return (\r\n    <div\r\n      data-slot=\"styled-tabs-viewport\"\r\n      className=\"-m-1 flex max-w-full overflow-x-auto p-1 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden\"\r\n    >\r\n      <div\r\n        data-slot=\"styled-tabs\"\r\n        role=\"tablist\"\r\n        onKeyDown={onKeyDown}\r\n        className={cn(\"inline-flex items-center gap-1 border-b border-border\", className)}\r\n      >\r\n        {list.map((tab, i) => {\r\n          const on = tab.value === active\r\n          return (\r\n            <button\r\n              key={tab.value}\r\n              ref={(el) => { refs.current[i] = el }}\r\n              type=\"button\"\r\n              role=\"tab\"\r\n              aria-selected={on}\r\n              tabIndex={on ? 0 : -1}\r\n              onClick={() => select(tab.value)}\r\n              className={cn(tabBase, sizeTab[size], \"-mb-px rounded-t-md\", on ? \"text-foreground\" : \"text-muted-foreground hover:text-foreground\")}\r\n            >\r\n              {tab.label}\r\n              {on && (\r\n                <motion.span\r\n                  layoutId={`${id}-underline`}\r\n                  transition={transition}\r\n                  className=\"absolute inset-x-0 -bottom-px h-0.5 rounded-full bg-primary\"\r\n                />\r\n              )}\r\n            </button>\r\n          )\r\n        })}\r\n      </div>\r\n    </div>\r\n  )\r\n}\r\n\r\n/* Pill: aktif sekmenin ardinda token dolgulu pill kayar. */\r\nexport function PillTabs({ className, size = \"md\", ...rest }: TabsProps) {\r\n  const { list, active, select, refs, onKeyDown } = useTabsState(rest, DEFAULT_TABS)\r\n  const id = React.useId()\r\n  const transition = useSlide()\r\n  return (\r\n    <div\r\n      data-slot=\"styled-tabs-viewport\"\r\n      className=\"-m-1 flex max-w-full overflow-x-auto p-1 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden\"\r\n    >\r\n      <div\r\n        data-slot=\"styled-tabs\"\r\n        role=\"tablist\"\r\n        onKeyDown={onKeyDown}\r\n        className={cn(\"inline-flex items-center gap-1 rounded-full bg-muted p-1\", className)}\r\n      >\r\n        {list.map((tab, i) => {\r\n          const on = tab.value === active\r\n          return (\r\n            <button\r\n              key={tab.value}\r\n              ref={(el) => { refs.current[i] = el }}\r\n              type=\"button\"\r\n              role=\"tab\"\r\n              aria-selected={on}\r\n              tabIndex={on ? 0 : -1}\r\n              onClick={() => select(tab.value)}\r\n              className={cn(tabBase, sizeTab[size], \"rounded-full\", on ? \"text-primary-foreground\" : \"text-muted-foreground hover:text-foreground\")}\r\n            >\r\n              {on && (\r\n                <motion.span\r\n                  layoutId={`${id}-pill`}\r\n                  transition={transition}\r\n                  className=\"absolute inset-0 -z-10 rounded-full bg-primary\"\r\n                />\r\n              )}\r\n              {tab.label}\r\n            </button>\r\n          )\r\n        })}\r\n      </div>\r\n    </div>\r\n  )\r\n}\r\n\r\n/* Segmented: segment kontrol gorunumu, aktif segment token dolgu ile yukselir. */\r\nexport function SegmentedTabs({ className, size = \"md\", ...rest }: TabsProps) {\r\n  const { list, active, select, refs, onKeyDown } = useTabsState(rest, DEFAULT_TABS)\r\n  const id = React.useId()\r\n  const transition = useSlide()\r\n  return (\r\n    <div\r\n      data-slot=\"styled-tabs-viewport\"\r\n      className=\"-m-1 flex max-w-full overflow-x-auto p-1 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden\"\r\n    >\r\n      <div\r\n        data-slot=\"styled-tabs\"\r\n        role=\"tablist\"\r\n        onKeyDown={onKeyDown}\r\n        className={cn(\"inline-flex items-center gap-0.5 rounded-lg border border-border bg-muted p-1\", className)}\r\n      >\r\n        {list.map((tab, i) => {\r\n          const on = tab.value === active\r\n          return (\r\n            <button\r\n              key={tab.value}\r\n              ref={(el) => { refs.current[i] = el }}\r\n              type=\"button\"\r\n              role=\"tab\"\r\n              aria-selected={on}\r\n              tabIndex={on ? 0 : -1}\r\n              onClick={() => select(tab.value)}\r\n              className={cn(tabBase, sizeTab[size], \"rounded-md\", on ? \"text-foreground\" : \"text-muted-foreground hover:text-foreground\")}\r\n            >\r\n              {on && (\r\n                <motion.span\r\n                  layoutId={`${id}-segment`}\r\n                  transition={transition}\r\n                  className=\"absolute inset-0 -z-10 rounded-md border border-border bg-background shadow-sm\"\r\n                />\r\n              )}\r\n              {tab.label}\r\n            </button>\r\n          )\r\n        })}\r\n      </div>\r\n    </div>\r\n  )\r\n}\r\n\r\n/* Boxed: klasor/kutulu sekmeler, aktif sekme icerik kenarina baglanir. */\r\nexport function BoxedTabs({ className, size = \"md\", ...rest }: TabsProps) {\r\n  const { list, active, select, refs, onKeyDown } = useTabsState(rest, DEFAULT_TABS)\r\n  const id = React.useId()\r\n  const transition = useSlide()\r\n  return (\r\n    <div\r\n      data-slot=\"styled-tabs-viewport\"\r\n      className=\"-m-1 flex max-w-full overflow-x-auto p-1 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden\"\r\n    >\r\n      <div\r\n        data-slot=\"styled-tabs\"\r\n        role=\"tablist\"\r\n        onKeyDown={onKeyDown}\r\n        className={cn(\"inline-flex items-end gap-1 border-b border-border\", className)}\r\n      >\r\n        {list.map((tab, i) => {\r\n          const on = tab.value === active\r\n          return (\r\n            <button\r\n              key={tab.value}\r\n              ref={(el) => { refs.current[i] = el }}\r\n              type=\"button\"\r\n              role=\"tab\"\r\n              aria-selected={on}\r\n              tabIndex={on ? 0 : -1}\r\n              onClick={() => select(tab.value)}\r\n              className={cn(tabBase, sizeTab[size], \"-mb-px rounded-t-md\", on ? \"text-foreground\" : \"text-muted-foreground hover:text-foreground\")}\r\n            >\r\n              {on && (\r\n                <motion.span\r\n                  layoutId={`${id}-box`}\r\n                  transition={transition}\r\n                  className=\"absolute inset-x-0 top-0 bottom-[-1px] -z-10 rounded-t-md border border-border border-b-0 bg-background\"\r\n                />\r\n              )}\r\n              {tab.label}\r\n            </button>\r\n          )\r\n        })}\r\n      </div>\r\n    </div>\r\n  )\r\n}\r\n\r\n/* Icon: ikon + etiket sekmeler, token aktif gostergesi (soft dolgu). */\r\nexport function IconTabs({ className, size = \"md\", ...rest }: TabsProps) {\r\n  const { list, active, select, refs, onKeyDown } = useTabsState(rest, ICON_TABS)\r\n  const id = React.useId()\r\n  const transition = useSlide()\r\n  return (\r\n    <div\r\n      data-slot=\"styled-tabs-viewport\"\r\n      className=\"-m-1 flex max-w-full overflow-x-auto p-1 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden\"\r\n    >\r\n      <div\r\n        data-slot=\"styled-tabs\"\r\n        role=\"tablist\"\r\n        onKeyDown={onKeyDown}\r\n        className={cn(\"inline-flex items-center gap-1\", className)}\r\n      >\r\n        {list.map((tab, i) => {\r\n          const on = tab.value === active\r\n          return (\r\n            <button\r\n              key={tab.value}\r\n              ref={(el) => { refs.current[i] = el }}\r\n              type=\"button\"\r\n              role=\"tab\"\r\n              aria-selected={on}\r\n              tabIndex={on ? 0 : -1}\r\n              onClick={() => select(tab.value)}\r\n              className={cn(tabBase, sizeTab[size], \"rounded-md\", on ? \"text-primary\" : \"text-muted-foreground hover:text-foreground\")}\r\n            >\r\n              {on && (\r\n                <motion.span\r\n                  layoutId={`${id}-icon`}\r\n                  transition={transition}\r\n                  className=\"absolute inset-0 -z-10 rounded-md bg-primary/10\"\r\n                />\r\n              )}\r\n              {tab.label}\r\n            </button>\r\n          )\r\n        })}\r\n      </div>\r\n    </div>\r\n  )\r\n}\r\n",
      "type": "registry:component",
      "target": "components/ui/tabs-styled.tsx"
    }
  ],
  "categories": [
    "styled",
    "tabs"
  ],
  "type": "registry:component"
}