UNPKG

preact-arco-design

Version:

Arco Design React UI Library.

437 lines (384 loc) 14.4 kB
var __assign = this && this.__assign || function () { __assign = Object.assign || function (t) { for (var s, i = 1, n = arguments.length; i < n; i++) { s = arguments[i]; for (var p in s) { if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p]; } } return t; }; return __assign.apply(this, arguments); }; var __rest = this && this.__rest || function (s, e) { var t = {}; for (var p in s) { if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0) t[p] = s[p]; } if (s != null && typeof Object.getOwnPropertySymbols === "function") for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) { if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i])) t[p[i]] = s[p[i]]; } return t; }; var __read = this && this.__read || function (o, n) { var m = typeof Symbol === "function" && o[Symbol.iterator]; if (!m) return o; var i = m.call(o), r, ar = [], e; try { while ((n === void 0 || n-- > 0) && !(r = i.next()).done) { ar.push(r.value); } } catch (error) { e = { error: error }; } finally { try { if (r && !r.done && (m = i["return"])) m.call(i); } finally { if (e) throw e.error; } } return ar; }; import { findDOMNode } from "preact/compat"; import React, { useState, forwardRef, useContext, useRef, useEffect, useCallback } from "preact/compat"; import { CSSTransition } from "preact-transition-group-4"; import IconClose from "../../icon/react-icon/IconClose"; import cs from "../_util/classNames"; import { isServerRendering } from "../_util/dom"; import { Esc } from "../_util/keycode"; import Button from "../Button"; import Portal from "../Portal"; import confirm from "./confirm"; import ConfigProvider, { ConfigContext } from "../ConfigProvider"; import IconHover from "../_class/icon-hover"; import { setModalConfig, destroyList } from "./config"; import { isFunction, isObject } from "../_util/is"; import omit from "../_util/omit"; import useOverflowHidden from "../_util/hooks/useOverflowHidden"; import useModal from "./useModal"; import useMergeValue from "../_util/hooks/useMergeValue"; import useMergeProps from "../_util/hooks/useMergeProps"; var cursorPosition = null; var globalDialogIndex = 0; if (!isServerRendering) { document.documentElement.addEventListener('click', function (e) { cursorPosition = { left: e.clientX, top: e.clientY }; // 受控模式下,用户不一定马上打开弹窗,这期间可能出现其他 UI 操作,那这个位置就不可用了。 setTimeout(function () { cursorPosition = null; }, 100); }, true); } var defaultProps = { mask: true, maskClosable: true, mountOnEnter: true, escToExit: true, getPopupContainer: function getPopupContainer() { return document.body; }, alignCenter: true }; function Modal(baseProps, ref) { var _a, _b; var _c; var context = useContext(ConfigContext); var props = useMergeProps(baseProps, defaultProps, (_c = context.componentConfig) === null || _c === void 0 ? void 0 : _c.Modal); var className = props.className, style = props.style, visible = props.visible, simple = props.simple, title = props.title, children = props.children, cancelText = props.cancelText, okText = props.okText, okButtonProps = props.okButtonProps, cancelButtonProps = props.cancelButtonProps, _d = props.getPopupContainer, getPopupContainer = _d === void 0 ? function () { return document.body; } : _d, footer = props.footer, afterClose = props.afterClose, confirmLoading = props.confirmLoading, mountOnEnter = props.mountOnEnter, unmountOnExit = props.unmountOnExit, afterOpen = props.afterOpen, hideCancel = props.hideCancel, autoFocus = props.autoFocus, focusLock = props.focusLock, maskClosable = props.maskClosable, mask = props.mask, alignCenter = props.alignCenter, getChildrenPopupContainer = props.getChildrenPopupContainer, wrapClassName = props.wrapClassName, escToExit = props.escToExit, modalRender = props.modalRender, maskStyle = props.maskStyle, wrapStyle = props.wrapStyle, closeIcon = props.closeIcon, rest = __rest(props, ["className", "style", "visible", "simple", "title", "children", "cancelText", "okText", "okButtonProps", "cancelButtonProps", "getPopupContainer", "footer", "afterClose", "confirmLoading", "mountOnEnter", "unmountOnExit", "afterOpen", "hideCancel", "autoFocus", "focusLock", "maskClosable", "mask", "alignCenter", "getChildrenPopupContainer", "wrapClassName", "escToExit", "modalRender", "maskStyle", "wrapStyle", "closeIcon"]); var modalWrapperRef = useRef(null); var contentWrapper = useRef(null); var _e = __read(useState(), 2), wrapperVisible = _e[0], setWrapperVisible = _e[1]; var _f = __read(useState(), 2), popupZIndex = _f[0], setPopupZIndex = _f[1]; var cursorPositionRef = useRef(null); var haveOriginTransformOrigin = useRef(false); var maskClickRef = useRef(false); var dialogIndex = useRef(); if (!dialogIndex.current) { dialogIndex.current = globalDialogIndex++; } var _g = __read(useMergeValue(false, { defaultValue: false, value: confirmLoading }), 2), loading = _g[0], setLoading = _g[1]; var prefixCls = context.getPrefixCls('modal', props.prefixCls); var locale = context.locale, rtl = context.rtl; // 简洁模式下默认不显示关闭按钮 var defaultClosable = !simple; var closable = 'closable' in props ? props.closable : defaultClosable; var getContainer = useCallback(function () { return findDOMNode(getPopupContainer()); }, [getPopupContainer]); useOverflowHidden(getContainer, { hidden: visible && mask }); var onCancel = function onCancel() { props.onCancel && props.onCancel(); }; var onEscExit = function onEscExit(event) { if (escToExit && visible && event.key === Esc.key) { event.stopPropagation(); onCancel(); } }; var inExit = useRef(false); var onClickMask = function onClickMask(e) { if (!maskClickRef.current) return; maskClickRef.current = false; if (!inExit.current && maskClosable && mask && e.target === e.currentTarget) { setTimeout(function () { onCancel(); }, 100); } }; var onConfirmModal = function onConfirmModal(e) { var onConfirm = props.onConfirm, onOk = props.onOk; var _onConfirm = onOk || onConfirm; var ret; if (_onConfirm) { ret = _onConfirm(e); } if (ret && ret.then) { setLoading(true); ret.then(function () { setLoading(false); }, function (e) { setLoading(false); console.error(e); }); } }; useEffect(function () { var timer = null; if (escToExit) { timer = setTimeout(function () { var _a; (_a = modalWrapperRef.current) === null || _a === void 0 ? void 0 : _a.focus(); }); } return function () { timer && clearTimeout(timer); }; }, [visible, escToExit]); useEffect(function () { var _a; if (visible && popupZIndex === undefined) { if (modalWrapperRef.current) { // 根据wrapper的zindex,设置内部所有弹出型组件的zindex。 var zIndex = +((_a = window.getComputedStyle(modalWrapperRef.current, null)) === null || _a === void 0 ? void 0 : _a.zIndex); if (!isNaN(zIndex)) { setPopupZIndex(zIndex + 1); } } } }, [visible, popupZIndex]); var renderFooter = function renderFooter() { if (footer === null) return; var cancelButtonNode = React.createElement(Button, __assign({ onClick: onCancel }, cancelButtonProps), cancelText || locale.Modal.cancelText); var okButtonNode = React.createElement(Button, __assign({ loading: loading, onClick: onConfirmModal, type: "primary" }, okButtonProps), okText || locale.Modal.okText); var footerContent = isFunction(footer) ? footer(cancelButtonNode, okButtonNode) : footer || React.createElement(React.Fragment, null, !hideCancel && cancelButtonNode, okButtonNode); return React.createElement("div", { className: "".concat(prefixCls, "-footer") }, footerContent); }; var globalFocusLockConfig = context.focusLock.modal; var globalFocusLock = !!globalFocusLockConfig; var globalAutoFocus = isObject(globalFocusLockConfig) && globalFocusLockConfig.autoFocus; var innerFocusLock = focusLock !== undefined ? focusLock : globalFocusLock; var innerAutoFocus = autoFocus !== undefined ? autoFocus : globalAutoFocus; var element = React.createElement(ConfigProvider, __assign({}, context, { prefixCls: props.prefixCls || context.prefixCls, locale: locale, zIndex: popupZIndex || 1050, getPopupContainer: function getPopupContainer(node) { return typeof getChildrenPopupContainer === 'function' ? getChildrenPopupContainer(node) : contentWrapper.current; } }), title && React.createElement("div", { className: "".concat(prefixCls, "-header") }, React.createElement("div", { className: "".concat(prefixCls, "-title"), id: "arco-dialog-".concat(dialogIndex.current) }, title)), React.createElement("div", { ref: contentWrapper, className: "".concat(prefixCls, "-content") }, children), renderFooter(), closable && (closeIcon !== undefined ? React.createElement("span", { onClick: onCancel, className: "".concat(prefixCls, "-close-icon") }, closeIcon) : React.createElement(IconHover, { tabIndex: -1, onClick: onCancel, className: "".concat(prefixCls, "-close-icon"), role: "button", "aria-label": "Close" }, React.createElement(IconClose, null)))); var ariaProps = title ? { 'aria-labelledby': "arco-dialog-".concat(dialogIndex.current) } : {}; var modalDom = React.createElement("div", __assign({ role: "dialog" }, ariaProps, { className: cs(prefixCls, (_a = {}, _a["".concat(prefixCls, "-simple")] = simple, _a["".concat(prefixCls, "-rtl")] = rtl, _a), className), style: style }), innerFocusLock ? element : element); var setTransformOrigin = function setTransformOrigin(e) { if (haveOriginTransformOrigin.current) return; var transformOrigin = ''; if (cursorPositionRef.current) { var eRect = e.getBoundingClientRect(); var _a = cursorPositionRef.current, left = _a.left, top_1 = _a.top; transformOrigin = "".concat(left - eRect.left, "px ").concat(top_1 - eRect.top, "px"); } e.style.transformOrigin = transformOrigin; }; return React.createElement(Portal, { visible: visible, forceRender: !mountOnEnter, getContainer: getPopupContainer }, React.createElement("div", { ref: ref }, mask ? React.createElement(CSSTransition, { in: visible, timeout: 400, appear: true, mountOnEnter: mountOnEnter, classNames: "fadeModal", unmountOnExit: unmountOnExit, onEnter: function onEnter(e) { e.style.display = 'block'; }, onExited: function onExited(e) { e.style.display = 'none'; } }, React.createElement("div", { "aria-hidden": true, className: "".concat(prefixCls, "-mask"), style: maskStyle })) : null, React.createElement("div", __assign({}, omit(rest, ['content', 'icon', 'showIcon', 'isNotice', 'noticeType', 'onCancel', 'onOk', 'onConfirm', 'closable', 'prefixCls']), { tabIndex: !innerFocusLock || !innerAutoFocus ? -1 : null, ref: modalWrapperRef, className: cs("".concat(prefixCls, "-wrapper"), (_b = {}, _b["".concat(prefixCls, "-wrapper-no-mask")] = !mask, _b["".concat(prefixCls, "-wrapper-align-center")] = alignCenter, _b["".concat(prefixCls, "-wrapper-rtl")] = rtl, _b), wrapClassName), style: __assign(__assign({}, wrapStyle || {}), { // 必须 visible=false,立即设置display:none,否则modal加载react-monaco-editor的时候,编辑器显示异常 display: visible || wrapperVisible ? 'block' : 'none', overflow: !visible && wrapperVisible ? 'hidden' : '' }), // 如果 autoFocus 是 false 需要在 modal 外层绑定 onKeyDown, 因为此时 FocusLock 绑定的 onKeyDown 不起作用 onKeyDown: !innerFocusLock || !innerAutoFocus ? onEscExit : null, onMouseDown: function onMouseDown(e) { maskClickRef.current = e.target === e.currentTarget; }, onClick: onClickMask }), React.createElement(CSSTransition, { in: visible, timeout: 400, appear: true, classNames: "zoomModal", unmountOnExit: unmountOnExit, mountOnEnter: mountOnEnter, onEnter: function onEnter(e) { setWrapperVisible(true); cursorPositionRef.current = cursorPosition; haveOriginTransformOrigin.current = !!e.style.transformOrigin; setTransformOrigin(e); }, onEntered: function onEntered(e) { setTransformOrigin(e); cursorPositionRef.current = null; afterOpen && afterOpen(); }, onExit: function onExit() { inExit.current = true; }, onExited: function onExited(e) { setWrapperVisible(false); setTransformOrigin(e); afterClose && afterClose(); inExit.current = false; } }, React.cloneElement(isFunction(modalRender) ? modalRender(modalDom) : modalDom, { onMouseDown: function onMouseDown() { maskClickRef.current = false; }, onMouseUp: function onMouseUp() { maskClickRef.current = false; } }))))); } var ExportedModalComponent = forwardRef(Modal); ExportedModalComponent.displayName = 'Modal'; ExportedModalComponent.config = setModalConfig; ExportedModalComponent.confirm = function (props) { return confirm(props); }; ExportedModalComponent.useModal = useModal; ['info', 'success', 'warning', 'error'].forEach(function (type) { ExportedModalComponent[type] = function (props) { return confirm(__assign(__assign({}, props), { isNotice: true, noticeType: type })); }; }); ExportedModalComponent.destroyAll = function () { while (destroyList.length) { var close_1 = destroyList.pop(); if (close_1) { close_1(); } } }; export default ExportedModalComponent;