Compare commits

..

1 Commits

Author SHA1 Message Date
Liam DeBeasi
b8ee3efb76 fix(footer, tab-bar): do not hide when webview resizing disabled 2023-10-09 09:59:48 -04:00
22 changed files with 105 additions and 459 deletions

View File

@@ -8,12 +8,7 @@ on:
# at 6:00 UTC (6:00 am UTC)
- cron: '00 06 * * 1-5'
workflow_dispatch:
inputs:
npm_release_tag:
required: true
type: string
description: What version should be pulled from NPM?
default: nightly
# allows for manual invocations in the GitHub UI
# When pushing a new commit we should
# cancel the previous test run to not
@@ -29,7 +24,7 @@ jobs:
- uses: actions/checkout@v3
- uses: ./.github/workflows/actions/build-core-stencil-prerelease
with:
stencil-version: ${{ inputs.npm_release_tag || 'nightly' }}
stencil-version: nightly
test-core-clean-build:
needs: [build-core-with-stencil-nightly]
@@ -52,7 +47,7 @@ jobs:
- uses: actions/checkout@v3
- uses: ./.github/workflows/actions/test-core-spec
with:
stencil-version: ${{ inputs.npm_release_tag || 'nightly' }}
stencil-version: nightly
test-core-screenshot:
strategy:

14
core/package-lock.json generated
View File

@@ -9,7 +9,7 @@
"version": "7.4.3",
"license": "MIT",
"dependencies": {
"@stencil/core": "^4.4.1",
"@stencil/core": "^4.4.0",
"ionicons": "7.1.0",
"tslib": "^2.1.0"
},
@@ -1630,9 +1630,9 @@
}
},
"node_modules/@stencil/core": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.4.1.tgz",
"integrity": "sha512-SirGcrb5yKHCn2BwdM7HGVXuvCdmwiXlVczEj8jJxQIm42CAUQCUECxtZidTzp+oZBZnWLnoAvfanchJsgkQzA==",
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.4.0.tgz",
"integrity": "sha512-YlLyCqGBsMEuZb3XTO/STT0TX9eSwjoVhCJgtjVfQOF+ebIMVlojTh40CmDveWiWbth687cbr6S2heeussV8Sg==",
"bin": {
"stencil": "bin/stencil"
},
@@ -11536,9 +11536,9 @@
"requires": {}
},
"@stencil/core": {
"version": "4.4.1",
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.4.1.tgz",
"integrity": "sha512-SirGcrb5yKHCn2BwdM7HGVXuvCdmwiXlVczEj8jJxQIm42CAUQCUECxtZidTzp+oZBZnWLnoAvfanchJsgkQzA=="
"version": "4.4.0",
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-4.4.0.tgz",
"integrity": "sha512-YlLyCqGBsMEuZb3XTO/STT0TX9eSwjoVhCJgtjVfQOF+ebIMVlojTh40CmDveWiWbth687cbr6S2heeussV8Sg=="
},
"@stencil/react-output-target": {
"version": "0.5.3",

View File

@@ -31,7 +31,7 @@
"loader/"
],
"dependencies": {
"@stencil/core": "^4.4.1",
"@stencil/core": "^4.4.0",
"ionicons": "7.1.0",
"tslib": "^2.1.0"
},

View File

@@ -211,10 +211,6 @@ export class Checkbox implements ComponentInterface {
};
private onClick = (ev: MouseEvent) => {
if (this.disabled) {
return;
}
this.toggleChecked(ev);
};

View File

@@ -1,24 +0,0 @@
import { newSpecPage } from '@stencil/core/testing';
import { Checkbox } from '../checkbox';
describe('ion-checkbox: disabled', () => {
it('clicking disabled checkbox should not toggle checked state', async () => {
const page = await newSpecPage({
components: [Checkbox],
html: `
<ion-checkbox disabled="true">Checkbox</ion-checkbox>
`,
});
const checkbox = page.body.querySelector('ion-checkbox');
expect(checkbox.checked).toBe(false);
checkbox.click();
await page.waitForChanges();
expect(checkbox.checked).toBe(false);
});
});

View File

@@ -3,6 +3,7 @@ import { Component, Element, Host, Prop, State, h } from '@stencil/core';
import { findIonContent, getScrollElement, printIonContentErrorMsg } from '@utils/content';
import type { KeyboardController } from '@utils/keyboard/keyboard-controller';
import { createKeyboardController } from '@utils/keyboard/keyboard-controller';
import { Keyboard, KeyboardResize } from '@utils/native/keyboard';
import { getIonMode } from '../../global/ionic-global';
@@ -52,18 +53,28 @@ export class Footer implements ComponentInterface {
}
async connectedCallback() {
this.keyboardCtrl = await createKeyboardController(async (keyboardOpen, waitForResize) => {
/**
* If the keyboard is hiding, then we need to wait
* for the webview to resize. Otherwise, the footer
* will flicker before the webview resizes.
*/
if (keyboardOpen === false && waitForResize !== undefined) {
await waitForResize;
}
const resizeMode = await Keyboard.getResizeMode();
this.keyboardVisible = keyboardOpen; // trigger re-render by updating state
});
/**
* If the resize mode is set to None then we don't want to
* hide the tab bar here since it will never sit on top
* of the keyboard. Hiding the tab bar will cause a layout shift
* in apps that have resize set to None.
*/
if (resizeMode === undefined || resizeMode.mode !== KeyboardResize.None) {
this.keyboardCtrl = await createKeyboardController(async (keyboardOpen, waitForResize) => {
/**
* If the keyboard is hiding, then we need to wait
* for the webview to resize. Otherwise, the footer
* will flicker before the webview resizes.
*/
if (keyboardOpen === false && waitForResize !== undefined) {
await waitForResize;
}
this.keyboardVisible = keyboardOpen; // trigger re-render by updating state
});
}
}
disconnectedCallback() {

View File

@@ -40,15 +40,6 @@ export class Menu implements ComponentInterface, MenuI {
private blocker = GESTURE_CONTROLLER.createBlocker({ disableScroll: true });
private didLoad = false;
/**
* Flag used to determine if an open/close
* operation was cancelled. For example, if
* an app calls "menu.open" then disables the menu
* part way through the animation, then this would
* be considered a cancelled operation.
*/
private operationCancelled = false;
isAnimating = false;
width!: number;
_isOpen = false;
@@ -441,17 +432,6 @@ export class Menu implements ComponentInterface, MenuI {
await this.loadAnimation();
await this.startAnimation(shouldOpen, animated);
/**
* If the animation was cancelled then
* return false because the operation
* did not succeed.
*/
if (this.operationCancelled) {
this.operationCancelled = false;
return false;
}
this.afterAnimation(shouldOpen);
return true;
@@ -492,24 +472,18 @@ export class Menu implements ComponentInterface, MenuI {
const easingReverse = mode === 'ios' ? iosEasingReverse : mdEasingReverse;
const ani = (this.animation as Animation)!
.direction(isReversed ? 'reverse' : 'normal')
.easing(isReversed ? easingReverse : easing);
.easing(isReversed ? easingReverse : easing)
.onFinish(() => {
if (ani.getDirection() === 'reverse') {
ani.direction('normal');
}
});
if (animated) {
await ani.play();
} else {
ani.play({ sync: true });
}
/**
* We run this after the play invocation
* instead of using ani.onFinish so that
* multiple onFinish callbacks do not get
* run if an animation is played, stopped,
* and then played again.
*/
if (ani.getDirection() === 'reverse') {
ani.direction('normal');
}
}
private _isActive() {
@@ -669,6 +643,8 @@ export class Menu implements ComponentInterface, MenuI {
}
private afterAnimation(isOpen: boolean) {
assert(this.isAnimating, '_before() should be called while animating');
// keep opening/closing the menu disabled for a touch more yet
// only add listeners/css if it's enabled and isOpen
// and only remove listeners/css if it's not open
@@ -737,30 +713,10 @@ export class Menu implements ComponentInterface, MenuI {
this.gesture.enable(isActive && this.swipeGesture);
}
/**
* If the menu is disabled but it is still open
* then we should close the menu immediately.
* Additionally, if the menu is in the process
* of animating {open, close} and the menu is disabled
* then it should still be closed immediately.
*/
if (!isActive) {
/**
* It is possible to disable the menu while
* it is mid-animation. When this happens, we
* need to set the operationCancelled flag
* so that this._setOpen knows to return false
* and not run the "afterAnimation" callback.
*/
if (this.isAnimating) {
this.operationCancelled = true;
}
/**
* If the menu is disabled then we should
* forcibly close the menu even if it is open.
*/
this.afterAnimation(false);
// Close menu immediately
if (!isActive && this._isOpen) {
// close if this menu is open, and should not be enabled
this.forceClosing();
}
if (doc?.contains(this.el)) {
@@ -774,6 +730,19 @@ export class Menu implements ComponentInterface, MenuI {
menuController._setActiveMenu(this);
}
}
assert(!this.isAnimating, 'can not be animating');
}
private forceClosing() {
assert(this._isOpen, 'menu cannot be closed');
this.isAnimating = true;
const ani = (this.animation as Animation)!.direction('reverse');
ani.play({ sync: true });
this.afterAnimation(false);
}
render() {

View File

@@ -1,41 +0,0 @@
<!DOCTYPE html>
<html lang="en" dir="ltr">
<head>
<meta charset="UTF-8" />
<title>Menu - Disable</title>
<meta
name="viewport"
content="width=device-width, initial-scale=1.0, minimum-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover"
/>
<link href="../../../../../css/ionic.bundle.css" rel="stylesheet" />
<link href="../../../../../scripts/testing/styles.css" rel="stylesheet" />
<script src="../../../../../scripts/testing/scripts.js"></script>
<script nomodule src="../../../../../dist/ionic/ionic.js"></script>
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
</head>
<body>
<ion-app>
<ion-menu side="start" id="start-menu" menu-id="start-menu" content-id="main">
<ion-header>
<ion-toolbar color="primary">
<ion-title>Menu</ion-title>
</ion-toolbar>
</ion-header>
<ion-content class="ion-padding"> Menu Content </ion-content>
</ion-menu>
<div class="ion-page" id="main">
<ion-header>
<ion-toolbar>
<ion-buttons slot="start">
<ion-menu-button></ion-menu-button>
</ion-buttons>
<ion-title>Menu - Disable</ion-title>
</ion-toolbar>
</ion-header>
<ion-content class="ion-padding">Content</ion-content>
</div>
</ion-app>
</body>
</html>

View File

@@ -1,66 +0,0 @@
import { expect } from '@playwright/test';
import { configs, test } from '@utils/test/playwright';
/**
* This behavior does not vary across modes/directions
*/
configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => {
test.describe(title('menu: disable'), () => {
test.beforeEach(async ({ page }) => {
await page.goto(`/src/components/menu/test/disable`, config);
});
test('should disable when menu is fully open', async ({ page }) => {
const logs: string[] = [];
page.on('console', (msg) => {
if (msg.type() === 'error') {
logs.push(msg.text());
}
});
const menu = page.locator('ion-menu');
// Should be visible on initial presentation
await menu.evaluate((el: HTMLIonMenuElement) => el.open());
await expect(menu).toBeVisible();
// Disabling menu should hide it
await menu.evaluate((el: HTMLIonMenuElement) => (el.disabled = true));
await expect(menu).toBeHidden();
// Re-enabling menu and opening it show make it visible
await menu.evaluate((el: HTMLIonMenuElement) => (el.disabled = false));
await menu.evaluate((el: HTMLIonMenuElement) => el.open());
await expect(menu).toBeVisible();
expect(logs.length).toBe(0);
});
test('should disable when menu is animating', async ({ page }) => {
const logs: string[] = [];
page.on('console', (msg) => {
if (msg.type() === 'error') {
logs.push(msg.text());
}
});
const menu = page.locator('ion-menu');
// Opening and quickly disabling menu should hide it
menu.evaluate((el: HTMLIonMenuElement) => {
el.open();
setTimeout(() => (el.disabled = true), 0);
});
await expect(menu).toBeHidden();
// Re-enabling menu and opening it show make it visible
await menu.evaluate((el: HTMLIonMenuElement) => (el.disabled = false));
await menu.evaluate((el: HTMLIonMenuElement) => el.open());
await expect(menu).toBeVisible();
expect(logs.length).toBe(0);
});
});
});

View File

@@ -414,11 +414,9 @@ export class PickerColumnInternal implements ComponentInterface {
}
render() {
const { items, color, isActive, numericInput, value } = this;
const { items, color, isActive, numericInput } = this;
const mode = getIonMode(this);
const activeItemIndex = items.findIndex(item => item.value === value);
/**
* exportparts is needed so ion-datetime can expose the parts
* from two layers of shadow nesting. If this causes problems,
@@ -427,7 +425,6 @@ export class PickerColumnInternal implements ComponentInterface {
*/
return (
<Host
role="listbox"
exportparts={`${PICKER_ITEM_PART}, ${PICKER_ITEM_ACTIVE_PART}`}
tabindex={0}
class={createColorClasses(color, {
@@ -458,9 +455,6 @@ export class PickerColumnInternal implements ComponentInterface {
}
return (
<button
role="option"
aria-selected={activeItemIndex === index ? 'true' : null}
aria-hidden={activeItemIndex === index || Math.abs(activeItemIndex - index) <= 2 ? null : 'true'}
tabindex="-1"
class={{
'picker-item': true,

View File

@@ -113,7 +113,7 @@ export class RadioGroup implements ComponentInterface {
* using the `name` attribute.
*/
const selectedRadio = ev.target && (ev.target as HTMLElement).closest('ion-radio');
if (selectedRadio && selectedRadio.disabled === false) {
if (selectedRadio) {
const currentValue = this.value;
const newValue = selectedRadio.value;
if (newValue !== currentValue) {

View File

@@ -200,11 +200,7 @@ export class Radio implements ComponentInterface {
};
private onClick = () => {
const { radioGroup, checked, disabled } = this;
if (disabled) {
return;
}
const { radioGroup, checked } = this;
/**
* The legacy control uses a native input inside

View File

@@ -31,27 +31,3 @@ describe('ion-radio', () => {
expect(radio.classList.contains('radio-checked')).toBe(true);
});
});
describe('ion-radio: disabled', () => {
it('clicking disabled radio should not set checked state', async () => {
const page = await newSpecPage({
components: [Radio, RadioGroup],
html: `
<ion-radio-group>
<ion-radio disabled="true" value="a">Radio</ion-radio>
</ion-radio-group>
`,
});
const radio = page.body.querySelector('ion-radio');
const radioGroup = page.body.querySelector('ion-radio-group');
expect(radioGroup.value).toBe(undefined);
radio.click();
await page.waitForChanges();
expect(radioGroup.value).toBe(undefined);
});
});

View File

@@ -316,46 +316,29 @@ export class Select implements ComponentInterface {
// focus selected option for popovers
if (this.interface === 'popover') {
const indexOfSelected = this.childOpts.map((o) => o.value).indexOf(this.value);
let indexOfSelected = this.childOpts.map((o) => o.value).indexOf(this.value);
indexOfSelected = indexOfSelected > -1 ? indexOfSelected : 0; // default to first option if nothing selected
const selectedItem = overlay.querySelector<HTMLElement>(
`.select-interface-option:nth-child(${indexOfSelected + 1})`
);
if (indexOfSelected > -1) {
const selectedItem = overlay.querySelector<HTMLElement>(
`.select-interface-option:nth-child(${indexOfSelected + 1})`
);
if (selectedItem) {
focusElement(selectedItem);
if (selectedItem) {
focusElement(selectedItem);
/**
* Browsers such as Firefox do not
* correctly delegate focus when manually
* focusing an element with delegatesFocus.
* We work around this by manually focusing
* the interactive element.
* ion-radio and ion-checkbox are the only
* elements that ion-select-popover uses, so
* we only need to worry about those two components
* when focusing.
*/
const interactiveEl = selectedItem.querySelector<HTMLElement>('ion-radio, ion-checkbox');
if (interactiveEl) {
interactiveEl.focus();
}
}
} else {
/**
* If no value is set then focus the first enabled option.
* Browsers such as Firefox do not
* correctly delegate focus when manually
* focusing an element with delegatesFocus.
* We work around this by manually focusing
* the interactive element.
* ion-radio and ion-checkbox are the only
* elements that ion-select-popover uses, so
* we only need to worry about those two components
* when focusing.
*/
const firstEnabledOption = overlay.querySelector<HTMLElement>(
'ion-radio:not(.radio-disabled), ion-checkbox:not(.checkbox-disabled)'
);
if (firstEnabledOption) {
focusElement(firstEnabledOption.closest('ion-item')!);
/**
* Focus the option for the same reason as we do above.
*/
firstEnabledOption.focus();
const interactiveEl = selectedItem.querySelector<HTMLElement>('ion-radio, ion-checkbox');
if (interactiveEl) {
interactiveEl.focus();
}
}
}

View File

@@ -1,36 +0,0 @@
import { expect } from '@playwright/test';
import { configs, test } from '@utils/test/playwright';
configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => {
test.describe(title('select: disabled options'), () => {
test('should not focus a disabled option when no value is set', async ({ page, skip }) => {
// TODO (FW-2979)
skip.browser('webkit', 'Safari 16 only allows text fields and pop-up menus to be focused.');
test.info().annotations.push({
type: 'issue',
description: 'https://github.com/ionic-team/ionic-framework/issues/28284',
});
await page.setContent(
`
<ion-select interface="popover">
<ion-select-option value="a" disabled="true">A</ion-select-option>
<ion-select-option value="b">B</ion-select-option>
</ion-select>
`,
config
);
const select = page.locator('ion-select');
const popover = page.locator('ion-popover');
const ionPopoverDidPresent = await page.spyOnEvent('ionPopoverDidPresent');
await select.click();
await ionPopoverDidPresent.next();
const popoverOption = popover.locator('.select-interface-option:nth-of-type(2) ion-radio');
await expect(popoverOption).toBeFocused();
});
});
});

View File

@@ -2,6 +2,7 @@ import type { ComponentInterface, EventEmitter } from '@stencil/core';
import { Component, Element, Event, Host, Prop, State, Watch, h } from '@stencil/core';
import type { KeyboardController } from '@utils/keyboard/keyboard-controller';
import { createKeyboardController } from '@utils/keyboard/keyboard-controller';
import { Keyboard, KeyboardResize } from '@utils/native/keyboard';
import { createColorClasses } from '@utils/theme';
import { getIonMode } from '../../global/ionic-global';
@@ -70,18 +71,28 @@ export class TabBar implements ComponentInterface {
}
async connectedCallback() {
this.keyboardCtrl = await createKeyboardController(async (keyboardOpen, waitForResize) => {
/**
* If the keyboard is hiding, then we need to wait
* for the webview to resize. Otherwise, the tab bar
* will flicker before the webview resizes.
*/
if (keyboardOpen === false && waitForResize !== undefined) {
await waitForResize;
}
const resizeMode = await Keyboard.getResizeMode();
this.keyboardVisible = keyboardOpen; // trigger re-render by updating state
});
/**
* If the resize mode is set to None then we don't want to
* hide the tab bar here since it will never sit on top
* of the keyboard. Hiding the tab bar will cause a layout shift
* in apps that have resize set to None.
*/
if (resizeMode === undefined || resizeMode.mode !== KeyboardResize.None) {
this.keyboardCtrl = await createKeyboardController(async (keyboardOpen, waitForResize) => {
/**
* If the keyboard is hiding, then we need to wait
* for the webview to resize. Otherwise, the tab bar
* will flicker before the webview resizes.
*/
if (keyboardOpen === false && waitForResize !== undefined) {
await waitForResize;
}
this.keyboardVisible = keyboardOpen; // trigger re-render by updating state
});
}
}
disconnectedCallback() {

View File

@@ -41,24 +41,3 @@ describe('toggle', () => {
});
});
});
describe('ion-toggle: disabled', () => {
it('clicking disabled toggle should not toggle checked state', async () => {
const page = await newSpecPage({
components: [Toggle],
html: `
<ion-toggle disabled="true">Toggle</ion-toggle>
`,
});
const toggle = page.body.querySelector('ion-toggle');
expect(toggle.checked).toBe(false);
toggle.click();
await page.waitForChanges();
expect(toggle.checked).toBe(false);
});
});

View File

@@ -259,10 +259,6 @@ export class Toggle implements ComponentInterface {
}
private onClick = (ev: MouseEvent) => {
if (this.disabled) {
return;
}
ev.preventDefault();
if (this.lastDrag + 300 < Date.now()) {

View File

@@ -30,8 +30,6 @@ interface AnimationOnFinishCallback {
o?: AnimationCallbackOptions;
}
type AnimationOnStopCallback = AnimationOnFinishCallback;
export const createAnimation = (animationId?: string): Animation => {
let _delay: number | undefined;
let _duration: number | undefined;
@@ -65,7 +63,6 @@ export const createAnimation = (animationId?: string): Animation => {
const id: string | undefined = animationId;
const onFinishCallbacks: AnimationOnFinishCallback[] = [];
const onFinishOneTimeCallbacks: AnimationOnFinishCallback[] = [];
const onStopOneTimeCallbacks: AnimationOnStopCallback[] = [];
const elements: HTMLElement[] = [];
const childAnimations: Animation[] = [];
const stylesheets: HTMLElement[] = [];
@@ -137,35 +134,6 @@ export const createAnimation = (animationId?: string): Animation => {
return numAnimationsRunning !== 0 && !paused;
};
/**
* @internal
* Remove a callback from a chosen callback array
* @param callbackToRemove: A reference to the callback that should be removed
* @param callbackObjects: An array of callbacks that callbackToRemove should be removed from.
*/
const clearCallback = (
callbackToRemove: AnimationLifecycle,
callbackObjects: AnimationOnFinishCallback[] | AnimationOnStopCallback[]
) => {
const index = callbackObjects.findIndex((callbackObject) => callbackObject.c === callbackToRemove);
if (index > -1) {
callbackObjects.splice(index, 1);
}
};
/**
* @internal
* Add a callback to be fired when an animation is stopped/cancelled.
* @param callback: A reference to the callback that should be fired
* @param opts: Any options associated with this particular callback
*/
const onStop = (callback: AnimationLifecycle, opts?: AnimationCallbackOptions) => {
onStopOneTimeCallbacks.push({ c: callback, o: opts });
return ani;
};
const onFinish = (callback: AnimationLifecycle, opts?: AnimationCallbackOptions) => {
const callbacks = opts?.oneTimeCallback ? onFinishOneTimeCallbacks : onFinishCallbacks;
callbacks.push({ c: callback, o: opts });
@@ -985,34 +953,7 @@ export const createAnimation = (animationId?: string): Animation => {
shouldCalculateNumAnimations = false;
}
/**
* When one of these callbacks fires we
* need to clear the other's callback otherwise
* you can potentially get these callbacks
* firing multiple times if the play method
* is subsequently called.
* Example:
* animation.play() (onStop and onFinish callbacks are registered)
* animation.stop() (onStop callback is fired, onFinish is not)
* animation.play() (onStop and onFinish callbacks are registered)
* Total onStop callbacks: 1
* Total onFinish callbacks: 2
*/
const onStopCallback = () => {
clearCallback(onFinishCallback, onFinishOneTimeCallbacks);
resolve();
};
const onFinishCallback = () => {
clearCallback(onStopCallback, onStopOneTimeCallbacks);
resolve();
};
/**
* The play method resolves when an animation
* run either finishes or is cancelled.
*/
onFinish(onFinishCallback, { oneTimeCallback: true });
onStop(onStopCallback, { oneTimeCallback: true });
onFinish(() => resolve(), { oneTimeCallback: true });
childAnimations.forEach((animation) => {
animation.play();
@@ -1028,14 +969,6 @@ export const createAnimation = (animationId?: string): Animation => {
});
};
/**
* Stops an animation and resets it state to the
* beginning. This does not fire any onFinish
* callbacks because the animation did not finish.
* However, since the animation was not destroyed
* (i.e. the animation could run again) we do not
* clear the onFinish callbacks.
*/
const stop = () => {
childAnimations.forEach((animation) => {
animation.stop();
@@ -1047,9 +980,6 @@ export const createAnimation = (animationId?: string): Animation => {
}
resetFlags();
onStopOneTimeCallbacks.forEach((onStopCallback) => onStopCallback.c(0, ani));
onStopOneTimeCallbacks.length = 0;
};
const from = (property: string, value: any) => {

View File

@@ -4,24 +4,6 @@ import { processKeyframes } from '../animation-utils';
import { getTimeGivenProgression } from '../cubic-bezier';
describe('Animation Class', () => {
describe('play()', () => {
it('should resolve when the animation is cancelled', async () => {
// Tell Jest to expect 1 assertion for async code
expect.assertions(1);
const el = document.createElement('div');
const animation = createAnimation()
.addElement(el)
.fromTo('transform', 'translateX(0px)', 'translateX(100px)')
.duration(100000);
const animationPromise = animation.play();
animation.stop();
// Expect that the promise resolves and returns undefined
expect(animationPromise).resolves.toEqual(undefined);
});
});
describe('isRunning()', () => {
let animation: Animation;
beforeEach(() => {

View File

@@ -79,11 +79,7 @@ export const createSwipeBackGesture = (
return createGesture({
el,
gestureName: 'goback-swipe',
/**
* Swipe to go back should have priority over other horizontal swipe
* gestures. These gestures have a priority of 100 which is why 101 was chosen here.
*/
gesturePriority: 101,
gesturePriority: 40,
threshold: 10,
canStart,
onStart: onStartHandler,

View File

@@ -1,6 +1,5 @@
import { doc, win } from '@utils/browser';
import { Keyboard, KeyboardResize } from '../native/keyboard';
import { Keyboard, KeyboardResize } from '@utils/native/keyboard';
/**
* The element that resizes when the keyboard opens