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
71 changes: 46 additions & 25 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 All @@ -23,6 +23,7 @@ const FloatButtonGroup: React.FC<FloatButtonGroupProps> = (props) => {
description,
trigger,
children,
clickOutAutoClose = true,
onOpenChange,
} = props;

Expand All @@ -41,37 +42,57 @@ 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(() => {
if (trigger === 'hover') {
return hoverTypeAction;
li-jia-nan marked this conversation as resolved.
Show resolved Hide resolved
}
}, [trigger]);

if (trigger === 'click') {
clickAction.current = {
onClick() {
setOpen((prevState) => {
onOpenChange?.(!prevState);
return !prevState;
});
},
};
}
const openChange = () => {
li-jia-nan marked this conversation as resolved.
Show resolved Hide resolved
setOpen((prevState) => {
onOpenChange?.(!prevState);
return !prevState;
});
};

if (trigger === 'hover') {
hoverAction.current = {
onMouseEnter() {
setOpen(true);
onOpenChange?.(true);
},
onMouseLeave() {
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;
openChange();
return;
MadCcc marked this conversation as resolved.
Show resolved Hide resolved
}
if (clickOutAutoClose) {
setOpen(false);
onOpenChange?.(false);
},
}
},
[clickOutAutoClose, trigger],
);

useEffect(() => {
document.addEventListener('click', onClick);
li-jia-nan marked this conversation as resolved.
Show resolved Hide resolved
return () => {
document.removeEventListener('click', onClick);
};
}
}, []);

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 +101,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
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`,可通过 `clickOutAutoClose` 选择是否开启点击外侧自动关闭

## 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`, you can choose whether to open by clicking `clickOutAutoClose`
7 changes: 6 additions & 1 deletion components/float-button/demo/group-menu.tsx
Expand Up @@ -3,7 +3,12 @@ import { FloatButton } from 'antd';
import { CustomerServiceOutlined, CommentOutlined } from '@ant-design/icons';

const App: React.FC = () => (
<FloatButton.Group icon={<CustomerServiceOutlined />} type="primary" trigger="click">
<FloatButton.Group
icon={<CustomerServiceOutlined />}
type="primary"
trigger='click'
clickOutAutoClose
>
<FloatButton />
<FloatButton icon={<CommentOutlined />} />
</FloatButton.Group>
Expand Down
2 changes: 2 additions & 0 deletions components/float-button/interface.ts
Expand Up @@ -36,6 +36,8 @@ export interface FloatButtonGroupProps extends FloatButtonProps {
children: React.ReactNode;
// 触发方式 (有触发方式为菜单模式)
trigger?: FloatButtonGroupTrigger;
// 触发方式为 click 时,是否开启点击外侧自动关闭
clickOutAutoClose?: boolean;
li-jia-nan marked this conversation as resolved.
Show resolved Hide resolved
// 受控展开
open?: boolean;
// 关闭按钮自定义图标
Expand Down