@orca-fe/hooks
Version:
React Hooks Collections
241 lines (239 loc) • 7.82 kB
JavaScript
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));