import { useState, useRef } from 'react'; import { useSwipeable } from 'react-swipeable'; import { useIsMobile } from '../hooks/useIsMobile'; import './SwipeableView.css'; export default function SwipeableView({ tabs = [], activeIndex: controlledIndex, onTabChange, showTabs = true, }) { const isMobile = useIsMobile(); const [internalIndex, setInternalIndex] = useState(0); const [swipeOffset, setSwipeOffset] = useState(0); const [isSwiping, setIsSwiping] = useState(false); const trackRef = useRef(null); const activeIndex = controlledIndex !== undefined ? controlledIndex : internalIndex; const setIndex = (idx) => { const clamped = Math.max(0, Math.min(tabs.length - 1, idx)); if (controlledIndex === undefined) setInternalIndex(clamped); onTabChange?.(clamped); }; const handlers = useSwipeable({ onSwiping: ({ deltaX }) => { if (!isMobile) return; setIsSwiping(true); setSwipeOffset(deltaX); }, onSwipedLeft: ({ deltaX }) => { if (!isMobile) return; setIsSwiping(false); setSwipeOffset(0); if (Math.abs(deltaX) > 30) setIndex(activeIndex + 1); }, onSwipedRight: ({ deltaX }) => { if (!isMobile) return; setIsSwiping(false); setSwipeOffset(0); if (Math.abs(deltaX) > 30) setIndex(activeIndex - 1); }, onTouchEndOrOnMouseUp: () => { setIsSwiping(false); setSwipeOffset(0); }, trackMouse: false, trackTouch: true, delta: 30, preventScrollOnSwipe: false, }); const trackTranslate = -activeIndex * 100 + (isSwiping ? (swipeOffset / (trackRef.current?.offsetWidth || 1)) * 100 : 0); return (