diff --git a/UNRELEASED.md b/UNRELEASED.md
index ea91b1bdc80..14b2a598a6f 100644
--- a/UNRELEASED.md
+++ b/UNRELEASED.md
@@ -15,6 +15,7 @@ Use [the changelog guidelines](https://git.io/polaris-changelog-guidelines) to f
- Fixed tabs that don't wrap correctly on small screens in pre-iOS 13 Safari ([#2232](https://github.com/Shopify/polaris-react/pull/2232))
- Fixed `BulkActions` checkbox losing on selection focus ([#2138](https://github.com/Shopify/polaris-react/pull/2138))
- Moved rendering of the portal component’s node within the node created by the theme provider component to enable theming through CSS Custom Properties ([#2224](https://github.com/Shopify/polaris-react/pull/2224))
+- Fixed bug which caused the `Popover` overlay to remain in the DOM if it was updated during exiting ([#2246](https://github.com/Shopify/polaris-react/pull/2246))
### Documentation
diff --git a/src/components/Popover/components/PopoverOverlay/PopoverOverlay.tsx b/src/components/Popover/components/PopoverOverlay/PopoverOverlay.tsx
index 2ff8b59f766..b88e2d10d98 100644
--- a/src/components/Popover/components/PopoverOverlay/PopoverOverlay.tsx
+++ b/src/components/Popover/components/PopoverOverlay/PopoverOverlay.tsx
@@ -85,11 +85,10 @@ export class PopoverOverlay extends React.PureComponent<
}
componentDidUpdate(oldProps: PopoverOverlayProps) {
- this.clearTransitionTimeout();
-
if (this.props.active && !oldProps.active) {
this.focusContent();
this.changeTransitionStatus(TransitionStatus.Entering, () => {
+ this.clearTransitionTimeout();
this.enteringTimer = window.setTimeout(() => {
this.setState({transitionStatus: TransitionStatus.Entered});
}, durationBase);
@@ -98,6 +97,7 @@ export class PopoverOverlay extends React.PureComponent<
if (!this.props.active && oldProps.active) {
this.changeTransitionStatus(TransitionStatus.Exiting, () => {
+ this.clearTransitionTimeout();
this.exitingTimer = window.setTimeout(() => {
this.setState({transitionStatus: TransitionStatus.Exited});
}, durationBase);
diff --git a/src/components/Popover/components/PopoverOverlay/tests/PopoverOverlay.test.tsx b/src/components/Popover/components/PopoverOverlay/tests/PopoverOverlay.test.tsx
index 75f859f3f41..95c173ca6e7 100644
--- a/src/components/Popover/components/PopoverOverlay/tests/PopoverOverlay.test.tsx
+++ b/src/components/Popover/components/PopoverOverlay/tests/PopoverOverlay.test.tsx
@@ -1,4 +1,5 @@
import React from 'react';
+import {ReactWrapper} from 'enzyme';
import {mountWithAppProvider} from 'test-utilities/legacy';
import {TextContainer} from 'components';
import {Key} from '../../../../../types';
@@ -174,6 +175,43 @@ describe('', () => {
/PopoverOverlay-entering/,
);
});
+
+ it('does not render after exiting when the component is updated during exit', () => {
+ jest.useFakeTimers();
+
+ const popoverOverlay = mountWithAppProvider(
+
+ {children}
+ ,
+ );
+
+ // Start exiting
+ close(popoverOverlay);
+
+ // Update before exiting is complete
+ triggerSomeUpdate(popoverOverlay);
+
+ // Run any timers and a final update for changed state
+ jest.runOnlyPendingTimers();
+ popoverOverlay.update();
+
+ expect(popoverOverlay.find(PositionedOverlay)).toHaveLength(0);
+ });
});
function noop() {}
+
+function close(wrapper: ReactWrapper) {
+ wrapper.setProps({active: false});
+ wrapper.update();
+}
+
+function triggerSomeUpdate(wrapper: ReactWrapper) {
+ wrapper.setProps({fullWidth: true});
+ wrapper.update();
+}