diff --git a/docs/resources/changelog.md b/docs/resources/changelog.md index 540d9ee13..22c064f73 100644 --- a/docs/resources/changelog.md +++ b/docs/resources/changelog.md @@ -18,6 +18,7 @@ _During the beta period, these restrictions may be relaxed in the event of a mis - Fixed a bug in `` where dynamically changing slotted items wouldn't update the tree properly - Fixed a bug in `` that caused the panel to stack when clicking on the divider in mobile versions of Chrome [#862](https://github.com/shoelace-style/shoelace/issues/862) - Fixed a bug in `` that prevented flip fallbacks from working as intended +- Fixed a bug that caused concurrent animations to work incorrectly when the durations were different [#867](https://github.com/shoelace-style/shoelace/issues/867) - Improved single selection in `` so nodes expand and collapse and receive selection when clicking on the label - Renamed `expanded-icon` and `collapsed-icon` slots to `expand-icon` and `collapse-icon` in the experimental `` and `` components - Improved RTL support for `` diff --git a/src/components/dialog/dialog.ts b/src/components/dialog/dialog.ts index 9dcdbd71b..f297e73af 100644 --- a/src/components/dialog/dialog.ts +++ b/src/components/dialog/dialog.ts @@ -206,12 +206,25 @@ export default class SlDialog extends ShoelaceElement { await Promise.all([stopAnimations(this.dialog), stopAnimations(this.overlay)]); const panelAnimation = getAnimation(this, 'dialog.hide', { dir: this.localize.dir() }); const overlayAnimation = getAnimation(this, 'dialog.overlay.hide', { dir: this.localize.dir() }); + + // Animate the overlay and the panel at the same time. Because animation durations might be different, we need to + // hide each one individually when the animation finishes, otherwise the first one that finishes will reappear + // unexpectedly. We'll unhide them after all animations have completed. await Promise.all([ - animateTo(this.panel, panelAnimation.keyframes, panelAnimation.options), - animateTo(this.overlay, overlayAnimation.keyframes, overlayAnimation.options) + animateTo(this.overlay, overlayAnimation.keyframes, overlayAnimation.options).then(() => { + this.overlay.hidden = true; + }), + animateTo(this.panel, panelAnimation.keyframes, panelAnimation.options).then(() => { + this.panel.hidden = true; + }) ]); + this.dialog.hidden = true; + // Now that the dialog is hidden, restore the overlay and panel for next time + this.overlay.hidden = false; + this.panel.hidden = false; + unlockBodyScrolling(this); // Restore focus to the original trigger diff --git a/src/components/drawer/drawer.ts b/src/components/drawer/drawer.ts index f4d555d06..ab8166b77 100644 --- a/src/components/drawer/drawer.ts +++ b/src/components/drawer/drawer.ts @@ -231,13 +231,25 @@ export default class SlDrawer extends ShoelaceElement { dir: this.localize.dir() }); const overlayAnimation = getAnimation(this, 'drawer.overlay.hide', { dir: this.localize.dir() }); + + // Animate the overlay and the panel at the same time. Because animation durations might be different, we need to + // hide each one individually when the animation finishes, otherwise the first one that finishes will reappear + // unexpectedly. We'll unhide them after all animations have completed. await Promise.all([ - animateTo(this.panel, panelAnimation.keyframes, panelAnimation.options), - animateTo(this.overlay, overlayAnimation.keyframes, overlayAnimation.options) + animateTo(this.overlay, overlayAnimation.keyframes, overlayAnimation.options).then(() => { + this.overlay.hidden = true; + }), + animateTo(this.panel, panelAnimation.keyframes, panelAnimation.options).then(() => { + this.panel.hidden = true; + }) ]); this.drawer.hidden = true; + // Now that the dialog is hidden, restore the overlay and panel for next time + this.overlay.hidden = false; + this.panel.hidden = false; + // Restore focus to the original trigger const trigger = this.originalTrigger; if (typeof trigger?.focus === 'function') {