Skip to content
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,13 +64,13 @@ ReactDOM.render(
| maskTransitionName | String | | mask animation css class name | |
| title | String\|React.Element | | Title of the dialog | |
| footer | React.Element | | footer of the dialog | |
| closable | Boolean \| ({ closeIcon?: React.ReactNode; disabled?: boolean } & React.AriaAttributes | true | whether show close button | |
| closable | Boolean \| ({ closeIcon?: React.ReactNode; disabled?: boolean, afterClose:function } & React.AriaAttributes) | true | whether show close button | |
| mask | Boolean | true | whether show mask | |
| maskClosable | Boolean | true | whether click mask to close | |
| keyboard | Boolean | true | whether support press esc to close | |
| mousePosition | {x:number,y:number} | | set pageX and pageY of current mouse(it will cause transform origin to be set). | |
| onClose | function() | | called when click close button or mask | |
| afterClose | function() | | called when close animation end | |
| ~~afterClose~~ | function() | | called when close animation end | |
| getContainer | function(): HTMLElement | | to determine where Dialog will be mounted | |
| destroyOnHidden | Boolean | false | to unmount child compenents on onClose | |
| closeIcon | ReactNode | | specific the close icon. | |
Expand Down
4 changes: 2 additions & 2 deletions src/Dialog/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import KeyCode from '@rc-component/util/lib/KeyCode';
import pickAttrs from '@rc-component/util/lib/pickAttrs';
import * as React from 'react';
import { useEffect, useRef } from 'react';
import type { IDialogPropTypes } from '../IDialogPropTypes';
import type { ClosableType, IDialogPropTypes } from '../IDialogPropTypes';
import { getMotionName } from '../util';
import Content, { type ContentRef } from './Content';
import Mask from './Mask';
Expand Down Expand Up @@ -95,7 +95,7 @@ const Dialog: React.FC<IDialogPropTypes> = (props) => {

// Trigger afterClose only when change visible from true to false
if (animatedVisible) {
afterClose?.();
((closable as ClosableType)?.afterClose ?? afterClose)?.();
}
}

Expand Down
5 changes: 3 additions & 2 deletions src/DialogWrap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ import Portal from '@rc-component/portal';
import * as React from 'react';
import { RefContext } from './context';
import Dialog from './Dialog';
import type { IDialogPropTypes } from './IDialogPropTypes';
import type { ClosableType, IDialogPropTypes } from './IDialogPropTypes';

// fix issue #10656
/*
Expand All @@ -20,6 +20,7 @@ const DialogWrap: React.FC<IDialogPropTypes> = (props) => {
forceRender,
destroyOnHidden = false,
afterClose,
closable,
panelRef,
} = props;
const [animatedVisible, setAnimatedVisible] = React.useState<boolean>(visible);
Expand Down Expand Up @@ -49,7 +50,7 @@ const DialogWrap: React.FC<IDialogPropTypes> = (props) => {
{...props}
destroyOnHidden={destroyOnHidden}
afterClose={() => {
afterClose?.();
((closable as ClosableType)?.afterClose ?? afterClose)?.();
setAnimatedVisible(false);
}}
/>
Expand Down
9 changes: 8 additions & 1 deletion src/IDialogPropTypes.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,24 @@ export type ModalClassNames = Partial<Record<SemanticName, string>>;

export type ModalStyles = Partial<Record<SemanticName, CSSProperties>>;

export type ClosableType = {
closeIcon?: React.ReactNode;
disabled?: boolean;
afterClose?: () => any;
};

export type IDialogPropTypes = {
className?: string;
keyboard?: boolean;
style?: CSSProperties;
rootStyle?: CSSProperties;
mask?: boolean;
children?: React.ReactNode;
/** @description please use `closable.afterClose` instead */
afterClose?: () => any;
afterOpenChange?: (open: boolean) => void;
onClose?: (e: SyntheticEvent) => any;
closable?: boolean | ({ closeIcon?: React.ReactNode; disabled?: boolean } & React.AriaAttributes);
closable?: boolean | (ClosableType & React.AriaAttributes);
maskClosable?: boolean;
visible?: boolean;
destroyOnHidden?: boolean;
Expand Down
34 changes: 34 additions & 0 deletions tests/index.spec.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -552,6 +552,40 @@ describe('dialog', () => {

expect(afterClose).toHaveBeenCalledTimes(0);
});

it('should trigger closable.afterClose when using new API', () => {
const afterClose = jest.fn();

const { rerender } = render(<Dialog closable={{ afterClose }} visible />);
act(() => {
jest.runAllTimers();
});

rerender(<Dialog closable={{ afterClose }} visible={false} />);
act(() => {
jest.runAllTimers();
});
expect(afterClose).toHaveBeenCalledTimes(1);
});

it('should prioritize closable.afterClose when both exist', () => {
const afterClose = jest.fn();
const legacyAfterClose = jest.fn();

const { rerender } = render(
<Dialog closable={{ afterClose }} afterClose={legacyAfterClose} visible />,
);
act(() => {
jest.runAllTimers();
});

rerender(<Dialog closable={{ afterClose }} afterClose={legacyAfterClose} visible={false} />);
act(() => {
jest.runAllTimers();
});
expect(afterClose).toHaveBeenCalledTimes(1);
expect(legacyAfterClose).toHaveBeenCalledTimes(0);
});
});

describe('afterOpenChange', () => {
Expand Down