UNPKG

@nutui/nutui-react

Version:

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

145 lines (144 loc) 6.17 kB
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 };