From 6f6e23c78c81a5b7ee73cd2d8dcf53fdcfa86c1d Mon Sep 17 00:00:00 2001 From: Cory LaViska Date: Tue, 22 Jul 2025 14:00:21 -0400 Subject: [PATCH] Fix details animation by preventing overflow during animation (#1214) * don't overflow content; fixes #1149 * fix details overflow; closes #1149 --- .../docs/docs/resources/changelog.md | 5 +++ .../src/components/details/details.css | 10 +----- .../src/components/details/details.ts | 34 +++++++++++++++---- 3 files changed, 34 insertions(+), 15 deletions(-) diff --git a/packages/webawesome/docs/docs/resources/changelog.md b/packages/webawesome/docs/docs/resources/changelog.md index 829d27e42..0f8d995c5 100644 --- a/packages/webawesome/docs/docs/resources/changelog.md +++ b/packages/webawesome/docs/docs/resources/changelog.md @@ -13,6 +13,11 @@ Components with the Experimental badge sh ### New Features {data-no-outline} - Added the `icon-position` attribute to `` [discuss:1099] +- Added the `animating` custom state to `` + +### Bug Fixes and Improvements {data-no-outline} + +- Fixed a bug in `` that caused the content to overflow the container when animating [issue:1149] ### Bug Fixes and Improvements {data-no-outline} diff --git a/packages/webawesome/src/components/details/details.css b/packages/webawesome/src/components/details/details.css index bf21d0f87..39ba25ed4 100644 --- a/packages/webawesome/src/components/details/details.css +++ b/packages/webawesome/src/components/details/details.css @@ -129,8 +129,7 @@ details { display: none; } -/* Overflows get clipped during the closing animation if we don't wait until the close is gone. */ -:host(:not([open])) .body { +.body.animating { overflow: hidden; } @@ -140,10 +139,3 @@ details { padding-inline: var(--spacing); /* Add horizontal padding */ padding-block-end: var(--spacing); /* Add bottom padding */ } - -@keyframes show { - from { - } - to { - } -} diff --git a/packages/webawesome/src/components/details/details.ts b/packages/webawesome/src/components/details/details.ts index 3653c9ca1..b4a2dfbd5 100644 --- a/packages/webawesome/src/components/details/details.ts +++ b/packages/webawesome/src/components/details/details.ts @@ -1,5 +1,7 @@ +import type { PropertyValues } from 'lit'; import { html } from 'lit'; -import { customElement, property, query } from 'lit/decorators.js'; +import { customElement, property, query, state } from 'lit/decorators.js'; +import { classMap } from 'lit/directives/class-map.js'; import { WaAfterHideEvent } from '../../events/after-hide.js'; import { WaAfterShowEvent } from '../../events/after-show.js'; import { WaHideEvent } from '../../events/hide.js'; @@ -40,6 +42,8 @@ import styles from './details.css'; * @cssproperty --spacing - The amount of space around and between the details' content. Expects a single value. * @cssproperty [--show-duration=200ms] - The show duration to use when applying built-in animation classes. * @cssproperty [--hide-duration=200ms] - The hide duration to use when applying built-in animation classes. + * + * @cssstate animating - Applied when the details is animating expand/collapse. */ @customElement('wa-details') export default class WaDetails extends WebAwesomeElement { @@ -53,6 +57,8 @@ export default class WaDetails extends WebAwesomeElement { @query('.body') body: HTMLElement; @query('.expand-icon-slot') expandIconSlot: HTMLSlotElement; + @state() isAnimating = false; + /** * Indicates whether or not the details is open. You can toggle this attribute to show and hide the details, or you * can use the `show()` and `hide()` methods and this attribute will reflect the details' open state. @@ -74,6 +80,11 @@ export default class WaDetails extends WebAwesomeElement { /** The position of the expand/collapse icon. */ @property({ attribute: 'icon-position', reflect: true }) iconPosition: 'start' | 'end' = 'end'; + disconnectedCallback() { + super.disconnectedCallback(); + this.detailsObserver?.disconnect(); + } + firstUpdated() { this.body.style.height = this.open ? 'auto' : '0'; if (this.open) { @@ -94,9 +105,10 @@ export default class WaDetails extends WebAwesomeElement { this.detailsObserver.observe(this.details, { attributes: true }); } - disconnectedCallback() { - super.disconnectedCallback(); - this.detailsObserver?.disconnect(); + updated(changedProperties: PropertyValues) { + if (changedProperties.has('isAnimating')) { + this.customStates.set('animating', this.isAnimating); + } } private handleSummaryClick(event: MouseEvent) { @@ -171,6 +183,7 @@ export default class WaDetails extends WebAwesomeElement { // Close other details with the same name this.closeOthersWithSameName(); + this.isAnimating = true; const duration = parseDuration(getComputedStyle(this.body).getPropertyValue('--show-duration')); // We can't animate to 'auto', so use the scroll height for now await animate( @@ -185,6 +198,7 @@ export default class WaDetails extends WebAwesomeElement { }, ); this.body.style.height = 'auto'; + this.isAnimating = false; this.dispatchEvent(new WaAfterShowEvent()); } else { @@ -197,6 +211,7 @@ export default class WaDetails extends WebAwesomeElement { return; } + this.isAnimating = true; const duration = parseDuration(getComputedStyle(this.body).getPropertyValue('--hide-duration')); // We can't animate from 'auto', so use the scroll height for now await animate( @@ -208,7 +223,7 @@ export default class WaDetails extends WebAwesomeElement { { duration, easing: 'linear' }, ); this.body.style.height = 'auto'; - + this.isAnimating = false; this.details.open = false; this.dispatchEvent(new WaAfterHideEvent()); } @@ -271,7 +286,14 @@ export default class WaDetails extends WebAwesomeElement { -
+