From 61d783354a3541355b289f05c6f4e0b298ac00a7 Mon Sep 17 00:00:00 2001 From: atomiks Date: Tue, 16 Apr 2024 16:46:28 +1000 Subject: [PATCH] Fix unmounting --- docs/pages/experiments/tooltip.tsx | 30 +++++++++---------- .../mui-base/src/useTooltip/useTooltip.ts | 23 ++++++++++---- 2 files changed, 33 insertions(+), 20 deletions(-) diff --git a/docs/pages/experiments/tooltip.tsx b/docs/pages/experiments/tooltip.tsx index dc6447f794..741f294675 100644 --- a/docs/pages/experiments/tooltip.tsx +++ b/docs/pages/experiments/tooltip.tsx @@ -2,21 +2,6 @@ import * as React from 'react'; import * as Tooltip from '@base_ui/react/Tooltip'; import { styled } from '@mui/system'; -export default function UnstyledTooltipIntroduction() { - return ( -
- - - Anchor - - - Tooltip - - -
- ); -} - const blue = { 400: '#3399FF', 600: '#0072E6', @@ -65,3 +50,18 @@ export const AnchorButton = styled('button')` background: ${blue[800]}; } `; + +export default function TooltipTransitionExperiment() { + return ( +
+ + + Anchor + + + Tooltip + + +
+ ); +} diff --git a/packages/mui-base/src/useTooltip/useTooltip.ts b/packages/mui-base/src/useTooltip/useTooltip.ts index 61b521a408..be5e72e6ae 100644 --- a/packages/mui-base/src/useTooltip/useTooltip.ts +++ b/packages/mui-base/src/useTooltip/useTooltip.ts @@ -24,6 +24,7 @@ import { getSide, getAlignment } from '@floating-ui/utils'; import type { UseTooltipParameters, UseTooltipReturnValue } from './useTooltip.types'; import { mergeReactProps } from '../utils/mergeReactProps'; import { useTransitionStatus } from '../Tooltip/useTransitionStatus'; +import { ownerWindow } from '../utils/owner'; /** * The basic building block for creating custom tooltips. @@ -57,6 +58,8 @@ export function useTooltip(params: UseTooltipParameters): UseTooltipReturnValue arrowPadding = 5, } = params; + const { mounted, setMounted, status } = useTransitionStatus(open); + // Using a ref assumes that the arrow element is always present in the DOM for the lifetime of // the tooltip. If this assumption ends up being false, we can switch to state to manage the // arrow's presence. @@ -151,7 +154,17 @@ export function useTooltip(params: UseTooltipParameters): UseTooltipReturnValue placement, middleware, open, - onOpenChange, + onOpenChange(openValue, eventValue, reasonValue) { + onOpenChange(openValue, eventValue, reasonValue); + const transitioningChild = refs.floating.current?.firstElementChild; + if (!openValue && transitioningChild) { + const computedStyles = ownerWindow(transitioningChild).getComputedStyle(transitioningChild); + const transitionDuration = parseFloat(computedStyles.transitionDuration); + if (transitionDuration === 0) { + setMounted(false); + } + } + }, whileElementsMounted: autoUpdate, elements: { reference: anchorEl, @@ -186,8 +199,6 @@ export function useTooltip(params: UseTooltipParameters): UseTooltipReturnValue clientPoint, ]); - const { mounted, setMounted, status } = useTransitionStatus(open); - const getAnchorProps: UseTooltipReturnValue['getAnchorProps'] = React.useCallback( (externalProps = {}) => mergeReactProps(externalProps, getReferenceProps()), [getReferenceProps], @@ -209,8 +220,10 @@ export function useTooltip(params: UseTooltipParameters): UseTooltipReturnValue pointerEvents: isHidden || followCursorAxis === 'both' ? 'none' : undefined, zIndex: 2147483647, // max z-index }, - onTransitionEnd() { - setMounted((prevMounted) => (prevMounted ? false : prevMounted)); + onTransitionEnd({ target, currentTarget }) { + if (target === currentTarget) { + setMounted((prevMounted) => (prevMounted ? false : prevMounted)); + } }, }), ),