mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-19 19:57:22 +08:00
feat(app): keyboard open and close events (#18478)
This commit is contained in:
@ -1,6 +1,6 @@
|
||||
import { DOCUMENT } from '@angular/common';
|
||||
import { Inject, Injectable, NgZone } from '@angular/core';
|
||||
import { BackButtonEventDetail, Platforms, getPlatforms, isPlatform } from '@ionic/core';
|
||||
import { BackButtonEventDetail, KeyboardEventDetail, Platforms, getPlatforms, isPlatform } from '@ionic/core';
|
||||
import { Subject, Subscription } from 'rxjs';
|
||||
|
||||
export interface BackButtonEmitter extends Subject<BackButtonEventDetail> {
|
||||
@ -20,6 +20,18 @@ export class Platform {
|
||||
*/
|
||||
backButton: BackButtonEmitter = new Subject<BackButtonEventDetail>() as any;
|
||||
|
||||
/**
|
||||
* The keyboardDidShow event emits when the
|
||||
* on-screen keyboard is presented.
|
||||
*/
|
||||
keyboardDidShow = new Subject<KeyboardEventDetail>() as any;
|
||||
|
||||
/**
|
||||
* The keyboardDidHide event emits when the
|
||||
* on-screen keyboard is hidden.
|
||||
*/
|
||||
keyboardDidHide = new Subject<void>();
|
||||
|
||||
/**
|
||||
* The pause event emits when the native platform puts the application
|
||||
* into the background, typically when the user switches to a different
|
||||
@ -55,6 +67,8 @@ export class Platform {
|
||||
proxyEvent(this.resume, doc, 'resume');
|
||||
proxyEvent(this.backButton, doc, 'ionBackButton');
|
||||
proxyEvent(this.resize, this.win, 'resize');
|
||||
proxyEvent(this.keyboardDidShow, this.win, 'ionKeyboardDidShow');
|
||||
proxyEvent(this.keyboardDidHide, this.win, 'ionKeyboardDidHide');
|
||||
|
||||
let readyResolve: (value: string) => void;
|
||||
this._readyPromise = new Promise(res => { readyResolve = res; });
|
||||
|
@ -28,6 +28,9 @@ export class App implements ComponentInterface {
|
||||
if (config.getBoolean('hardwareBackButton', isHybrid)) {
|
||||
import('../../utils/hardware-back-button').then(module => module.startHardwareBackButton());
|
||||
}
|
||||
if (typeof (window as any) !== 'undefined') {
|
||||
import('../../utils/keyboard').then(module => module.startKeyboardAssist(window));
|
||||
}
|
||||
import('../../utils/focus-visible').then(module => module.startFocusVisible());
|
||||
});
|
||||
}
|
||||
|
4
core/src/interface.d.ts
vendored
4
core/src/interface.d.ts
vendored
@ -56,6 +56,10 @@ export interface BackButtonEventDetail {
|
||||
register(priority: number, handler: (processNextHandler: () => void) => Promise<any> | void): void;
|
||||
}
|
||||
|
||||
export interface KeyboardEventDetail {
|
||||
keyboardHeight: number;
|
||||
}
|
||||
|
||||
export interface StyleEventDetail {
|
||||
[styleName: string]: boolean;
|
||||
}
|
||||
|
@ -6,7 +6,8 @@ import { getScrollData } from './scroll-data';
|
||||
export const enableScrollAssist = (
|
||||
componentEl: HTMLElement,
|
||||
inputEl: HTMLInputElement | HTMLTextAreaElement,
|
||||
contentEl: HTMLIonContentElement,
|
||||
contentEl: HTMLIonContentElement | null,
|
||||
footerEl: HTMLIonFooterElement | null,
|
||||
keyboardHeight: number
|
||||
) => {
|
||||
let coord: any;
|
||||
@ -29,7 +30,7 @@ export const enableScrollAssist = (
|
||||
ev.stopPropagation();
|
||||
|
||||
// begin the input focus process
|
||||
jsSetFocus(componentEl, inputEl, contentEl, keyboardHeight);
|
||||
jsSetFocus(componentEl, inputEl, contentEl, footerEl, keyboardHeight);
|
||||
}
|
||||
};
|
||||
componentEl.addEventListener('touchstart', touchStart, true);
|
||||
@ -44,11 +45,14 @@ export const enableScrollAssist = (
|
||||
const jsSetFocus = (
|
||||
componentEl: HTMLElement,
|
||||
inputEl: HTMLInputElement | HTMLTextAreaElement,
|
||||
contentEl: HTMLIonContentElement,
|
||||
contentEl: HTMLIonContentElement | null,
|
||||
footerEl: HTMLIonFooterElement | null,
|
||||
keyboardHeight: number
|
||||
) => {
|
||||
const scrollData = getScrollData(componentEl, contentEl, keyboardHeight);
|
||||
if (Math.abs(scrollData.scrollAmount) < 4) {
|
||||
if (!contentEl && !footerEl) { return; }
|
||||
const scrollData = getScrollData(componentEl, (contentEl || footerEl)!, keyboardHeight);
|
||||
|
||||
if (contentEl && Math.abs(scrollData.scrollAmount) < 4) {
|
||||
// the text input is in a safe position that doesn't
|
||||
// require it to be scrolled into view, just set focus now
|
||||
inputEl.focus();
|
||||
@ -73,7 +77,9 @@ const jsSetFocus = (
|
||||
window.removeEventListener('keyboardWillShow', scrollContent);
|
||||
|
||||
// scroll the input into place
|
||||
await contentEl.scrollByPoint(0, scrollData.scrollAmount, scrollData.scrollDuration);
|
||||
if (contentEl) {
|
||||
await contentEl.scrollByPoint(0, scrollData.scrollAmount, scrollData.scrollDuration);
|
||||
}
|
||||
|
||||
// the scroll view is in the correct position now
|
||||
// give the native text input focus
|
||||
|
@ -30,6 +30,7 @@ export const startInputShims = (config: Config) => {
|
||||
const inputRoot = componentEl.shadowRoot || componentEl;
|
||||
const inputEl = inputRoot.querySelector('input') || inputRoot.querySelector('textarea');
|
||||
const scrollEl = componentEl.closest('ion-content');
|
||||
const footerEl = (!scrollEl) ? componentEl.closest('ion-footer') as HTMLIonFooterElement | null : null;
|
||||
|
||||
if (!inputEl) {
|
||||
return;
|
||||
@ -40,8 +41,8 @@ export const startInputShims = (config: Config) => {
|
||||
hideCaretMap.set(componentEl, rmFn);
|
||||
}
|
||||
|
||||
if (SCROLL_ASSIST && !!scrollEl && scrollAssist && !scrollAssistMap.has(componentEl)) {
|
||||
const rmFn = enableScrollAssist(componentEl, inputEl, scrollEl, keyboardHeight);
|
||||
if (SCROLL_ASSIST && (!!scrollEl || !!footerEl) && scrollAssist && !scrollAssistMap.has(componentEl)) {
|
||||
const rmFn = enableScrollAssist(componentEl, inputEl, scrollEl, footerEl, keyboardHeight);
|
||||
scrollAssistMap.set(componentEl, rmFn);
|
||||
}
|
||||
};
|
||||
|
176
core/src/utils/keyboard/index.ts
Normal file
176
core/src/utils/keyboard/index.ts
Normal file
@ -0,0 +1,176 @@
|
||||
export const KEYBOARD_DID_OPEN = 'ionKeyboardDidShow';
|
||||
export const KEYBOARD_DID_CLOSE = 'ionKeyboardDidHide';
|
||||
const KEYBOARD_THRESHOLD = 150;
|
||||
|
||||
let previousVisualViewport: any = {};
|
||||
let currentVisualViewport: any = {};
|
||||
|
||||
let previousLayoutViewport: any = {};
|
||||
let currentLayoutViewport: any = {};
|
||||
|
||||
let keyboardOpen = false;
|
||||
|
||||
/**
|
||||
* This is only used for tests
|
||||
*/
|
||||
export const resetKeyboardAssist = () => {
|
||||
previousVisualViewport = {};
|
||||
currentVisualViewport = {};
|
||||
previousLayoutViewport = {};
|
||||
currentLayoutViewport = {};
|
||||
keyboardOpen = false;
|
||||
};
|
||||
|
||||
export const startKeyboardAssist = (win: Window) => {
|
||||
startNativeListeners(win);
|
||||
|
||||
if (!(win as any).visualViewport) { return; }
|
||||
|
||||
currentVisualViewport = copyVisualViewport((win as any).visualViewport);
|
||||
currentLayoutViewport = copyLayoutViewport(win);
|
||||
|
||||
(win as any).visualViewport.onresize = () => {
|
||||
trackViewportChanges(win);
|
||||
|
||||
if (keyboardDidOpen() || keyboardDidResize(win)) {
|
||||
setKeyboardOpen(win);
|
||||
} else if (keyboardDidClose(win)) {
|
||||
setKeyboardClose(win);
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Listen for events fired by native keyboard plugin
|
||||
* in Capacitor/Cordova so devs only need to listen
|
||||
* in one place.
|
||||
*/
|
||||
const startNativeListeners = (win: Window) => {
|
||||
win.addEventListener('keyboardDidShow', ev => setKeyboardOpen(win, ev));
|
||||
win.addEventListener('keyboardDidHide', () => setKeyboardClose(win));
|
||||
};
|
||||
|
||||
export const setKeyboardOpen = (win: Window, ev?: any) => {
|
||||
fireKeyboardOpenEvent(win, ev);
|
||||
keyboardOpen = true;
|
||||
};
|
||||
|
||||
export const setKeyboardClose = (win: Window) => {
|
||||
fireKeyboardCloseEvent(win);
|
||||
keyboardOpen = false;
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns `true` if the `keyboardOpen` flag is not
|
||||
* set, the previous visual viewport width equal the current
|
||||
* visual viewport width, and if the scaled difference
|
||||
* of the previous visual viewport height minus the current
|
||||
* visual viewport height is greater than KEYBOARD_THRESHOLD
|
||||
*
|
||||
* We need to be able to accomodate users who have zooming
|
||||
* enabled in their browser (or have zoomed in manually) which
|
||||
* is why we take into account the current visual viewport's
|
||||
* scale value.
|
||||
*/
|
||||
export const keyboardDidOpen = (): boolean => {
|
||||
const scaledHeightDifference = (previousVisualViewport.height - currentVisualViewport.height) * currentVisualViewport.scale;
|
||||
return (
|
||||
!keyboardOpen &&
|
||||
previousVisualViewport.width === currentVisualViewport.width &&
|
||||
scaledHeightDifference > KEYBOARD_THRESHOLD &&
|
||||
!layoutViewportDidChange()
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Returns `true` if the keyboard is open,
|
||||
* but the keyboard did not close
|
||||
*/
|
||||
export const keyboardDidResize = (win: Window): boolean => {
|
||||
return keyboardOpen && !keyboardDidClose(win);
|
||||
};
|
||||
|
||||
/**
|
||||
* Determine if the keyboard was closed
|
||||
* Returns `true` if the `keyboardOpen` flag is set and
|
||||
* the current visual viewport height equals the
|
||||
* layout viewport height.
|
||||
*/
|
||||
export const keyboardDidClose = (win: Window): boolean => {
|
||||
return keyboardOpen && currentVisualViewport.height === win.innerHeight;
|
||||
};
|
||||
|
||||
/**
|
||||
* Determine if the layout viewport has
|
||||
* changed since the last visual viewport change.
|
||||
* It is rare that a layout viewport change is not
|
||||
* associated with a visual viewport change so we
|
||||
* want to make sure we don't get any false positives.
|
||||
*/
|
||||
const layoutViewportDidChange = (): boolean => {
|
||||
return (
|
||||
currentLayoutViewport.width !== previousLayoutViewport.width ||
|
||||
currentLayoutViewport.height !== previousLayoutViewport.height
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Dispatch a keyboard open event
|
||||
*/
|
||||
const fireKeyboardOpenEvent = (win: Window, nativeEv?: any): void => {
|
||||
const keyboardHeight = nativeEv ? nativeEv.keyboardHeight : win.innerHeight - currentVisualViewport.height;
|
||||
const ev = new CustomEvent(KEYBOARD_DID_OPEN, {
|
||||
detail: { keyboardHeight }
|
||||
});
|
||||
|
||||
win.dispatchEvent(ev);
|
||||
};
|
||||
|
||||
/**
|
||||
* Dispatch a keyboard close event
|
||||
*/
|
||||
const fireKeyboardCloseEvent = (win: Window): void => {
|
||||
const ev = new CustomEvent(KEYBOARD_DID_CLOSE);
|
||||
win.dispatchEvent(ev);
|
||||
};
|
||||
|
||||
/**
|
||||
* Given a window object, create a copy of
|
||||
* the current visual and layout viewport states
|
||||
* while also preserving the previous visual and
|
||||
* layout viewport states
|
||||
*/
|
||||
export const trackViewportChanges = (win: Window) => {
|
||||
previousVisualViewport = { ...currentVisualViewport };
|
||||
currentVisualViewport = copyVisualViewport((win as any).visualViewport);
|
||||
|
||||
previousLayoutViewport = { ...currentLayoutViewport };
|
||||
currentLayoutViewport = copyLayoutViewport(win);
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a deep copy of the visual viewport
|
||||
* at a given state
|
||||
*/
|
||||
export const copyVisualViewport = (visualViewport: any): any => {
|
||||
return {
|
||||
width: Math.round(visualViewport.width),
|
||||
height: Math.round(visualViewport.height),
|
||||
offsetTop: visualViewport.offsetTop,
|
||||
offsetLeft: visualViewport.offsetLeft,
|
||||
pageTop: visualViewport.pageTop,
|
||||
pageLeft: visualViewport.pageLeft,
|
||||
scale: visualViewport.scale
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Creates a deep copy of the layout viewport
|
||||
* at a given state
|
||||
*/
|
||||
export const copyLayoutViewport = (win: Window): any => {
|
||||
return {
|
||||
width: win.innerWidth,
|
||||
height: win.innerHeight
|
||||
};
|
||||
};
|
68
core/src/utils/keyboard/test/index.html
Normal file
68
core/src/utils/keyboard/test/index.html
Normal file
@ -0,0 +1,68 @@
|
||||
<!DOCTYPE html>
|
||||
<html dir="ltr">
|
||||
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>App - Keyboard</title>
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no">
|
||||
<link href="../../../../css/ionic.bundle.css" rel="stylesheet">
|
||||
<link href="../../../../scripts/testing/styles.css" rel="stylesheet">
|
||||
<script src="../../../../scripts/testing/scripts.js"></script>
|
||||
<script src="../../../../dist/ionic.js"></script>
|
||||
<style>
|
||||
f {
|
||||
display: block;
|
||||
margin: 15px auto;
|
||||
max-width: 150px;
|
||||
height: 150px;
|
||||
background: blue;
|
||||
}
|
||||
|
||||
ion-footer {
|
||||
transition: all 0.5s cubic-bezier(0.38, 0.7, 0.128, 1);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<ion-app>
|
||||
<ion-header>
|
||||
<ion-toolbar color="primary">
|
||||
<ion-title>App - Keyboard</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content>
|
||||
<f></f>
|
||||
<f></f>
|
||||
<f></f>
|
||||
<f></f>
|
||||
</ion-content>
|
||||
|
||||
<ion-footer>
|
||||
<ion-toolbar>
|
||||
<ion-input type="text" placeholder="Enter some text..."></ion-input>
|
||||
<ion-input type="text" placeholder="Enter some text..."></ion-input>
|
||||
</ion-toolbar>
|
||||
</ion-footer>
|
||||
</ion-app>
|
||||
|
||||
<script>
|
||||
const input = document.querySelector('ion-footer');
|
||||
|
||||
window.addEventListener('ionKeyboardDidShow', (e) => {
|
||||
console.log('ionKeyboardDidShow');
|
||||
setInputOffset(e.detail.keyboardHeight);
|
||||
});
|
||||
|
||||
window.addEventListener('ionKeyboardDidHide', () => {
|
||||
console.log('ionKeyboardDidHide');
|
||||
setInputOffset(0);
|
||||
});
|
||||
|
||||
function setInputOffset(offset) {
|
||||
input.setAttribute('style', `transform: translate3d(0, ${-offset}px, 0)`);
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
243
core/src/utils/keyboard/test/keyboard.spec.ts
Normal file
243
core/src/utils/keyboard/test/keyboard.spec.ts
Normal file
@ -0,0 +1,243 @@
|
||||
import { copyLayoutViewport, copyVisualViewport, setKeyboardClose, setKeyboardOpen, keyboardDidClose, keyboardDidOpen, keyboardDidResize, resetKeyboardAssist, startKeyboardAssist, trackViewportChanges, KEYBOARD_DID_OPEN, KEYBOARD_DID_CLOSE } from '../';
|
||||
|
||||
const mockVisualViewport = (win: Window, visualViewport: any = { width: 320, height: 568 }, layoutViewport = { innerWidth: 320, innerHeight: 568 }): any => {
|
||||
win.visualViewport = {
|
||||
width: 320,
|
||||
height: 568,
|
||||
offsetTop: 0,
|
||||
offsetLeft: 0,
|
||||
pageTop: 0,
|
||||
pageLeft: 0,
|
||||
scale: 1,
|
||||
onresize: undefined,
|
||||
onscroll: undefined
|
||||
};
|
||||
|
||||
win.visualViewport = Object.assign(win.visualViewport, visualViewport);
|
||||
win = Object.assign(win, layoutViewport);
|
||||
win.dispatchEvent = jest.fn(() => {});
|
||||
|
||||
trackViewportChanges(win);
|
||||
|
||||
return win;
|
||||
}
|
||||
|
||||
const resizeVisualViewport = (win: Window, visualViewport: any = {}) => {
|
||||
win.visualViewport = Object.assign(win.visualViewport, visualViewport);
|
||||
|
||||
if (win.visualViewport.onresize) {
|
||||
win.visualViewport.onresize();
|
||||
} else {
|
||||
trackViewportChanges(win);
|
||||
}
|
||||
}
|
||||
|
||||
describe('Keyboard Assist Tests', () => {
|
||||
describe('copyLayoutViewport()', () => {
|
||||
it('should properly copy the layout viewport', () => {
|
||||
const win = {
|
||||
innerWidth: 100,
|
||||
innerHeight: 200
|
||||
};
|
||||
|
||||
const copiedViewport = copyLayoutViewport(win);
|
||||
|
||||
win.innerWidth = 400;
|
||||
win.innerHeight = 800;
|
||||
|
||||
expect(copiedViewport.width).toEqual(100);
|
||||
expect(copiedViewport.height).toEqual(200);
|
||||
});
|
||||
});
|
||||
|
||||
describe('copyVisualViewport()', () => {
|
||||
it('should properly copy the visual viewport', () => {
|
||||
const visualViewport = {
|
||||
width: 100,
|
||||
height: 200,
|
||||
offsetTop: 5,
|
||||
offsetLeft: 10,
|
||||
pageTop: 0,
|
||||
pageLeft: 0,
|
||||
scale: 2
|
||||
};
|
||||
|
||||
const copiedViewport = copyVisualViewport(visualViewport);
|
||||
|
||||
visualViewport.width = 400;
|
||||
visualViewport.height = 800;
|
||||
visualViewport.scale = 3;
|
||||
visualViewport.offsetTop = 0;
|
||||
|
||||
expect(copiedViewport.width).toEqual(100);
|
||||
expect(copiedViewport.height).toEqual(200);
|
||||
expect(copiedViewport.scale).toEqual(2);
|
||||
expect(copiedViewport.offsetTop).toEqual(5);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setKeyboardOpen()', () => {
|
||||
it('should dispatch the keyboard open event on the window', () => {
|
||||
window.dispatchEvent = jest.fn(() => {});
|
||||
|
||||
setKeyboardOpen(window);
|
||||
|
||||
expect(window.dispatchEvent.mock.calls.length).toEqual(1);
|
||||
expect(window.dispatchEvent.mock.calls[0][0].type).toEqual(KEYBOARD_DID_OPEN);
|
||||
});
|
||||
});
|
||||
|
||||
describe('setKeyboardClose()', () => {
|
||||
it('should dispatch the keyboard close event on the window', () => {
|
||||
window.dispatchEvent = jest.fn(() => {});
|
||||
|
||||
setKeyboardClose(window);
|
||||
|
||||
expect(window.dispatchEvent.mock.calls.length).toEqual(1);
|
||||
expect(window.dispatchEvent.mock.calls[0][0].type).toEqual(KEYBOARD_DID_CLOSE);
|
||||
});
|
||||
});
|
||||
|
||||
describe('keyboardDidOpen()', () => {
|
||||
beforeEach(() => {
|
||||
resetKeyboardAssist(window);
|
||||
mockVisualViewport(window);
|
||||
});
|
||||
|
||||
it('should return true when visual viewport height < layout viewport height and meets or exceeds the keyboard threshold', () => {
|
||||
resizeVisualViewport(window, { height: 200 });
|
||||
|
||||
expect(keyboardDidOpen(window)).toEqual(true);
|
||||
});
|
||||
|
||||
it('should return false when visual viewport height < layout viewport heigh but does not meet the keyboard threshold', () => {
|
||||
resizeVisualViewport(window, { height: 500 });
|
||||
|
||||
expect(keyboardDidOpen(window)).toEqual(false);
|
||||
});
|
||||
|
||||
it('should return false on orientation change', () => {
|
||||
resizeVisualViewport(window, { width: 320, height: 250 });
|
||||
resizeVisualViewport(window, { width: 250, height: 320 });
|
||||
|
||||
expect(keyboardDidOpen(window)).toEqual(false);
|
||||
});
|
||||
|
||||
it('should return false when both the visual and layout viewports change', () => {
|
||||
resizeVisualViewport(window, { width: 250, height: 320 }, { innerWidth: 250, innerHeight: 320 });
|
||||
|
||||
expect(keyboardDidOpen(window)).toEqual(false);
|
||||
});
|
||||
|
||||
it('should return true when the keyboard shows even if the user is zoomed in', () => {
|
||||
// User zooms in
|
||||
resizeVisualViewport(window, { width: 160, height: 284, scale: 2 });
|
||||
|
||||
// User taps input and keyboard appears
|
||||
resizeVisualViewport(window, { width: 160, height: 184, scale: 2 });
|
||||
|
||||
expect(keyboardDidOpen(window)).toEqual(true);
|
||||
});
|
||||
});
|
||||
|
||||
describe('keyboardDidClose()', () => {
|
||||
beforeEach(() => {
|
||||
resetKeyboardAssist(window);
|
||||
mockVisualViewport(window);
|
||||
});
|
||||
|
||||
it('should return false when keyboard is not open', () => {
|
||||
expect(keyboardDidClose(window)).toEqual(false);
|
||||
});
|
||||
|
||||
it('should return false when keyboard is open but visual viewport !== layout viewport', () => {
|
||||
resizeVisualViewport(window, { width: 320, height: 250 });
|
||||
|
||||
setKeyboardOpen(window);
|
||||
|
||||
expect(keyboardDidClose(window)).toEqual(false);
|
||||
});
|
||||
|
||||
it('should return true when keyboard is open and viewport === layout viewport', () => {
|
||||
resizeVisualViewport(window, { width: 320, height: 250 });
|
||||
|
||||
setKeyboardOpen(window);
|
||||
|
||||
resizeVisualViewport(window, { width: 320, height: 568 });
|
||||
|
||||
expect(keyboardDidClose(window)).toEqual(true);
|
||||
});
|
||||
|
||||
it('should return false on orientation change', () => {
|
||||
resizeVisualViewport(window, { width: 320, height: 250 });
|
||||
|
||||
setKeyboardOpen(window);
|
||||
|
||||
resizeVisualViewport(window, { width: 250, height: 320 });
|
||||
|
||||
expect(keyboardDidClose(window)).toEqual(false);
|
||||
});
|
||||
});
|
||||
|
||||
describe('keyboardDidResize()', () => {
|
||||
it('should return true when the keyboard is open but did not close', () => {
|
||||
mockVisualViewport(window, { width: 250, height: 320 });
|
||||
setKeyboardOpen(window);
|
||||
|
||||
mockVisualViewport(window, { width: 250, height: 300 });
|
||||
|
||||
expect(keyboardDidResize(window)).toEqual(true);
|
||||
});
|
||||
|
||||
it('should return false when the keyboard is not open', () => {
|
||||
mockVisualViewport(window);
|
||||
|
||||
expect(keyboardDidResize(window)).toEqual(false);
|
||||
});
|
||||
|
||||
it('should return false when the keyboard has closed', () => {
|
||||
mockVisualViewport(window, { width: 320, height: 250 });
|
||||
setKeyboardOpen(window);
|
||||
setKeyboardClose(window);
|
||||
|
||||
expect(keyboardDidResize(window)).toEqual(false);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
describe('Keyboard Assist Integration', () => {
|
||||
beforeEach(() => {
|
||||
resetKeyboardAssist(window);
|
||||
mockVisualViewport(window);
|
||||
startKeyboardAssist(window);
|
||||
});
|
||||
|
||||
it('should properly set the keyboard to be open', () => {
|
||||
resizeVisualViewport(window, { width: 320, height: 350 });
|
||||
|
||||
expect(window.dispatchEvent.mock.calls.length).toEqual(1);
|
||||
expect(window.dispatchEvent.mock.calls[0][0].type).toEqual(KEYBOARD_DID_OPEN);
|
||||
});
|
||||
|
||||
it('should properly set the keyboard to be closed', () => {
|
||||
resizeVisualViewport(window, { width: 320, height: 350 });
|
||||
resizeVisualViewport(window, { width: 320, height: 568 });
|
||||
|
||||
expect(window.dispatchEvent.mock.calls.length).toEqual(2);
|
||||
expect(window.dispatchEvent.mock.calls[1][0].type).toEqual(KEYBOARD_DID_CLOSE);
|
||||
});
|
||||
|
||||
it('should properly set the keyboard to be resized', () => {
|
||||
resizeVisualViewport(window, { width: 320, height: 350 });
|
||||
resizeVisualViewport(window, { width: 320, height: 360 });
|
||||
|
||||
expect(window.dispatchEvent.mock.calls.length).toEqual(2);
|
||||
expect(window.dispatchEvent.mock.calls[0][0].type).toEqual(KEYBOARD_DID_OPEN);
|
||||
expect(window.dispatchEvent.mock.calls[1][0].type).toEqual(KEYBOARD_DID_OPEN);
|
||||
});
|
||||
|
||||
it('should not set keyboard open on orientation change', () => {
|
||||
resizeVisualViewport(window, { width: 568, height: 320 });
|
||||
expect(window.dispatchEvent.mock.calls.length).toEqual(0);
|
||||
});
|
||||
});
|
Reference in New Issue
Block a user