UNPKG

@nutui/nutui-react

Version:

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

236 lines (235 loc) 12.1 kB
import { _ as _define_property } from "@swc/helpers/_/_define_property"; import { _ as _object_spread } from "@swc/helpers/_/_object_spread"; import { _ as _object_spread_props } from "@swc/helpers/_/_object_spread_props"; import { _ as _sliced_to_array } from "@swc/helpers/_/_sliced_to_array"; import React, { useEffect, useState, useRef } from "react"; import { createPortal } from "react-dom"; import { CSSTransition } from "react-transition-group"; import classNames from "classnames"; import { Close } from "@nutui/icons-react"; import { defaultOverlayProps } from "../overlay/overlay"; import Overlay from "../overlay"; import { useLockScroll } from "../../hooks/use-lock-scroll"; import { useConfig } from "../configprovider"; var defaultProps = _object_spread_props(_object_spread({}, defaultOverlayProps), { position: 'center', transition: '', overlayStyle: {}, overlayClassName: '', closeable: false, closeIconPosition: 'top-right', closeIcon: 'close', destroyOnClose: false, portal: null, overlay: true, round: false, resizable: false, minHeight: '', onOpen: function() {}, onClose: function() {}, onOverlayClick: function() { return true; }, onCloseIconClick: function() { return true; }, onTouchStart: function() {}, onTouchMove: function() {}, onTouchEnd: function() {} }); // 默认1000,参看variables var _zIndex = 1100; export var Popup = function(props) { var _$_object_spread = _object_spread({}, defaultProps, props), children = _$_object_spread.children, visible = _$_object_spread.visible, overlay = _$_object_spread.overlay, closeOnOverlayClick = _$_object_spread.closeOnOverlayClick, overlayStyle = _$_object_spread.overlayStyle, overlayClassName = _$_object_spread.overlayClassName, zIndex = _$_object_spread.zIndex, lockScroll = _$_object_spread.lockScroll, duration = _$_object_spread.duration, closeable = _$_object_spread.closeable, closeIconPosition = _$_object_spread.closeIconPosition, closeIcon = _$_object_spread.closeIcon, left = _$_object_spread.left, title = _$_object_spread.title, top = _$_object_spread.top, description = _$_object_spread.description, style = _$_object_spread.style, transition = _$_object_spread.transition, round = _$_object_spread.round, position = _$_object_spread.position, className = _$_object_spread.className, destroyOnClose = _$_object_spread.destroyOnClose, portal = _$_object_spread.portal, resizable = _$_object_spread.resizable, minHeight = _$_object_spread.minHeight, onOpen = _$_object_spread.onOpen, onClose = _$_object_spread.onClose, onOverlayClick = _$_object_spread.onOverlayClick, onCloseIconClick = _$_object_spread.onCloseIconClick, afterShow = _$_object_spread.afterShow, afterClose = _$_object_spread.afterClose, onClick = _$_object_spread.onClick, onTouchStart = _$_object_spread.onTouchStart, onTouchMove = _$_object_spread.onTouchMove, onTouchEnd = _$_object_spread.onTouchEnd, closeAriaLabel = _$_object_spread.closeAriaLabel; var nodeRef = React.useRef(null); var topNodeRef = React.useRef(null); var innerIndex = zIndex || _zIndex; var _useState = _sliced_to_array(useState(innerIndex), 2), index = _useState[0], setIndex = _useState[1]; var _useState1 = _sliced_to_array(useState(visible), 2), innerVisible = _useState1[0], setInnerVisible = _useState1[1]; var _useState2 = _sliced_to_array(useState(true), 2), showChildren = _useState2[0], setShowChildren = _useState2[1]; var _useState3 = _sliced_to_array(useState(''), 2), transitionName = _useState3[0], setTransitionName = _useState3[1]; var touchStartRef = useRef(0); var touchMoveDistanceRef = useRef(0); var heightRef = useRef(0); // 首次可调整时记录的默认高度 var defaultHeightRef = useRef(0); var isTouching = useRef(false); var locale = useConfig().locale; useLockScroll(nodeRef, innerVisible && lockScroll); var classPrefix = 'nut-popup'; var overlayStyles = _object_spread({}, overlayStyle); var popStyles = _object_spread_props(_object_spread({}, style), { zIndex: index, minHeight: minHeight }); var _obj; var popClassName = classNames(classPrefix, (_obj = {}, _define_property(_obj, "".concat(classPrefix, "-round"), round || position === 'bottom'), _define_property(_obj, "".concat(classPrefix, "-").concat(position), true), _obj), className); var open = function() { if (!innerVisible) { // 当高度改变后,再次打开时,将高度置为初始高度 if (position === 'bottom' && resizable && nodeRef.current && heightRef.current) { nodeRef.current.style.height = "".concat(defaultHeightRef.current, "px"); } setInnerVisible(true); setIndex(++innerIndex); } if (destroyOnClose) { setShowChildren(true); } onOpen && onOpen(); }; useEffect(function() { if (topNodeRef.current && nodeRef.current) { var _nodeRef_current; topNodeRef.current.style.bottom = "".concat((_nodeRef_current = nodeRef.current) === null || _nodeRef_current === void 0 ? void 0 : _nodeRef_current.clientHeight, "px"); } }, [ innerVisible ]); var close = function() { if (innerVisible) { setInnerVisible(false); if (destroyOnClose) { setTimeout(function() { setShowChildren(false); }, Number(duration)); } onClose && onClose(); } }; var handleOverlayClick = function(e) { e.stopPropagation(); if (closeOnOverlayClick && onOverlayClick(e)) { close(); } }; var handleCloseIconClick = function(e) { onCloseIconClick(e) && close(); }; var renderCloseIcon = function() { var closeClasses = classNames("".concat(classPrefix, "-title-right"), "".concat(classPrefix, "-title-right-").concat(closeIconPosition)); return /*#__PURE__*/ React.createElement(React.Fragment, null, closeable && /*#__PURE__*/ React.createElement("div", { className: closeClasses, onClick: handleCloseIconClick, role: "button", "aria-label": closeAriaLabel || locale.close, tabIndex: -1 }, /*#__PURE__*/ React.isValidElement(closeIcon) ? closeIcon : /*#__PURE__*/ React.createElement(Close, null))); }; var renderTop = function() { if (!top) return null; return /*#__PURE__*/ React.createElement("div", { className: "".concat(classPrefix, "-bottom-top"), ref: topNodeRef }, top); }; var renderTitle = function() { if (left || title || description) { return /*#__PURE__*/ React.createElement("div", { className: "".concat(classPrefix, "-title") }, position === 'bottom' && /*#__PURE__*/ React.createElement(React.Fragment, null, left && /*#__PURE__*/ React.createElement("div", { className: "".concat(classPrefix, "-title-left") }, left), (title || description) && /*#__PURE__*/ React.createElement("div", { className: "".concat(classPrefix, "-title-wrapper") }, title && /*#__PURE__*/ React.createElement("div", { className: "".concat(classPrefix, "-title-title") }, title), description && /*#__PURE__*/ React.createElement("div", { className: "".concat(classPrefix, "-title-description ").concat(title ? "".concat(classPrefix, "-title-description-gap") : '') }, description))), renderCloseIcon()); } if (closeable) { return renderCloseIcon(); } }; var handleTouchStart = function(event) { var _nodeRef_current; if (position !== 'bottom' || !resizable || !nodeRef.current) return; // 开始touch,记录下touch的pageY,用以判断是向上滑动还是向下滑动 touchStartRef.current = event.touches[0].pageY; // 标记开始滑动 isTouching.current = true; // 标记当前popup的高度 heightRef.current = ((_nodeRef_current = nodeRef.current) === null || _nodeRef_current === void 0 ? void 0 : _nodeRef_current.offsetHeight) || 0; if (!defaultHeightRef.current) defaultHeightRef.current = heightRef.current; onTouchStart === null || onTouchStart === void 0 ? void 0 : onTouchStart(heightRef.current, event); }; var handleTouchMove = function(event) { if (position !== 'bottom' || !resizable || !nodeRef.current) return; event.stopPropagation(); // move过程中,当前的pageY 与 start值比较 touchMoveDistanceRef.current = event.touches[0].pageY - touchStartRef.current; var min = typeof minHeight === 'number' ? minHeight : parseInt(String(minHeight || 0), 10) || 0; var currentHeight = Math.max(min, heightRef.current - touchMoveDistanceRef.current); nodeRef.current.style.height = "".concat(currentHeight, "px"); // 向下滑动 if (touchMoveDistanceRef.current > 0) { onTouchMove === null || onTouchMove === void 0 ? void 0 : onTouchMove(currentHeight, event, 'down'); } else { // 向上滑动 onTouchMove === null || onTouchMove === void 0 ? void 0 : onTouchMove(currentHeight, event, 'up'); } }; var handleTouchEnd = function(event) { if (position !== 'bottom' || !resizable || !nodeRef.current) return; isTouching.current = false; var min = typeof minHeight === 'number' ? minHeight : parseInt(String(minHeight || 0), 10) || 0; var currentHeight = Math.max(min, heightRef.current - touchMoveDistanceRef.current); onTouchEnd === null || onTouchEnd === void 0 ? void 0 : onTouchEnd(currentHeight, event); }; var renderPop = function() { return /*#__PURE__*/ React.createElement(CSSTransition, { nodeRef: nodeRef, classNames: transitionName, mountOnEnter: true, unmountOnExit: destroyOnClose, timeout: duration, in: innerVisible, onEntered: afterShow, onExited: afterClose }, /*#__PURE__*/ React.createElement("div", { ref: nodeRef, style: popStyles, className: popClassName, onClick: onClick, onTouchStart: handleTouchStart, onTouchMove: handleTouchMove, onTouchEnd: handleTouchEnd, onTouchCancel: handleTouchEnd }, renderTop(), renderTitle(), showChildren && children)); }; var renderNode = function() { return /*#__PURE__*/ React.createElement(React.Fragment, null, overlay && /*#__PURE__*/ React.createElement(Overlay, { zIndex: index, style: overlayStyles, className: overlayClassName, visible: innerVisible, closeOnOverlayClick: closeOnOverlayClick, lockScroll: lockScroll, duration: duration, onClick: handleOverlayClick }), renderPop()); }; useEffect(function() { visible ? open() : close(); }, [ visible ]); useEffect(function() { setTransitionName(transition || "".concat(classPrefix, "-slide-").concat(position)); }, [ position, transition ]); var resolveContainer = function(getContainer) { return (typeof getContainer === 'function' ? getContainer() : getContainer) || document.body; }; var renderToContainer = function(getContainer, node) { if (getContainer) { var container = resolveContainer(getContainer); return /*#__PURE__*/ createPortal(node, container); } return node; }; return /*#__PURE__*/ React.createElement(React.Fragment, null, renderToContainer(portal, renderNode())); }; Popup.displayName = 'NutPopup';