UNPKG

flowbite-react

Version:

Official React components built for Flowbite and Tailwind CSS

290 lines (286 loc) 9.29 kB
'use strict'; var jsxRuntime = require('react/jsx-runtime'); var classnames = require('classnames'); var debounce = require('debounce'); var React = require('react'); var __defProp = Object.defineProperty; var __defNormalProp = (obj, key, value) => key in obj ? __defProp(obj, key, { enumerable: true, configurable: true, writable: true, value }) : obj[key] = value; var __publicField = (obj, key, value) => __defNormalProp(obj, typeof key !== "symbol" ? key + "" : key, value); const SCROLL_END_DEBOUNCE = 300; const LEFT_BUTTON = 0; class ScrollContainer extends React.PureComponent { constructor(props) { super(props); __publicField(this, "container"); __publicField(this, "scrolling"); __publicField(this, "started"); __publicField(this, "pressed"); __publicField(this, "isMobile", false); __publicField(this, "internal"); __publicField(this, "scrollLeft"); __publicField(this, "scrollTop"); __publicField(this, "clientX"); __publicField(this, "clientY"); // Simulate 'onEndScroll' event that fires when scrolling is stopped __publicField(this, "onEndScroll", () => { this.scrolling = false; if (!this.pressed && this.started) { this.processEnd(); } }); __publicField(this, "onScroll", () => { const container = this.container.current; if (container.scrollLeft !== this.scrollLeft || container.scrollTop !== this.scrollTop) { this.scrolling = true; this.processScroll(); this.onEndScroll(); } }); __publicField(this, "onTouchStart", (e) => { const { nativeMobileScroll } = this.props; if (this.isDraggable(e.target)) { this.internal = true; if (nativeMobileScroll && this.scrolling) { this.pressed = true; } else { const touch = e.touches[0]; this.processClick(touch.clientX, touch.clientY); if (!nativeMobileScroll && this.props.stopPropagation) { e.stopPropagation(); } } } }); __publicField(this, "onTouchEnd", () => { const { nativeMobileScroll } = this.props; if (this.pressed) { if (this.started && (!this.scrolling || !nativeMobileScroll)) { this.processEnd(); } else { this.pressed = false; } this.forceUpdate(); } }); __publicField(this, "onTouchMove", (e) => { const { nativeMobileScroll } = this.props; if (this.pressed && (!nativeMobileScroll || !this.isMobile)) { const touch = e.touches[0]; if (touch) { this.processMove(touch.clientX, touch.clientY); } e.preventDefault(); if (this.props.stopPropagation) { e.stopPropagation(); } } }); __publicField(this, "onMouseDown", (e) => { if (this.isDraggable(e.target) && this.isScrollable()) { this.internal = true; if (this.props?.buttons?.indexOf(e.button) !== -1) { this.processClick(e.clientX, e.clientY); e.preventDefault(); if (this.props.stopPropagation) { e.stopPropagation(); } } } }); __publicField(this, "onMouseMove", (e) => { if (this.pressed) { this.processMove(e.clientX, e.clientY); e.preventDefault(); if (this.props.stopPropagation) { e.stopPropagation(); } } }); __publicField(this, "onMouseUp", (e) => { if (this.pressed) { if (this.started) { this.processEnd(); } else { this.internal = false; this.pressed = false; this.forceUpdate(); if (this.props.onClick) { this.props.onClick(e); } } e.preventDefault(); if (this.props.stopPropagation) { e.stopPropagation(); } } }); this.container = React.createRef(); this.onEndScroll = debounce(this.onEndScroll, SCROLL_END_DEBOUNCE); this.scrolling = false; this.started = false; this.pressed = false; this.internal = false; this.getRef = this.getRef.bind(this); } componentDidMount() { const { nativeMobileScroll } = this.props; const container = this.container.current; window.addEventListener("mouseup", this.onMouseUp); window.addEventListener("mousemove", this.onMouseMove); window.addEventListener("touchmove", this.onTouchMove, { passive: false }); window.addEventListener("touchend", this.onTouchEnd); container.addEventListener("touchstart", this.onTouchStart, { passive: false }); container.addEventListener("mousedown", this.onMouseDown, { passive: false }); if (nativeMobileScroll) { this.isMobile = this.isMobileDevice(); if (this.isMobile) { this.forceUpdate(); } } } componentWillUnmount() { window.removeEventListener("mouseup", this.onMouseUp); window.removeEventListener("mousemove", this.onMouseMove); window.removeEventListener("touchmove", this.onTouchMove); window.removeEventListener("touchend", this.onTouchEnd); } getElement() { return this.container.current; } isMobileDevice() { return typeof window.orientation !== "undefined" || navigator.userAgent.indexOf("IEMobile") !== -1; } isDraggable(target) { const ignoreElements = this.props.ignoreElements; if (ignoreElements) { const closest = target.closest(ignoreElements); return closest === null || closest.contains(this.getElement()); } else { return true; } } isScrollable() { const container = this.container.current; return container && (container.scrollWidth > container.clientWidth || container.scrollHeight > container.clientHeight); } processClick(clientX, clientY) { const container = this.container.current; this.scrollLeft = container?.scrollLeft; this.scrollTop = container?.scrollTop; this.clientX = clientX; this.clientY = clientY; this.pressed = true; } processStart(changeCursor = true) { const { onStartScroll } = this.props; this.started = true; if (changeCursor) { document.body.classList.add("cursor-grab"); } if (onStartScroll) { onStartScroll({ external: !this.internal }); } this.forceUpdate(); } // Process native scroll (scrollbar, mobile scroll) processScroll() { if (this.started) { const { onScroll } = this.props; if (onScroll) { onScroll({ external: !this.internal }); } } else { this.processStart(false); } } // Process non-native scroll processMove(newClientX, newClientY) { const { horizontal, vertical, activationDistance, onScroll } = this.props; const container = this.container.current; if (!this.started) { if (horizontal && Math.abs(newClientX - this.clientX) > activationDistance || vertical && Math.abs(newClientY - this.clientY) > activationDistance) { this.clientX = newClientX; this.clientY = newClientY; this.processStart(); } } else { if (horizontal) { container.scrollLeft -= newClientX - this.clientX; } if (vertical) { container.scrollTop -= newClientY - this.clientY; } if (onScroll) { onScroll({ external: !this.internal }); } this.clientX = newClientX; this.clientY = newClientY; this.scrollLeft = container.scrollLeft; this.scrollTop = container.scrollTop; } } processEnd() { const { onEndScroll } = this.props; const container = this.container.current; if (container && onEndScroll) { onEndScroll({ external: !this.internal }); } this.pressed = false; this.started = false; this.scrolling = false; this.internal = false; document.body.classList.remove("cursor-grab"); this.forceUpdate(); } getRef(el) { [this.container, this.props.innerRef].forEach((ref) => { if (ref) { if (typeof ref === "function") { ref(el); } else { ref.current = el; } } }); } render() { const { children, draggingClassName, className, style, hideScrollbars } = this.props; return /* @__PURE__ */ jsxRuntime.jsx( "div", { className: classnames(className, this.pressed && draggingClassName, { "!scroll-auto [&>*]:pointer-events-none [&>*]:cursor-grab": this.pressed, "overflow-auto": this.isMobile, "overflow-hidden !overflow-x-hidden [scrollbar-width:none]": hideScrollbars, "[&::-webkit-scrollbar]:[-webkit-appearance:none !important] [&::-webkit-scrollbar]:!hidden [&::-webkit-scrollbar]:!h-0 [&::-webkit-scrollbar]:!w-0 [&::-webkit-scrollbar]:!bg-transparent": hideScrollbars }), style, ref: this.getRef, onScroll: this.onScroll, children } ); } } __publicField(ScrollContainer, "defaultProps", { nativeMobileScroll: true, hideScrollbars: true, activationDistance: 10, vertical: true, horizontal: true, stopPropagation: false, style: {}, buttons: [LEFT_BUTTON] }); module.exports = ScrollContainer; //# sourceMappingURL=drag-scroll.cjs.map