From ad1f8ac2b3d5b7100c4b242c1b70d81dbbefbae8 Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Mon, 29 Aug 2022 15:57:06 +0000 Subject: [PATCH 1/5] chore(): add test file --- .../utils/input-shims/hacks/test/index.html | 94 +++++++++++++++++++ 1 file changed, 94 insertions(+) create mode 100644 core/src/utils/input-shims/hacks/test/index.html diff --git a/core/src/utils/input-shims/hacks/test/index.html b/core/src/utils/input-shims/hacks/test/index.html new file mode 100644 index 00000000000..4cf4103a7e1 --- /dev/null +++ b/core/src/utils/input-shims/hacks/test/index.html @@ -0,0 +1,94 @@ + + + + + Scroll Padding + + + + + + + + + +
+ + + + Modal - Inline + + + + + + Input Above Keyboard + + + + + Textarea Above Keyboard + + + +
+ + + Input Below Keyboard + + + + + Textarea Below Keyboard + + + +
+ + + Input Outside Viewport + + + + + Textarea Outside Viewport + + +
+ + +
+ + From 6d679825a1159fac9c684cb75315a6a07dff962a Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Mon, 29 Aug 2022 16:22:39 +0000 Subject: [PATCH 2/5] test(scroll-assist): add basic scroll assist tests --- .../utils/input-shims/hacks/test/index.html | 2 +- .../hacks/test/scroll-assist.e2e.ts | 60 +++++++++++++++++++ 2 files changed, 61 insertions(+), 1 deletion(-) create mode 100644 core/src/utils/input-shims/hacks/test/scroll-assist.e2e.ts diff --git a/core/src/utils/input-shims/hacks/test/index.html b/core/src/utils/input-shims/hacks/test/index.html index 4cf4103a7e1..ac588d0ce82 100644 --- a/core/src/utils/input-shims/hacks/test/index.html +++ b/core/src/utils/input-shims/hacks/test/index.html @@ -59,7 +59,7 @@
- + Input Below Keyboard diff --git a/core/src/utils/input-shims/hacks/test/scroll-assist.e2e.ts b/core/src/utils/input-shims/hacks/test/scroll-assist.e2e.ts new file mode 100644 index 00000000000..977964cd141 --- /dev/null +++ b/core/src/utils/input-shims/hacks/test/scroll-assist.e2e.ts @@ -0,0 +1,60 @@ +import { expect } from '@playwright/test'; +import type { Locator } from '@playwright/test'; +import { test } from '@utils/test/playwright'; + +test.describe('scroll-assist', () => { + const getScrollPosition = async (contentEl: Locator) => { + return await contentEl.evaluate(async (el: HTMLIonContentElement) => { + const scrollEl = await el.getScrollElement(); + + return scrollEl.scrollTop; + }); + } + test.beforeEach(async ({ page, skip }) => { + skip.rtl(); + skip.mode('md', 'Scroll utils are only needed on iOS mode'); + skip.browser('firefox'); + skip.browser('chromium') + + await page.goto('/src/utils/input-shims/hacks/test'); + }) + test('should not activate when input is above the keyboard', async ({ page }) => { + const input = page.locator('#input-above-keyboard'); + const content = page.locator('ion-content'); + + await expect(await getScrollPosition(content)).toBe(0); + + await input.click(); + await expect(input.locator('input')).toBeFocused(); + await page.waitForChanges(); + + await expect(await getScrollPosition(content)).toBe(0); + }); + + test('should activate when input is below the keyboard', async ({ page }) => { + const input = page.locator('#input-below-keyboard'); + const content = page.locator('ion-content'); + + await expect(await getScrollPosition(content)).toBe(0); + + await input.click({ force: true }); + await page.waitForChanges(); + await expect(input.locator('input:not(.cloned-input)')).toBeFocused(); + + await expect(await getScrollPosition(content)).not.toBe(0); + }); + + test('should activate even when not explicitly tapping input', async ({ page }) => { + const label = page.locator('#item-below-keyboard ion-label'); + const input = page.locator('#input-below-keyboard'); + const content = page.locator('ion-content'); + + await expect(await getScrollPosition(content)).toBe(0); + + await label.click({ force: true }); + await page.waitForChanges(); + await expect(input.locator('input:not(.cloned-input)')).toBeFocused(); + + await expect(await getScrollPosition(content)).not.toBe(0); + }); +}); From 3d725b6baf9135aace9d822bf03b677aaf25b8f0 Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Mon, 29 Aug 2022 16:22:45 +0000 Subject: [PATCH 3/5] fix(scroll-assist): adjust inputs on focus --- .../utils/input-shims/hacks/scroll-assist.ts | 55 ++++--------------- 1 file changed, 11 insertions(+), 44 deletions(-) diff --git a/core/src/utils/input-shims/hacks/scroll-assist.ts b/core/src/utils/input-shims/hacks/scroll-assist.ts index b58cb76585a..a744389dc00 100644 --- a/core/src/utils/input-shims/hacks/scroll-assist.ts +++ b/core/src/utils/input-shims/hacks/scroll-assist.ts @@ -1,7 +1,7 @@ import { getScrollElement, scrollByPoint } from '../../content'; -import { pointerCoord, raf } from '../../helpers'; +import { raf } from '../../helpers'; -import { isFocused, relocateInput } from './common'; +import { relocateInput } from './common'; import { getScrollData } from './scroll-data'; export const enableScrollAssist = ( @@ -11,32 +11,18 @@ export const enableScrollAssist = ( footerEl: HTMLIonFooterElement | null, keyboardHeight: number ) => { - let coord: any; - const touchStart = (ev: Event) => { - coord = pointerCoord(ev); - }; - - const touchEnd = (ev: Event) => { - // input cover touchend/mouseup - if (!coord) { - return; - } - // get where the touchend/mouseup ended - const endCoord = pointerCoord(ev); - - // focus this input if the pointer hasn't moved XX pixels - // and the input doesn't already have focus - if (!hasPointerMoved(6, coord, endCoord) && !isFocused(inputEl)) { - // begin the input focus process - jsSetFocus(componentEl, inputEl, contentEl, footerEl, keyboardHeight); - } + /** + * When the input is about to receive + * focus, we need to move it to prevent + * mobile Safari from adjusting the viewport. + */ + const focusIn = () => { + jsSetFocus(componentEl, inputEl, contentEl, footerEl, keyboardHeight); }; - componentEl.addEventListener('touchstart', touchStart, { capture: true, passive: true }); - componentEl.addEventListener('touchend', touchEnd, true); + componentEl.addEventListener('focusin', focusIn, true); return () => { - componentEl.removeEventListener('touchstart', touchStart, true); - componentEl.removeEventListener('touchend', touchEnd, true); + componentEl.removeEventListener('focusin', focusIn, true); }; }; @@ -145,22 +131,3 @@ const jsSetFocus = async ( scrollContent(); } }; - -const hasPointerMoved = ( - threshold: number, - startCoord: PointerCoordinates | undefined, - endCoord: PointerCoordinates | undefined -) => { - if (startCoord && endCoord) { - const deltaX = startCoord.x - endCoord.x; - const deltaY = startCoord.y - endCoord.y; - const distance = deltaX * deltaX + deltaY * deltaY; - return distance > threshold * threshold; - } - return false; -}; - -export interface PointerCoordinates { - x: number; - y: number; -} From 7202c2e40d29a3f82b65690d24d854e2ed31b13f Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Mon, 29 Aug 2022 17:22:03 -0400 Subject: [PATCH 4/5] chore(): lint --- core/src/utils/input-shims/hacks/test/scroll-assist.e2e.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/core/src/utils/input-shims/hacks/test/scroll-assist.e2e.ts b/core/src/utils/input-shims/hacks/test/scroll-assist.e2e.ts index 977964cd141..5bbd28d1f9d 100644 --- a/core/src/utils/input-shims/hacks/test/scroll-assist.e2e.ts +++ b/core/src/utils/input-shims/hacks/test/scroll-assist.e2e.ts @@ -9,15 +9,15 @@ test.describe('scroll-assist', () => { return scrollEl.scrollTop; }); - } + }; test.beforeEach(async ({ page, skip }) => { skip.rtl(); skip.mode('md', 'Scroll utils are only needed on iOS mode'); skip.browser('firefox'); - skip.browser('chromium') + skip.browser('chromium'); await page.goto('/src/utils/input-shims/hacks/test'); - }) + }); test('should not activate when input is above the keyboard', async ({ page }) => { const input = page.locator('#input-above-keyboard'); const content = page.locator('ion-content'); From 4ff1cbfc6f9e49e9e693b7611b4d516eca7061c0 Mon Sep 17 00:00:00 2001 From: Liam DeBeasi Date: Thu, 1 Sep 2022 14:17:18 +0000 Subject: [PATCH 5/5] fix(scroll-assist): improve accuracy of adjustments --- core/src/utils/input-shims/hacks/common.ts | 7 +++++++ core/src/utils/input-shims/hacks/scroll-assist.ts | 4 ++-- core/src/utils/input-shims/hacks/scroll-data.ts | 4 +++- 3 files changed, 12 insertions(+), 3 deletions(-) diff --git a/core/src/utils/input-shims/hacks/common.ts b/core/src/utils/input-shims/hacks/common.ts index 0ab0463de4d..aa729221b73 100644 --- a/core/src/utils/input-shims/hacks/common.ts +++ b/core/src/utils/input-shims/hacks/common.ts @@ -59,3 +59,10 @@ const removeClone = (componentEl: HTMLElement, inputEl: HTMLElement) => { componentEl.style.pointerEvents = ''; inputEl.style.transform = ''; }; + +/** + * Factoring in 50px gives us some room + * in case the keyboard shows password/autofill bars + * asynchronously. + */ +export const SCROLL_AMOUNT_PADDING = 50; diff --git a/core/src/utils/input-shims/hacks/scroll-assist.ts b/core/src/utils/input-shims/hacks/scroll-assist.ts index a744389dc00..72845c953c9 100644 --- a/core/src/utils/input-shims/hacks/scroll-assist.ts +++ b/core/src/utils/input-shims/hacks/scroll-assist.ts @@ -1,7 +1,7 @@ import { getScrollElement, scrollByPoint } from '../../content'; import { raf } from '../../helpers'; -import { relocateInput } from './common'; +import { relocateInput, SCROLL_AMOUNT_PADDING } from './common'; import { getScrollData } from './scroll-data'; export const enableScrollAssist = ( @@ -111,7 +111,7 @@ const jsSetFocus = async ( */ if (inputEl.type === 'password') { // Add 50px to account for the "Passwords" bar - scrollData.scrollAmount += 50; + scrollData.scrollAmount += SCROLL_AMOUNT_PADDING; window.addEventListener('ionKeyboardDidShow', doubleKeyboardEventListener); } else { window.addEventListener('ionKeyboardDidShow', scrollContent); diff --git a/core/src/utils/input-shims/hacks/scroll-data.ts b/core/src/utils/input-shims/hacks/scroll-data.ts index 6a36d5309ea..1b6d83cbfa9 100644 --- a/core/src/utils/input-shims/hacks/scroll-data.ts +++ b/core/src/utils/input-shims/hacks/scroll-data.ts @@ -1,3 +1,5 @@ +import { SCROLL_AMOUNT_PADDING } from './common'; + const SCROLL_ASSIST_SPEED = 0.3; export interface ScrollData { @@ -33,7 +35,7 @@ const calcScrollData = ( // compute safe area const safeAreaTop = visibleAreaTop + 15; - const safeAreaBottom = visibleAreaBottom * 0.75; + const safeAreaBottom = visibleAreaBottom - SCROLL_AMOUNT_PADDING; // figure out if each edge of the input is within the safe area const distanceToBottom = safeAreaBottom - inputBottom;