mirror of
https://gitee.com/ant-design/ant-design.git
synced 2024-12-02 03:59:01 +08:00
feat(modal): Ingested changes from rc-dialog to disable modal close button (#50522)
Co-authored-by: Alina Andrieieva <Alina_Andrieieva@epam.com> Co-authored-by: afc163 <afc163@gmail.com>
This commit is contained in:
parent
b5b0918970
commit
a75c481ddf
@ -1,10 +1,10 @@
|
|||||||
import type { ReactNode } from 'react';
|
import type { ReactNode } from 'react';
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
import CloseOutlined from '@ant-design/icons/CloseOutlined';
|
import CloseOutlined from '@ant-design/icons/CloseOutlined';
|
||||||
|
import type { DialogProps } from 'rc-dialog';
|
||||||
import pickAttrs from 'rc-util/lib/pickAttrs';
|
import pickAttrs from 'rc-util/lib/pickAttrs';
|
||||||
|
|
||||||
export type BaseClosableType = { closeIcon?: React.ReactNode } & React.AriaAttributes;
|
export type ClosableType = DialogProps['closable'];
|
||||||
export type ClosableType = boolean | BaseClosableType;
|
|
||||||
|
|
||||||
export type BaseContextClosable = { closable?: ClosableType; closeIcon?: ReactNode };
|
export type BaseContextClosable = { closable?: ClosableType; closeIcon?: ReactNode };
|
||||||
export type ContextClosable<T extends BaseContextClosable = any> = Partial<
|
export type ContextClosable<T extends BaseContextClosable = any> = Partial<
|
||||||
@ -49,7 +49,7 @@ function useClosableConfig(closableCollection?: ClosableCollection | null) {
|
|||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
let closableConfig: BaseClosableType = {
|
let closableConfig: ClosableType = {
|
||||||
closeIcon: typeof closeIcon !== 'boolean' && closeIcon !== null ? closeIcon : undefined,
|
closeIcon: typeof closeIcon !== 'boolean' && closeIcon !== null ? closeIcon : undefined,
|
||||||
};
|
};
|
||||||
if (closable && typeof closable === 'object') {
|
if (closable && typeof closable === 'object') {
|
||||||
@ -104,10 +104,12 @@ export default function useClosable(
|
|||||||
*/
|
*/
|
||||||
closeIconRender?: (closeIcon: ReactNode) => ReactNode;
|
closeIconRender?: (closeIcon: ReactNode) => ReactNode;
|
||||||
} = EmptyFallbackCloseCollection,
|
} = EmptyFallbackCloseCollection,
|
||||||
): [closable: boolean, closeIcon: React.ReactNode | null] {
|
): [closable: boolean, closeIcon: React.ReactNode, closeBtnIsDisabled: boolean] {
|
||||||
// Align the `props`, `context` `fallback` to config object first
|
// Align the `props`, `context` `fallback` to config object first
|
||||||
const propCloseConfig = useClosableConfig(propCloseCollection);
|
const propCloseConfig = useClosableConfig(propCloseCollection);
|
||||||
const contextCloseConfig = useClosableConfig(contextCloseCollection);
|
const contextCloseConfig = useClosableConfig(contextCloseCollection);
|
||||||
|
const closeBtnIsDisabled =
|
||||||
|
typeof propCloseConfig !== 'boolean' ? !!propCloseConfig?.disabled : false;
|
||||||
const mergedFallbackCloseCollection = React.useMemo(
|
const mergedFallbackCloseCollection = React.useMemo(
|
||||||
() => ({
|
() => ({
|
||||||
closeIcon: <CloseOutlined />,
|
closeIcon: <CloseOutlined />,
|
||||||
@ -149,7 +151,7 @@ export default function useClosable(
|
|||||||
// Calculate the final closeIcon
|
// Calculate the final closeIcon
|
||||||
return React.useMemo(() => {
|
return React.useMemo(() => {
|
||||||
if (mergedClosableConfig === false) {
|
if (mergedClosableConfig === false) {
|
||||||
return [false, null];
|
return [false, null, closeBtnIsDisabled];
|
||||||
}
|
}
|
||||||
|
|
||||||
const { closeIconRender } = mergedFallbackCloseCollection;
|
const { closeIconRender } = mergedFallbackCloseCollection;
|
||||||
@ -173,6 +175,6 @@ export default function useClosable(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return [true, mergedCloseIcon];
|
return [true, mergedCloseIcon, closeBtnIsDisabled];
|
||||||
}, [mergedClosableConfig, mergedFallbackCloseCollection]);
|
}, [mergedClosableConfig, mergedFallbackCloseCollection]);
|
||||||
}
|
}
|
||||||
|
@ -107,7 +107,7 @@ const Modal: React.FC<ModalProps> = (props) => {
|
|||||||
<Footer {...props} onOk={handleOk} onCancel={handleCancel} />
|
<Footer {...props} onOk={handleOk} onCancel={handleCancel} />
|
||||||
) : null;
|
) : null;
|
||||||
|
|
||||||
const [mergedClosable, mergedCloseIcon] = useClosable(
|
const [mergedClosable, mergedCloseIcon, closeBtnIsDisabled] = useClosable(
|
||||||
pickClosable(props),
|
pickClosable(props),
|
||||||
pickClosable(modalContext),
|
pickClosable(modalContext),
|
||||||
{
|
{
|
||||||
@ -139,7 +139,11 @@ const Modal: React.FC<ModalProps> = (props) => {
|
|||||||
visible={open ?? visible}
|
visible={open ?? visible}
|
||||||
mousePosition={restProps.mousePosition ?? mousePosition}
|
mousePosition={restProps.mousePosition ?? mousePosition}
|
||||||
onClose={handleCancel as any}
|
onClose={handleCancel as any}
|
||||||
closable={mergedClosable}
|
closable={
|
||||||
|
mergedClosable
|
||||||
|
? { disabled: closeBtnIsDisabled, closeIcon: mergedCloseIcon }
|
||||||
|
: mergedClosable
|
||||||
|
}
|
||||||
closeIcon={mergedCloseIcon}
|
closeIcon={mergedCloseIcon}
|
||||||
focusTriggerAfterClose={focusTriggerAfterClose}
|
focusTriggerAfterClose={focusTriggerAfterClose}
|
||||||
transitionName={getTransitionName(rootPrefixCls, 'zoom', props.transitionName)}
|
transitionName={getTransitionName(rootPrefixCls, 'zoom', props.transitionName)}
|
||||||
|
@ -41,6 +41,11 @@ describe('Modal', () => {
|
|||||||
expect(baseElement.querySelector('.ant-modal-close')).toBeFalsy();
|
expect(baseElement.querySelector('.ant-modal-close')).toBeFalsy();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
it('support disable close button when setting disable to true', () => {
|
||||||
|
const { baseElement } = render(<Modal open closable={{ disabled: true }} />);
|
||||||
|
expect(baseElement.querySelector('.ant-modal-close')).toHaveAttribute('disabled');
|
||||||
|
});
|
||||||
|
|
||||||
it('render correctly', () => {
|
it('render correctly', () => {
|
||||||
const { asFragment } = render(<ModalTester />);
|
const { asFragment } = render(<ModalTester />);
|
||||||
expect(asFragment().firstChild).toMatchSnapshot();
|
expect(asFragment().firstChild).toMatchSnapshot();
|
||||||
|
@ -53,7 +53,7 @@ Common props ref:[Common props](/docs/react/common-props)
|
|||||||
| cancelButtonProps | The cancel button props | [ButtonProps](/components/button/#api) | - | |
|
| cancelButtonProps | The cancel button props | [ButtonProps](/components/button/#api) | - | |
|
||||||
| cancelText | Text of the Cancel button | ReactNode | `Cancel` | |
|
| cancelText | Text of the Cancel button | ReactNode | `Cancel` | |
|
||||||
| centered | Centered Modal | boolean | false | |
|
| centered | Centered Modal | boolean | false | |
|
||||||
| closable | Whether a close (x) button is visible on top right or not | boolean \| { closeIcon?: React.ReactNode } | true | |
|
| closable | Whether a close (x) button is visible on top right or not | boolean \| { closeIcon?: React.ReactNode; disabled?: boolean; } | true | |
|
||||||
| closeIcon | Custom close icon. 5.7.0: close button will be hidden when setting to `null` or `false` | ReactNode | <CloseOutlined /> | |
|
| closeIcon | Custom close icon. 5.7.0: close button will be hidden when setting to `null` or `false` | ReactNode | <CloseOutlined /> | |
|
||||||
| confirmLoading | Whether to apply loading visual effect for OK button or not | boolean | false | |
|
| confirmLoading | Whether to apply loading visual effect for OK button or not | boolean | false | |
|
||||||
| destroyOnClose | Whether to unmount child components on onClose | boolean | false | |
|
| destroyOnClose | Whether to unmount child components on onClose | boolean | false | |
|
||||||
|
@ -54,7 +54,7 @@ demo:
|
|||||||
| cancelButtonProps | cancel 按钮 props | [ButtonProps](/components/button-cn#api) | - | |
|
| cancelButtonProps | cancel 按钮 props | [ButtonProps](/components/button-cn#api) | - | |
|
||||||
| cancelText | 取消按钮文字 | ReactNode | `取消` | |
|
| cancelText | 取消按钮文字 | ReactNode | `取消` | |
|
||||||
| centered | 垂直居中展示 Modal | boolean | false | |
|
| centered | 垂直居中展示 Modal | boolean | false | |
|
||||||
| closable | 是否显示右上角的关闭按钮 | boolean \| { closeIcon?: React.ReactNode } | true | |
|
| closable | 是否显示右上角的关闭按钮 | boolean \| { closeIcon?: React.ReactNode; disabled?: boolean; } | true | |
|
||||||
| closeIcon | 自定义关闭图标。5.7.0:设置为 `null` 或 `false` 时隐藏关闭按钮 | ReactNode | <CloseOutlined /> | |
|
| closeIcon | 自定义关闭图标。5.7.0:设置为 `null` 或 `false` 时隐藏关闭按钮 | ReactNode | <CloseOutlined /> | |
|
||||||
| confirmLoading | 确定按钮 loading | boolean | false | |
|
| confirmLoading | 确定按钮 loading | boolean | false | |
|
||||||
| destroyOnClose | 关闭时销毁 Modal 里的子元素 | boolean | false | |
|
| destroyOnClose | 关闭时销毁 Modal 里的子元素 | boolean | false | |
|
||||||
|
@ -1,7 +1,6 @@
|
|||||||
import type React from 'react';
|
import type React from 'react';
|
||||||
import type { DialogProps } from 'rc-dialog';
|
import type { DialogProps } from 'rc-dialog';
|
||||||
|
|
||||||
import type { ClosableType } from '../_util/hooks/useClosable';
|
|
||||||
import type { ButtonProps, LegacyButtonType } from '../button/button';
|
import type { ButtonProps, LegacyButtonType } from '../button/button';
|
||||||
import type { DirectionType } from '../config-provider';
|
import type { DirectionType } from '../config-provider';
|
||||||
|
|
||||||
@ -21,8 +20,6 @@ export interface ModalProps extends ModalCommonProps {
|
|||||||
confirmLoading?: boolean;
|
confirmLoading?: boolean;
|
||||||
/** The modal dialog's title */
|
/** The modal dialog's title */
|
||||||
title?: React.ReactNode;
|
title?: React.ReactNode;
|
||||||
/** Whether a close (x) button is visible on top right of the modal dialog or not. Recommend to use closeIcon instead. */
|
|
||||||
closable?: ClosableType;
|
|
||||||
/** Specify a function that will be called when a user clicks the OK button */
|
/** Specify a function that will be called when a user clicks the OK button */
|
||||||
onOk?: (e: React.MouseEvent<HTMLButtonElement>) => void;
|
onOk?: (e: React.MouseEvent<HTMLButtonElement>) => void;
|
||||||
/** Specify a function that will be called when a user clicks mask, close button on top right or Cancel button */
|
/** Specify a function that will be called when a user clicks mask, close button on top right or Cancel button */
|
||||||
@ -89,7 +86,6 @@ export interface ModalFuncProps extends ModalCommonProps {
|
|||||||
/** @deprecated Please use `open` instead. */
|
/** @deprecated Please use `open` instead. */
|
||||||
visible?: boolean;
|
visible?: boolean;
|
||||||
title?: React.ReactNode;
|
title?: React.ReactNode;
|
||||||
closable?: ClosableType;
|
|
||||||
content?: React.ReactNode;
|
content?: React.ReactNode;
|
||||||
// TODO: find out exact types
|
// TODO: find out exact types
|
||||||
onOk?: (...args: any[]) => any;
|
onOk?: (...args: any[]) => any;
|
||||||
|
@ -287,6 +287,10 @@ const genModalStyle: GenerateStyle<ModalToken> = (token) => {
|
|||||||
textRendering: 'auto',
|
textRendering: 'auto',
|
||||||
},
|
},
|
||||||
|
|
||||||
|
'&:disabled': {
|
||||||
|
pointerEvents: 'none',
|
||||||
|
},
|
||||||
|
|
||||||
'&:hover': {
|
'&:hover': {
|
||||||
color: token.modalCloseIconHoverColor,
|
color: token.modalCloseIconHoverColor,
|
||||||
backgroundColor: token.colorBgTextHover,
|
backgroundColor: token.colorBgTextHover,
|
||||||
|
Loading…
Reference in New Issue
Block a user