PromucFlow_constructor/app/client/src/components/ads/ScrollIndicator.tsx
2021-05-13 14:05:39 +05:30

139 lines
3.4 KiB
TypeScript

import React, { useEffect, useState, useRef } from "react";
import styled from "styled-components";
import _ from "lodash";
import { animated } from "react-spring";
import { useSpring, interpolate } from "react-spring";
export const ScrollThumb = styled(animated.div)<{
mode?: "DARK" | "LIGHT";
}>`
position: relative;
width: 4px;
transform: translate3d(0, 0, 0);
background-color: ${(props) =>
props.mode
? props.mode === "LIGHT"
? props.theme.colors.scrollbarLight
: props.theme.colors.scrollbarDark
: props.theme.colors.scrollbarLight};
border-radius: ${(props) => props.theme.radii[3]}px;
`;
const ScrollTrack = styled.div<{
isVisible: boolean;
top?: string;
bottom?: string;
right?: string;
mode?: "DARK" | "LIGHT";
}>`
position: absolute;
z-index: 100;
overflow: hidden;
transition: opacity 0.15s ease-in;
top: ${(props) => (props.top ? props.top : "0px")};
bottom: ${(props) => (props.bottom ? props.bottom : "0px")};
right: ${(props) => (props.right ? props.right : "2px")};
opacity: ${(props) => (props.isVisible ? 1 : 0)};
box-shadow: inset 0 0 6px
${(props) =>
props.mode
? props.mode === "LIGHT"
? props.theme.colors.scrollbarLightBG
: props.theme.colors.scrollbarDarkBG
: props.theme.colors.scrollbarLightBG};
width: 4px;
`;
interface Props {
containerRef: React.RefObject<HTMLElement>;
top?: string;
bottom?: string;
right?: string;
alwaysShowScrollbar?: boolean;
mode?: "DARK" | "LIGHT";
}
function ScrollIndicator({
alwaysShowScrollbar,
bottom,
containerRef,
right,
top,
}: Props) {
const [{ thumbPosition }, setThumbPosition] = useSpring<{
thumbPosition: number;
config: {
clamp: boolean;
friction: number;
precision: number;
tension: number;
};
}>(() => ({
thumbPosition: 0,
config: {
clamp: true,
friction: 10,
precision: 0.1,
tension: 800,
},
}));
const [isScrollVisible, setIsScrollVisible] = useState(
alwaysShowScrollbar || false,
);
const thumbRef = useRef<HTMLDivElement>(null);
useEffect(() => {
const handleContainerScroll = (e: any): void => {
setIsScrollVisible(true);
const thumbHeight =
e.target.offsetHeight / (e.target.scrollHeight / e.target.offsetHeight);
const thumbPosition = (e.target.scrollTop / e.target.offsetHeight) * 100;
/* set scroll thumb height */
if (thumbRef.current) {
thumbRef.current.style.height = thumbHeight + "px";
}
setThumbPosition({
thumbPosition,
});
};
containerRef.current?.addEventListener("scroll", handleContainerScroll);
return () => {
containerRef.current?.removeEventListener(
"scroll",
handleContainerScroll,
);
};
}, []);
useEffect(() => {
if (isScrollVisible) {
hideScrollbar();
}
}, [isScrollVisible]);
const hideScrollbar = _.debounce(() => {
setIsScrollVisible(alwaysShowScrollbar || false);
}, 1500);
return (
<ScrollTrack
bottom={bottom}
isVisible={isScrollVisible}
right={right}
top={top}
>
<ScrollThumb
ref={thumbRef}
style={{
transform: interpolate(
[thumbPosition],
(top: number) => `translate3d(0px, ${top}%, 0)`,
),
}}
/>
</ScrollTrack>
);
}
export default ScrollIndicator;