Skip to content

Commit 6f6e23c

Browse files
authored
Fix details animation by preventing overflow during animation (#1214)
* don't overflow content; fixes #1149 * fix details overflow; closes #1149
1 parent 310f7a8 commit 6f6e23c

File tree

3 files changed

+34
-15
lines changed

3 files changed

+34
-15
lines changed

packages/webawesome/docs/docs/resources/changelog.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,11 @@ Components with the <wa-badge variant="warning">Experimental</wa-badge> badge sh
1313
### New Features {data-no-outline}
1414

1515
- Added the `icon-position` attribute to `<wa-details>` [discuss:1099]
16+
- Added the `animating` custom state to `<wa-details>`
17+
18+
### Bug Fixes and Improvements {data-no-outline}
19+
20+
- Fixed a bug in `<wa-details>` that caused the content to overflow the container when animating [issue:1149]
1621

1722
### Bug Fixes and Improvements {data-no-outline}
1823

packages/webawesome/src/components/details/details.css

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -129,8 +129,7 @@ details {
129129
display: none;
130130
}
131131

132-
/* Overflows get clipped during the closing animation if we don't wait until the close is gone. */
133-
:host(:not([open])) .body {
132+
.body.animating {
134133
overflow: hidden;
135134
}
136135

@@ -140,10 +139,3 @@ details {
140139
padding-inline: var(--spacing); /* Add horizontal padding */
141140
padding-block-end: var(--spacing); /* Add bottom padding */
142141
}
143-
144-
@keyframes show {
145-
from {
146-
}
147-
to {
148-
}
149-
}

packages/webawesome/src/components/details/details.ts

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1+
import type { PropertyValues } from 'lit';
12
import { html } from 'lit';
2-
import { customElement, property, query } from 'lit/decorators.js';
3+
import { customElement, property, query, state } from 'lit/decorators.js';
4+
import { classMap } from 'lit/directives/class-map.js';
35
import { WaAfterHideEvent } from '../../events/after-hide.js';
46
import { WaAfterShowEvent } from '../../events/after-show.js';
57
import { WaHideEvent } from '../../events/hide.js';
@@ -40,6 +42,8 @@ import styles from './details.css';
4042
* @cssproperty --spacing - The amount of space around and between the details' content. Expects a single value.
4143
* @cssproperty [--show-duration=200ms] - The show duration to use when applying built-in animation classes.
4244
* @cssproperty [--hide-duration=200ms] - The hide duration to use when applying built-in animation classes.
45+
*
46+
* @cssstate animating - Applied when the details is animating expand/collapse.
4347
*/
4448
@customElement('wa-details')
4549
export default class WaDetails extends WebAwesomeElement {
@@ -53,6 +57,8 @@ export default class WaDetails extends WebAwesomeElement {
5357
@query('.body') body: HTMLElement;
5458
@query('.expand-icon-slot') expandIconSlot: HTMLSlotElement;
5559

60+
@state() isAnimating = false;
61+
5662
/**
5763
* Indicates whether or not the details is open. You can toggle this attribute to show and hide the details, or you
5864
* 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 {
7480
/** The position of the expand/collapse icon. */
7581
@property({ attribute: 'icon-position', reflect: true }) iconPosition: 'start' | 'end' = 'end';
7682

83+
disconnectedCallback() {
84+
super.disconnectedCallback();
85+
this.detailsObserver?.disconnect();
86+
}
87+
7788
firstUpdated() {
7889
this.body.style.height = this.open ? 'auto' : '0';
7990
if (this.open) {
@@ -94,9 +105,10 @@ export default class WaDetails extends WebAwesomeElement {
94105
this.detailsObserver.observe(this.details, { attributes: true });
95106
}
96107

97-
disconnectedCallback() {
98-
super.disconnectedCallback();
99-
this.detailsObserver?.disconnect();
108+
updated(changedProperties: PropertyValues<this>) {
109+
if (changedProperties.has('isAnimating')) {
110+
this.customStates.set('animating', this.isAnimating);
111+
}
100112
}
101113

102114
private handleSummaryClick(event: MouseEvent) {
@@ -171,6 +183,7 @@ export default class WaDetails extends WebAwesomeElement {
171183
// Close other details with the same name
172184
this.closeOthersWithSameName();
173185

186+
this.isAnimating = true;
174187
const duration = parseDuration(getComputedStyle(this.body).getPropertyValue('--show-duration'));
175188
// We can't animate to 'auto', so use the scroll height for now
176189
await animate(
@@ -185,6 +198,7 @@ export default class WaDetails extends WebAwesomeElement {
185198
},
186199
);
187200
this.body.style.height = 'auto';
201+
this.isAnimating = false;
188202

189203
this.dispatchEvent(new WaAfterShowEvent());
190204
} else {
@@ -197,6 +211,7 @@ export default class WaDetails extends WebAwesomeElement {
197211
return;
198212
}
199213

214+
this.isAnimating = true;
200215
const duration = parseDuration(getComputedStyle(this.body).getPropertyValue('--hide-duration'));
201216
// We can't animate from 'auto', so use the scroll height for now
202217
await animate(
@@ -208,7 +223,7 @@ export default class WaDetails extends WebAwesomeElement {
208223
{ duration, easing: 'linear' },
209224
);
210225
this.body.style.height = 'auto';
211-
226+
this.isAnimating = false;
212227
this.details.open = false;
213228
this.dispatchEvent(new WaAfterHideEvent());
214229
}
@@ -271,7 +286,14 @@ export default class WaDetails extends WebAwesomeElement {
271286
</span>
272287
</summary>
273288
274-
<div class="body" role="region" aria-labelledby="header">
289+
<div
290+
class=${classMap({
291+
body: true,
292+
animating: this.isAnimating,
293+
})}
294+
role="region"
295+
aria-labelledby="header"
296+
>
275297
<slot part="content" id="content" class="content"></slot>
276298
</div>
277299
</details>

0 commit comments

Comments
 (0)