fix(accordion): moving to state-based re-rendering instead of calling forceUpdate to try to prevent race conditions

This commit is contained in:
ShaneK
2025-10-30 06:33:17 -07:00
parent e345efd50a
commit f84c48447d

View File

@ -1,5 +1,5 @@
import type { ComponentInterface } from '@stencil/core';
import { Component, Element, Host, Prop, State, Watch, forceUpdate, h } from '@stencil/core';
import { Component, Element, Host, Prop, State, Watch, h } from '@stencil/core';
import { addEventListener, getElementRoot, raf, removeEventListener, transitionEndAsync } from '@utils/helpers';
import { chevronDown } from 'ionicons/icons';
@ -48,20 +48,19 @@ export class Accordion implements ComponentInterface {
private headerEl: HTMLDivElement | undefined;
private currentRaf: number | undefined;
/**
* If true, the next animation will be skipped.
* We want to skip the animation when the accordion
* is expanded or collapsed on the initial load.
* This prevents the accordion from animating when
* it starts expanded or collapsed.
*/
private skipNextAnimation = true;
@Element() el?: HTMLElement;
@State() state: AccordionState = AccordionState.Collapsed;
@State() isNext = false;
@State() isPrevious = false;
/**
* Tracks whether the component has completed its initial render.
* Animations are disabled until after the first render completes.
* This prevents the accordion from animating when it starts
* expanded or collapsed on initial load.
*/
@State() hasRendered = false;
/**
* The value of the accordion. Defaults to an autogenerated
@ -132,14 +131,14 @@ export class Accordion implements ComponentInterface {
}
componentDidRender() {
if (this.skipNextAnimation) {
this.skipNextAnimation = false;
/**
* The initial render disables animations so framework-provided
* values do not cause the accordion to animate. Force a repaint
* so subsequent user interactions animate as expected.
*/
forceUpdate(this);
/**
* After the first render completes, mark that we've rendered.
* Setting this state property triggers a re-render, at which point
* animations will be enabled. This ensures animations are disabled
* only for the initial render, avoiding unwanted animations on load.
*/
if (!this.hasRendered) {
this.hasRendered = true;
}
}
@ -315,7 +314,12 @@ export class Accordion implements ComponentInterface {
* of what is set in the config.
*/
private shouldAnimate = () => {
if (this.skipNextAnimation) {
/**
* Don't animate until after the first render cycle completes.
* This prevents animations on initial load when accordions
* start in an expanded or collapsed state.
*/
if (!this.hasRendered) {
return false;
}
@ -351,11 +355,6 @@ export class Accordion implements ComponentInterface {
const value = accordionGroup.value;
const shouldExpand = Array.isArray(value) ? value.includes(accordionValue) : value === accordionValue;
const shouldDisableAnimation = initialUpdate && shouldExpand;
if (shouldDisableAnimation) {
this.skipNextAnimation = true;
}
if (shouldExpand) {
this.expandAccordion(initialUpdate);