diff --git a/components/_util/ActionButton.tsx b/components/_util/ActionButton.tsx index 410e9aad24..aed3cd7439 100644 --- a/components/_util/ActionButton.tsx +++ b/components/_util/ActionButton.tsx @@ -14,6 +14,11 @@ export interface ActionButtonProps { emitEvent?: boolean; quitOnNullishReturnValue?: boolean; children?: React.ReactNode; + + /** + * Do not throw if is await mode + */ + isSilent?: () => boolean; } function isThenable(thing?: PromiseLike): boolean { @@ -29,6 +34,7 @@ const ActionButton: React.FC = (props) => { close, autoFocus, emitEvent, + isSilent, quitOnNullishReturnValue, actionFn, } = props; @@ -70,6 +76,12 @@ const ActionButton: React.FC = (props) => { // See: https://github.com/ant-design/ant-design/issues/6183 setLoading(false, true); clickedRef.current = false; + + // Do not throw if is `await` mode + if (isSilent?.()) { + return; + } + return Promise.reject(e); }, ); diff --git a/components/modal/ConfirmDialog.tsx b/components/modal/ConfirmDialog.tsx index 17968cbf8b..ca9dd2f7db 100644 --- a/components/modal/ConfirmDialog.tsx +++ b/components/modal/ConfirmDialog.tsx @@ -16,6 +16,12 @@ import type { ModalFuncProps, ModalLocale } from './interface'; interface ConfirmDialogProps extends ModalFuncProps { afterClose?: () => void; close?: (...args: any[]) => void; + /** + * `close` prop support `...args` that pass to the developer + * that we can not break this. + * Provider `onClose` for internal usage + */ + onConfirm?: (confirmed: boolean) => void; autoFocusButton?: null | 'ok' | 'cancel'; rootPrefixCls: string; iconPrefixCls?: string; @@ -23,6 +29,11 @@ interface ConfirmDialogProps extends ModalFuncProps { /** @private Internal Usage. Do not override this */ locale?: ModalLocale; + + /** + * Do not throw if is await mode + */ + isSilent?: () => boolean; } export function ConfirmContent( @@ -35,6 +46,8 @@ export function ConfirmContent( onCancel, onOk, close, + onConfirm, + isSilent, okText, okButtonProps, cancelText, @@ -89,8 +102,12 @@ export function ConfirmContent( const cancelButton = mergedOkCancel && ( { + close?.(...args); + onConfirm?.(false); + }} autoFocus={autoFocusButton === 'cancel'} buttonProps={cancelButtonProps} prefixCls={`${rootPrefixCls}-btn`} @@ -112,9 +129,13 @@ export function ConfirmContent(
{cancelButton} { + close?.(...args); + onConfirm?.(true); + }} autoFocus={autoFocusButton === 'ok'} buttonProps={okButtonProps} prefixCls={`${rootPrefixCls}-btn`} diff --git a/components/modal/__tests__/hook.test.tsx b/components/modal/__tests__/hook.test.tsx index 0867fe06ad..cd12e1a032 100644 --- a/components/modal/__tests__/hook.test.tsx +++ b/components/modal/__tests__/hook.test.tsx @@ -367,4 +367,48 @@ describe('Modal.hook', () => { expect(afterClose).toHaveBeenCalledTimes(1); }); + + it('support await', async () => { + jest.useFakeTimers(); + + let notReady = true; + let lastResult: boolean | null = null; + + const Demo = () => { + const [modal, contextHolder] = Modal.useModal(); + + React.useEffect(() => { + (async () => { + lastResult = await modal.confirm({ + content: , + onOk: async () => { + if (notReady) { + notReady = false; + return Promise.reject(); + } + }, + }); + })(); + }, []); + + return contextHolder; + }; + + render(); + + // Wait for modal show + await waitFakeTimer(); + + // First time click should not close + fireEvent.click(document.querySelector('.ant-btn-primary')!); + await waitFakeTimer(); + expect(lastResult).toBeFalsy(); + + // Second time click to close + fireEvent.click(document.querySelector('.ant-btn-primary')!); + await waitFakeTimer(); + expect(lastResult).toBeTruthy(); + + jest.useRealTimers(); + }); }); diff --git a/components/modal/demo/hooks.md b/components/modal/demo/hooks.md index e4686a2515..17c9f36c0b 100644 --- a/components/modal/demo/hooks.md +++ b/components/modal/demo/hooks.md @@ -1,7 +1,7 @@ ## zh-CN -通过 `Modal.useModal` 创建支持读取 context 的 `contextHolder`。 +通过 `Modal.useModal` 创建支持读取 context 的 `contextHolder`。其中仅有 hooks 方法支持 Promise `await` 操作。 ## en-US -Use `Modal.useModal` to get `contextHolder` with context accessible issue. +Use `Modal.useModal` to get `contextHolder` with context accessible issue. Only hooks method support Promise `await` operation. diff --git a/components/modal/demo/hooks.tsx b/components/modal/demo/hooks.tsx index 135314c348..01cb9dd83e 100644 --- a/components/modal/demo/hooks.tsx +++ b/components/modal/demo/hooks.tsx @@ -22,8 +22,9 @@ const App: React.FC = () => {