UNPKG

@ducor/react

Version:

admin template ui interface

102 lines (101 loc) 6.62 kB
var __rest = (this && this.__rest) || function (s, e) { var t = {}; for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime"; import { forwardRef, useEffect, useRef, useState, useCallback, } from 'react'; const ScrollAreaAuto = forwardRef((_a, ref) => { var { children, className = '', direction = 'vertical', scrollbarAlwaysVisible = false } = _a, rest = __rest(_a, ["children", "className", "direction", "scrollbarAlwaysVisible"]); const viewportRef = useRef(null); const scrollbarThumbRef = useRef(null); const [thumbSize, setThumbSize] = useState(20); const [thumbPosition, setThumbPosition] = useState(0); const [isDragging, setIsDragging] = useState(false); const isVertical = direction === 'vertical' || direction === 'both'; const isHorizontal = direction === 'horizontal' || direction === 'both'; const calculateThumbSize = useCallback(() => { if (!viewportRef.current) return; if (isVertical) { const { scrollHeight, clientHeight } = viewportRef.current; const visibleRatio = clientHeight / scrollHeight; const thumbHeightRatio = visibleRatio * clientHeight; setThumbSize(Math.max(thumbHeightRatio, 20)); } if (isHorizontal) { const { scrollWidth, clientWidth } = viewportRef.current; const visibleRatio = clientWidth / scrollWidth; const thumbWidthRatio = visibleRatio * clientWidth; setThumbSize(Math.max(thumbWidthRatio, 20)); } }, [isVertical, isHorizontal]); const handleScroll = useCallback(() => { if (!viewportRef.current || !scrollbarThumbRef.current) return; if (isVertical) { const { scrollTop, scrollHeight, clientHeight } = viewportRef.current; const scrollRatio = scrollTop / (scrollHeight - clientHeight); const trackHeight = clientHeight - thumbSize; setThumbPosition(scrollRatio * trackHeight); } if (isHorizontal) { const { scrollLeft, scrollWidth, clientWidth } = viewportRef.current; const scrollRatio = scrollLeft / (scrollWidth - clientWidth); const trackWidth = clientWidth - thumbSize; setThumbPosition(scrollRatio * trackWidth); } }, [thumbSize, isVertical, isHorizontal]); const handleThumbMouseDown = useCallback((e) => { e.preventDefault(); setIsDragging(true); document.addEventListener('mousemove', handleMouseMove); document.addEventListener('mouseup', handleMouseUp); }, []); const handleMouseMove = useCallback((e) => { if (!isDragging || !viewportRef.current || !scrollbarThumbRef.current) return; if (isVertical) { const { clientHeight } = viewportRef.current; const trackHeight = clientHeight - thumbSize; const mousePosition = e.clientY - viewportRef.current.getBoundingClientRect().top; const newPosition = Math.min(Math.max(mousePosition - thumbSize / 2, 0), trackHeight); const scrollRatio = newPosition / trackHeight; viewportRef.current.scrollTop = scrollRatio * (viewportRef.current.scrollHeight - clientHeight); } if (isHorizontal) { const { clientWidth } = viewportRef.current; const trackWidth = clientWidth - thumbSize; const mousePosition = e.clientX - viewportRef.current.getBoundingClientRect().left; const newPosition = Math.min(Math.max(mousePosition - thumbSize / 2, 0), trackWidth); const scrollRatio = newPosition / trackWidth; viewportRef.current.scrollLeft = scrollRatio * (viewportRef.current.scrollWidth - clientWidth); } }, [isDragging, thumbSize, isVertical, isHorizontal]); const handleMouseUp = useCallback(() => { setIsDragging(false); document.removeEventListener('mousemove', handleMouseMove); document.removeEventListener('mouseup', handleMouseUp); }, [handleMouseMove]); useEffect(() => { calculateThumbSize(); window.addEventListener('resize', calculateThumbSize); return () => window.removeEventListener('resize', calculateThumbSize); }, [calculateThumbSize]); return (_jsxs("div", Object.assign({ ref: ref, className: `relative flex ${className} ${scrollbarAlwaysVisible ? 'hover:[&_.scrollbar]:opacity-100' : 'hover:[&_.scrollbar]:opacity-60'}` }, rest, { children: [_jsx("div", { ref: viewportRef, onScroll: handleScroll, className: `flex-1 overflow-auto scrollbar-none ${isVertical ? 'overflow-y-auto' : ''} ${isHorizontal ? 'overflow-x-auto' : ''}`, children: children }), isVertical && (_jsx("div", { className: `scrollbar absolute top-0 right-0 w-2 h-full transition-opacity duration-200 pointer-events-none select-none py-[2px] ${scrollbarAlwaysVisible ? 'opacity-100' : 'opacity-0'}`, children: _jsx("div", { className: "w-full h-full bg-black/5 rounded relative", children: _jsx("div", { ref: scrollbarThumbRef, className: `absolute w-full rounded cursor-pointer pointer-events-auto transition-all duration-200 ${isDragging ? 'bg-black/50' : 'bg-black/30 hover:bg-black/40'}`, style: { height: thumbSize, transform: `translateY(${thumbPosition}px)`, }, onMouseDown: handleThumbMouseDown }) }) })), isHorizontal && (_jsx("div", { className: `scrollbar absolute bottom-0 left-0 h-2 w-full transition-opacity duration-200 pointer-events-none select-none px-[2px] ${scrollbarAlwaysVisible ? 'opacity-100' : 'opacity-0'}`, children: _jsx("div", { className: "h-full w-full bg-black/5 rounded relative", children: _jsx("div", { className: `absolute h-full rounded cursor-pointer pointer-events-auto transition-all duration-200 ${isDragging ? 'bg-black/50' : 'bg-black/30 hover:bg-black/40'}`, style: { width: thumbSize, transform: `translateX(${thumbPosition}px)`, }, onMouseDown: handleThumbMouseDown }) }) }))] }))); }); export default ScrollAreaAuto;