import { motion } from 'framer-motion' import { useEffect, useRef } from 'react' import { useLocation } from 'react-router-dom' import { clientAnimationTransition } from '@/lib/clientAnimation' import { useClientBehaviourSettings } from '@/lib/useClientBehaviourSettings' import { useVerticalPreview } from '@/lib/useLocale' import { cn } from '@/lib/utils' import type { FC, ReactNode } from 'react' type Props = { children: ReactNode className?: string animateLayout?: boolean verticalContent?: boolean } const MainArea: FC = ( { children, className, animateLayout = true, verticalContent = true }, ) => { const behaviourSettings = useClientBehaviourSettings () const verticalPreview = useVerticalPreview () const horizontal = verticalPreview && verticalContent const { pathname, search } = useLocation () const rootRef = useRef (null) const animationMode = behaviourSettings.animation ?? 'normal' const layoutTransition = clientAnimationTransition ( animationMode, { normal: { duration: .2, ease: 'easeOut' as const } }) useEffect (() => { if (horizontal && rootRef.current != null) rootRef.current.scrollLeft = 0 }, [horizontal, pathname, search]) useEffect (() => { const root = rootRef.current if (!horizontal || root == null) return const handleWheel = (event: WheelEvent) => { if (event.ctrlKey || event.metaKey || event.shiftKey || event.deltaX !== 0 || event.deltaY === 0 || event.defaultPrevented) return // Nested tables, forms and code blocks retain their own scrolling. let node = event.target instanceof HTMLElement ? event.target : null while (node != null && node !== root) { if (node.matches ('input, select, textarea, [contenteditable="true"]')) return const style = getComputedStyle (node) if ((/auto|scroll/.test (style.overflowY) && node.scrollHeight > node.clientHeight) || (/auto|scroll/.test (style.overflowX) && node.scrollWidth > node.clientWidth)) return node = node.parentElement } const unit = event.deltaMode === 1 ? 16 : (event.deltaMode === 2 ? root.clientWidth : 1) const delta = event.deltaY * unit if ((delta < 0 && root.scrollLeft <= 0) || (delta > 0 && root.scrollLeft + root.clientWidth >= root.scrollWidth)) return event.preventDefault () root.scrollLeft += delta } root.addEventListener ('wheel', handleWheel, { passive: false }) return () => root.removeEventListener ('wheel', handleWheel) }, [horizontal]) return ( {children} ) } export default MainArea