chore: Move to Typescript (#2783)
This PR moves the entire project to Typescript. Due to the ~1000 ignores this will lead to a messy codebase for a while, but the churn is worth it – all of those ignore comments are places that were never type-safe previously. closes #1282
This commit is contained in:
92
app/components/Scrollable.tsx
Normal file
92
app/components/Scrollable.tsx
Normal file
@@ -0,0 +1,92 @@
|
||||
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;
|
||||
children: React.ReactNode;
|
||||
};
|
||||
|
||||
function Scrollable(
|
||||
{ shadow, topShadow, bottomShadow, flex, ...rest }: Props,
|
||||
ref: React.RefObject<HTMLDivElement>
|
||||
) {
|
||||
const fallbackRef = React.useRef<HTMLDivElement>();
|
||||
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 (
|
||||
<Wrapper
|
||||
ref={ref || fallbackRef}
|
||||
onScroll={updateShadows}
|
||||
$flex={flex}
|
||||
$topShadowVisible={topShadowVisible}
|
||||
$bottomShadowVisible={bottomShadowVisible}
|
||||
{...rest}
|
||||
/>
|
||||
);
|
||||
}
|
||||
|
||||
const Wrapper = styled.div<{
|
||||
$flex?: boolean;
|
||||
$topShadowVisible?: boolean;
|
||||
$bottomShadowVisible?: 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: all 100ms ease-in-out;
|
||||
`;
|
||||
|
||||
export default observer(React.forwardRef(Scrollable));
|
||||
Reference in New Issue
Block a user