UNPKG

@mantine/core

Version:

React components library focused on usability, accessibility and developer experience

104 lines (101 loc) 3.96 kB
'use client'; import { jsx } from 'react/jsx-runtime'; import { forwardRef, useState, useRef, useEffect } from 'react'; import { useMergedRef, useCallbackRef, useDebouncedCallback } from '@mantine/hooks'; import { useScrollAreaContext } from '../ScrollArea.context.mjs'; import { useResizeObserver } from '../use-resize-observer.mjs'; import { composeEventHandlers } from '../utils/compose-event-handlers.mjs'; import { ScrollbarProvider } from './Scrollbar.context.mjs'; const Scrollbar = forwardRef((props, forwardedRef) => { const { sizes, hasThumb, onThumbChange, onThumbPointerUp, onThumbPointerDown, onThumbPositionChange, onDragScroll, onWheelScroll, onResize, ...scrollbarProps } = props; const context = useScrollAreaContext(); const [scrollbar, setScrollbar] = useState(null); const composeRefs = useMergedRef(forwardedRef, (node) => setScrollbar(node)); const rectRef = useRef(null); const prevWebkitUserSelectRef = useRef(""); const { viewport } = context; const maxScrollPos = sizes.content - sizes.viewport; const handleWheelScroll = useCallbackRef(onWheelScroll); const handleThumbPositionChange = useCallbackRef(onThumbPositionChange); const handleResize = useDebouncedCallback(onResize, 10); const handleDragScroll = (event) => { if (rectRef.current) { const x = event.clientX - rectRef.current.left; const y = event.clientY - rectRef.current.top; onDragScroll({ x, y }); } }; useEffect(() => { const handleWheel = (event) => { const element = event.target; const isScrollbarWheel = scrollbar?.contains(element); if (isScrollbarWheel) { handleWheelScroll(event, maxScrollPos); } }; document.addEventListener("wheel", handleWheel, { passive: false }); return () => document.removeEventListener("wheel", handleWheel, { passive: false }); }, [viewport, scrollbar, maxScrollPos, handleWheelScroll]); useEffect(handleThumbPositionChange, [sizes, handleThumbPositionChange]); useResizeObserver(scrollbar, handleResize); useResizeObserver(context.content, handleResize); return /* @__PURE__ */ jsx( ScrollbarProvider, { value: { scrollbar, hasThumb, onThumbChange: useCallbackRef(onThumbChange), onThumbPointerUp: useCallbackRef(onThumbPointerUp), onThumbPositionChange: handleThumbPositionChange, onThumbPointerDown: useCallbackRef(onThumbPointerDown) }, children: /* @__PURE__ */ jsx( "div", { ...scrollbarProps, ref: composeRefs, "data-mantine-scrollbar": true, style: { position: "absolute", ...scrollbarProps.style }, onPointerDown: composeEventHandlers(props.onPointerDown, (event) => { event.preventDefault(); const mainPointer = 0; if (event.button === mainPointer) { const element = event.target; element.setPointerCapture(event.pointerId); rectRef.current = scrollbar.getBoundingClientRect(); prevWebkitUserSelectRef.current = document.body.style.webkitUserSelect; document.body.style.webkitUserSelect = "none"; handleDragScroll(event); } }), onPointerMove: composeEventHandlers(props.onPointerMove, handleDragScroll), onPointerUp: composeEventHandlers(props.onPointerUp, (event) => { const element = event.target; if (element.hasPointerCapture(event.pointerId)) { event.preventDefault(); element.releasePointerCapture(event.pointerId); } }), onLostPointerCapture: () => { document.body.style.webkitUserSelect = prevWebkitUserSelectRef.current; rectRef.current = null; } } ) } ); }); export { Scrollbar }; //# sourceMappingURL=Scrollbar.mjs.map