fix(android): account for chrome 108 resize (#26244)

This commit is contained in:
Liam DeBeasi
2022-11-08 15:31:23 -05:00
committed by GitHub
parent 526e4113d8
commit 1a0b9ed3ba
6 changed files with 86 additions and 19 deletions

View File

@ -25,7 +25,12 @@ export class App implements ComponentInterface {
import('../../utils/status-tap').then((module) => module.startStatusTap());
}
if (config.getBoolean('inputShims', needInputShims())) {
import('../../utils/input-shims/input-shims').then((module) => module.startInputShims(config));
/**
* needInputShims() ensures that only iOS and Android
* platforms proceed into this block.
*/
const platform = isPlatform(window, 'ios') ? 'ios' : 'android';
import('../../utils/input-shims/input-shims').then((module) => module.startInputShims(config, platform));
}
const hardwareBackButtonModule = await import('../../utils/hardware-back-button');
if (config.getBoolean('hardwareBackButton', isHybrid)) {
@ -73,7 +78,25 @@ export class App implements ComponentInterface {
}
const needInputShims = () => {
return isPlatform(window, 'ios') && isPlatform(window, 'mobile');
/**
* iOS always needs input shims
*/
const needsShimsIOS = isPlatform(window, 'ios') && isPlatform(window, 'mobile');
if (needsShimsIOS) {
return true;
}
/**
* Android only needs input shims when running
* in the browser and only if the browser is using the
* new Chrome 108+ resize behavior: https://developer.chrome.com/blog/viewport-resize-behavior/
*/
const isAndroidMobileWeb = isPlatform(window, 'android') && isPlatform(window, 'mobileweb');
if (isAndroidMobileWeb) {
return true;
}
return false;
};
const rIC = (callback: () => void) => {

View File

@ -105,12 +105,10 @@
}
}
.native-input[disabled] {
.native-input[disabled]:not(.cloned-input) {
opacity: .4;
}
// Input Cover: Unfocused
// --------------------------------------------------
// The input cover is the div that actually receives the
@ -127,6 +125,15 @@
pointer-events: none;
}
/**
* The cloned input needs to be disabled on
* Android otherwise the viewport will still
* shift when running scroll assist.
*/
.cloned-input:disabled {
opacity: 1;
}
// Clear Input Icon
// --------------------------------------------------

View File

@ -139,7 +139,7 @@
}
}
.native-textarea[disabled] {
.native-textarea[disabled]:not(.cloned-input) {
opacity: 0.4;
}
@ -159,6 +159,15 @@
pointer-events: none;
}
/**
* The cloned input needs to be disabled on
* Android otherwise the viewport will still
* shift when running scroll assist.
*/
.cloned-input:disabled {
opacity: 1;
}
:host([auto-grow]) .cloned-input {
// Workaround for webkit rendering issue with scroll assist.
// When cloning the textarea and scrolling into view,

View File

@ -4,14 +4,15 @@ export const relocateInput = (
componentEl: HTMLElement,
inputEl: HTMLInputElement | HTMLTextAreaElement,
shouldRelocate: boolean,
inputRelativeY = 0
inputRelativeY = 0,
disabledClonedInput = false
) => {
if (cloneMap.has(componentEl) === shouldRelocate) {
return;
}
if (shouldRelocate) {
addClone(componentEl, inputEl, inputRelativeY);
addClone(componentEl, inputEl, inputRelativeY, disabledClonedInput);
} else {
removeClone(componentEl, inputEl);
}
@ -24,7 +25,8 @@ export const isFocused = (input: HTMLInputElement | HTMLTextAreaElement): boolea
const addClone = (
componentEl: HTMLElement,
inputEl: HTMLInputElement | HTMLTextAreaElement,
inputRelativeY: number
inputRelativeY: number,
disabledClonedInput = false
) => {
// this allows for the actual input to receive the focus from
// the user's touch event, but before it receives focus, it
@ -38,9 +40,25 @@ const addClone = (
const parentEl = inputEl.parentNode!;
// DOM WRITES
const clonedEl = inputEl.cloneNode(false) as HTMLElement;
const clonedEl = inputEl.cloneNode(false) as HTMLInputElement | HTMLTextAreaElement;
clonedEl.classList.add('cloned-input');
clonedEl.tabIndex = -1;
/**
* Making the cloned input disabled prevents
* Chrome for Android from still scrolling
* the entire page since this cloned input
* will briefly be hidden by the keyboard
* even though it is not focused.
*
* This is not needed on iOS. While this
* does not cause functional issues on iOS,
* the input still appears slightly dimmed even
* if we set opacity: 1.
*/
if (disabledClonedInput) {
clonedEl.disabled = true;
}
parentEl.appendChild(clonedEl);
cloneMap.set(componentEl, clonedEl);

View File

@ -9,7 +9,8 @@ export const enableScrollAssist = (
inputEl: HTMLInputElement | HTMLTextAreaElement,
contentEl: HTMLElement | null,
footerEl: HTMLIonFooterElement | null,
keyboardHeight: number
keyboardHeight: number,
disableClonedInput = false
) => {
let coord: any;
const touchStart = (ev: Event) => {
@ -28,7 +29,7 @@ export const enableScrollAssist = (
// 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);
jsSetFocus(componentEl, inputEl, contentEl, footerEl, keyboardHeight, disableClonedInput);
}
};
componentEl.addEventListener('touchstart', touchStart, { capture: true, passive: true });
@ -45,7 +46,8 @@ const jsSetFocus = async (
inputEl: HTMLInputElement | HTMLTextAreaElement,
contentEl: HTMLElement | null,
footerEl: HTMLIonFooterElement | null,
keyboardHeight: number
keyboardHeight: number,
disableClonedInput = false
) => {
if (!contentEl && !footerEl) {
return;
@ -62,7 +64,7 @@ const jsSetFocus = async (
// temporarily move the focus to the focus holder so the browser
// doesn't freak out while it's trying to get the input in place
// at this point the native text input still does not have focus
relocateInput(componentEl, inputEl, true, scrollData.inputSafeY);
relocateInput(componentEl, inputEl, true, scrollData.inputSafeY, disableClonedInput);
inputEl.focus();
/**

View File

@ -12,12 +12,20 @@ const SCROLL_ASSIST = true;
const SCROLL_PADDING = true;
const HIDE_CARET = true;
export const startInputShims = (config: Config) => {
export const startInputShims = (config: Config, platform: 'ios' | 'android') => {
const doc = document;
const isIOS = platform === 'ios';
const isAndroid = platform === 'android';
/**
* Hide Caret and Input Blurring are needed on iOS.
* Scroll Assist and Scroll Padding are needed on iOS and Android
* with Chrome web browser (not Chrome webview).
*/
const keyboardHeight = config.getNumber('keyboardHeight', 290);
const scrollAssist = config.getBoolean('scrollAssist', true);
const hideCaret = config.getBoolean('hideCaretOnScroll', true);
const inputBlurring = config.getBoolean('inputBlurring', true);
const hideCaret = config.getBoolean('hideCaretOnScroll', isIOS);
const inputBlurring = config.getBoolean('inputBlurring', isIOS);
const scrollPadding = config.getBoolean('scrollPadding', true);
const inputs = Array.from(doc.querySelectorAll('ion-input, ion-textarea')) as HTMLElement[];
@ -55,7 +63,7 @@ export const startInputShims = (config: Config) => {
scrollAssist &&
!scrollAssistMap.has(componentEl)
) {
const rmFn = enableScrollAssist(componentEl, inputEl, scrollEl, footerEl, keyboardHeight);
const rmFn = enableScrollAssist(componentEl, inputEl, scrollEl, footerEl, keyboardHeight, isAndroid);
scrollAssistMap.set(componentEl, rmFn);
}
};