From 2aca2e9ed9b5599404ba0c69d3cb555b23b9e8e8 Mon Sep 17 00:00:00 2001 From: Brian Ferry Date: Wed, 11 Jun 2025 13:36:50 -0400 Subject: [PATCH] fix(core): prevent race condition on programmatic scroll --- core/pfe-core/controllers/scroll-spy-controller.ts | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/core/pfe-core/controllers/scroll-spy-controller.ts b/core/pfe-core/controllers/scroll-spy-controller.ts index 5edd597f7a..5994c961a0 100644 --- a/core/pfe-core/controllers/scroll-spy-controller.ts +++ b/core/pfe-core/controllers/scroll-spy-controller.ts @@ -66,6 +66,8 @@ export class ScrollSpyController implements ReactiveController { /** Has the intersection observer found an element? */ #intersected = false; + #destinationTarget: Element | null = null; + #root: ScrollSpyControllerOptions['root']; #rootMargin?: string; @@ -201,6 +203,12 @@ export class ScrollSpyController implements ReactiveController { } async #onIo(entries: IntersectionObserverEntry[]) { + if (this.#force && this.#destinationTarget) { + if (entries.some(e => e.target === this.#destinationTarget && e.isIntersecting)) { + this.#force = false; + this.#destinationTarget = null; + } + } if (!this.#force) { for (const { target, boundingClientRect, intersectionRect } of entries) { const selector = `:is(${this.#tagNames.join(',')})[href="#${target.id}"]`; @@ -244,6 +252,7 @@ export class ScrollSpyController implements ReactiveController { public async setActive(link: EventTarget | null): Promise { this.#force = true; this.#setActive(link); + this.#destinationTarget = this.#linkTargetMap.get(link as Element) ?? null; let sawActive = false; for (const child of this.#linkChildren) { this.#markPassed(child, !sawActive); @@ -251,7 +260,5 @@ export class ScrollSpyController implements ReactiveController { sawActive = true; } } - await this.#nextIntersection(); - this.#force = false; } }