import { FloatingIndicator, UnstyledButton, Box, Text, ScrollArea } from "@mantine/core"; import { Carousel } from "@mantine/carousel"; import { useState, useEffect, ReactNode } from "react"; interface TabItem { label: string; content: ReactNode; } interface SwipeableTabsProps { tabs: TabItem[]; defaultTab?: number; onTabChange?: (index: number, tab: TabItem) => void; } function SwipeableTabs({ tabs, defaultTab = 0, onTabChange }: SwipeableTabsProps) { const [activeTab, setActiveTab] = useState(defaultTab); const [embla, setEmbla] = useState(null); const [rootRef, setRootRef] = useState(null); const [controlsRefs, setControlsRefs] = useState>({}); useEffect(() => { if (!embla) return; const onSelect = () => { const newIndex = embla.selectedScrollSnap(); setActiveTab(newIndex); }; embla.on("select", onSelect); return () => { embla.off("select", onSelect); }; }, [embla]); const handleTabChange = (index: number) => { if (index !== activeTab && index >= 0 && index < tabs.length) { setActiveTab(index); embla?.scrollTo(index); onTabChange?.(index, tabs[index]); } }; const setControlRef = (index: number) => (node: HTMLSpanElement | null) => { controlsRefs[index] = node; setControlsRefs(controlsRefs); }; return ( {tabs.map((tab, index) => ( handleTabChange(index)} style={{ flex: 1, padding: 'var(--mantine-spacing-sm) var(--mantine-spacing-md)', textAlign: 'center', color: activeTab === index ? 'var(--mantine-color-blue-6)' : 'var(--mantine-color-text)', fontWeight: activeTab === index ? 600 : 400, transition: 'color 200ms ease, font-weight 200ms ease', backgroundColor: 'transparent', border: 'none', borderRadius: 0, }} > {tab.label} ))} {tabs.map((tab, index) => ( {tab.content} ))} ); } export default SwipeableTabs;