Skip to content

Commit 1a0b9ed

Browse files
authored
fix(android): account for chrome 108 resize (#26244)
1 parent 526e411 commit 1a0b9ed

File tree

6 files changed

+86
-19
lines changed

6 files changed

+86
-19
lines changed

core/src/components/app/app.tsx

Lines changed: 25 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,12 @@ export class App implements ComponentInterface {
2525
import('../../utils/status-tap').then((module) => module.startStatusTap());
2626
}
2727
if (config.getBoolean('inputShims', needInputShims())) {
28-
import('../../utils/input-shims/input-shims').then((module) => module.startInputShims(config));
28+
/**
29+
* needInputShims() ensures that only iOS and Android
30+
* platforms proceed into this block.
31+
*/
32+
const platform = isPlatform(window, 'ios') ? 'ios' : 'android';
33+
import('../../utils/input-shims/input-shims').then((module) => module.startInputShims(config, platform));
2934
}
3035
const hardwareBackButtonModule = await import('../../utils/hardware-back-button');
3136
if (config.getBoolean('hardwareBackButton', isHybrid)) {
@@ -73,7 +78,25 @@ export class App implements ComponentInterface {
7378
}
7479

7580
const needInputShims = () => {
76-
return isPlatform(window, 'ios') && isPlatform(window, 'mobile');
81+
/**
82+
* iOS always needs input shims
83+
*/
84+
const needsShimsIOS = isPlatform(window, 'ios') && isPlatform(window, 'mobile');
85+
if (needsShimsIOS) {
86+
return true;
87+
}
88+
89+
/**
90+
* Android only needs input shims when running
91+
* in the browser and only if the browser is using the
92+
* new Chrome 108+ resize behavior: https://developer.chrome.com/blog/viewport-resize-behavior/
93+
*/
94+
const isAndroidMobileWeb = isPlatform(window, 'android') && isPlatform(window, 'mobileweb');
95+
if (isAndroidMobileWeb) {
96+
return true;
97+
}
98+
99+
return false;
77100
};
78101

79102
const rIC = (callback: () => void) => {

core/src/components/input/input.scss

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -105,12 +105,10 @@
105105
}
106106
}
107107

108-
.native-input[disabled] {
108+
.native-input[disabled]:not(.cloned-input) {
109109
opacity: .4;
110110
}
111111

112-
113-
114112
// Input Cover: Unfocused
115113
// --------------------------------------------------
116114
// The input cover is the div that actually receives the
@@ -127,6 +125,15 @@
127125
pointer-events: none;
128126
}
129127

128+
/**
129+
* The cloned input needs to be disabled on
130+
* Android otherwise the viewport will still
131+
* shift when running scroll assist.
132+
*/
133+
.cloned-input:disabled {
134+
opacity: 1;
135+
}
136+
130137

131138
// Clear Input Icon
132139
// --------------------------------------------------

core/src/components/textarea/textarea.scss

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,7 @@
139139
}
140140
}
141141

142-
.native-textarea[disabled] {
142+
.native-textarea[disabled]:not(.cloned-input) {
143143
opacity: 0.4;
144144
}
145145

@@ -159,13 +159,22 @@
159159
pointer-events: none;
160160
}
161161

162+
/**
163+
* The cloned input needs to be disabled on
164+
* Android otherwise the viewport will still
165+
* shift when running scroll assist.
166+
*/
167+
.cloned-input:disabled {
168+
opacity: 1;
169+
}
170+
162171
:host([auto-grow]) .cloned-input {
163172
// Workaround for webkit rendering issue with scroll assist.
164173
// When cloning the textarea and scrolling into view,
165174
// a white box is rendered from the difference in height
166175
// from the auto grow container.
167176
// This change forces the cloned input to match the true
168-
// height of the textarea container.
177+
// height of the textarea container.
169178
height: 100%;
170179
}
171180

core/src/utils/input-shims/hacks/common.ts

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,15 @@ export const relocateInput = (
44
componentEl: HTMLElement,
55
inputEl: HTMLInputElement | HTMLTextAreaElement,
66
shouldRelocate: boolean,
7-
inputRelativeY = 0
7+
inputRelativeY = 0,
8+
disabledClonedInput = false
89
) => {
910
if (cloneMap.has(componentEl) === shouldRelocate) {
1011
return;
1112
}
1213

1314
if (shouldRelocate) {
14-
addClone(componentEl, inputEl, inputRelativeY);
15+
addClone(componentEl, inputEl, inputRelativeY, disabledClonedInput);
1516
} else {
1617
removeClone(componentEl, inputEl);
1718
}
@@ -24,7 +25,8 @@ export const isFocused = (input: HTMLInputElement | HTMLTextAreaElement): boolea
2425
const addClone = (
2526
componentEl: HTMLElement,
2627
inputEl: HTMLInputElement | HTMLTextAreaElement,
27-
inputRelativeY: number
28+
inputRelativeY: number,
29+
disabledClonedInput = false
2830
) => {
2931
// this allows for the actual input to receive the focus from
3032
// the user's touch event, but before it receives focus, it
@@ -38,9 +40,25 @@ const addClone = (
3840
const parentEl = inputEl.parentNode!;
3941

4042
// DOM WRITES
41-
const clonedEl = inputEl.cloneNode(false) as HTMLElement;
43+
const clonedEl = inputEl.cloneNode(false) as HTMLInputElement | HTMLTextAreaElement;
4244
clonedEl.classList.add('cloned-input');
4345
clonedEl.tabIndex = -1;
46+
47+
/**
48+
* Making the cloned input disabled prevents
49+
* Chrome for Android from still scrolling
50+
* the entire page since this cloned input
51+
* will briefly be hidden by the keyboard
52+
* even though it is not focused.
53+
*
54+
* This is not needed on iOS. While this
55+
* does not cause functional issues on iOS,
56+
* the input still appears slightly dimmed even
57+
* if we set opacity: 1.
58+
*/
59+
if (disabledClonedInput) {
60+
clonedEl.disabled = true;
61+
}
4462
parentEl.appendChild(clonedEl);
4563
cloneMap.set(componentEl, clonedEl);
4664

core/src/utils/input-shims/hacks/scroll-assist.ts

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,8 @@ export const enableScrollAssist = (
99
inputEl: HTMLInputElement | HTMLTextAreaElement,
1010
contentEl: HTMLElement | null,
1111
footerEl: HTMLIonFooterElement | null,
12-
keyboardHeight: number
12+
keyboardHeight: number,
13+
disableClonedInput = false
1314
) => {
1415
let coord: any;
1516
const touchStart = (ev: Event) => {
@@ -28,7 +29,7 @@ export const enableScrollAssist = (
2829
// and the input doesn't already have focus
2930
if (!hasPointerMoved(6, coord, endCoord) && !isFocused(inputEl)) {
3031
// begin the input focus process
31-
jsSetFocus(componentEl, inputEl, contentEl, footerEl, keyboardHeight);
32+
jsSetFocus(componentEl, inputEl, contentEl, footerEl, keyboardHeight, disableClonedInput);
3233
}
3334
};
3435
componentEl.addEventListener('touchstart', touchStart, { capture: true, passive: true });
@@ -45,7 +46,8 @@ const jsSetFocus = async (
4546
inputEl: HTMLInputElement | HTMLTextAreaElement,
4647
contentEl: HTMLElement | null,
4748
footerEl: HTMLIonFooterElement | null,
48-
keyboardHeight: number
49+
keyboardHeight: number,
50+
disableClonedInput = false
4951
) => {
5052
if (!contentEl && !footerEl) {
5153
return;
@@ -62,7 +64,7 @@ const jsSetFocus = async (
6264
// temporarily move the focus to the focus holder so the browser
6365
// doesn't freak out while it's trying to get the input in place
6466
// at this point the native text input still does not have focus
65-
relocateInput(componentEl, inputEl, true, scrollData.inputSafeY);
67+
relocateInput(componentEl, inputEl, true, scrollData.inputSafeY, disableClonedInput);
6668
inputEl.focus();
6769

6870
/**

core/src/utils/input-shims/input-shims.ts

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,20 @@ const SCROLL_ASSIST = true;
1212
const SCROLL_PADDING = true;
1313
const HIDE_CARET = true;
1414

15-
export const startInputShims = (config: Config) => {
15+
export const startInputShims = (config: Config, platform: 'ios' | 'android') => {
1616
const doc = document;
17+
const isIOS = platform === 'ios';
18+
const isAndroid = platform === 'android';
19+
20+
/**
21+
* Hide Caret and Input Blurring are needed on iOS.
22+
* Scroll Assist and Scroll Padding are needed on iOS and Android
23+
* with Chrome web browser (not Chrome webview).
24+
*/
1725
const keyboardHeight = config.getNumber('keyboardHeight', 290);
1826
const scrollAssist = config.getBoolean('scrollAssist', true);
19-
const hideCaret = config.getBoolean('hideCaretOnScroll', true);
20-
const inputBlurring = config.getBoolean('inputBlurring', true);
27+
const hideCaret = config.getBoolean('hideCaretOnScroll', isIOS);
28+
const inputBlurring = config.getBoolean('inputBlurring', isIOS);
2129
const scrollPadding = config.getBoolean('scrollPadding', true);
2230
const inputs = Array.from(doc.querySelectorAll('ion-input, ion-textarea')) as HTMLElement[];
2331

@@ -55,7 +63,7 @@ export const startInputShims = (config: Config) => {
5563
scrollAssist &&
5664
!scrollAssistMap.has(componentEl)
5765
) {
58-
const rmFn = enableScrollAssist(componentEl, inputEl, scrollEl, footerEl, keyboardHeight);
66+
const rmFn = enableScrollAssist(componentEl, inputEl, scrollEl, footerEl, keyboardHeight, isAndroid);
5967
scrollAssistMap.set(componentEl, rmFn);
6068
}
6169
};

0 commit comments

Comments
 (0)