Skip to content

Commit

Permalink
feat[float-button]: add clickOutAutoClose feature
Browse files Browse the repository at this point in the history
  • Loading branch information
BoyYangzai committed Dec 12, 2022
1 parent 11a5866 commit a3978a7
Show file tree
Hide file tree
Showing 4 changed files with 84 additions and 30 deletions.
101 changes: 74 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, useState } 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,
onOpenChange,
} = props;

Expand All @@ -41,37 +42,82 @@ const FloatButtonGroup: React.FC<FloatButtonGroupProps> = (props) => {

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

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

const hoverAction = useRef<React.HTMLAttributes<HTMLDivElement>>({});
const [clickAction, setClickAction] = useState({});

if (trigger === 'click') {
clickAction.current = {
onClick() {
setOpen((prevState) => {
onOpenChange?.(!prevState);
return !prevState;
});
},
};
}
const [hoverAction, setHoverAction] = useState({});

if (trigger === 'hover') {
hoverAction.current = {
onMouseEnter() {
setOpen(true);
onOpenChange?.(true);
},
onMouseLeave() {
setOpen(false);
onOpenChange?.(false);
},
};
}
const openChange = () => {
setOpen((prevState) => {
onOpenChange?.(!prevState);
return !prevState;
});
};

const clickTypeAction = {
onClick() {
openChange();
},
};

const hoverTypeAction = {
onMouseEnter() {
setOpen(true);
onOpenChange?.(true);
},
onMouseLeave() {
setOpen(false);
onOpenChange?.(false);
},
};

useEffect(() => {
if (trigger === 'click') {
if (clickOutAutoClose) {
const BigestEl = document;
const clickFn = (e: MouseEvent) => {
let clickTarget = e.target as Node;
let clickWhich = null;
// Distinguish between clicking a button and expanding it in a group
const clickMap: Record<string, any> = {
clickButton: openChange,
clickOther: () => {},
};
while (clickTarget) {
if (clickTarget === floatButtonRef.current) {
clickWhich = 'clickButton';
break;
}
if (clickTarget === floatButtonGroupRef.current) {
clickWhich = 'clickOther';
}
clickTarget = clickTarget.parentNode!;
}
if (clickWhich) {
clickMap[clickWhich]();
return;
}
setOpen(false);
};
BigestEl?.addEventListener('click', clickFn);
} else {
setClickAction(clickTypeAction);
}
}
if (trigger === 'hover') {
setHoverAction(hoverTypeAction);
}
// 非严格模式下 会在组件卸载时自动 remove ,在合并前取消注释
// return (
// BigestEl?.removeEventListener('click', clickFn)
// )
}, []);

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 +126,12 @@ const FloatButtonGroup: React.FC<FloatButtonGroupProps> = (props) => {
)}
</CSSMotion>
<FloatButton
ref={floatButtonRef}
type={type}
shape={shape}
icon={open ? closeIcon : icon}
description={description}
{...clickAction.current}
{...clickAction}
/>
</>
) : (
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;
// 受控展开
open?: boolean;
// 关闭按钮自定义图标
Expand Down

0 comments on commit a3978a7

Please sign in to comment.