diff --git a/components/float-button/FloatButtonGroup.tsx b/components/float-button/FloatButtonGroup.tsx index c4d0bc6684..92056eb637 100644 --- a/components/float-button/FloatButtonGroup.tsx +++ b/components/float-button/FloatButtonGroup.tsx @@ -1,8 +1,9 @@ -import React, { memo, useCallback, useContext, useEffect } from 'react'; +import React, { memo, useContext } from 'react'; import CloseOutlined from '@ant-design/icons/CloseOutlined'; import FileTextOutlined from '@ant-design/icons/FileTextOutlined'; import classNames from 'classnames'; import CSSMotion from 'rc-motion'; +import { useEvent } from 'rc-util'; import useMergedState from 'rc-util/lib/hooks/useMergedState'; import { devUseWarning } from '../_util/warning'; @@ -11,7 +12,7 @@ import { ConfigContext } from '../config-provider'; import useCSSVarCls from '../config-provider/hooks/useCSSVarCls'; import { FloatButtonGroupProvider } from './context'; import FloatButton, { floatButtonPrefixCls } from './FloatButton'; -import type { FloatButtonGroupProps, FloatButtonRef } from './interface'; +import type { FloatButtonGroupProps } from './interface'; import useStyle from './style'; const FloatButtonGroup: React.FC = (props) => { @@ -28,6 +29,7 @@ const FloatButtonGroup: React.FC = (props) => { children, onOpenChange, open: customOpen, + onClick: onTriggerButtonClick, ...floatButtonProps } = props; @@ -53,53 +55,61 @@ const FloatButtonGroup: React.FC = (props) => { const floatButtonGroupRef = React.useRef(null); - const floatButtonRef = React.useRef(null); - - const hoverAction = React.useMemo>(() => { - const hoverTypeAction = { - onMouseEnter() { - setOpen(true); - onOpenChange?.(true); - }, - onMouseLeave() { - setOpen(false); - onOpenChange?.(false); - }, - }; - return trigger === 'hover' ? hoverTypeAction : {}; - }, [trigger]); - - const handleOpenChange = () => { - setOpen((prevState) => { - onOpenChange?.(!prevState); - return !prevState; - }); + // ========================== Open ========================== + const hoverTrigger = trigger === 'hover'; + const clickTrigger = trigger === 'click'; + + const triggerOpen = useEvent((nextOpen: boolean) => { + if (open !== nextOpen) { + setOpen(nextOpen); + onOpenChange?.(nextOpen); + } + }); + + // ===================== Trigger: Hover ===================== + const onMouseEnter = () => { + if (hoverTrigger) { + triggerOpen(true); + } + }; + + const onMouseLeave = () => { + if (hoverTrigger) { + triggerOpen(false); + } + }; + + // ===================== Trigger: Click ===================== + const onInternalTriggerButtonClick: FloatButtonGroupProps['onClick'] = (e) => { + if (clickTrigger) { + triggerOpen(!open); + } + onTriggerButtonClick?.(e); }; - const onClick = useCallback( - (e: MouseEvent) => { - if (floatButtonGroupRef.current?.contains(e.target as Node)) { - if (floatButtonRef.current?.contains(e.target as Node)) { - handleOpenChange(); + React.useEffect(() => { + if (clickTrigger) { + const onDocClick = (e: MouseEvent) => { + // Skip if click on the group + if (floatButtonGroupRef.current?.contains(e.target as Node)) { + return; } - return; - } - setOpen(false); - onOpenChange?.(false); - }, - [trigger], - ); - useEffect(() => { - if (trigger === 'click') { - document.addEventListener('click', onClick); + triggerOpen(false); + }; + + document.addEventListener('click', onDocClick, { + capture: true, + }); return () => { - document.removeEventListener('click', onClick); + document.removeEventListener('click', onDocClick, { + capture: true, + }); }; } - }, [trigger]); + }, [clickTrigger]); - // =================== Warning ===================== + // ======================== Warning ========================= if (process.env.NODE_ENV !== 'production') { const warning = devUseWarning('FloatButton.Group'); @@ -110,9 +120,17 @@ const FloatButtonGroup: React.FC = (props) => { ); } + // ========================= Render ========================= return wrapCSSVar( -
+
{trigger && ['click', 'hover'].includes(trigger) ? ( <> @@ -121,12 +139,12 @@ const FloatButtonGroup: React.FC = (props) => { )}