web new component scrollbar
This commit is contained in:
parent
160ed8748f
commit
3eb0cc6dbf
159
packages/components/scrollbar/customScrollbar.js
Normal file
159
packages/components/scrollbar/customScrollbar.js
Normal 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;
|
@ -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}
|
||||
/>
|
||||
</>
|
||||
);
|
||||
});
|
||||
|
||||
|
56
packages/components/scrollbar/style.css
Normal file
56
packages/components/scrollbar/style.css
Normal 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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user