From d5324675ef04238e6ff2e2f68eb33810bbea4f7f Mon Sep 17 00:00:00 2001 From: Nino Righi Date: Wed, 3 Dec 2025 14:16:21 +0000 Subject: [PATCH] Merged PR 2067: fix(ui-layout): Ipad Dropdown Scrolling Fix fix(ui-layout): Ipad Dropdown Scrolling Fix --- .gitignore | 3 +++ libs/ui/layout/src/lib/close-on-scroll.directive.ts | 11 +++++++---- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/.gitignore b/.gitignore index 9d4e681c5..54bd8e244 100644 --- a/.gitignore +++ b/.gitignore @@ -80,3 +80,6 @@ CLAUDE.md *.pyc .vite reports/ + +# Local iPad dev setup (proxy) +/local-dev/ diff --git a/libs/ui/layout/src/lib/close-on-scroll.directive.ts b/libs/ui/layout/src/lib/close-on-scroll.directive.ts index 6bf5594fc..566a977e4 100644 --- a/libs/ui/layout/src/lib/close-on-scroll.directive.ts +++ b/libs/ui/layout/src/lib/close-on-scroll.directive.ts @@ -84,8 +84,11 @@ export class CloseOnScrollDirective implements OnDestroy { } this.#isActive = true; - // Delay listener registration to next frame to skip any stale scroll events - this.#pendingActivation = requestAnimationFrame(() => { + // Delay listener registration to skip scroll events caused by: + // 1. Stale scroll events from before activation + // 2. iOS Safari's automatic "scroll into view" when focusing elements + // Using setTimeout with 100ms to ensure iOS scroll-into-view completes + this.#pendingActivation = window.setTimeout(() => { this.#scrollListener = (event: Event) => { const excludeElement = this.closeOnScrollExclude(); if (excludeElement?.contains(event.target as HTMLElement)) { @@ -101,12 +104,12 @@ export class CloseOnScrollDirective implements OnDestroy { { capture: true, passive: true }, ); this.#logger.debug('Activated scroll listener'); - }); + }, 100); } #deactivate(): void { if (this.#pendingActivation) { - cancelAnimationFrame(this.#pendingActivation); + clearTimeout(this.#pendingActivation); this.#pendingActivation = undefined; }