@nutui/nutui-react
Version:
京东风格的轻量级移动端 React 组件库,支持一套代码生成 H5 和小程序
145 lines (144 loc) • 6.17 kB
JavaScript
import React__default, { useState, useEffect } from "react";
import { createPortal } from "react-dom";
import { CSSTransition } from "react-transition-group";
import classNames from "classnames";
import { Close } from "@nutui/icons-react";
import { d as defaultOverlayProps, u as useLockScroll } from "./overlay2.js";
import Overlay__default from "./Overlay.js";
import { C as ComponentDefaults } from "./typings.js";
const defaultProps = Object.assign(Object.assign(Object.assign({}, ComponentDefaults), { position: "center", transition: "", overlayStyle: {}, overlayClassName: "", closeable: false, closeIconPosition: "top-right", closeIcon: "close", destroyOnClose: false, portal: null, overlay: true, round: false, onOpen: () => {
}, onClose: () => {
}, onOverlayClick: (e) => true, onCloseIconClick: (e) => true }), defaultOverlayProps);
const _zIndex = 1100;
const Popup = (props) => {
const { children, visible, overlay, closeOnOverlayClick, overlayStyle, overlayClassName, zIndex, lockScroll, duration, closeable, closeIconPosition, closeIcon, left, title, description, style, transition, round, position, className, destroyOnClose, portal, onOpen, onClose, onOverlayClick, onCloseIconClick, afterShow, afterClose, onClick } = Object.assign(Object.assign({}, defaultProps), props);
const nodeRef = React__default.useRef(null);
let innerIndex = zIndex || _zIndex;
const [index, setIndex] = useState(innerIndex);
const [innerVisible, setInnerVisible] = useState(visible);
const [showChildren, setShowChildren] = useState(true);
const [transitionName, setTransitionName] = useState("");
useLockScroll(nodeRef, innerVisible && lockScroll);
const classPrefix = "nut-popup";
const baseStyle = {
zIndex: index
};
const overlayStyles = Object.assign(Object.assign({}, overlayStyle), { "--nutui-overlay-zIndex": index });
const popStyles = Object.assign(Object.assign({}, style), baseStyle);
const popClassName = classNames({
[`${classPrefix}`]: true,
[`${classPrefix}-round`]: round || position === "bottom",
[`${classPrefix}-${position}`]: true
}, className);
const closeClasses = classNames({
[`${classPrefix}-title-right`]: true,
[`${classPrefix}-title-right-${closeIconPosition}`]: true
});
const open = () => {
if (!innerVisible) {
setInnerVisible(true);
setIndex(++innerIndex);
}
if (destroyOnClose) {
setShowChildren(true);
}
onOpen && onOpen();
};
const close = () => {
if (innerVisible) {
setInnerVisible(false);
if (destroyOnClose) {
setTimeout(() => {
setShowChildren(false);
}, Number(duration));
}
onClose && onClose();
}
};
const onHandleClickOverlay = (e) => {
e.stopPropagation();
if (closeOnOverlayClick) {
const closed = onOverlayClick && onOverlayClick(e);
closed && close();
}
};
const onHandleClick = (e) => {
onClick && onClick(e);
};
const onHandleClickCloseIcon = (e) => {
const closed = onCloseIconClick && onCloseIconClick(e);
closed && close();
};
const onHandleOpened = (e) => {
afterShow && afterShow();
};
const onHandleClosed = (e) => {
afterClose && afterClose();
};
const resolveContainer = (getContainer) => {
const container = typeof getContainer === "function" ? getContainer() : getContainer;
return container || document.body;
};
const renderToContainer = (getContainer, node) => {
if (getContainer) {
const container = resolveContainer(getContainer);
return createPortal(node, container);
}
return node;
};
const renderTitle = () => {
if (left || title || description) {
return React__default.createElement(
"div",
{ className: `${classPrefix}-title` },
position === "bottom" && React__default.createElement(
React__default.Fragment,
null,
left && React__default.createElement("div", { className: `${classPrefix}-title-left` }, left),
(title || description) && React__default.createElement(
"div",
{ className: `${classPrefix}-title-title` },
title,
description && React__default.createElement("div", { className: `${classPrefix}-title-description` }, description)
)
),
closeable && React__default.createElement("div", { className: closeClasses, onClick: onHandleClickCloseIcon }, React__default.isValidElement(closeIcon) ? closeIcon : React__default.createElement(Close, null))
);
}
if (closeable) {
return React__default.createElement(React__default.Fragment, null, closeable && React__default.createElement("div", { className: closeClasses, onClick: onHandleClickCloseIcon }, React__default.isValidElement(closeIcon) ? closeIcon : React__default.createElement(Close, null)));
}
};
const renderPop = () => {
return React__default.createElement(
CSSTransition,
{ nodeRef, classNames: transitionName, mountOnEnter: true, unmountOnExit: destroyOnClose, timeout: duration, in: innerVisible, onEntered: onHandleOpened, onExited: onHandleClosed },
React__default.createElement(
"div",
{ ref: nodeRef, style: popStyles, className: popClassName, onClick: onHandleClick },
renderTitle(),
showChildren ? children : ""
)
);
};
const renderNode = () => {
return React__default.createElement(
React__default.Fragment,
null,
overlay ? React__default.createElement(Overlay__default, { style: overlayStyles, className: overlayClassName, visible: innerVisible, closeOnOverlayClick, lockScroll, duration, onClick: onHandleClickOverlay }) : null,
React__default.createElement(React__default.Fragment, null, renderPop())
);
};
useEffect(() => {
visible && open();
!visible && close();
}, [visible]);
useEffect(() => {
setTransitionName(transition || `${classPrefix}-slide-${position}`);
}, [position, transition]);
return React__default.createElement(React__default.Fragment, null, renderToContainer(portal, renderNode()));
};
Popup.displayName = "NutPopup";
export {
Popup as P
};