feat: ⌨️ Popconfirm can be closed by pressing ESC (#24420)

* feat: support ESC to close Popconfirm

close #15203

* add test case

* fix focus in other element inside inner-content

* no fit

* fix snapshot

* refactor it

* use util cloneElement

* fix test case
This commit is contained in:
偏右 2020-05-25 17:43:59 +08:00 committed by GitHub
parent 4b485d393b
commit c93400d375
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 44 additions and 4 deletions

View File

@ -176,4 +176,23 @@ describe('Popconfirm', () => {
triggerNode.simulate('click'); triggerNode.simulate('click');
expect(ref.current.getPopupDomNode()).toBeFalsy(); expect(ref.current.getPopupDomNode()).toBeFalsy();
}); });
it('should be closed by pressing ESC', () => {
const onVisibleChange = jest.fn();
const wrapper = mount(
<Popconfirm
title="title"
mouseEnterDelay={0}
mouseLeaveDelay={0}
onVisibleChange={onVisibleChange}
>
<span>Delete</span>
</Popconfirm>,
);
const triggerNode = wrapper.find('span').at(0);
triggerNode.simulate('click');
expect(onVisibleChange).toHaveBeenLastCalledWith(true, undefined);
triggerNode.simulate('keydown', { key: 'Escape', keyCode: 27 });
expect(onVisibleChange).toHaveBeenLastCalledWith(false, eventObject);
});
}); });

View File

@ -1,5 +1,6 @@
import * as React from 'react'; import * as React from 'react';
import ExclamationCircleFilled from '@ant-design/icons/ExclamationCircleFilled'; import ExclamationCircleFilled from '@ant-design/icons/ExclamationCircleFilled';
import KeyCode from 'rc-util/lib/KeyCode';
import Tooltip, { AbstractTooltipProps } from '../tooltip'; import Tooltip, { AbstractTooltipProps } from '../tooltip';
import Button from '../button'; import Button from '../button';
import { LegacyButtonType, NativeButtonProps, convertLegacyProps } from '../button/button'; import { LegacyButtonType, NativeButtonProps, convertLegacyProps } from '../button/button';
@ -7,6 +8,7 @@ import LocaleReceiver from '../locale-provider/LocaleReceiver';
import defaultLocale from '../locale/default'; import defaultLocale from '../locale/default';
import { ConfigContext } from '../config-provider'; import { ConfigContext } from '../config-provider';
import { getRenderPropValue, RenderFunction } from '../_util/getRenderPropValue'; import { getRenderPropValue, RenderFunction } from '../_util/getRenderPropValue';
import { cloneElement } from '../_util/reactNode';
export interface PopconfirmProps extends AbstractTooltipProps { export interface PopconfirmProps extends AbstractTooltipProps {
title: React.ReactNode | RenderFunction; title: React.ReactNode | RenderFunction;
@ -19,7 +21,10 @@ export interface PopconfirmProps extends AbstractTooltipProps {
okButtonProps?: NativeButtonProps; okButtonProps?: NativeButtonProps;
cancelButtonProps?: NativeButtonProps; cancelButtonProps?: NativeButtonProps;
icon?: React.ReactNode; icon?: React.ReactNode;
onVisibleChange?: (visible: boolean, e?: React.MouseEvent<HTMLElement>) => void; onVisibleChange?: (
visible: boolean,
e?: React.MouseEvent<HTMLElement> | React.KeyboardEvent<HTMLDivElement>,
) => void;
} }
export interface PopconfirmState { export interface PopconfirmState {
@ -46,7 +51,10 @@ const Popconfirm = React.forwardRef<unknown, PopconfirmProps>((props, ref) => {
} }
}, [props.defaultVisible]); }, [props.defaultVisible]);
const settingVisible = (value: boolean, e?: React.MouseEvent<HTMLButtonElement>) => { const settingVisible = (
value: boolean,
e?: React.MouseEvent<HTMLButtonElement> | React.KeyboardEvent<HTMLDivElement>,
) => {
if (!('visible' in props)) { if (!('visible' in props)) {
setVisible(value); setVisible(value);
} }
@ -72,6 +80,12 @@ const Popconfirm = React.forwardRef<unknown, PopconfirmProps>((props, ref) => {
} }
}; };
const onKeyDown = (e: React.KeyboardEvent<HTMLDivElement>) => {
if (e.keyCode === KeyCode.ESC && visible) {
settingVisible(false, e);
}
};
const onVisibleChange = (value: boolean) => { const onVisibleChange = (value: boolean) => {
const { disabled } = props; const { disabled } = props;
if (disabled) { if (disabled) {
@ -107,7 +121,7 @@ const Popconfirm = React.forwardRef<unknown, PopconfirmProps>((props, ref) => {
const { getPrefixCls } = React.useContext(ConfigContext); const { getPrefixCls } = React.useContext(ConfigContext);
const { prefixCls: customizePrefixCls, placement, ...restProps } = props; const { prefixCls: customizePrefixCls, placement, children, ...restProps } = props;
const prefixCls = getPrefixCls('popover', customizePrefixCls); const prefixCls = getPrefixCls('popover', customizePrefixCls);
const overlay = ( const overlay = (
@ -125,7 +139,14 @@ const Popconfirm = React.forwardRef<unknown, PopconfirmProps>((props, ref) => {
visible={visible} visible={visible}
overlay={overlay} overlay={overlay}
ref={ref as any} ref={ref as any}
/> >
{cloneElement(children, {
onKeyDown: (e: React.KeyboardEvent<any>) => {
children?.props.onKeyDown?.(e);
onKeyDown(e);
},
})}
</Tooltip>
); );
}); });