UNPKG

@nutui/nutui-react-taro

Version:

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

137 lines (136 loc) 4.8 kB
import { _ as __rest } from "./tslib.es6-iWu3F_1J.js"; import React__default, { useEffect, useRef, useState } from "react"; import { CSSTransition } from "react-transition-group"; import classNames from "classnames"; import { View } from "@tarojs/components"; import { C as ComponentDefaults } from "./typings-DV9RBfhj.js"; import { getEnv } from "@tarojs/taro"; import { u as useTouch } from "./use-touch-BeiLHDO9.js"; import { c as canUseDom, g as getScrollParent } from "./get-scroll-parent-DB1VRg11.js"; let passiveSupported = false; if (canUseDom) { try { const opts = Object.defineProperty({}, "passive", { get() { passiveSupported = true; } }); window.addEventListener("test-passive-supported", null, opts); } catch (e) { console.log(e); } } 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 useLockScrollTaro = (shouldLock) => { const refObject = useRef(null); if (getEnv() === "WEB") { useLockScroll(refObject, shouldLock); } return refObject; }; 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 = useLockScrollTaro(!!lockScroll && innerVisible); useEffect(() => { if (visible) { setInnerVisible(true); } else { setInnerVisible(false); } }, [visible]); 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(View, Object.assign({ ref: nodeRef, className: classes, style: styles }, rest, { catchMove: lockScroll, onClick: handleClick }), children) ); }; Overlay.displayName = "NutOverlay"; export { Overlay as O, defaultOverlayProps as d, passiveSupported as p, useLockScrollTaro as u };