From 25209edde4be813ee72a5be38307bdfed2eda853 Mon Sep 17 00:00:00 2001 From: 7w1 Date: Mon, 20 Jul 2026 14:10:02 -0500 Subject: [PATCH 1/2] fix(pwa): make ios safe area viewport height stateless --- src/app/styles/edgeToEdgeInsets.test.ts | 6 ++++-- src/app/utils/iosPwaViewport.ts | 27 ++++++++++++++++--------- 2 files changed, 21 insertions(+), 12 deletions(-) diff --git a/src/app/styles/edgeToEdgeInsets.test.ts b/src/app/styles/edgeToEdgeInsets.test.ts index 522d31329..a5ef0e2df 100644 --- a/src/app/styles/edgeToEdgeInsets.test.ts +++ b/src/app/styles/edgeToEdgeInsets.test.ts @@ -73,9 +73,11 @@ describe('android edge-to-edge inset contract', () => { expect(indexTsx).toContain('installIosPwaViewportHeight();'); expect(iosPwaViewport).toContain("window.matchMedia('(display-mode: standalone)').matches"); expect(iosPwaViewport).toContain('const MIN_KEYBOARD_HEIGHT = 100'); - expect(iosPwaViewport).toContain('const keyboardOpen = fullHeight - visibleHeight'); - expect(iosPwaViewport).toContain('const height = keyboardOpen ? visibleBottom : fullHeight'); + expect(iosPwaViewport).toContain('isEditableFocused()'); + expect(iosPwaViewport).toContain('screenHeight - visibleHeight > MIN_KEYBOARD_HEIGHT'); expect(iosPwaViewport).toContain('window.setTimeout(updateHeight, 350)'); + expect(iosPwaViewport).not.toContain('fullHeight'); + expect(iosPwaViewport).not.toContain('viewportWidth'); }); it('removes the scattered safe-area css consumers', () => { diff --git a/src/app/utils/iosPwaViewport.ts b/src/app/utils/iosPwaViewport.ts index 326884273..9b149f1c1 100644 --- a/src/app/utils/iosPwaViewport.ts +++ b/src/app/utils/iosPwaViewport.ts @@ -5,13 +5,24 @@ const isStandaloneIosPwa = (): boolean => window.matchMedia('(display-mode: standalone)').matches && CSS.supports('-webkit-touch-callout: none'); +const isEditableFocused = (): boolean => { + const el = document.activeElement as HTMLElement | null; + if (!el) return false; + return el.tagName === 'INPUT' || el.tagName === 'TEXTAREA' || el.isContentEditable; +}; + +const fullScreenHeight = (): number => { + const { width, height } = window.screen; + return window.matchMedia('(orientation: portrait)').matches + ? Math.max(width, height) + : Math.min(width, height); +}; + export function installIosPwaViewportHeight(): void { if (!isStandaloneIosPwa()) return; let frame = 0; let settleTimer = 0; - let fullHeight = 0; - let viewportWidth = window.innerWidth; const updateHeight = () => { frame = 0; @@ -19,15 +30,11 @@ export function installIosPwaViewportHeight(): void { const visibleHeight = viewport?.height ?? window.innerHeight; const visibleBottom = visibleHeight + (viewport?.offsetTop ?? 0); - if (window.innerWidth !== viewportWidth) { - viewportWidth = window.innerWidth; - fullHeight = visibleBottom; - } - - const keyboardOpen = fullHeight - visibleHeight > MIN_KEYBOARD_HEIGHT; - if (!keyboardOpen) fullHeight = Math.max(fullHeight, visibleBottom); + const screenHeight = fullScreenHeight(); + const keyboardOpen = + isEditableFocused() && screenHeight - visibleHeight > MIN_KEYBOARD_HEIGHT; + const height = keyboardOpen ? visibleBottom : screenHeight; - const height = keyboardOpen ? visibleBottom : fullHeight; document.documentElement.style.setProperty(IOS_PWA_VIEWPORT_HEIGHT, `${Math.round(height)}px`); }; From a6dbee00995a3abc0f3d2f597f28ff6f596d08ef Mon Sep 17 00:00:00 2001 From: 7w1 Date: Mon, 20 Jul 2026 14:56:11 -0500 Subject: [PATCH 2/2] formatting --- src/app/utils/iosPwaViewport.ts | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/app/utils/iosPwaViewport.ts b/src/app/utils/iosPwaViewport.ts index 9b149f1c1..b2e5c177b 100644 --- a/src/app/utils/iosPwaViewport.ts +++ b/src/app/utils/iosPwaViewport.ts @@ -31,8 +31,7 @@ export function installIosPwaViewportHeight(): void { const visibleBottom = visibleHeight + (viewport?.offsetTop ?? 0); const screenHeight = fullScreenHeight(); - const keyboardOpen = - isEditableFocused() && screenHeight - visibleHeight > MIN_KEYBOARD_HEIGHT; + const keyboardOpen = isEditableFocused() && screenHeight - visibleHeight > MIN_KEYBOARD_HEIGHT; const height = keyboardOpen ? visibleBottom : screenHeight; document.documentElement.style.setProperty(IOS_PWA_VIEWPORT_HEIGHT, `${Math.round(height)}px`);