2023-12-05 16:52:30 +00:00
|
|
|
import React, { useEffect, useRef, useState } from "react";
|
2023-07-20 14:53:59 +00:00
|
|
|
import { useTheme } from "styled-components";
|
2023-12-05 16:52:30 +00:00
|
|
|
|
2023-12-14 10:02:52 +00:00
|
|
|
import { classNames } from "../../utils";
|
2023-12-05 16:52:30 +00:00
|
|
|
|
|
|
|
import StyledScrollbar from "./Scrollbar.styled";
|
|
|
|
import { ScrollbarProps } from "./Scrollbar.types";
|
|
|
|
|
|
|
|
const Scrollbar = React.forwardRef((props: ScrollbarProps, ref) => {
|
|
|
|
const {
|
|
|
|
id,
|
|
|
|
onScroll,
|
|
|
|
autoHide,
|
|
|
|
hideTrackTimer,
|
2023-07-26 12:20:33 +00:00
|
|
|
scrollclass,
|
2023-11-23 15:46:31 +00:00
|
|
|
fixedSize,
|
2023-12-05 16:52:30 +00:00
|
|
|
...rest
|
|
|
|
} = props;
|
|
|
|
|
2023-07-28 12:17:56 +00:00
|
|
|
const { interfaceDirection } = useTheme();
|
2023-12-05 16:52:30 +00:00
|
|
|
const [isScrolling, setIsScrolling] = useState(false);
|
|
|
|
const [isMouseOver, setIsMouseOver] = useState(false);
|
2023-12-14 10:02:52 +00:00
|
|
|
const timerId = useRef<null | ReturnType<typeof setTimeout>>();
|
2023-12-05 16:52:30 +00:00
|
|
|
|
|
|
|
const isRtl = interfaceDirection === "rtl";
|
|
|
|
|
|
|
|
const showTrack = () => {
|
|
|
|
if (timerId.current) clearTimeout(timerId.current);
|
|
|
|
|
|
|
|
setIsScrolling(true);
|
|
|
|
};
|
|
|
|
|
|
|
|
const hideTrack = () => {
|
|
|
|
timerId.current = setTimeout(() => {
|
|
|
|
setIsScrolling(false);
|
|
|
|
}, hideTrackTimer);
|
|
|
|
};
|
|
|
|
|
|
|
|
const onScrollStart = () => showTrack();
|
|
|
|
|
|
|
|
const onScrollStop = () => {
|
|
|
|
if (isMouseOver) return;
|
|
|
|
hideTrack();
|
|
|
|
};
|
|
|
|
|
|
|
|
const onMouseEnter = () => {
|
|
|
|
showTrack();
|
|
|
|
|
|
|
|
setIsMouseOver(true);
|
|
|
|
};
|
|
|
|
|
|
|
|
const onMouseLeave = () => {
|
|
|
|
hideTrack();
|
|
|
|
|
|
|
|
setIsMouseOver(false);
|
|
|
|
};
|
|
|
|
|
|
|
|
const scrollAutoHideHandlers = autoHide
|
|
|
|
? { onScrollStart, onScrollStop }
|
|
|
|
: {};
|
|
|
|
const tracksAutoHideHandlers = autoHide ? { onMouseEnter, onMouseLeave } : {};
|
|
|
|
const tracksAutoHideStyles = autoHide
|
|
|
|
? {
|
|
|
|
opacity: !isScrolling ? 0 : 1,
|
|
|
|
transition: "opacity 0.4s ease-in-out",
|
|
|
|
}
|
|
|
|
: {};
|
|
|
|
|
|
|
|
// onScroll handler placed here on Scroller element to get native event instead of parameters that library put
|
|
|
|
const renderScroller = (libProps: {
|
|
|
|
elementRef: React.RefObject<HTMLDivElement>;
|
|
|
|
}) => {
|
|
|
|
const { elementRef, ...restLibProps } = libProps;
|
|
|
|
return (
|
|
|
|
<div
|
|
|
|
{...restLibProps}
|
2023-12-14 10:02:52 +00:00
|
|
|
className={classNames("scroller", scrollclass || "") || "scroller"}
|
2023-12-05 16:52:30 +00:00
|
|
|
ref={elementRef}
|
|
|
|
onScroll={onScroll}
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
};
|
|
|
|
|
|
|
|
useEffect(() => {
|
|
|
|
return () => {
|
|
|
|
if (timerId.current) clearTimeout(timerId.current);
|
|
|
|
};
|
|
|
|
}, []);
|
|
|
|
|
|
|
|
return (
|
|
|
|
<StyledScrollbar
|
|
|
|
{...rest}
|
|
|
|
id={id}
|
|
|
|
data-testid="scrollbar"
|
|
|
|
disableTracksWidthCompensation
|
2023-11-23 15:46:31 +00:00
|
|
|
$fixedSize={fixedSize}
|
2023-12-05 16:52:30 +00:00
|
|
|
rtl={isRtl}
|
|
|
|
ref={ref}
|
|
|
|
{...scrollAutoHideHandlers}
|
|
|
|
onScrollStart={onScrollStart}
|
|
|
|
wrapperProps={{ className: "scroll-wrapper" }}
|
|
|
|
scrollerProps={{ renderer: renderScroller }}
|
2023-11-29 18:47:06 +00:00
|
|
|
contentProps={{ className: "scroll-body" }}
|
|
|
|
thumbYProps={{ className: "thumb thumb-vertical" }}
|
|
|
|
thumbXProps={{ className: "thumb thumb-horizontal" }}
|
2023-12-05 16:52:30 +00:00
|
|
|
trackYProps={{
|
2023-11-23 15:46:31 +00:00
|
|
|
className: "track track-vertical",
|
2023-11-29 18:47:06 +00:00
|
|
|
style: { ...tracksAutoHideStyles },
|
2023-12-05 16:52:30 +00:00
|
|
|
...tracksAutoHideHandlers,
|
|
|
|
}}
|
|
|
|
trackXProps={{
|
2023-11-23 15:46:31 +00:00
|
|
|
className: "track track-horizontal",
|
2023-11-29 18:47:06 +00:00
|
|
|
style: { ...tracksAutoHideStyles },
|
2023-12-05 16:52:30 +00:00
|
|
|
...tracksAutoHideHandlers,
|
|
|
|
}}
|
|
|
|
/>
|
|
|
|
);
|
|
|
|
});
|
|
|
|
|
|
|
|
Scrollbar.displayName = "Scrollbar";
|
|
|
|
|
|
|
|
Scrollbar.defaultProps = {
|
|
|
|
autoHide: false,
|
|
|
|
hideTrackTimer: 500,
|
2023-11-23 15:46:31 +00:00
|
|
|
fixedSize: false,
|
2023-12-05 16:52:30 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
export { Scrollbar };
|