@nutui/nutui-react
Version:
京东风格的轻量级移动端 React 组件库,支持一套代码生成 H5 和小程序
116 lines (115 loc) • 4.24 kB
JavaScript
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
};