UNPKG

@nutui/nutui-react

Version:

京东风格的轻量级移动端 React 组件库,支持一套代码生成 H5 和小程序

116 lines (115 loc) 4.24 kB
import { _ as __rest } from "./tslib.es6.js"; import React__default, { useEffect, useState, useRef } from "react"; import { CSSTransition } from "react-transition-group"; import classNames from "classnames"; import { C as ComponentDefaults } from "./typings.js"; import { u as useTouch } from "./use-touch.js"; import { g as getScrollParent } from "./get-scroll-parent.js"; import { p as passiveSupported } from "./supports-passive.js"; let totalLockCount = 0; const BODY_LOCK_CLASS = "nut-overflow-hidden"; function getScrollableElement(el) { let current = el === null || el === void 0 ? void 0 : el.parentElement; while (current) { if (current.clientHeight < current.scrollHeight) { return current; } current = current.parentElement; } return null; } function useLockScroll(rootRef, shouldLock) { const touch = useTouch(); const onTouchMove = (event) => { touch.move(event); const direction = touch.deltaY.current > 0 ? "10" : "01"; const el = getScrollParent(event.target, rootRef.current); if (!el) return; if (shouldLock === "strict") { const scrollableParent = getScrollableElement(event.target); if (scrollableParent === document.body || scrollableParent === document.documentElement) { event.preventDefault(); return; } } const { scrollHeight, offsetHeight, scrollTop } = el; let status = "11"; if (scrollTop === 0) { status = offsetHeight >= scrollHeight ? "00" : "01"; } else if (scrollTop + offsetHeight >= scrollHeight) { status = "10"; } if (status !== "11" && touch.isVertical() && !(parseInt(status, 2) & parseInt(direction, 2))) { if (event.cancelable) { event.preventDefault(); } } }; const lock = () => { document.addEventListener("touchstart", touch.start); document.addEventListener("touchmove", onTouchMove, passiveSupported ? { passive: false } : false); if (!totalLockCount) { document.body.classList.add(BODY_LOCK_CLASS); } totalLockCount++; }; const unlock = () => { if (totalLockCount) { document.removeEventListener("touchstart", touch.start); document.removeEventListener("touchmove", onTouchMove); totalLockCount--; if (!totalLockCount) { document.body.classList.remove(BODY_LOCK_CLASS); } } }; useEffect(() => { if (shouldLock) { lock(); return () => { unlock(); }; } }, [shouldLock]); } const defaultOverlayProps = Object.assign(Object.assign({}, ComponentDefaults), { zIndex: 1e3, duration: 300, closeOnOverlayClick: true, visible: false, lockScroll: true, onClick: (event) => { } }); const Overlay = (props) => { const _a = Object.assign(Object.assign({}, defaultOverlayProps), props), { children, zIndex, duration, className, closeOnOverlayClick, visible, lockScroll, style, afterShow, afterClose, onClick } = _a, rest = __rest(_a, ["children", "zIndex", "duration", "className", "closeOnOverlayClick", "visible", "lockScroll", "style", "afterShow", "afterClose", "onClick"]); const classPrefix = `nut-overlay`; const [innerVisible, setInnerVisible] = useState(visible); const nodeRef = useRef(null); useEffect(() => { if (visible) { setInnerVisible(true); } else { setInnerVisible(false); } }, [visible]); useLockScroll(nodeRef, !!lockScroll && innerVisible); const classes = classNames(classPrefix, className); const styles = Object.assign({}, style); const handleClick = (e) => { if (closeOnOverlayClick) { onClick && onClick(e); } }; const onHandleOpened = (e) => { afterShow && afterShow(); }; const onHandleClosed = (e) => { afterClose && afterClose(); }; return React__default.createElement( CSSTransition, { nodeRef, classNames: `${classPrefix}-slide`, unmountOnExit: true, timeout: duration, in: innerVisible, onEntered: onHandleOpened, onExited: onHandleClosed }, React__default.createElement("div", Object.assign({ ref: nodeRef, className: classes, style: styles }, rest, { onClick: handleClick }), children) ); }; Overlay.displayName = "NutOverlay"; export { Overlay as O, defaultOverlayProps as d, useLockScroll as u };