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
45 changed files with 141 additions and 581 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:

View File

@@ -3,24 +3,6 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [7.4.4](https://github.com/ionic-team/ionic-framework/compare/v7.4.3...v7.4.4) (2023-10-11)
### Bug Fixes
* **animation:** play method resolves when animation is stopped ([#28264](https://github.com/ionic-team/ionic-framework/issues/28264)) ([e6031fb](https://github.com/ionic-team/ionic-framework/commit/e6031fbef0698dac0a346cd6202c47f2abf54f95))
* **checkbox, radio, toggle:** disabled elements are not interactive ([#28294](https://github.com/ionic-team/ionic-framework/issues/28294)) ([c70432e](https://github.com/ionic-team/ionic-framework/commit/c70432e6934bcf1d570e1f7cf671c52d2bb52a8b)), closes [#28293](https://github.com/ionic-team/ionic-framework/issues/28293)
* **content:** fullscreen offset is computed correctly with tab bar ([#28245](https://github.com/ionic-team/ionic-framework/issues/28245)) ([7375dd6](https://github.com/ionic-team/ionic-framework/commit/7375dd6abafdf7457f23deb53ad5f016456a6af2)), closes [#21130](https://github.com/ionic-team/ionic-framework/issues/21130)
* **core:** allow fullscreen scroll content to flow outside container for translucent tab bar ([#28246](https://github.com/ionic-team/ionic-framework/issues/28246)) ([b297529](https://github.com/ionic-team/ionic-framework/commit/b297529afc4b93a93f7eaecd31dd5a88a3de5f4e)), closes [#17676](https://github.com/ionic-team/ionic-framework/issues/17676)
* **core:** swipe to go back gesture has priority over other horizontal swipe gestures ([#28304](https://github.com/ionic-team/ionic-framework/issues/28304)) ([d5f0c77](https://github.com/ionic-team/ionic-framework/commit/d5f0c776dfb5cb40b8119c596805dad3adb621e0)), closes [#28303](https://github.com/ionic-team/ionic-framework/issues/28303)
* **header:** collapsible large title main header does not flicker on load ([#28277](https://github.com/ionic-team/ionic-framework/issues/28277)) ([3259da0](https://github.com/ionic-team/ionic-framework/commit/3259da0de181c8f82c38d9de13733213c77d398f)), closes [#27060](https://github.com/ionic-team/ionic-framework/issues/27060)
* **menu:** do not error if disabled or swipeGesture is changed mid-animation ([#28268](https://github.com/ionic-team/ionic-framework/issues/28268)) ([a169044](https://github.com/ionic-team/ionic-framework/commit/a1690441e5bcee8176da32700de6f9e3fde9635e)), closes [#20092](https://github.com/ionic-team/ionic-framework/issues/20092) [#19676](https://github.com/ionic-team/ionic-framework/issues/19676) [#19000](https://github.com/ionic-team/ionic-framework/issues/19000)
* **segment:** scroll to active segment-button on first load ([#28276](https://github.com/ionic-team/ionic-framework/issues/28276)) ([1167a93](https://github.com/ionic-team/ionic-framework/commit/1167a9325fb930b6c727bc26889f5488d9620062)), closes [#28096](https://github.com/ionic-team/ionic-framework/issues/28096)
## [7.4.3](https://github.com/ionic-team/ionic-framework/compare/v7.4.2...v7.4.3) (2023-10-04)

View File

@@ -3,24 +3,6 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [7.4.4](https://github.com/ionic-team/ionic-framework/compare/v7.4.3...v7.4.4) (2023-10-11)
### Bug Fixes
* **animation:** play method resolves when animation is stopped ([#28264](https://github.com/ionic-team/ionic-framework/issues/28264)) ([e6031fb](https://github.com/ionic-team/ionic-framework/commit/e6031fbef0698dac0a346cd6202c47f2abf54f95))
* **checkbox, radio, toggle:** disabled elements are not interactive ([#28294](https://github.com/ionic-team/ionic-framework/issues/28294)) ([c70432e](https://github.com/ionic-team/ionic-framework/commit/c70432e6934bcf1d570e1f7cf671c52d2bb52a8b)), closes [#28293](https://github.com/ionic-team/ionic-framework/issues/28293)
* **content:** fullscreen offset is computed correctly with tab bar ([#28245](https://github.com/ionic-team/ionic-framework/issues/28245)) ([7375dd6](https://github.com/ionic-team/ionic-framework/commit/7375dd6abafdf7457f23deb53ad5f016456a6af2)), closes [#21130](https://github.com/ionic-team/ionic-framework/issues/21130)
* **core:** allow fullscreen scroll content to flow outside container for translucent tab bar ([#28246](https://github.com/ionic-team/ionic-framework/issues/28246)) ([b297529](https://github.com/ionic-team/ionic-framework/commit/b297529afc4b93a93f7eaecd31dd5a88a3de5f4e)), closes [#17676](https://github.com/ionic-team/ionic-framework/issues/17676)
* **core:** swipe to go back gesture has priority over other horizontal swipe gestures ([#28304](https://github.com/ionic-team/ionic-framework/issues/28304)) ([d5f0c77](https://github.com/ionic-team/ionic-framework/commit/d5f0c776dfb5cb40b8119c596805dad3adb621e0)), closes [#28303](https://github.com/ionic-team/ionic-framework/issues/28303)
* **header:** collapsible large title main header does not flicker on load ([#28277](https://github.com/ionic-team/ionic-framework/issues/28277)) ([3259da0](https://github.com/ionic-team/ionic-framework/commit/3259da0de181c8f82c38d9de13733213c77d398f)), closes [#27060](https://github.com/ionic-team/ionic-framework/issues/27060)
* **menu:** do not error if disabled or swipeGesture is changed mid-animation ([#28268](https://github.com/ionic-team/ionic-framework/issues/28268)) ([a169044](https://github.com/ionic-team/ionic-framework/commit/a1690441e5bcee8176da32700de6f9e3fde9635e)), closes [#20092](https://github.com/ionic-team/ionic-framework/issues/20092) [#19676](https://github.com/ionic-team/ionic-framework/issues/19676) [#19000](https://github.com/ionic-team/ionic-framework/issues/19000)
* **segment:** scroll to active segment-button on first load ([#28276](https://github.com/ionic-team/ionic-framework/issues/28276)) ([1167a93](https://github.com/ionic-team/ionic-framework/commit/1167a9325fb930b6c727bc26889f5488d9620062)), closes [#28096](https://github.com/ionic-team/ionic-framework/issues/28096)
## [7.4.3](https://github.com/ionic-team/ionic-framework/compare/v7.4.2...v7.4.3) (2023-10-04)

18
core/package-lock.json generated
View File

@@ -1,15 +1,15 @@
{
"name": "@ionic/core",
"version": "7.4.4",
"version": "7.4.3",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@ionic/core",
"version": "7.4.4",
"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

@@ -1,6 +1,6 @@
{
"name": "@ionic/core",
"version": "7.4.4",
"version": "7.4.3",
"description": "Base components for Ionic",
"keywords": [
"ionic",
@@ -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

@@ -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

View File

@@ -3,14 +3,6 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [7.4.4](https://github.com/ionic-team/ionic-framework/compare/v7.4.3...v7.4.4) (2023-10-11)
**Note:** Version bump only for package @ionic/docs
## [7.4.3](https://github.com/ionic-team/ionic-framework/compare/v7.4.2...v7.4.3) (2023-10-04)
**Note:** Version bump only for package @ionic/docs

View File

@@ -1,12 +1,12 @@
{
"name": "@ionic/docs",
"version": "7.4.4",
"version": "7.4.3",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@ionic/docs",
"version": "7.4.4",
"version": "7.4.3",
"license": "MIT"
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@ionic/docs",
"version": "7.4.4",
"version": "7.4.3",
"description": "Pre-packaged API documentation for the Ionic docs.",
"main": "core.json",
"types": "core.d.ts",

View File

@@ -4,5 +4,5 @@
"docs",
"packages/*"
],
"version": "7.4.4"
"version": "7.4.3"
}

View File

@@ -3,14 +3,6 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [7.4.4](https://github.com/ionic-team/ionic-framework/compare/v7.4.3...v7.4.4) (2023-10-11)
**Note:** Version bump only for package @ionic/angular-server
## [7.4.3](https://github.com/ionic-team/ionic-framework/compare/v7.4.2...v7.4.3) (2023-10-04)
**Note:** Version bump only for package @ionic/angular-server

View File

@@ -1,15 +1,15 @@
{
"name": "@ionic/angular-server",
"version": "7.4.4",
"version": "7.4.3",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@ionic/angular-server",
"version": "7.4.4",
"version": "7.4.3",
"license": "MIT",
"dependencies": {
"@ionic/core": "^7.4.4"
"@ionic/core": "^7.4.3"
},
"devDependencies": {
"@angular-eslint/eslint-plugin": "^14.0.0",

View File

@@ -1,6 +1,6 @@
{
"name": "@ionic/angular-server",
"version": "7.4.4",
"version": "7.4.3",
"description": "Angular SSR Module for Ionic",
"keywords": [
"ionic",
@@ -61,6 +61,6 @@
},
"prettier": "@ionic/prettier-config",
"dependencies": {
"@ionic/core": "^7.4.4"
"@ionic/core": "^7.4.3"
}
}

View File

@@ -3,14 +3,6 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [7.4.4](https://github.com/ionic-team/ionic-framework/compare/v7.4.3...v7.4.4) (2023-10-11)
**Note:** Version bump only for package @ionic/angular
## [7.4.3](https://github.com/ionic-team/ionic-framework/compare/v7.4.2...v7.4.3) (2023-10-04)
**Note:** Version bump only for package @ionic/angular

View File

@@ -1,15 +1,15 @@
{
"name": "@ionic/angular",
"version": "7.4.4",
"version": "7.4.3",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@ionic/angular",
"version": "7.4.4",
"version": "7.4.3",
"license": "MIT",
"dependencies": {
"@ionic/core": "^7.4.4",
"@ionic/core": "^7.4.3",
"ionicons": "^7.0.0",
"jsonc-parser": "^3.0.0",
"tslib": "^2.3.0"

View File

@@ -1,6 +1,6 @@
{
"name": "@ionic/angular",
"version": "7.4.4",
"version": "7.4.3",
"description": "Angular specific wrappers for @ionic/core",
"keywords": [
"ionic",
@@ -47,7 +47,7 @@
}
},
"dependencies": {
"@ionic/core": "^7.4.4",
"@ionic/core": "^7.4.3",
"ionicons": "^7.0.0",
"jsonc-parser": "^3.0.0",
"tslib": "^2.3.0"

View File

@@ -3,14 +3,6 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [7.4.4](https://github.com/ionic-team/ionic-framework/compare/v7.4.3...v7.4.4) (2023-10-11)
**Note:** Version bump only for package @ionic/react-router
## [7.4.3](https://github.com/ionic-team/ionic-framework/compare/v7.4.2...v7.4.3) (2023-10-04)
**Note:** Version bump only for package @ionic/react-router

View File

@@ -1,15 +1,15 @@
{
"name": "@ionic/react-router",
"version": "7.4.4",
"version": "7.4.3",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@ionic/react-router",
"version": "7.4.4",
"version": "7.4.3",
"license": "MIT",
"dependencies": {
"@ionic/react": "^7.4.4",
"@ionic/react": "^7.4.3",
"tslib": "*"
},
"devDependencies": {

View File

@@ -1,6 +1,6 @@
{
"name": "@ionic/react-router",
"version": "7.4.4",
"version": "7.4.3",
"description": "React Router wrapper for @ionic/react",
"keywords": [
"ionic",
@@ -37,7 +37,7 @@
"dist/"
],
"dependencies": {
"@ionic/react": "^7.4.4",
"@ionic/react": "^7.4.3",
"tslib": "*"
},
"peerDependencies": {

View File

@@ -3,14 +3,6 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [7.4.4](https://github.com/ionic-team/ionic-framework/compare/v7.4.3...v7.4.4) (2023-10-11)
**Note:** Version bump only for package @ionic/react
## [7.4.3](https://github.com/ionic-team/ionic-framework/compare/v7.4.2...v7.4.3) (2023-10-04)
**Note:** Version bump only for package @ionic/react

View File

@@ -1,15 +1,15 @@
{
"name": "@ionic/react",
"version": "7.4.4",
"version": "7.4.3",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@ionic/react",
"version": "7.4.4",
"version": "7.4.3",
"license": "MIT",
"dependencies": {
"@ionic/core": "^7.4.4",
"@ionic/core": "^7.4.3",
"ionicons": "^7.0.0",
"tslib": "*"
},

View File

@@ -1,6 +1,6 @@
{
"name": "@ionic/react",
"version": "7.4.4",
"version": "7.4.3",
"description": "React specific wrapper for @ionic/core",
"keywords": [
"ionic",
@@ -41,7 +41,7 @@
"css/"
],
"dependencies": {
"@ionic/core": "^7.4.4",
"@ionic/core": "^7.4.3",
"ionicons": "^7.0.0",
"tslib": "*"
},

View File

@@ -3,14 +3,6 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [7.4.4](https://github.com/ionic-team/ionic-framework/compare/v7.4.3...v7.4.4) (2023-10-11)
**Note:** Version bump only for package @ionic/vue-router
## [7.4.3](https://github.com/ionic-team/ionic-framework/compare/v7.4.2...v7.4.3) (2023-10-04)
**Note:** Version bump only for package @ionic/vue-router

View File

@@ -1,15 +1,15 @@
{
"name": "@ionic/vue-router",
"version": "7.4.4",
"version": "7.4.3",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@ionic/vue-router",
"version": "7.4.4",
"version": "7.4.3",
"license": "MIT",
"dependencies": {
"@ionic/vue": "^7.4.4"
"@ionic/vue": "^7.4.3"
},
"devDependencies": {
"@ionic/eslint-config": "^0.3.0",

View File

@@ -1,6 +1,6 @@
{
"name": "@ionic/vue-router",
"version": "7.4.4",
"version": "7.4.3",
"description": "Vue Router integration for @ionic/vue",
"scripts": {
"test.spec": "jest",
@@ -45,7 +45,7 @@
},
"homepage": "https://github.com/ionic-team/ionic#readme",
"dependencies": {
"@ionic/vue": "^7.4.4"
"@ionic/vue": "^7.4.3"
},
"devDependencies": {
"@ionic/eslint-config": "^0.3.0",

View File

@@ -3,14 +3,6 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [7.4.4](https://github.com/ionic-team/ionic-framework/compare/v7.4.3...v7.4.4) (2023-10-11)
**Note:** Version bump only for package @ionic/vue
## [7.4.3](https://github.com/ionic-team/ionic-framework/compare/v7.4.2...v7.4.3) (2023-10-04)
**Note:** Version bump only for package @ionic/vue

View File

@@ -1,15 +1,15 @@
{
"name": "@ionic/vue",
"version": "7.4.4",
"version": "7.4.3",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@ionic/vue",
"version": "7.4.4",
"version": "7.4.3",
"license": "MIT",
"dependencies": {
"@ionic/core": "^7.4.4",
"@ionic/core": "^7.4.3",
"ionicons": "^7.0.0"
},
"devDependencies": {

View File

@@ -1,6 +1,6 @@
{
"name": "@ionic/vue",
"version": "7.4.4",
"version": "7.4.3",
"description": "Vue specific wrapper for @ionic/core",
"scripts": {
"eslint": "eslint src",
@@ -66,7 +66,7 @@
"vue-router": "^4.0.16"
},
"dependencies": {
"@ionic/core": "^7.4.4",
"@ionic/core": "^7.4.3",
"ionicons": "^7.0.0"
},
"vetur": {