web new component scrollbar

This commit is contained in:
MrSubhonbek 2023-06-21 16:43:28 +03:00
parent 160ed8748f
commit 3eb0cc6dbf
3 changed files with 244 additions and 9 deletions

View File

@ -0,0 +1,159 @@
import React, { useState, useEffect, useRef, useCallback } from "react";
import "./style.css";
const Scrollbar = ({ children, className, ...props }) => {
const contentRef = useRef(null);
const scrollTrackRef = useRef(null);
const scrollThumbRef = useRef(null);
const observer = useRef(null);
const [thumbHeight, setThumbHeight] = useState(20);
const [scrollStartPosition, setScrollStartPosition] = useState(null);
const [initialScrollTop, setInitialScrollTop] = useState(0);
const [isDragging, setIsDragging] = useState(false);
function handleResize(ref, trackSize) {
const { clientHeight, scrollHeight } = ref;
setThumbHeight(Math.max((clientHeight / scrollHeight) * trackSize, 20));
}
const handleTrackClick = useCallback(
(e) => {
e.preventDefault();
e.stopPropagation();
const { current: trackCurrent } = scrollTrackRef;
const { current: contentCurrent } = contentRef;
if (trackCurrent && contentCurrent) {
const { clientY } = e;
const target = e.target;
const rect = target.getBoundingClientRect();
const trackTop = rect.top;
const thumbOffset = -(thumbHeight / 2);
const clickRatio =
(clientY - trackTop + thumbOffset) / trackCurrent.clientHeight;
const scrollAmount = Math.floor(
clickRatio * contentCurrent.scrollHeight
);
contentCurrent.scrollTo({
top: scrollAmount,
behavior: "smooth",
});
}
},
[thumbHeight]
);
const handleThumbPosition = useCallback(() => {
if (
!contentRef.current ||
!scrollTrackRef.current ||
!scrollThumbRef.current
) {
return;
}
const { scrollTop: contentTop, scrollHeight: contentHeight } =
contentRef.current;
const { clientHeight: trackHeight } = scrollTrackRef.current;
let newTop = (+contentTop / +contentHeight) * trackHeight;
newTop = Math.min(newTop, trackHeight - thumbHeight);
const thumb = scrollThumbRef.current;
thumb.style.top = `${newTop}px`;
}, []);
const handleThumbMousedown = useCallback((e) => {
e.preventDefault();
e.stopPropagation();
setScrollStartPosition(e.clientY);
if (contentRef.current) setInitialScrollTop(contentRef.current.scrollTop);
setIsDragging(true);
}, []);
const handleThumbMouseup = useCallback(
(e) => {
e.preventDefault();
e.stopPropagation();
if (isDragging) {
setIsDragging(false);
}
},
[isDragging]
);
const handleThumbMousemove = useCallback(
(e) => {
e.preventDefault();
e.stopPropagation();
if (isDragging) {
const {
scrollHeight: contentScrollHeight,
offsetHeight: contentOffsetHeight,
} = contentRef.current;
const deltaY =
(e.clientY - scrollStartPosition) *
(contentOffsetHeight / thumbHeight);
const newScrollTop = Math.min(
initialScrollTop + deltaY,
contentScrollHeight - contentOffsetHeight
);
contentRef.current.scrollTop = newScrollTop;
}
},
[isDragging, scrollStartPosition, thumbHeight]
);
useEffect(() => {
if (contentRef.current && scrollTrackRef.current) {
const ref = contentRef.current;
const { clientHeight: trackSize } = scrollTrackRef.current;
observer.current = new ResizeObserver(() => {
handleResize(ref, trackSize);
});
observer.current.observe(ref);
ref.addEventListener("scroll", handleThumbPosition);
return () => {
observer.current?.unobserve(ref);
ref.removeEventListener("scroll", handleThumbPosition);
};
}
}, []);
useEffect(() => {
document.addEventListener("mousemove", handleThumbMousemove);
document.addEventListener("mouseup", handleThumbMouseup);
document.addEventListener("mouseleave", handleThumbMouseup);
return () => {
document.removeEventListener("mousemove", handleThumbMousemove);
document.removeEventListener("mouseup", handleThumbMouseup);
document.removeEventListener("mouseleave", handleThumbMouseup);
};
}, [handleThumbMousemove, handleThumbMouseup]);
return (
<div className="custom-scrollbars__container">
<div className="custom-scrollbars__content" ref={contentRef} {...props}>
{children}
</div>
<div className="custom-scrollbars__scrollbar">
<div></div>
<div className="custom-scrollbars__track-and-thumb">
<div
className="custom-scrollbars__track"
ref={scrollTrackRef}
onClick={handleTrackClick}
></div>
<div
className="custom-scrollbars__thumb"
ref={scrollThumbRef}
onMouseDown={handleThumbMousedown}
style={{
height: `${thumbHeight}px`,
}}
></div>
</div>
<div></div>
</div>
</div>
);
};
export default Scrollbar;

View File

@ -5,6 +5,7 @@ import { useTheme } from "styled-components";
import { isMobile } from "@docspace/components/utils/device";
import StyledScrollbar from "./styled-scrollbar";
import { classNames } from "../utils/classNames";
import Scrollbar2 from "./customScrollbar";
const Scrollbar = React.forwardRef((props, ref) => {
const scrollbarType = {
@ -98,7 +99,7 @@ const Scrollbar = React.forwardRef((props, ref) => {
style={{
...style,
...view,
margin: isRtl ? "0 -15px -15px -15px" : "0 -15px -15px 0",
margin: isRtl ? "0 0 -15px -15px" : "0 -15px -15px 0",
}}
tabIndex={-1}
className={classNames("scroll-body", props.scrollclass)}
@ -120,14 +121,33 @@ const Scrollbar = React.forwardRef((props, ref) => {
);
};
return (
<StyledScrollbar
renderView={renderView}
renderThumbVertical={renderNavThumbVertical}
renderThumbHorizontal={renderNavThumbHorizontal}
renderTrackVertical={renderTrackNavVertical}
{...props}
ref={ref}
/>
<>
<Scrollbar2>
================================================================ Lorem
ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor
incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam,
quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit
esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat
cupidatat non proident, sunt in culpa qui officia deserunt mollit anim
id est laborum. Lorem ipsum dolor sit amet, consectetur adipiscing elit,
sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut
enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut
aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit
in voluptate velit esse cillum dolore eu fugiat nulla pariatur.
Excepteur sint occaecat cupidatat non proident, sunt in culpa qui
officia deserunt mollit anim id est laborum.
================================================================
</Scrollbar2>
<StyledScrollbar
renderView={renderView}
renderThumbVertical={renderNavThumbVertical}
renderThumbHorizontal={renderNavThumbHorizontal}
renderTrackVertical={renderTrackNavVertical}
{...props}
ref={ref}
/>
</>
);
});

View File

@ -0,0 +1,56 @@
.custom-scrollbars__container {
background-color: white;
display: grid;
height: 100%;
width: 300px;
grid-template: auto / 1fr 24px;
gap: 1rem;
overflow: hidden;
position: relative;
}
.custom-scrollbars__content {
height: 300px;
max-width: 300px;
-ms-overflow-style: none;
overflow: auto;
scrollbar-width: none;
}
.custom-scrollbars__content::-webkit-scrollbar {
display: none;
}
.custom-scrollbars__scrollbar {
display: grid;
gap: 1rem;
grid-auto-flow: row;
grid-template: auto 1fr auto / 1fr;
padding: 1rem;
place-items: center;
}
.custom-scrollbars__track-and-thumb {
display: block;
height: 100%;
position: relative;
width: 7px;
}
.custom-scrollbars__track {
background-color: #ccc;
border-radius: 12px;
bottom: 0;
cursor: pointer;
position: absolute;
top: 0;
width: 7px;
}
.custom-scrollbars__thumb {
border-radius: 12px;
background-color: #333;
position: absolute;
width: 7px;
}