From 8e34a511f4d23948ec38869bd8699fc74f95ad4f Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 9 Oct 2025 19:14:24 +0000 Subject: [PATCH 1/3] Initial plan From 7068643b45ffc78106602eead6d4d98447cbc674 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 9 Oct 2025 19:25:43 +0000 Subject: [PATCH 2/3] Fix memory leak in ResizeObserver for tooltip children cleanup Co-authored-by: danielbarion <9615850+danielbarion@users.noreply.github.com> --- src/components/Tooltip/Tooltip.tsx | 18 +++++++++++++++--- 1 file changed, 15 insertions(+), 3 deletions(-) diff --git a/src/components/Tooltip/Tooltip.tsx b/src/components/Tooltip/Tooltip.tsx index 63310afb..0ef85594 100644 --- a/src/components/Tooltip/Tooltip.tsx +++ b/src/components/Tooltip/Tooltip.tsx @@ -759,17 +759,29 @@ const Tooltip = ({ }, [updateTooltipPosition]) useEffect(() => { - if (!contentWrapperRef?.current) { + if (!rendered || !contentWrapperRef?.current) { return () => null } + const timeoutIds: Set = new Set() const contentObserver = new ResizeObserver(() => { - setTimeout(() => updateTooltipPosition()) + const timeoutId = setTimeout(() => { + timeoutIds.delete(timeoutId) + if (!mounted.current) { + return + } + updateTooltipPosition() + }) + timeoutIds.add(timeoutId) }) contentObserver.observe(contentWrapperRef.current) return () => { contentObserver.disconnect() + timeoutIds.forEach((timeoutId) => { + clearTimeout(timeoutId) + }) + timeoutIds.clear() } - }, [content, contentWrapperRef?.current]) + }, [rendered, contentWrapperRef?.current]) useEffect(() => { const anchorById = document.querySelector(`[id='${anchorId}']`) From 3a644de5309bd0740fea0f3c4b8aa68f73bf10ce Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Thu, 9 Oct 2025 19:29:15 +0000 Subject: [PATCH 3/3] Add cleanup for handleShow timeout and position calculation promises Co-authored-by: danielbarion <9615850+danielbarion@users.noreply.github.com> --- src/components/Tooltip/Tooltip.tsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/components/Tooltip/Tooltip.tsx b/src/components/Tooltip/Tooltip.tsx index 0ef85594..be35ab86 100644 --- a/src/components/Tooltip/Tooltip.tsx +++ b/src/components/Tooltip/Tooltip.tsx @@ -76,6 +76,7 @@ const Tooltip = ({ const tooltipShowDelayTimerRef = useRef(null) const tooltipHideDelayTimerRef = useRef(null) const missedTransitionTimerRef = useRef(null) + const tooltipShowTimerRef = useRef(null) const [computedPosition, setComputedPosition] = useState({ tooltipStyles: {}, tooltipArrowStyles: {}, @@ -194,7 +195,8 @@ const Tooltip = ({ * wait for the component to render and calculate position * before actually showing */ - setTimeout(() => { + clearTimeoutRef(tooltipShowTimerRef) + tooltipShowTimerRef.current = setTimeout(() => { if (!mounted.current) { return } @@ -348,6 +350,9 @@ const Tooltip = ({ border, arrowSize, }).then((computedStylesData) => { + if (!mounted.current) { + return + } handleComputedPosition(computedStylesData) }) } @@ -803,6 +808,7 @@ const Tooltip = ({ return () => { clearTimeoutRef(tooltipShowDelayTimerRef) clearTimeoutRef(tooltipHideDelayTimerRef) + clearTimeoutRef(tooltipShowTimerRef) } }, [])