diff --git a/CHANGELOG.md b/CHANGELOG.md index 310ec6546..dae8445b2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Allow to override the `type` on the `Combobox.Input` ([#1476](https://github.com/tailwindlabs/headlessui/pull/1476)) - Ensure the the `` closes correctly ([#1477](https://github.com/tailwindlabs/headlessui/pull/1477)) - Only render the `FocusSentinel` if required in the `Tabs` component ([#1493](https://github.com/tailwindlabs/headlessui/pull/1493)) +- Ensure the Transition stops once DOM Nodes are hidden ([#1500](https://github.com/tailwindlabs/headlessui/pull/1500)) ### Added diff --git a/packages/@headlessui-react/src/components/transitions/transition.tsx b/packages/@headlessui-react/src/components/transitions/transition.tsx index 6145d1076..d2c02d8a0 100644 --- a/packages/@headlessui-react/src/components/transitions/transition.tsx +++ b/packages/@headlessui-react/src/components/transitions/transition.tsx @@ -218,17 +218,6 @@ let TransitionChild = forwardRefWithAs(function TransitionChild< let id = useId() - let transitionInFlight = useRef(false) - - let nesting = useNesting(() => { - // When all children have been unmounted we can only hide ourselves if and only if we are not - // transitioning ourselves. Otherwise we would unmount before the transitions are finished. - if (!transitionInFlight.current) { - setState(TreeStates.Hidden) - unregister(id) - } - }) - useEffect(() => { if (!id) return return register(id) @@ -280,13 +269,28 @@ let TransitionChild = forwardRefWithAs(function TransitionChild< return show ? 'enter' : 'leave' })() as 'enter' | 'leave' | 'idle' + let transitioning = useRef(false) + + let nesting = useNesting(() => { + if (transitioning.current) return + + // When all children have been unmounted we can only hide ourselves if and only if we are not + // transitioning ourselves. Otherwise we would unmount before the transitions are finished. + setState(TreeStates.Hidden) + unregister(id) + }) + useTransition({ container, classes, events, direction: transitionDirection, - onStart: useLatestValue(() => {}), + onStart: useLatestValue(() => { + transitioning.current = true + }), onStop: useLatestValue((direction) => { + transitioning.current = false + if (direction === 'leave' && !hasChildren(nesting)) { // When we don't have children anymore we can safely unregister from the parent and hide // ourselves. diff --git a/packages/@headlessui-react/src/hooks/use-transition.ts b/packages/@headlessui-react/src/hooks/use-transition.ts index 7c1b029dd..dcf04bc28 100644 --- a/packages/@headlessui-react/src/hooks/use-transition.ts +++ b/packages/@headlessui-react/src/hooks/use-transition.ts @@ -72,6 +72,17 @@ export function useTransition({ if (latestDirection.current === 'idle') return // We don't need to transition if (!mounted.current) return + dd.add(() => { + if (!node) return + + let rect = node.getBoundingClientRect() + + if (rect.x === 0 && rect.y === 0 && rect.width === 0 && rect.height === 0) { + // The node is completely hidden + onStop.current(latestDirection.current) + } + }) + dd.dispose() beforeEvent()