diff --git a/semcore/notice-bubble/src/NoticeBubble.tsx b/semcore/notice-bubble/src/NoticeBubble.tsx index 87def5963a..cf2b57db4b 100644 --- a/semcore/notice-bubble/src/NoticeBubble.tsx +++ b/semcore/notice-bubble/src/NoticeBubble.tsx @@ -1,6 +1,6 @@ import { Animation, Box, Flex, Portal } from '@semcore/base-components'; import Button from '@semcore/button'; -import { createComponent, Component, sstyled, Root } from '@semcore/core'; +import { createComponent, Component, sstyled, Root, lastInteraction } from '@semcore/core'; import type { Intergalactic } from '@semcore/core'; import type { WithI18nEnhanceProps } from '@semcore/core/lib/utils/enhances/i18nEnhance'; import i18nEnhance from '@semcore/core/lib/utils/enhances/i18nEnhance'; @@ -9,7 +9,7 @@ import { getFocusableIn } from '@semcore/core/lib/utils/focus-lock/getFocusableI import isNode from '@semcore/core/lib/utils/isNode'; import { useForkRef } from '@semcore/core/lib/utils/ref'; import { contextThemeEnhance } from '@semcore/core/lib/utils/ThemeProvider'; -import { useFocusLock, setFocus } from '@semcore/core/lib/utils/use/useFocusLock'; +import { setFocus, isFocusInside, useFocusLock } from '@semcore/core/lib/utils/use/useFocusLock'; import { cssVariableEnhance } from '@semcore/core/lib/utils/useCssVariable'; import { ZIndexStackingContextProvider, @@ -206,6 +206,7 @@ class ViewInfo extends Component { timer: Timer | null = null; ref = React.createRef(); closeButtonRef = React.createRef(); + triggerButtonComponent: Element | null = null; componentDidMount() { const { duration } = this.props; @@ -214,24 +215,38 @@ class ViewInfo extends Component { document.body.addEventListener('mousemove', this.handleBodyMouseMove); } + this.triggerButtonComponent = document.activeElement; + const noticeElement = this.ref.current; if (noticeElement) { - const focusableNodes = getFocusableIn(noticeElement).filter( + const allFocusableNodes = getFocusableIn(noticeElement); + const focusableNodes = allFocusableNodes.filter( (node) => node !== this.closeButtonRef.current, ); - if (focusableNodes.length > 0) { + if (focusableNodes.length > 0 || (!duration && allFocusableNodes.length > 0)) { setTimeout(() => setFocus(noticeElement), 0); } } } componentWillUnmount() { + const triggerElement = this.triggerButtonComponent; + if (this.ref.current && isFocusInside(this.ref.current) && triggerElement instanceof HTMLElement) { + setTimeout(() => setFocus(triggerElement), 0); + } + this.clearTimer(); document.body.removeEventListener('mousemove', this.handleBodyMouseMove); } + isFocusInBubble() { + const noticeElement = this.ref.current; + + return noticeElement ? isFocusInside(noticeElement) : false; + } + clearTimer() { if (this.timer) { this.timer.clear(); @@ -251,18 +266,28 @@ class ViewInfo extends Component { } }; + handleFocus = () => { + if (!this.timer) return; + this.timer.pause(); + }; + + handleBlur = () => { + if (!this.timer) return; + this.timer.resume(); + }; + handleMouseEnter = () => { if (!this.timer) return; this.timer.pause(); }; handleMouseLeave = () => { - if (!this.timer) return; + if (!this.timer || this.isFocusInBubble()) return; this.timer.resume(); }; handleBodyMouseMove = (event: MouseEvent) => { - if (!this.timer?.paused) return; + if (!this.timer?.paused || this.isFocusInBubble()) return; const rect = this.ref.current?.getBoundingClientRect(); if (!rect) return; const mouseInRect = @@ -303,10 +328,13 @@ class ViewInfo extends Component { keyframes={[styles['@enter'], styles['@exit']]} >