{
  "$schema": "https://ui.shadcn.com/schema/registry-item.json",
  "name": "tabs",
  "title": "Tabs",
  "description": "Tabs and a floating tab bar with a lens you can drag.",
  "dependencies": [
    "@base-ui/react@^1.8.0"
  ],
  "registryDependencies": [
    "https://liquikit.dev/r/core.json",
    "https://liquikit.dev/r/glass.json",
    "https://liquikit.dev/r/segments.json"
  ],
  "files": [
    {
      "path": "src/tabs.tsx",
      "content": "\"use client\";\n\nimport { Tabs as BaseTabs } from \"@base-ui/react/tabs\";\nimport {\n\ttype CSSProperties,\n\tcreateContext,\n\ttype ReactNode,\n\tuseCallback,\n\tuseContext,\n\tuseEffect,\n\tuseLayoutEffect,\n\tuseMemo,\n\tuseRef,\n\tuseState,\n} from \"react\";\nimport {\n\tGlassPane,\n\ttype GlassRefraction,\n\tGlassSegmentedSurface,\n\ttype LensProfile,\n\ttype UseGlassSegmentedResult,\n} from \"./glass\";\nimport { indicesOf, Name, over } from \"./segments\";\nimport { cx, type GlassOptions, type Segment, toSegment } from \"./types\";\nimport \"./liquikit.css\";\n\nconst ActiveTab = createContext<{\n\tvalue: string | undefined;\n\tadopt: (value: string) => void;\n\tselect: (value: string) => void;\n} | null>(null);\n\nfunction useActiveTab() {\n\tconst context = useContext(ActiveTab);\n\tif (!context) throw new Error(\"Tabs.List must be inside Tabs.Root.\");\n\treturn context;\n}\n\nexport type TabsRootProps = Omit<\n\tBaseTabs.Root.Props,\n\t\"value\" | \"defaultValue\" | \"onValueChange\" | \"className\" | \"orientation\"\n> & {\n\tvalue?: string;\n\tdefaultValue?: string;\n\tonValueChange?: (\n\t\tvalue: string,\n\t\teventDetails?: BaseTabs.Root.ChangeEventDetails,\n\t) => void;\n\tclassName?: string;\n};\n\nfunction Root({\n\tvalue,\n\tdefaultValue,\n\tonValueChange,\n\tclassName,\n\t...rootProps\n}: TabsRootProps) {\n\tconst [uncontrolled, setUncontrolled] = useState(defaultValue);\n\tconst current = value ?? uncontrolled;\n\tconst controlled = value !== undefined;\n\tconst adopt = useCallback(\n\t\t(first: string) => {\n\t\t\tif (!controlled) setUncontrolled((held) => held ?? first);\n\t\t},\n\t\t[controlled],\n\t);\n\tconst latest = useRef({ current, onValueChange });\n\tlatest.current = { current, onValueChange };\n\tconst select = useCallback(\n\t\t(next: string) => {\n\t\t\tif (next === latest.current.current) return;\n\t\t\tif (!controlled) setUncontrolled(next);\n\t\t\tlatest.current.onValueChange?.(next);\n\t\t},\n\t\t[controlled],\n\t);\n\tconst shared = useMemo(\n\t\t() => ({ value: current, adopt, select }),\n\t\t[adopt, current, select],\n\t);\n\n\treturn (\n\t\t<ActiveTab.Provider value={shared}>\n\t\t\t<BaseTabs.Root\n\t\t\t\t{...rootProps}\n\t\t\t\tvalue={current ?? null}\n\t\t\t\tonValueChange={(next, eventDetails) => {\n\t\t\t\t\tconst chosen = String(next);\n\t\t\t\t\tif (value === undefined) setUncontrolled(chosen);\n\t\t\t\t\tonValueChange?.(chosen, eventDetails);\n\t\t\t\t}}\n\t\t\t\tclassName={cx(\"glass-ui-tabs\", className)}\n\t\t\t/>\n\t\t</ActiveTab.Provider>\n\t);\n}\n\nexport type TabsListProps = Omit<\n\tBaseTabs.List.Props,\n\t\"children\" | \"render\" | \"className\" | \"style\"\n> &\n\tGlassOptions & {\n\t\ttabs: ReadonlyArray<string | Segment>;\n\t\theight?: number;\n\t\tclassName?: string;\n\t\tstyle?: CSSProperties;\n\t};\n\nfunction TabRow({\n\tsegments,\n\theight,\n\tinset,\n\tpressScale,\n\ttheme,\n\tlens,\n\tliquid,\n\tclassName,\n}: GlassOptions & {\n\tsegments: Segment[];\n\theight?: number;\n\tinset?: number;\n\tpressScale?: number;\n\tclassName?: string;\n}) {\n\tconst { value, adopt, select } = useActiveTab();\n\tconst controls = useRef<UseGlassSegmentedResult>(null);\n\tconst first = segments[0]?.value;\n\n\tuseLayoutEffect(() => {\n\t\tif (value === undefined && first !== undefined) adopt(first);\n\t}, [adopt, first, value]);\n\n\tconst shown = useRef(value);\n\tuseEffect(() => {\n\t\tif (shown.current !== undefined && value !== shown.current) {\n\t\t\tcontrols.current?.flash();\n\t\t}\n\t\tshown.current = value;\n\t}, [value]);\n\n\treturn (\n\t\t<GlassSegmentedSurface\n\t\t\tclassName={className}\n\t\t\toptions={segments}\n\t\t\tselected={indicesOf(segments, [value ?? first])}\n\t\t\theight={height}\n\t\t\tinset={inset}\n\t\t\tpressScale={pressScale}\n\t\t\tlens={lens}\n\t\t\ttheme={theme}\n\t\t\tliquid={liquid}\n\t\t\tonDragSelect={(index) => {\n\t\t\t\tconst segment = segments[index];\n\t\t\t\tif (segment && !segment.disabled) select(segment.value);\n\t\t\t}}\n\t\t\tcontrolsRef={controls}\n\t\t\titems={(bounds) =>\n\t\t\t\tsegments.map((segment, index) => (\n\t\t\t\t\t<BaseTabs.Tab\n\t\t\t\t\t\tkey={segment.value}\n\t\t\t\t\t\tvalue={segment.value}\n\t\t\t\t\t\tdisabled={segment.disabled}\n\t\t\t\t\t\tclassName=\"glass-segmented__hit glass-ui-item\"\n\t\t\t\t\t\tstyle={over(bounds, index)}\n\t\t\t\t\t>\n\t\t\t\t\t\t<Name segment={segment} />\n\t\t\t\t\t</BaseTabs.Tab>\n\t\t\t\t))\n\t\t\t}\n\t\t/>\n\t);\n}\n\nconst LIST_PRESS_SCALE = 1.8;\n\nfunction List({\n\ttabs,\n\theight,\n\ttheme,\n\tlens,\n\tliquid,\n\tclassName,\n\tstyle,\n\t...listProps\n}: TabsListProps) {\n\treturn (\n\t\t<BaseTabs.List\n\t\t\t{...listProps}\n\t\t\tclassName={cx(\"glass-ui-segmented\", className)}\n\t\t\tstyle={style}\n\t\t>\n\t\t\t<TabRow\n\t\t\t\tsegments={tabs.map(toSegment)}\n\t\t\t\theight={height}\n\t\t\t\tpressScale={LIST_PRESS_SCALE}\n\t\t\t\ttheme={theme}\n\t\t\t\tlens={lens}\n\t\t\t\tliquid={liquid}\n\t\t\t/>\n\t\t</BaseTabs.List>\n\t);\n}\n\nexport type TabBarItem = {\n\tvalue: string;\n\tlabel: string;\n\ticon: ReactNode;\n\tdisabled?: boolean;\n};\n\nexport type TabsBarProps = Omit<TabsListProps, \"tabs\"> & {\n\ttabs: ReadonlyArray<TabBarItem>;\n\trefraction?: GlassRefraction;\n};\n\nconst BAR_LENS: Partial<LensProfile> = {\n\trestEdgeShadow: \"none\",\n\tmagnification: 1.12,\n\tdomeLength: 0,\n\tsoftness: 0.3,\n\tbase: 8,\n};\n\nconst BAR_PRESS_SCALE = 1.55;\n\nfunction Bar({\n\ttabs,\n\theight = 50,\n\ttheme,\n\tlens = BAR_LENS,\n\tliquid,\n\trefraction,\n\tclassName,\n\tstyle,\n\t...listProps\n}: TabsBarProps) {\n\tconst segments = tabs.map<Segment>((tab) => ({\n\t\tvalue: tab.value,\n\t\tdisabled: tab.disabled,\n\t\tlabel: (\n\t\t\t<span className=\"glass-ui-tabbar__item\">\n\t\t\t\t<span className=\"glass-ui-tabbar__icon\" aria-hidden=\"true\">\n\t\t\t\t\t{tab.icon}\n\t\t\t\t</span>\n\t\t\t\t<span className=\"glass-ui-tabbar__label\">{tab.label}</span>\n\t\t\t</span>\n\t\t),\n\t}));\n\n\treturn (\n\t\t<BaseTabs.List\n\t\t\t{...listProps}\n\t\t\tclassName={cx(\"glass-ui-tabbar\", className)}\n\t\t\tstyle={style}\n\t\t>\n\t\t\t<GlassPane radius=\"capsule\" theme={theme} refraction={refraction}>\n\t\t\t\t<div className=\"glass-ui-tabbar__inner\">\n\t\t\t\t\t<TabRow\n\t\t\t\t\t\tclassName=\"glass-ui-tabbar__row\"\n\t\t\t\t\t\tsegments={segments}\n\t\t\t\t\t\theight={height}\n\t\t\t\t\t\tinset={0}\n\t\t\t\t\t\tpressScale={BAR_PRESS_SCALE}\n\t\t\t\t\t\ttheme={theme}\n\t\t\t\t\t\tlens={lens}\n\t\t\t\t\t\tliquid={liquid}\n\t\t\t\t\t/>\n\t\t\t\t</div>\n\t\t\t</GlassPane>\n\t\t</BaseTabs.List>\n\t);\n}\n\nexport type TabsPanelProps = Omit<\n\tBaseTabs.Panel.Props,\n\t\"value\" | \"className\"\n> & {\n\tvalue: string;\n\tclassName?: string;\n};\n\nfunction Panel({ className, ...panelProps }: TabsPanelProps) {\n\treturn (\n\t\t<BaseTabs.Panel\n\t\t\t{...panelProps}\n\t\t\tclassName={cx(\"glass-ui-tabs__panel\", className)}\n\t\t/>\n\t);\n}\n\nexport const Tabs = { Root, List, Bar, Panel };\n\nexport const TabsRoot = Tabs.Root;\nexport const TabsList = Tabs.List;\nexport const TabsBar = Tabs.Bar;\nexport const TabsPanel = Tabs.Panel;\n",
      "type": "registry:ui",
      "target": "@components/liquikit/tabs.tsx"
    }
  ],
  "type": "registry:ui"
}