import { observer } from "mobx-react"; import * as React from "react"; import styled from "styled-components"; import { hideScrollbars } from "@shared/styles"; import useWindowSize from "~/hooks/useWindowSize"; type Props = React.HTMLAttributes & { shadow?: boolean; topShadow?: boolean; bottomShadow?: boolean; hiddenScrollbars?: boolean; flex?: boolean; children: React.ReactNode; }; function Scrollable( { shadow, topShadow, bottomShadow, hiddenScrollbars, flex, ...rest }: Props, ref: React.RefObject ) { const fallbackRef = React.useRef(); const [topShadowVisible, setTopShadow] = React.useState(false); const [bottomShadowVisible, setBottomShadow] = React.useState(false); const { height } = useWindowSize(); const updateShadows = React.useCallback(() => { const c = (ref || fallbackRef).current; if (!c) { return; } const scrollTop = c.scrollTop; const tsv = !!((shadow || topShadow) && scrollTop > 0); if (tsv !== topShadowVisible) { setTopShadow(tsv); } const wrapperHeight = c.scrollHeight - c.clientHeight; const bsv = !!((shadow || bottomShadow) && wrapperHeight - scrollTop !== 0); if (bsv !== bottomShadowVisible) { setBottomShadow(bsv); } }, [ shadow, topShadow, bottomShadow, ref, topShadowVisible, bottomShadowVisible, ]); React.useEffect(() => { updateShadows(); }, [height, updateShadows]); return ( ); } const Wrapper = styled.div<{ $flex?: boolean; $topShadowVisible?: boolean; $bottomShadowVisible?: boolean; $hiddenScrollbars?: boolean; }>` display: ${(props) => (props.$flex ? "flex" : "block")}; flex-direction: column; height: 100%; overflow-y: auto; overflow-x: hidden; overscroll-behavior: none; -webkit-overflow-scrolling: touch; box-shadow: ${(props) => { if (props.$topShadowVisible && props.$bottomShadowVisible) { return "0 1px inset rgba(0,0,0,.1), 0 -1px inset rgba(0,0,0,.1)"; } if (props.$topShadowVisible) { return "0 1px inset rgba(0,0,0,.1)"; } if (props.$bottomShadowVisible) { return "0 -1px inset rgba(0,0,0,.1)"; } return "none"; }}; transition: box-shadow 100ms ease-in-out; ${(props) => props.$hiddenScrollbars && hideScrollbars()} `; export default observer(React.forwardRef(Scrollable));