import type { CSSProperties, RefObject, MouseEvent, Dispatch, SetStateAction } from 'react'; import React from 'react'; import { computeRatio } from './utils'; import type { ActionPosition, BoxSize } from './types'; import './ThumbBar.less'; export interface ThumbBarProps { scrollRef: React.MutableRefObject; visible: boolean; trackStyle?: (horizontal?: boolean) => CSSProperties; thumbStyle?: (horizontal?: boolean) => CSSProperties; minThumbSize?: number; start: number; gap: number; horizontal?: boolean; pin: boolean | undefined; trackRef: RefObject; boxSize: BoxSize; update: Dispatch>; onScroll: (scrollOffset: number, horizontal?: boolean) => void; } export default function ThumbBar({ scrollRef, visible, trackStyle, thumbStyle, minThumbSize, start, gap, horizontal, pin, trackRef, boxSize, update, onScroll, }: ThumbBarProps) { const { CW, CH, PT, PR, PB, PL, SW, SH } = boxSize; const [sizeKey, offsetSize, scrollSize] = horizontal ? ['width', CW, SW] : ['height', CH, SH]; function handleThumbBarClick(e: MouseEvent) { const containerBox = scrollRef.current!; const { scrollLeft, scrollTop } = containerBox; const scrollPosition = horizontal ? scrollLeft : scrollTop; const rect = (e.target as HTMLDivElement).getBoundingClientRect(); const clickPosition = horizontal ? (e.clientX - rect.left) / rect.width : (e.clientY - rect.top) / rect.height; const scrollRatio = scrollPosition / scrollSize; const position = clickPosition > scrollRatio ? Math.min(scrollSize, scrollPosition + offsetSize) : Math.max(0, scrollPosition - offsetSize); onScroll(position, horizontal); } function handleStart(e: MouseEvent) { e.stopPropagation(); const { scrollLeft, scrollTop } = scrollRef.current!; update({ pinX: horizontal, pinY: !horizontal, lastST: scrollTop, lastSL: scrollLeft, startX: e.clientX, startY: e.clientY, }); } const style: CSSProperties = { ...(typeof document !== undefined && scrollRef.current === document.documentElement ? { [sizeKey]: gap > 0 ? `calc(100% - ${gap}px)` : undefined } : { [sizeKey]: offsetSize - gap, ...(horizontal ? { bottom: -PB, left: -PL + start } : { top: PT - gap + start, right: -PR, transform: 'translateY(-100%)' }), }), ...(trackStyle && trackStyle(horizontal)), }; return (
{ e.preventDefault(); e.stopPropagation(); }} onMouseDown={handleStart} onClick={(e) => e.stopPropagation()} style={{ [sizeKey]: computeRatio(scrollSize, offsetSize, gap, minThumbSize).thumbSize, ...(thumbStyle && thumbStyle(horizontal)), }} />
); }