// @flow import { observer } from "mobx-react"; import * as React from "react"; import styled from "styled-components"; import useWindowSize from "hooks/useWindowSize"; type Props = {| shadow?: boolean, topShadow?: boolean, bottomShadow?: boolean, flex?: boolean, |}; function Scrollable( { shadow, topShadow, bottomShadow, flex, ...rest }: Props, ref: any ) { 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` 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: all 100ms ease-in-out; `; export default observer(React.forwardRef(Scrollable));