Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat[float-button]: add clickOutAutoClose feature #39501

Merged
merged 13 commits into from Dec 14, 2022
69 changes: 42 additions & 27 deletions components/float-button/FloatButtonGroup.tsx
@@ -1,4 +1,4 @@
import React, { useRef, memo, useContext } from 'react';
import React, { useRef, memo, useContext, useEffect, useCallback, useMemo } from 'react';
import CloseOutlined from '@ant-design/icons/CloseOutlined';
import FileTextOutlined from '@ant-design/icons/FileTextOutlined';
import classNames from 'classnames';
Expand Down Expand Up @@ -41,37 +41,52 @@ const FloatButtonGroup: React.FC<FloatButtonGroupProps> = (props) => {

const [open, setOpen] = useMergedState(false, { value: props.open });

const clickAction = useRef<React.HTMLAttributes<HTMLAnchorElement | HTMLButtonElement>>({});
const floatButtonGroupRef = useRef<HTMLDivElement>(null);
const floatButtonRef = useRef<HTMLButtonElement>(null);

const hoverAction = useRef<React.HTMLAttributes<HTMLDivElement>>({});
const hoverTypeAction = {
li-jia-nan marked this conversation as resolved.
Show resolved Hide resolved
onMouseEnter() {
setOpen(true);
onOpenChange?.(true);
},
onMouseLeave() {
setOpen(false);
onOpenChange?.(false);
},
};
const hoverAction = useMemo(() => (trigger === 'hover' ? hoverTypeAction : {}), [trigger]);

if (trigger === 'click') {
clickAction.current = {
onClick() {
setOpen((prevState) => {
onOpenChange?.(!prevState);
return !prevState;
});
},
};
}
const handleOpenChange = () => {
setOpen((prevState) => {
onOpenChange?.(!prevState);
return !prevState;
});
};

if (trigger === 'hover') {
hoverAction.current = {
onMouseEnter() {
setOpen(true);
onOpenChange?.(true);
},
onMouseLeave() {
setOpen(false);
onOpenChange?.(false);
},
};
}
const onClick = useCallback(
(e: MouseEvent) => {
if (trigger !== 'click') return;
MadCcc marked this conversation as resolved.
Show resolved Hide resolved
li-jia-nan marked this conversation as resolved.
Show resolved Hide resolved
if (floatButtonGroupRef.current!.contains(e.target as Node)) {
if (!floatButtonRef.current!.contains(e.target as Node)) return;
handleOpenChange();
return;
MadCcc marked this conversation as resolved.
Show resolved Hide resolved
}
},
[trigger],
);

useEffect(() => {
if (trigger === 'click') {
document.addEventListener('click', onClick);
return () => {
document.removeEventListener('click', onClick);
};
}
}, [trigger]);

return wrapSSR(
<FloatButtonGroupProvider value={shape}>
<div className={groupCls} style={style} {...hoverAction.current}>
<div ref={floatButtonGroupRef} className={groupCls} style={style} {...hoverAction}>
{trigger && ['click', 'hover'].includes(trigger) ? (
<>
<CSSMotion visible={open} motionName={`${groupPrefixCls}-wrap`}>
Expand All @@ -80,11 +95,11 @@ const FloatButtonGroup: React.FC<FloatButtonGroupProps> = (props) => {
)}
</CSSMotion>
<FloatButton
ref={floatButtonRef}
type={type}
shape={shape}
icon={open ? closeIcon : icon}
description={description}
{...clickAction.current}
/>
</>
) : (
Expand Down
26 changes: 26 additions & 0 deletions components/float-button/__tests__/group.test.tsx
Expand Up @@ -58,4 +58,30 @@ describe('FloatButtonGroup', () => {
fireEvent.mouseLeave(container.querySelector('.ant-float-btn-group')!);
expect(onOpenChange).toHaveBeenCalled();
});
it('support click floatButtonGroup not close', () => {
const onOpenChange = jest.fn();
const { container } = render(
<FloatButton.Group trigger="click" onOpenChange={onOpenChange}>
<FloatButton />
<FloatButton />
<FloatButton />
</FloatButton.Group>,
);
fireEvent.click(container.querySelector('.ant-float-btn')!);
fireEvent.click(container.querySelector('.ant-float-btn-group')!);
expect(onOpenChange).toHaveBeenCalledTimes(1);
});
it('support click out auto close', () => {
const onOpenChange = jest.fn();
const { container } = render(
<FloatButton.Group trigger="click" onOpenChange={onOpenChange}>
<FloatButton />
<FloatButton />
<FloatButton />
</FloatButton.Group>,
);
fireEvent.click(container.querySelector('.ant-float-btn')!);
fireEvent.click(container);
expect(onOpenChange).toHaveBeenCalledTimes(2);
});
});
4 changes: 2 additions & 2 deletions components/float-button/demo/group-menu.md
@@ -1,7 +1,7 @@
## zh-CN

设置 `trigger` 属性即可开启菜单模式。提供 `hover` 和 `click` 两种触发方式
设置 `trigger` 属性即可开启菜单模式。提供 `hover` 和 `click` 两种触发方式。若设置为 `click`,点击外侧会**自动关闭** `menu`

## en-US

Open menu mode with `trigger`, which could be `hover` or `click`.
Open menu mode with `trigger`, which could be `hover` or `click`. if set to `click`, `clickOutAutoClose` is enabled by default
li-jia-nan marked this conversation as resolved.
Show resolved Hide resolved