mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-11-10 00:27:41 +08:00
fix(android): account for chrome 108 resize (#26244)
This commit is contained in:
@ -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) => {
|
||||
|
||||
@ -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
|
||||
// --------------------------------------------------
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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);
|
||||
|
||||
|
||||
@ -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();
|
||||
|
||||
/**
|
||||
|
||||
@ -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);
|
||||
}
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user