UNPKG

@orca-fe/hooks

Version:

React Hooks Collections

241 lines (239 loc) 7.82 kB
import _objectSpread from "@babel/runtime/helpers/esm/objectSpread2"; import _slicedToArray from "@babel/runtime/helpers/esm/slicedToArray"; import React, { useEffect, useMemo, useState } from 'react'; import { useDebounceFn, useMemoizedFn } from 'ahooks'; import useMemorizedFn from "./useMemorizedFn"; var emptyFn = () => undefined; export var PromisifyModalContext = /*#__PURE__*/React.createContext({ ok: emptyFn, cancel: emptyFn, destroy: emptyFn, minimize: emptyFn, resume: emptyFn, resolve: emptyFn, update: emptyFn }); var readyVisible = 'data-promisify-modal-ready'; /** * 帮助你管理维护弹框的 open 状态,适用于 antd-modal 及基于 modal 封装的自定义弹框 * 通过 show 方法,直接弹出 modal 即可。工具会自动接管 onOk 和 onCancel 事件,并更新 open * @param options */ export default function usePromisifyModal(options = {}) { var _options$openField = options.openField, openField = _options$openField === void 0 ? 'open' : _options$openField, _options$onOkField = options.onOkField, onOkField = _options$onOkField === void 0 ? 'onOk' : _options$onOkField, _options$onCloseField = options.onCloseField, onCloseField = _options$onCloseField === void 0 ? 'onCancel' : _options$onCloseField, _options$confirmLoadi = options.confirmLoadingPropName, confirmLoadingPropName = _options$confirmLoadi === void 0 ? 'confirmLoading' : _options$confirmLoadi, _options$destroyDelay = options.destroyDelay, destroyDelay = _options$destroyDelay === void 0 ? 300 : _options$destroyDelay, rejectOnClose = options.rejectOnClose; var _useState = useState(null), _useState2 = _slicedToArray(_useState, 2), instance = _useState2[0], setInstance = _useState2[1]; useEffect(() => { if (instance !== null && instance !== void 0 && instance.props[readyVisible]) { setInstance( /*#__PURE__*/React.cloneElement(instance, { [openField]: true, [readyVisible]: false })); } }, [instance]); var destroyAfterClose = useDebounceFn(() => { setInstance(null); }, { wait: destroyDelay }); var _useState3 = useState({ ok: () => {}, cancel: () => {}, resolveFn: () => {}, // 原始的 onOk 事件 originOnOk: () => {}, // 原始的 onCancel 事件 originOnCancel: () => {} }), _useState4 = _slicedToArray(_useState3, 1), _this = _useState4[0]; /** * 更新当前弹框实例的属性 */ var update = useMemorizedFn(props => { var newProps = _objectSpread({}, props); // 特殊处理,onOk 和 onCancel 已经被代理,不得通过 update 直接设置到组件实例 if (onOkField && typeof newProps[onOkField] === 'function') { _this.originOnOk = newProps[onOkField]; // eslint-disable-next-line @typescript-eslint/no-dynamic-delete delete newProps[onOkField]; } if (onCloseField && typeof newProps[onCloseField] === 'function') { _this.originOnCancel = newProps[onCloseField]; // eslint-disable-next-line @typescript-eslint/no-dynamic-delete delete newProps[onCloseField]; } setInstance(instance => instance ? /*#__PURE__*/React.cloneElement(instance, newProps) : null); }); var clearThis = () => { _this.ok = undefined; _this.cancel = undefined; _this.resolveFn = undefined; _this.originOnOk = undefined; _this.originOnCancel = undefined; }; var destroy = useMemorizedFn(() => { clearThis(); update({ [openField]: false }); destroyAfterClose.run(); }); var minimize = useMemorizedFn(() => { update({ [openField]: false }); }); var resume = useMemorizedFn(() => { update({ [openField]: true }); }); var open = useMemorizedFn((element = instance) => { var ok = () => {}; var cancel = () => {}; var resolveFn = () => {}; clearThis(); var extendHandler = () => ({ hide: destroy, destroy, ok, cancel, resolve: resolveFn }); if (!element) { // 未传入组件实例 var p = Promise.reject(new Error('Empty show')); Object.assign(p, extendHandler()); return p; } destroyAfterClose.cancel(); var key = new Date().getTime(); // 在 open 时,记录下原始的 element 的 onOk 和 onCancel 事件,用于回调 if (onOkField && typeof element.props[onOkField] === 'function') { _this.originOnOk = element.props[onOkField]; } if (onCloseField && typeof element.props[onCloseField] === 'function') { _this.originOnCancel = element.props[onCloseField]; } var handler = new Promise((resolve, reject) => { var onOkHandler = (...args) => { if (typeof _this.originOnOk === 'function') { var res = _this.originOnOk.apply(null, args); if (res instanceof Promise) { if (confirmLoadingPropName) { update({ [confirmLoadingPropName]: true }); } return res.then(r => { destroy(); if (r !== undefined) { resolve(r); } else { resolve(args[0]); } return r; }).catch(() => { if (confirmLoadingPropName) { update({ [confirmLoadingPropName]: false }); } }); } else if (res === false) { return undefined; } destroy(); resolve(args[0]); return res; } destroy(); resolve(args[0]); return undefined; }; // 代理 onCancel 事件 var onCancelHandler = (...args) => { var _this$originOnCancel; destroy(); if (rejectOnClose) { reject(new Error('close')); } (_this$originOnCancel = _this.originOnCancel) === null || _this$originOnCancel === void 0 || _this$originOnCancel.apply(null, args); return undefined; }; ok = onOkHandler; cancel = onCancelHandler; resolveFn = resolve; var newElement = /*#__PURE__*/React.cloneElement(element, _objectSpread(_objectSpread({ key, [openField]: false, [readyVisible]: true }, onOkField ? { [onOkField]: onOkHandler } : {}), onCloseField ? { [onCloseField]: onCancelHandler } : {})); setInstance(newElement); }); Object.assign(handler, extendHandler()); _this.ok = ok; _this.cancel = cancel; _this.resolveFn = resolveFn; return handler; }); var ok = useMemoizedFn((...args) => { var _this$ok; (_this$ok = _this.ok) === null || _this$ok === void 0 || _this$ok.call(_this, ...args); }); var cancel = useMemoizedFn((...args) => { var _this$cancel; (_this$cancel = _this.cancel) === null || _this$cancel === void 0 || _this$cancel.call(_this, ...args); }); var resolve = useMemoizedFn((...args) => { var _this$resolveFn; (_this$resolveFn = _this.resolveFn) === null || _this$resolveFn === void 0 || _this$resolveFn.call(_this, ...args); }); var instanceWithContext = /*#__PURE__*/React.createElement(PromisifyModalContext.Provider, { value: useMemo(() => ({ cancel, destroy, minimize, resume, ok, resolve, update }), []) }, instance); return { show: open, open, hide: destroy, destroy, instance: instanceWithContext, resume, minimize, ok, cancel, resolve, update, isOpen: Boolean(instance) }; } export var usePromisifyDrawer = (options = {}) => usePromisifyModal(_objectSpread({ onCloseField: 'onClose', onOkField: '', confirmLoadingPropName: '' }, options));