import { forwardRef, Ref, useEffect, useRef, useState } from 'react'; import type { ScrollAreaProps as MantineScrollAreaProps } from '@mantine/core'; import { ScrollArea as MantineScrollArea } from '@mantine/core'; import { useMergedRef, useTimeout } from '@mantine/hooks'; import { motion, useScroll } from 'framer-motion'; import styled from 'styled-components'; import { PageHeader, PageHeaderProps } from '/@/renderer/components/page-header'; interface ScrollAreaProps extends MantineScrollAreaProps { children: React.ReactNode; } const StyledScrollArea = styled(MantineScrollArea)` & .mantine-ScrollArea-thumb { background: var(--scrollbar-thumb-bg); border-radius: 0; } & .mantine-ScrollArea-scrollbar { padding: 0; background: var(--scrollbar-track-bg); } & .mantine-ScrollArea-viewport > div { display: block !important; } `; const StyledNativeScrollArea = styled.div<{ scrollBarOffset?: string }>` height: 100%; overflow-y: overlay !important; &::-webkit-scrollbar-track { margin-top: ${(props) => props.scrollBarOffset || '35px'}; } &::-webkit-scrollbar-thumb { margin-top: ${(props) => props.scrollBarOffset || '35px'}; } `; export const ScrollArea = forwardRef(({ children, ...props }: ScrollAreaProps, ref: Ref) => { return ( {children} ); }); interface NativeScrollAreaProps { children: React.ReactNode; debugScrollPosition?: boolean; pageHeaderProps?: PageHeaderProps & { offset?: any; target?: any }; scrollBarOffset?: string; } export const NativeScrollArea = forwardRef( ( { children, pageHeaderProps, debugScrollPosition, scrollBarOffset, ...props }: NativeScrollAreaProps, ref: Ref, ) => { const [hideScrollbar, setHideScrollbar] = useState(false); const [hideHeader, setHideHeader] = useState(true); const { start, clear } = useTimeout(() => setHideScrollbar(true), 1000); const containerRef = useRef(null); const mergedRef = useMergedRef(ref, containerRef); const { scrollYProgress } = useScroll({ container: containerRef, offset: pageHeaderProps?.offset || ['center start', 'end start'], target: pageHeaderProps?.target, }); // Automatically hide the scrollbar after the timeout duration useEffect(() => { start(); // eslint-disable-next-line react-hooks/exhaustive-deps }, []); useEffect(() => { const setHeaderVisibility = (v: number) => { if (v === 1) { return setHideHeader(false); } if (hideHeader === false) { return setHideHeader(true); } return undefined; }; const unsubscribe = scrollYProgress.on('change', setHeaderVisibility); return () => { unsubscribe(); }; }, [hideHeader, scrollYProgress]); return ( <> { setHideScrollbar(false); clear(); }} onMouseLeave={() => { start(); }} {...props} > {children} {debugScrollPosition && ( )} ); }, );