@ionic/core
Version:
Base components for Ionic
114 lines (113 loc) • 4.87 kB
JavaScript
/*!
* (C) Ionic http://ionicframework.com - MIT License
*/
import { doc } from "../browser/index";
import { findClosestIonContent } from "../content";
import { componentOnReady } from "../helpers";
import { Keyboard } from "../native/keyboard";
import { enableHideCaretOnScroll } from "./hacks/hide-caret";
import { enableInputBlurring } from "./hacks/input-blurring";
import { enableScrollAssist } from "./hacks/scroll-assist";
const INPUT_BLURRING = true;
const SCROLL_ASSIST = true;
const HIDE_CARET = true;
export const startInputShims = async (config, platform) => {
/**
* If doc is undefined then we are in an SSR environment
* where input shims do not apply.
*/
if (doc === undefined) {
return;
}
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', isIOS);
/**
* The team is evaluating if inputBlurring is still needed. As a result
* this feature is disabled by default as of Ionic 8.0. Developers are
* able to re-enable it temporarily. The team may remove this utility
* if it is determined that doing so would not bring any adverse side effects.
* TODO FW-6014 remove input blurring utility (including implementation)
*/
const inputBlurring = config.getBoolean('inputBlurring', false);
const scrollPadding = config.getBoolean('scrollPadding', true);
const inputs = Array.from(doc.querySelectorAll('ion-input, ion-textarea'));
const hideCaretMap = new WeakMap();
const scrollAssistMap = new WeakMap();
/**
* Grab the native keyboard resize configuration
* and pass it to scroll assist. Scroll assist requires
* that we adjust the input right before the input
* is about to be focused. If we called `Keyboard.getResizeMode`
* on focusin in scroll assist, we could potentially adjust the
* input too late since this call is async.
*/
const keyboardResizeMode = await Keyboard.getResizeMode();
const registerInput = async (componentEl) => {
await new Promise((resolve) => componentOnReady(componentEl, resolve));
const inputRoot = componentEl.shadowRoot || componentEl;
const inputEl = inputRoot.querySelector('input') || inputRoot.querySelector('textarea');
const scrollEl = findClosestIonContent(componentEl);
const footerEl = !scrollEl ? componentEl.closest('ion-footer') : null;
if (!inputEl) {
return;
}
if (HIDE_CARET && !!scrollEl && hideCaret && !hideCaretMap.has(componentEl)) {
const rmFn = enableHideCaretOnScroll(componentEl, inputEl, scrollEl);
hideCaretMap.set(componentEl, rmFn);
}
/**
* date/datetime-locale inputs on mobile devices show date picker
* overlays instead of keyboards. As a result, scroll assist is
* not needed. This also works around a bug in iOS <16 where
* scroll assist causes the browser to lock up. See FW-1997.
*/
const isDateInput = inputEl.type === 'date' || inputEl.type === 'datetime-local';
if (SCROLL_ASSIST &&
!isDateInput &&
(!!scrollEl || !!footerEl) &&
scrollAssist &&
!scrollAssistMap.has(componentEl)) {
const rmFn = enableScrollAssist(componentEl, inputEl, scrollEl, footerEl, keyboardHeight, scrollPadding, keyboardResizeMode, isAndroid);
scrollAssistMap.set(componentEl, rmFn);
}
};
const unregisterInput = (componentEl) => {
if (HIDE_CARET && hideCaret) {
const fn = hideCaretMap.get(componentEl);
if (fn) {
fn();
}
hideCaretMap.delete(componentEl);
}
if (SCROLL_ASSIST && scrollAssist) {
const fn = scrollAssistMap.get(componentEl);
if (fn) {
fn();
}
scrollAssistMap.delete(componentEl);
}
};
if (inputBlurring && INPUT_BLURRING) {
enableInputBlurring();
}
// Input might be already loaded in the DOM before ion-device-hacks did.
// At this point we need to look for all of the inputs not registered yet
// and register them.
for (const input of inputs) {
registerInput(input);
}
doc.addEventListener('ionInputDidLoad', (ev) => {
registerInput(ev.detail);
});
doc.addEventListener('ionInputDidUnload', (ev) => {
unregisterInput(ev.detail);
});
};