diff --git a/packages/design/src/tooltip/__tests__/index.test.tsx b/packages/design/src/tooltip/__tests__/index.test.tsx index a974ea529..033a0ded2 100644 --- a/packages/design/src/tooltip/__tests__/index.test.tsx +++ b/packages/design/src/tooltip/__tests__/index.test.tsx @@ -1,4 +1,4 @@ -import React from 'react'; +import React, { useState } from 'react'; import { render, fireEvent } from '@testing-library/react'; import { Tooltip } from '@oceanbase/design'; import { waitFakeTimer } from '../../../../../tests/util'; @@ -68,4 +68,72 @@ describe('Tooltip', () => { await waitFakeTimer(); expect(container.querySelector('.ant-tooltip-open')).toBeNull(); }); + + it('close icon should work correctly for open', async () => { + const Demo = () => { + const [open, setOpen] = useState(true); + return ( + { + setOpen(false); + }} + > + + + ); + }; + const { container } = render(); + + // tooltip is open by default + expect(container.querySelector('.ant-tooltip-open')).not.toBeNull(); + + // click close icon => tooltip close + const closeIconElement = document.querySelector('.ant-tooltip-close-icon'); + fireEvent.click(closeIconElement!); + await waitFakeTimer(); + expect(container.querySelector('.ant-tooltip-open')).toBeNull(); + + // mouse enter div => tooltip is still closed + const buttonElement = container.querySelector('#button'); + fireEvent.mouseEnter(buttonElement!); + await waitFakeTimer(); + expect(container.querySelector('.ant-tooltip-open')).toBeNull(); + }); + + it('close icon should work correctly for visible', async () => { + const Demo = () => { + const [visible, setVisible] = useState(true); + return ( + { + setVisible(false); + }} + > + + + ); + }; + const { container } = render(); + + // tooltip is open by default + expect(container.querySelector('.ant-tooltip-open')).not.toBeNull(); + + // click close icon => tooltip close + const closeIconElement = document.querySelector('.ant-tooltip-close-icon'); + fireEvent.click(closeIconElement!); + await waitFakeTimer(); + expect(container.querySelector('.ant-tooltip-open')).toBeNull(); + + // mouse enter div => tooltip is still closed + const buttonElement = container.querySelector('#button'); + fireEvent.mouseEnter(buttonElement!); + await waitFakeTimer(); + expect(container.querySelector('.ant-tooltip-open')).toBeNull(); + }); }); diff --git a/packages/design/src/tooltip/demo/close-icon.tsx b/packages/design/src/tooltip/demo/close-icon.tsx index ad29ef045..b3d5ed1f7 100644 --- a/packages/design/src/tooltip/demo/close-icon.tsx +++ b/packages/design/src/tooltip/demo/close-icon.tsx @@ -1,40 +1,46 @@ -import { Space, Tooltip, Button } from '@oceanbase/design'; -import { CloseCircleOutlined } from '@oceanbase/icons'; +import { Button, Space, Tooltip, message } from '@oceanbase/design'; +import { CloseCircleOutlined, ReloadOutlined, SyncOutlined } from '@oceanbase/icons'; import React, { useState } from 'react'; const App: React.FC = () => { - const [open, setOpen] = useState(true); - const log = (e: React.MouseEvent) => { - console.log(e); - }; + const [open1, setOpen1] = useState(true); + const [open2, setOpen2] = useState(true); return ( - - - - - + { - setOpen(false); - }} - onOpenChange={v => { - setOpen(v); + setOpen1(false); + message.success('Default close icon is clicked'); }} > - + } - onClose={log} + onClose={() => { + setOpen2(false); + message.success('Custom close icon is clicked'); + }} > - + + ); }; + export default App; diff --git a/packages/design/src/tooltip/index.tsx b/packages/design/src/tooltip/index.tsx index b9ff5ded3..f179dace5 100644 --- a/packages/design/src/tooltip/index.tsx +++ b/packages/design/src/tooltip/index.tsx @@ -1,6 +1,6 @@ import { Tooltip as AntTooltip, Space } from 'antd'; import type { TooltipPropsWithTitle as AntTooltipPropsWithTitle } from 'antd/es/tooltip'; -import React, { useContext, useMemo, useState } from 'react'; +import React, { useContext, useEffect, useState } from 'react'; import { CloseOutlined } from '@oceanbase/icons'; import { isNil } from 'lodash'; import { token } from '../static-function'; @@ -55,15 +55,20 @@ type CompoundedComponent = React.FC & { const Tooltip: CompoundedComponent = ({ children, + title, type = 'default', color, - overlayInnerStyle, mouseFollow, closeIcon = false, onClose, - title, + open, + defaultOpen, + onOpenChange, + visible, + defaultVisible, + onVisibleChange, + overlayInnerStyle, className, - open: propOpen, ...restProps }) => { const { getPrefixCls } = useContext(ConfigProvider.ConfigContext); @@ -73,9 +78,17 @@ const Tooltip: CompoundedComponent = ({ const { wrapSSR, hashId } = useStyle(prefixCls); const tooltipCls = classNames(className, hashId); - const [innerOpen, setInnerOpen] = useState(undefined); + const [innerOpen, setInnerOpen] = useState(open ?? visible ?? defaultOpen ?? defaultVisible); - const open = isNil(propOpen) ? innerOpen : propOpen; + const newOpen = open ?? visible ?? innerOpen; + + useEffect(() => { + if (!isNil(open)) { + setInnerOpen(open); + } else if (!isNil(visible)) { + setInnerOpen(visible); + } + }, [open, visible]); const handleCloseClick = (e: React.MouseEvent) => { e.stopPropagation(); @@ -88,27 +101,24 @@ const Tooltip: CompoundedComponent = ({ setInnerOpen(false); }; - const hasCloseIcon = !!closeIcon; - - const CloseIconNode = useMemo(() => { - if (!hasCloseIcon) { - return null; - } - return closeIcon === true ? ( + const closeIconNode = closeIcon ? ( + closeIcon === true ? ( ) : ( {closeIcon} - ); - }, [closeIcon]); + ) + ) : null; const titleNode = typeof title === 'function' ? title() : title; - const titleWithCloseIcon = ( + const newTitle = closeIcon ? ( {titleNode} - {CloseIconNode} + {closeIconNode} + ) : ( + titleNode ); const typeList = getTooltipTypeList(); @@ -129,11 +139,14 @@ const Tooltip: CompoundedComponent = ({ ) : ( { - setInnerOpen(newOpen); + open={newOpen} + defaultOpen={defaultOpen} + onOpenChange={value => { + setInnerOpen(value); + onVisibleChange?.(value); + onOpenChange?.(value); }} overlayInnerStyle={{ color: typeItem?.color,