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
59 changes: 39 additions & 20 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,23 +41,11 @@ 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| HTMLAnchorElement>(null);

const hoverAction = useRef<React.HTMLAttributes<HTMLDivElement>>({});

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

if (trigger === 'hover') {
hoverAction.current = {
const hoverAction = useMemo(() => {
const hoverTypeAction = {
onMouseEnter() {
setOpen(true);
onOpenChange?.(true);
Expand All @@ -67,11 +55,42 @@ const FloatButtonGroup: React.FC<FloatButtonGroupProps> = (props) => {
onOpenChange?.(false);
},
};
}
return trigger === 'hover' ? hoverTypeAction : {};
}, [trigger]);

const handleOpenChange = () => {
setOpen((prevState) => {
onOpenChange?.(!prevState);
return !prevState;
});
};

const onClick = useCallback(
(e: MouseEvent) => {
if (floatButtonGroupRef.current!.contains(e.target as Node)) {
if (floatButtonRef.current!.contains(e.target as Node)) {
handleOpenChange();
}
return;
MadCcc marked this conversation as resolved.
Show resolved Hide resolved
}
setOpen(false);
onOpenChange?.(false);
},
[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 +99,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);
});
});