DocSpace-client/packages/components/scrollbar/index.js

245 lines
5.6 KiB
JavaScript

import React, { useEffect, useRef, useState } from "react";
import PropTypes from "prop-types";
import { classNames } from "../utils/classNames";
import { isMobile } from "@docspace/components/utils/device";
import StyledScrollbar from "./styled-scrollbar";
import { useTheme } from "styled-components";
const scrollbarTypes = {
smallWhite: {
thumbV: {
width: "2px",
marginLeft: "2px",
borderRadius: "inherit",
},
thumbH: {
height: "2px",
marginTop: "2px",
borderRadius: "inherit",
},
trackV: {
width: "2px",
background: "transparent",
},
trackH: {
height: "2px",
background: "transparent",
},
content: { outline: "none", WebkitOverflowScrolling: "auto" },
},
smallBlack: {
thumbV: {
width: "3px",
marginLeft: "2px",
borderRadius: "inherit",
},
thumbH: {
height: "3px",
marginTop: "2px",
borderRadius: "inherit",
},
trackV: {
width: "3px",
background: "transparent",
},
trackH: {
height: "3px",
background: "transparent",
},
content: { outline: "none", WebkitOverflowScrolling: "auto" },
},
mediumBlack: {
thumbV: {
width: "8px",
borderRadius: "inherit",
},
thumbH: {
height: "8px",
borderRadius: "inherit",
},
trackV: {
width: "8px",
background: "transparent",
},
trackH: {
height: "8px",
background: "transparent",
},
content: {
outline: "none",
WebkitOverflowScrolling: "auto",
},
},
preMediumBlack: {
thumbV: {
width: "5px",
borderRadius: "inherit",
cursor: "default",
},
thumbH: {
height: "5px",
borderRadius: "inherit",
cursor: "default",
},
trackV: {
width: "5px",
background: "transparent",
},
trackH: {
height: "5px",
background: "transparent",
},
content: { outline: "none", WebkitOverflowScrolling: "auto" },
},
};
const Scrollbar = React.forwardRef((props, ref) => {
const {
id,
onScroll,
autoHide,
hideTrackTimer,
scrollclass,
stype,
...rest
} = props;
const { interfaceDirection } = useTheme();
const [isScrolling, setIsScrolling] = useState();
const [isMouseOver, setIsMouseOver] = useState();
const timerId = useRef();
const isRtl = interfaceDirection === "rtl";
const scrollbarType = scrollbarTypes[stype] ?? {};
const showTrack = () => {
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) => {
const { elementRef, ...restLibProps } = libProps;
return (
<div
{...restLibProps}
className={classNames("scroller", scrollclass)}
ref={elementRef}
onScroll={onScroll}
/>
);
};
useEffect(() => {
return () => clearTimeout(timerId.current);
}, []);
return (
<StyledScrollbar
{...rest}
id={id}
disableTracksWidthCompensation
rtl={isRtl}
ref={ref}
{...scrollAutoHideHandlers}
onScrollStart={onScrollStart}
wrapperProps={{ className: "scroll-wrapper" }}
scrollerProps={{ renderer: renderScroller }}
contentProps={{
tabIndex: -1,
className: "scroll-body",
style: {
...scrollbarType.content,
paddingRight: !isRtl && (isMobile() ? "8px" : "17px"),
paddingLeft: isRtl && (isMobile() ? "8px" : "17px"),
},
}}
thumbYProps={{
className: "nav-thumb-vertical",
style: scrollbarType.thumbV,
}}
thumbXProps={{
className: "nav-thumb-horizontal",
style: scrollbarType.thumbH,
}}
// Add 1px margin to vertical track to avoid scrollbar lib crashing when event.clientX equals 0
trackYProps={{
style: {
...scrollbarType.trackV,
...tracksAutoHideStyles,
marginLeft: isRtl ? "1px" : "0",
marginRight: isRtl ? "0" : "1px",
},
...tracksAutoHideHandlers,
}}
trackXProps={{
style: {
...scrollbarType.trackH,
...tracksAutoHideStyles,
direction: "ltr",
},
...tracksAutoHideHandlers,
}}
/>
);
});
Scrollbar.propTypes = {
/** Scrollbar style type */
stype: PropTypes.string,
/** Accepts class */
className: PropTypes.string,
/** Accepts id */
id: PropTypes.string,
/** Accepts css style */
style: PropTypes.oneOfType([PropTypes.object, PropTypes.array]),
/** Enable tracks auto hiding. */
autoHide: PropTypes.bool,
/** Track auto hiding delay in ms. */
hideTrackTimer: PropTypes.number,
};
Scrollbar.defaultProps = {
stype: "mediumBlack",
autoHide: false,
hideTrackTimer: 500,
};
export default Scrollbar;