"use client" import { cn } from "@/lib/utils" import * as TabsPrimitive from "@radix-ui/react-tabs" import { AnimatePresence, motion } from "framer-motion" import * as React from "react" const TabsContext = React.createContext<{ orientation?: "horizontal" | "vertical" value?: string }>({}) const Tabs = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef & { orientation?: "horizontal" | "vertical" } >(({ className, orientation = "horizontal", ...props }, ref) => { const [currentValue, setCurrentValue] = React.useState(props.defaultValue || props.value) const handleValueChange = (value: string) => { setCurrentValue(value) props.onValueChange?.(value) } return ( ) }) Tabs.displayName = TabsPrimitive.Root.displayName const TabsList = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >(({ className, children, ...props }, ref) => { const { orientation, value } = React.useContext(TabsContext) const containerRef = React.useRef(null) const [activeStyle, setActiveStyle] = React.useState({ left: "0px", top: "0px", width: "0px", height: "0px", }) const updateActiveStyle = React.useCallback(() => { if (!containerRef.current || !value) return const activeTab = containerRef.current.querySelector('[data-state="active"]') as HTMLElement if (!activeTab) return const containerRect = containerRef.current.getBoundingClientRect() const tabRect = activeTab.getBoundingClientRect() if (orientation === "horizontal") { setActiveStyle({ left: `${tabRect.left - containerRect.left}px`, top: "4px", width: `${tabRect.width}px`, height: "calc(100% - 8px)", }) } else { setActiveStyle({ left: "4px", top: `${tabRect.top - containerRect.top}px`, width: "calc(100% - 8px)", height: `${tabRect.height}px`, }) } }, [orientation, value]) React.useEffect(() => { const timeoutId = setTimeout(updateActiveStyle, 0) return () => clearTimeout(timeoutId) }, [updateActiveStyle, value]) React.useEffect(() => { const handleResize = () => { requestAnimationFrame(updateActiveStyle) } window.addEventListener("resize", handleResize) const resizeObserver = new ResizeObserver(() => { requestAnimationFrame(updateActiveStyle) }) if (containerRef.current) { resizeObserver.observe(containerRef.current) } return () => { window.removeEventListener("resize", handleResize) resizeObserver.disconnect() } }, [updateActiveStyle]) React.useEffect(() => { if (!containerRef.current) return const observer = new MutationObserver(() => { requestAnimationFrame(updateActiveStyle) }) observer.observe(containerRef.current, { childList: true, subtree: true, attributes: true, attributeFilter: ["data-state"], }) return () => observer.disconnect() }, [updateActiveStyle]) return ( { if (typeof ref === "function") ref(el) else if (ref) ref.current = el containerRef.current = el }} className={cn( "relative bg-muted py-1 px-1 rounded-[7px] inline-flex items-center justify-center", orientation === "horizontal" ? "flex-row h-9" : "flex-col h-fit w-fit", className, )} {...props} > {/* Animated indicator */} {children} ) }) TabsList.displayName = TabsPrimitive.List.displayName const TabsTrigger = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >(({ className, ...props }, ref) => ( )) TabsTrigger.displayName = TabsPrimitive.Trigger.displayName const TabsContent = React.forwardRef< React.ElementRef, React.ComponentPropsWithoutRef >(({ className, children, ...props }, ref) => { const { orientation } = React.useContext(TabsContext) return ( {children} ) }) TabsContent.displayName = TabsPrimitive.Content.displayName export { Tabs, TabsContent, TabsList, TabsTrigger }