Compare commits
16 Commits
v7.2.0
...
sp/refacto
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
5f56f069e5 | ||
|
|
824033f1d4 | ||
|
|
b8553d89f8 | ||
|
|
ba2f49b8a4 | ||
|
|
a08a5894ba | ||
|
|
0b8f1bc7dd | ||
|
|
bd71373f1a | ||
|
|
960adbbc5c | ||
|
|
db29871654 | ||
|
|
e9ee96a443 | ||
|
|
38626d9680 | ||
|
|
6e4919caff | ||
|
|
5122ced9e1 | ||
|
|
3c794d25d6 | ||
|
|
9c799a6eea | ||
|
|
08cc3d93ae |
12
CHANGELOG.md
@@ -3,6 +3,18 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [7.2.1](https://github.com/ionic-team/ionic-framework/compare/v7.2.0...v7.2.1) (2023-07-26)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **item-sliding:** buttons are not interactive on close ([#27829](https://github.com/ionic-team/ionic-framework/issues/27829)) ([6e4919c](https://github.com/ionic-team/ionic-framework/commit/6e4919caff90fc60988e5cc85ad7161844eb5b51)), closes [#22722](https://github.com/ionic-team/ionic-framework/issues/22722)
|
||||
* **modal:** body background is reset with inline card modals ([#27835](https://github.com/ionic-team/ionic-framework/issues/27835)) ([38626d9](https://github.com/ionic-team/ionic-framework/commit/38626d96809d1c6be523ea62a4fac1dec73ee891)), closes [#27830](https://github.com/ionic-team/ionic-framework/issues/27830)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [7.2.0](https://github.com/ionic-team/ionic-framework/compare/v7.1.4...v7.2.0) (2023-07-19)
|
||||
|
||||
|
||||
|
||||
@@ -3,6 +3,18 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [7.2.1](https://github.com/ionic-team/ionic-framework/compare/v7.2.0...v7.2.1) (2023-07-26)
|
||||
|
||||
|
||||
### Bug Fixes
|
||||
|
||||
* **item-sliding:** buttons are not interactive on close ([#27829](https://github.com/ionic-team/ionic-framework/issues/27829)) ([6e4919c](https://github.com/ionic-team/ionic-framework/commit/6e4919caff90fc60988e5cc85ad7161844eb5b51)), closes [#22722](https://github.com/ionic-team/ionic-framework/issues/22722)
|
||||
* **modal:** body background is reset with inline card modals ([#27835](https://github.com/ionic-team/ionic-framework/issues/27835)) ([38626d9](https://github.com/ionic-team/ionic-framework/commit/38626d96809d1c6be523ea62a4fac1dec73ee891)), closes [#27830](https://github.com/ionic-team/ionic-framework/issues/27830)
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [7.2.0](https://github.com/ionic-team/ionic-framework/compare/v7.1.4...v7.2.0) (2023-07-19)
|
||||
|
||||
|
||||
|
||||
66
core/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@ionic/core",
|
||||
"version": "7.2.0",
|
||||
"version": "7.2.1",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@ionic/core",
|
||||
"version": "7.2.0",
|
||||
"version": "7.2.1",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@stencil/core": "^3.4.0",
|
||||
@@ -15,19 +15,19 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@axe-core/playwright": "^4.7.3",
|
||||
"@capacitor/core": "^5.2.1",
|
||||
"@capacitor/core": "^5.2.2",
|
||||
"@capacitor/haptics": "^5.0.6",
|
||||
"@capacitor/keyboard": "^5.0.6",
|
||||
"@capacitor/status-bar": "^5.0.6",
|
||||
"@ionic/eslint-config": "^0.3.0",
|
||||
"@ionic/prettier-config": "^2.0.0",
|
||||
"@jest/core": "^27.5.1",
|
||||
"@playwright/test": "^1.36.1",
|
||||
"@playwright/test": "^1.36.2",
|
||||
"@rollup/plugin-node-resolve": "^8.4.0",
|
||||
"@rollup/plugin-virtual": "^2.0.3",
|
||||
"@stencil/angular-output-target": "^0.7.1",
|
||||
"@stencil/react-output-target": "^0.5.3",
|
||||
"@stencil/sass": "^3.0.4",
|
||||
"@stencil/sass": "^3.0.5",
|
||||
"@stencil/vue-output-target": "^0.8.6",
|
||||
"@types/jest": "^27.5.2",
|
||||
"@types/node": "^14.6.0",
|
||||
@@ -607,9 +607,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@capacitor/core": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/core/-/core-5.2.1.tgz",
|
||||
"integrity": "sha512-v7nzTQZj9l99Sp0v8C7Zq8QX6Cg5ljq7ASneWk/Hc5nBR5LOj/k3a+yEx/RoclWtkxJfs89Y5k+KJTFFQ6cLoA==",
|
||||
"version": "5.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/core/-/core-5.2.2.tgz",
|
||||
"integrity": "sha512-3jKECZC5+YD2rljMZm1e/K3AYyoxUmLDZCyofTPbRYPBSI0wJh5ZCkX+XIGzNM0o/Wokl3Voa1JB8xsLC0MPxA==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"tslib": "^2.1.0"
|
||||
@@ -1541,13 +1541,13 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@playwright/test": {
|
||||
"version": "1.36.1",
|
||||
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.36.1.tgz",
|
||||
"integrity": "sha512-YK7yGWK0N3C2QInPU6iaf/L3N95dlGdbsezLya4n0ZCh3IL7VgPGxC6Gnznh9ApWdOmkJeleT2kMTcWPRZvzqg==",
|
||||
"version": "1.36.2",
|
||||
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.36.2.tgz",
|
||||
"integrity": "sha512-2rVZeyPRjxfPH6J0oGJqE8YxiM1IBRyM8hyrXYK7eSiAqmbNhxwcLa7dZ7fy9Kj26V7FYia5fh9XJRq4Dqme+g==",
|
||||
"dev": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*",
|
||||
"playwright-core": "1.36.1"
|
||||
"playwright-core": "1.36.2"
|
||||
},
|
||||
"bin": {
|
||||
"playwright": "cli.js"
|
||||
@@ -1655,10 +1655,14 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@stencil/sass": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/sass/-/sass-3.0.4.tgz",
|
||||
"integrity": "sha512-k1dP0A2QBx62m250FATc1hErXxXs6Jnf4TBxdL1C/dc32Kzz2n5aCT4SodBz0ebT5WMnITauZyFqYxzCzDoKag==",
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/sass/-/sass-3.0.5.tgz",
|
||||
"integrity": "sha512-9nyllMXOEvHywo6fP2iwXgnq32A+OOUE36Aq7iUjzwT3wdr04qsvupO1JNIyRvmvCDF15hOKXztrZH1/wDu2Zg==",
|
||||
"dev": true,
|
||||
"engines": {
|
||||
"node": ">=12.0.0",
|
||||
"npm": ">=6.0.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@stencil/core": ">=2.0.0 || >=3.0.0-beta.0 || >= 4.0.0-beta.0 || >= 4.0.0"
|
||||
}
|
||||
@@ -8190,9 +8194,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/playwright-core": {
|
||||
"version": "1.36.1",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.36.1.tgz",
|
||||
"integrity": "sha512-7+tmPuMcEW4xeCL9cp9KxmYpQYHKkyjwoXRnoeTowaeNat8PoBMk/HwCYhqkH2fRkshfKEOiVus/IhID2Pg8kg==",
|
||||
"version": "1.36.2",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.36.2.tgz",
|
||||
"integrity": "sha512-sQYZt31dwkqxOrP7xy2ggDfEzUxM1lodjhsQ3NMMv5uGTRDsLxU0e4xf4wwMkF2gplIxf17QMBCodSFgm6bFVQ==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"playwright-core": "cli.js"
|
||||
@@ -10784,9 +10788,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@capacitor/core": {
|
||||
"version": "5.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/core/-/core-5.2.1.tgz",
|
||||
"integrity": "sha512-v7nzTQZj9l99Sp0v8C7Zq8QX6Cg5ljq7ASneWk/Hc5nBR5LOj/k3a+yEx/RoclWtkxJfs89Y5k+KJTFFQ6cLoA==",
|
||||
"version": "5.2.2",
|
||||
"resolved": "https://registry.npmjs.org/@capacitor/core/-/core-5.2.2.tgz",
|
||||
"integrity": "sha512-3jKECZC5+YD2rljMZm1e/K3AYyoxUmLDZCyofTPbRYPBSI0wJh5ZCkX+XIGzNM0o/Wokl3Voa1JB8xsLC0MPxA==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"tslib": "^2.1.0"
|
||||
@@ -11451,14 +11455,14 @@
|
||||
}
|
||||
},
|
||||
"@playwright/test": {
|
||||
"version": "1.36.1",
|
||||
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.36.1.tgz",
|
||||
"integrity": "sha512-YK7yGWK0N3C2QInPU6iaf/L3N95dlGdbsezLya4n0ZCh3IL7VgPGxC6Gnznh9ApWdOmkJeleT2kMTcWPRZvzqg==",
|
||||
"version": "1.36.2",
|
||||
"resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.36.2.tgz",
|
||||
"integrity": "sha512-2rVZeyPRjxfPH6J0oGJqE8YxiM1IBRyM8hyrXYK7eSiAqmbNhxwcLa7dZ7fy9Kj26V7FYia5fh9XJRq4Dqme+g==",
|
||||
"dev": true,
|
||||
"requires": {
|
||||
"@types/node": "*",
|
||||
"fsevents": "2.3.2",
|
||||
"playwright-core": "1.36.1"
|
||||
"playwright-core": "1.36.2"
|
||||
}
|
||||
},
|
||||
"@rollup/plugin-node-resolve": {
|
||||
@@ -11532,9 +11536,9 @@
|
||||
"requires": {}
|
||||
},
|
||||
"@stencil/sass": {
|
||||
"version": "3.0.4",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/sass/-/sass-3.0.4.tgz",
|
||||
"integrity": "sha512-k1dP0A2QBx62m250FATc1hErXxXs6Jnf4TBxdL1C/dc32Kzz2n5aCT4SodBz0ebT5WMnITauZyFqYxzCzDoKag==",
|
||||
"version": "3.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/sass/-/sass-3.0.5.tgz",
|
||||
"integrity": "sha512-9nyllMXOEvHywo6fP2iwXgnq32A+OOUE36Aq7iUjzwT3wdr04qsvupO1JNIyRvmvCDF15hOKXztrZH1/wDu2Zg==",
|
||||
"dev": true,
|
||||
"requires": {}
|
||||
},
|
||||
@@ -16328,9 +16332,9 @@
|
||||
}
|
||||
},
|
||||
"playwright-core": {
|
||||
"version": "1.36.1",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.36.1.tgz",
|
||||
"integrity": "sha512-7+tmPuMcEW4xeCL9cp9KxmYpQYHKkyjwoXRnoeTowaeNat8PoBMk/HwCYhqkH2fRkshfKEOiVus/IhID2Pg8kg==",
|
||||
"version": "1.36.2",
|
||||
"resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.36.2.tgz",
|
||||
"integrity": "sha512-sQYZt31dwkqxOrP7xy2ggDfEzUxM1lodjhsQ3NMMv5uGTRDsLxU0e4xf4wwMkF2gplIxf17QMBCodSFgm6bFVQ==",
|
||||
"dev": true
|
||||
},
|
||||
"postcss": {
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/core",
|
||||
"version": "7.2.0",
|
||||
"version": "7.2.1",
|
||||
"description": "Base components for Ionic",
|
||||
"keywords": [
|
||||
"ionic",
|
||||
@@ -37,19 +37,19 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@axe-core/playwright": "^4.7.3",
|
||||
"@capacitor/core": "^5.2.1",
|
||||
"@capacitor/core": "^5.2.2",
|
||||
"@capacitor/haptics": "^5.0.6",
|
||||
"@capacitor/keyboard": "^5.0.6",
|
||||
"@capacitor/status-bar": "^5.0.6",
|
||||
"@ionic/eslint-config": "^0.3.0",
|
||||
"@ionic/prettier-config": "^2.0.0",
|
||||
"@jest/core": "^27.5.1",
|
||||
"@playwright/test": "^1.36.1",
|
||||
"@playwright/test": "^1.36.2",
|
||||
"@rollup/plugin-node-resolve": "^8.4.0",
|
||||
"@rollup/plugin-virtual": "^2.0.3",
|
||||
"@stencil/angular-output-target": "^0.7.1",
|
||||
"@stencil/react-output-target": "^0.5.3",
|
||||
"@stencil/sass": "^3.0.4",
|
||||
"@stencil/sass": "^3.0.5",
|
||||
"@stencil/vue-output-target": "^0.8.6",
|
||||
"@types/jest": "^27.5.2",
|
||||
"@types/node": "^14.6.0",
|
||||
|
||||
4
core/src/components.d.ts
vendored
@@ -2176,7 +2176,7 @@ export namespace Components {
|
||||
*/
|
||||
"side": PositionSide;
|
||||
/**
|
||||
* Describes how to calculate the popover width. If `"cover"`, the popover width will match the width of the trigger. If `"auto"`, the popover width will be determined by the content in the popover.
|
||||
* Describes how to calculate the popover width. If `"cover"`, the popover width will match the width of the trigger. If `"auto"`, the popover width will be set to a static default value.
|
||||
*/
|
||||
"size": PopoverSize;
|
||||
/**
|
||||
@@ -6189,7 +6189,7 @@ declare namespace LocalJSX {
|
||||
*/
|
||||
"side"?: PositionSide;
|
||||
/**
|
||||
* Describes how to calculate the popover width. If `"cover"`, the popover width will match the width of the trigger. If `"auto"`, the popover width will be determined by the content in the popover.
|
||||
* Describes how to calculate the popover width. If `"cover"`, the popover width will match the width of the trigger. If `"auto"`, the popover width will be set to a static default value.
|
||||
*/
|
||||
"size"?: PopoverSize;
|
||||
/**
|
||||
|
||||
@@ -56,15 +56,17 @@ ion-item-options {
|
||||
}
|
||||
}
|
||||
|
||||
.item-options-start ion-item-option:first-child {
|
||||
@include padding-horizontal(null, var(--ion-safe-area-left));
|
||||
|
||||
/* stylelint-disable property-disallowed-list */
|
||||
[dir="ltr"] .item-options-start ion-item-option:first-child,
|
||||
[dir="rtl"] .item-options-start ion-item-option:last-child {
|
||||
padding-left: var(--ion-safe-area-left);
|
||||
}
|
||||
|
||||
.item-options-end ion-item-option:last-child {
|
||||
@include padding-horizontal(null, var(--ion-safe-area-right));
|
||||
|
||||
[dir="ltr"] .item-options-end ion-item-option:last-child,
|
||||
[dir="rtl"] .item-options-end ion-item-option:first-child {
|
||||
padding-right: var(--ion-safe-area-right);
|
||||
}
|
||||
/* stylelint-enable property-disallowed-list */
|
||||
|
||||
.item-sliding-active-slide {
|
||||
@include rtl() {
|
||||
|
||||
@@ -45,6 +45,14 @@ export class ItemOptions implements ComponentInterface {
|
||||
// Used internally for styling
|
||||
[`item-options-${mode}`]: true,
|
||||
|
||||
/**
|
||||
* Note: The "start" and "end" terms refer to the
|
||||
* direction ion-item-option instances within ion-item-options flow.
|
||||
* They do not refer to how ion-item-options flows within ion-item-sliding.
|
||||
* As a result, "item-options-start" means the ion-item-options container
|
||||
* always appears on the left, and "item-options-end" means the ion-item-options
|
||||
* container always appears on the right.
|
||||
*/
|
||||
'item-options-start': !isEnd,
|
||||
'item-options-end': isEnd,
|
||||
}}
|
||||
|
||||
@@ -29,6 +29,9 @@ ion-item-sliding .item {
|
||||
will-change: transform;
|
||||
}
|
||||
|
||||
.item-sliding-closing ion-item-options {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.item-sliding-active-swipe-end .item-options-end .item-option-expandable {
|
||||
@include multi-dir() {
|
||||
|
||||
@@ -407,6 +407,9 @@ export class ItemSliding implements ComponentInterface {
|
||||
if (!this.item) {
|
||||
return;
|
||||
}
|
||||
|
||||
const { el } = this;
|
||||
|
||||
const style = this.item.style;
|
||||
this.openAmount = openAmount;
|
||||
|
||||
@@ -425,6 +428,12 @@ export class ItemSliding implements ComponentInterface {
|
||||
? SlidingState.Start | SlidingState.SwipeStart
|
||||
: SlidingState.Start;
|
||||
} else {
|
||||
/**
|
||||
* The sliding options should not be
|
||||
* clickable while the item is closing.
|
||||
*/
|
||||
el.classList.add('item-sliding-closing');
|
||||
|
||||
/**
|
||||
* Item sliding cannot be interrupted
|
||||
* while closing the item. If it did,
|
||||
@@ -441,6 +450,7 @@ export class ItemSliding implements ComponentInterface {
|
||||
if (this.gesture) {
|
||||
this.gesture.enable(!this.disabled);
|
||||
}
|
||||
el.classList.remove('item-sliding-closing');
|
||||
}, 600);
|
||||
|
||||
openSlidingItem = undefined;
|
||||
|
||||
@@ -398,7 +398,7 @@ export class Item implements ComponentInterface, AnchorInterface, ButtonInterfac
|
||||
});
|
||||
const ariaDisabled = disabled || childStyles['item-interactive-disabled'] ? 'true' : null;
|
||||
const fillValue = fill || 'none';
|
||||
const inList = hostContext('ion-list', this.el);
|
||||
const inList = hostContext('ion-list', this.el) && !hostContext('ion-radio-group', this.el);
|
||||
|
||||
return (
|
||||
<Host
|
||||
|
||||
51
core/src/components/item/test/a11y/item.spec.ts
Normal file
@@ -0,0 +1,51 @@
|
||||
import { Radio } from '../../../radio/radio.tsx';
|
||||
import { RadioGroup } from '../../../radio-group/radio-group.tsx';
|
||||
import { Item } from '../../item.tsx';
|
||||
import { List } from '../../../list/list.tsx';
|
||||
import { newSpecPage } from '@stencil/core/testing';
|
||||
|
||||
describe('ion-item', () => {
|
||||
it('should not have a role when used without list', async () => {
|
||||
const page = await newSpecPage({
|
||||
components: [Item],
|
||||
html: `<ion-item>Hello World</ion-item>`,
|
||||
});
|
||||
|
||||
const item = page.body.querySelector('ion-item');
|
||||
expect(item.getAttribute('role')).toBe(null);
|
||||
});
|
||||
|
||||
it('should have a listitem role when used inside list', async () => {
|
||||
const page = await newSpecPage({
|
||||
components: [Item, List],
|
||||
html: `
|
||||
<ion-list>
|
||||
<ion-item>
|
||||
Hello World
|
||||
</ion-item>
|
||||
</ion-list>
|
||||
`,
|
||||
});
|
||||
|
||||
const item = page.body.querySelector('ion-item');
|
||||
expect(item.getAttribute('role')).toBe('listitem');
|
||||
});
|
||||
|
||||
it('should not have a role when used inside radio group and list', async () => {
|
||||
const page = await newSpecPage({
|
||||
components: [Radio, RadioGroup, Item, List],
|
||||
html: `
|
||||
<ion-list>
|
||||
<ion-radio-group value="a">
|
||||
<ion-item>
|
||||
<ion-radio value="other-value" aria-label="my radio"></ion-radio>
|
||||
</ion-item>
|
||||
</ion-radio-group>
|
||||
</ion-list>
|
||||
`,
|
||||
});
|
||||
|
||||
const item = page.body.querySelector('ion-item');
|
||||
expect(item.getAttribute('role')).toBe(null);
|
||||
});
|
||||
});
|
||||
@@ -51,9 +51,9 @@ export const iosLeaveAnimation = (baseEl: HTMLElement, opts: ModalAnimationOptio
|
||||
|
||||
presentingEl.style.setProperty('overflow', '');
|
||||
|
||||
const numModals = Array.from(bodyEl.querySelectorAll('ion-modal')).filter(
|
||||
(m) => m.presentingElement !== undefined
|
||||
).length;
|
||||
const numModals = (
|
||||
Array.from(bodyEl.querySelectorAll('ion-modal:not(.overlay-hidden)')) as HTMLIonModalElement[]
|
||||
).filter((m) => m.presentingElement !== undefined).length;
|
||||
if (numModals <= 1) {
|
||||
bodyEl.style.setProperty('background-color', '');
|
||||
}
|
||||
|
||||
@@ -180,8 +180,7 @@ export class Popover implements ComponentInterface, PopoverInterface {
|
||||
/**
|
||||
* Describes how to calculate the popover width.
|
||||
* If `"cover"`, the popover width will match the width of the trigger.
|
||||
* If `"auto"`, the popover width will be determined by the content in
|
||||
* the popover.
|
||||
* If `"auto"`, the popover width will be set to a static default value.
|
||||
*/
|
||||
@Prop() size: PopoverSize = 'auto';
|
||||
|
||||
|
||||
@@ -30,23 +30,19 @@
|
||||
</ion-list-header>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Item 1</ion-label>
|
||||
<ion-radio value="1" slot="start"></ion-radio>
|
||||
<ion-radio value="1">Item 1</ion-radio>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Item 2</ion-label>
|
||||
<ion-radio value="2" slot="start"></ion-radio>
|
||||
<ion-radio value="2">Item 2</ion-radio>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Item 3</ion-label>
|
||||
<ion-radio value="3" slot="start"></ion-radio>
|
||||
<ion-radio value="3">Item 3</ion-radio>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Item 4</ion-label>
|
||||
<ion-radio value="4" slot="start"></ion-radio>
|
||||
<ion-radio value="4">Item 4</ion-radio>
|
||||
</ion-item>
|
||||
</ion-radio-group>
|
||||
</ion-list>
|
||||
|
||||
@@ -1,19 +1,7 @@
|
||||
import { expect } from '@playwright/test';
|
||||
import type { Locator } from '@playwright/test';
|
||||
import { configs, test } from '@utils/test/playwright';
|
||||
import type { E2EPage } from '@utils/test/playwright';
|
||||
|
||||
configs().forEach(({ title, screenshot, config }) => {
|
||||
test.describe(title('radio-group: basic'), () => {
|
||||
test('should not have visual regressions', async ({ page }) => {
|
||||
await page.goto(`/src/components/radio-group/test/basic`, config);
|
||||
|
||||
const list = page.locator('ion-list');
|
||||
|
||||
await expect(list).toHaveScreenshot(screenshot(`radio-group-diff`));
|
||||
});
|
||||
});
|
||||
});
|
||||
import { RadioFixture } from '../fixtures';
|
||||
|
||||
/**
|
||||
* This behavior does not vary across modes/directions.
|
||||
@@ -31,8 +19,7 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
|
||||
`
|
||||
<ion-radio-group value="one" allow-empty-selection="false">
|
||||
<ion-item>
|
||||
<ion-label>One</ion-label>
|
||||
<ion-radio id="one" value="one"></ion-radio>
|
||||
<ion-radio id="one" value="one">One</ion-radio>
|
||||
</ion-item>
|
||||
</ion-radio-group>
|
||||
`,
|
||||
@@ -48,8 +35,7 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
|
||||
`
|
||||
<ion-radio-group value="one" allow-empty-selection="true">
|
||||
<ion-item>
|
||||
<ion-label>One</ion-label>
|
||||
<ion-radio id="one" value="one"></ion-radio>
|
||||
<ion-radio id="one" value="one">One</ion-radio>
|
||||
</ion-item>
|
||||
</ion-radio-group>
|
||||
`,
|
||||
@@ -65,8 +51,7 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
|
||||
`
|
||||
<ion-radio-group value="one" allow-empty-selection="false">
|
||||
<ion-item>
|
||||
<ion-label>One</ion-label>
|
||||
<ion-radio id="one" value="one"></ion-radio>
|
||||
<ion-radio id="one" value="one">One</ion-radio>
|
||||
</ion-item>
|
||||
</ion-radio-group>
|
||||
`,
|
||||
@@ -82,8 +67,7 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
|
||||
`
|
||||
<ion-radio-group value="one" allow-empty-selection="true">
|
||||
<ion-item>
|
||||
<ion-label>One</ion-label>
|
||||
<ion-radio id="one" value="one"></ion-radio>
|
||||
<ion-radio id="one" value="one">One</ion-radio>
|
||||
</ion-item>
|
||||
</ion-radio-group>
|
||||
`,
|
||||
@@ -99,18 +83,15 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
|
||||
`
|
||||
<ion-radio-group value="1">
|
||||
<ion-item>
|
||||
<ion-label>Item 1</ion-label>
|
||||
<ion-radio value="1" slot="start"></ion-radio>
|
||||
<ion-radio value="1">Item 1</ion-radio>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Item 2</ion-label>
|
||||
<ion-radio value="2" slot="start"></ion-radio>
|
||||
<ion-radio value="2">Item 2</ion-radio>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Item 3</ion-label>
|
||||
<ion-radio value="3" slot="start"></ion-radio>
|
||||
<ion-radio value="3">Item 3</ion-radio>
|
||||
</ion-item>
|
||||
</ion-radio-group>
|
||||
`,
|
||||
@@ -130,34 +111,3 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
class RadioFixture {
|
||||
readonly page: E2EPage;
|
||||
|
||||
private radio!: Locator;
|
||||
|
||||
constructor(page: E2EPage) {
|
||||
this.page = page;
|
||||
}
|
||||
|
||||
async checkRadio(method: 'keyboard' | 'mouse', selector = 'ion-radio') {
|
||||
const { page } = this;
|
||||
const radio = (this.radio = page.locator(selector));
|
||||
|
||||
if (method === 'keyboard') {
|
||||
await radio.focus();
|
||||
await page.keyboard.press('Space');
|
||||
} else {
|
||||
await radio.click();
|
||||
}
|
||||
|
||||
await page.waitForChanges();
|
||||
|
||||
return radio;
|
||||
}
|
||||
|
||||
async expectChecked(state: boolean) {
|
||||
const { radio } = this;
|
||||
await expect(radio.locator('input')).toHaveJSProperty('checked', state);
|
||||
}
|
||||
}
|
||||
|
||||
39
core/src/components/radio-group/test/fixtures.ts
Normal file
@@ -0,0 +1,39 @@
|
||||
import type { Locator } from '@playwright/test';
|
||||
import { expect } from '@playwright/test';
|
||||
import type { E2EPage } from '@utils/test/playwright';
|
||||
|
||||
export class RadioFixture {
|
||||
readonly page: E2EPage;
|
||||
|
||||
private radio!: Locator;
|
||||
|
||||
constructor(page: E2EPage) {
|
||||
this.page = page;
|
||||
}
|
||||
|
||||
async checkRadio(method: 'keyboard' | 'mouse', selector = 'ion-radio') {
|
||||
const { page } = this;
|
||||
const radio = (this.radio = page.locator(selector));
|
||||
|
||||
if (method === 'keyboard') {
|
||||
await radio.focus();
|
||||
await page.keyboard.press('Space');
|
||||
} else {
|
||||
await radio.click();
|
||||
}
|
||||
|
||||
await page.waitForChanges();
|
||||
|
||||
return radio;
|
||||
}
|
||||
|
||||
async expectChecked(state: boolean) {
|
||||
const { radio } = this;
|
||||
|
||||
if (state) {
|
||||
await expect(radio).toHaveClass(/radio-checked/);
|
||||
} else {
|
||||
await expect(radio).not.toHaveClass(/radio-checked/);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -31,32 +31,19 @@
|
||||
</ion-list-header>
|
||||
|
||||
<ion-item>
|
||||
<ion-label
|
||||
>Biff
|
||||
<span id="biff"></span>
|
||||
</ion-label>
|
||||
<ion-radio value="biff" slot="start"></ion-radio>
|
||||
<ion-radio value="biff">Biff</ion-radio>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label
|
||||
>Griff
|
||||
<span id="griff"></span>
|
||||
</ion-label>
|
||||
<ion-radio value="griff" slot="start"></ion-radio>
|
||||
<ion-radio value="griff">Griff</ion-radio>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label
|
||||
>Buford
|
||||
<span id="buford"></span>
|
||||
</ion-label>
|
||||
<ion-radio value="buford" slot="start"></ion-radio>
|
||||
<ion-radio value="buford">Buford</ion-radio>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>George</ion-label>
|
||||
<ion-radio value="george" disabled slot="start"></ion-radio>
|
||||
<ion-radio value="george" disabled>George</ion-radio>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
|
||||
56
core/src/components/radio-group/test/legacy/basic/index.html
Normal file
@@ -0,0 +1,56 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" dir="ltr">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Radio Group - Basic</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 nomodule src="../../../../../dist/ionic/ionic.js"></script>
|
||||
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<ion-app>
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>Radio Group - Basic</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content>
|
||||
<ion-list>
|
||||
<ion-radio-group name="items" id="group" value="1">
|
||||
<ion-list-header>
|
||||
<ion-label>Radio Group Header</ion-label>
|
||||
</ion-list-header>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Item 1</ion-label>
|
||||
<ion-radio value="1" slot="start"></ion-radio>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Item 2</ion-label>
|
||||
<ion-radio value="2" slot="start"></ion-radio>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Item 3</ion-label>
|
||||
<ion-radio value="3" slot="start"></ion-radio>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Item 4</ion-label>
|
||||
<ion-radio value="4" slot="start"></ion-radio>
|
||||
</ion-item>
|
||||
</ion-radio-group>
|
||||
</ion-list>
|
||||
</ion-content>
|
||||
</ion-app>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,163 @@
|
||||
import { expect } from '@playwright/test';
|
||||
import type { Locator } from '@playwright/test';
|
||||
import { configs, test } from '@utils/test/playwright';
|
||||
import type { E2EPage } from '@utils/test/playwright';
|
||||
|
||||
configs().forEach(({ title, screenshot, config }) => {
|
||||
test.describe(title('radio-group: basic'), () => {
|
||||
test('should not have visual regressions', async ({ page }) => {
|
||||
await page.goto(`/src/components/radio-group/test/legacy/basic`, config);
|
||||
|
||||
const list = page.locator('ion-list');
|
||||
|
||||
await expect(list).toHaveScreenshot(screenshot(`radio-group-diff`));
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
/**
|
||||
* This behavior does not vary across modes/directions.
|
||||
*/
|
||||
configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
test.describe(title('radio-group: interaction'), () => {
|
||||
let radioFixture: RadioFixture;
|
||||
|
||||
test.beforeEach(({ page }) => {
|
||||
radioFixture = new RadioFixture(page);
|
||||
});
|
||||
|
||||
test('spacebar should not deselect without allowEmptySelection', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-radio-group value="one" allow-empty-selection="false">
|
||||
<ion-item>
|
||||
<ion-label>One</ion-label>
|
||||
<ion-radio id="one" value="one"></ion-radio>
|
||||
</ion-item>
|
||||
</ion-radio-group>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
await radioFixture.checkRadio('keyboard');
|
||||
await radioFixture.expectChecked(true);
|
||||
});
|
||||
|
||||
test('spacebar should deselect with allowEmptySelection', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-radio-group value="one" allow-empty-selection="true">
|
||||
<ion-item>
|
||||
<ion-label>One</ion-label>
|
||||
<ion-radio id="one" value="one"></ion-radio>
|
||||
</ion-item>
|
||||
</ion-radio-group>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
await radioFixture.checkRadio('keyboard');
|
||||
await radioFixture.expectChecked(false);
|
||||
});
|
||||
|
||||
test('click should not deselect without allowEmptySelection', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-radio-group value="one" allow-empty-selection="false">
|
||||
<ion-item>
|
||||
<ion-label>One</ion-label>
|
||||
<ion-radio id="one" value="one"></ion-radio>
|
||||
</ion-item>
|
||||
</ion-radio-group>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
await radioFixture.checkRadio('mouse');
|
||||
await radioFixture.expectChecked(true);
|
||||
});
|
||||
|
||||
test('click should deselect with allowEmptySelection', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-radio-group value="one" allow-empty-selection="true">
|
||||
<ion-item>
|
||||
<ion-label>One</ion-label>
|
||||
<ion-radio id="one" value="one"></ion-radio>
|
||||
</ion-item>
|
||||
</ion-radio-group>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
await radioFixture.checkRadio('mouse');
|
||||
await radioFixture.expectChecked(false);
|
||||
});
|
||||
|
||||
test('programmatically assigning a value should update the checked radio', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-radio-group value="1">
|
||||
<ion-item>
|
||||
<ion-label>Item 1</ion-label>
|
||||
<ion-radio value="1" slot="start"></ion-radio>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Item 2</ion-label>
|
||||
<ion-radio value="2" slot="start"></ion-radio>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>Item 3</ion-label>
|
||||
<ion-radio value="3" slot="start"></ion-radio>
|
||||
</ion-item>
|
||||
</ion-radio-group>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
const radioGroup = page.locator('ion-radio-group');
|
||||
const radioOne = page.locator('ion-radio[value="1"]');
|
||||
const radioTwo = page.locator('ion-radio[value="2"]');
|
||||
|
||||
await radioGroup.evaluate((el: HTMLIonRadioGroupElement) => (el.value = '2'));
|
||||
|
||||
await page.waitForChanges();
|
||||
|
||||
await expect(radioOne).not.toHaveClass(/radio-checked/);
|
||||
await expect(radioTwo).toHaveClass(/radio-checked/);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
class RadioFixture {
|
||||
readonly page: E2EPage;
|
||||
|
||||
private radio!: Locator;
|
||||
|
||||
constructor(page: E2EPage) {
|
||||
this.page = page;
|
||||
}
|
||||
|
||||
async checkRadio(method: 'keyboard' | 'mouse', selector = 'ion-radio') {
|
||||
const { page } = this;
|
||||
const radio = (this.radio = page.locator(selector));
|
||||
|
||||
if (method === 'keyboard') {
|
||||
await radio.focus();
|
||||
await page.keyboard.press('Space');
|
||||
} else {
|
||||
await radio.click();
|
||||
}
|
||||
|
||||
await page.waitForChanges();
|
||||
|
||||
return radio;
|
||||
}
|
||||
|
||||
async expectChecked(state: boolean) {
|
||||
const { radio } = this;
|
||||
await expect(radio.locator('input')).toHaveJSProperty('checked', state);
|
||||
}
|
||||
}
|
||||
|
Before Width: | Height: | Size: 8.1 KiB After Width: | Height: | Size: 8.1 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 7.4 KiB |
|
Before Width: | Height: | Size: 8.0 KiB After Width: | Height: | Size: 8.0 KiB |
|
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
|
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 7.4 KiB |
|
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 9.3 KiB |
|
Before Width: | Height: | Size: 9.5 KiB After Width: | Height: | Size: 9.5 KiB |
|
Before Width: | Height: | Size: 8.2 KiB After Width: | Height: | Size: 8.2 KiB |
|
Before Width: | Height: | Size: 9.3 KiB After Width: | Height: | Size: 9.3 KiB |
|
Before Width: | Height: | Size: 9.7 KiB After Width: | Height: | Size: 9.7 KiB |
|
Before Width: | Height: | Size: 8.1 KiB After Width: | Height: | Size: 8.1 KiB |
114
core/src/components/radio-group/test/legacy/form/index.html
Normal file
@@ -0,0 +1,114 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" dir="ltr">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Radio Group - Form</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 nomodule src="../../../../../dist/ionic/ionic.js"></script>
|
||||
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<ion-app>
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>Radio Group - Form</ion-title>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content class="outer-content">
|
||||
<form>
|
||||
<ion-list>
|
||||
<ion-radio-group name="tannen" id="group" value="biff">
|
||||
<ion-list-header>
|
||||
<ion-label>Luckiest Man On Earth</ion-label>
|
||||
</ion-list-header>
|
||||
|
||||
<ion-item>
|
||||
<ion-label
|
||||
>Biff
|
||||
<span id="biff"></span>
|
||||
</ion-label>
|
||||
<ion-radio value="biff" slot="start"></ion-radio>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label
|
||||
>Griff
|
||||
<span id="griff"></span>
|
||||
</ion-label>
|
||||
<ion-radio value="griff" slot="start"></ion-radio>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label
|
||||
>Buford
|
||||
<span id="buford"></span>
|
||||
</ion-label>
|
||||
<ion-radio value="buford" slot="start"></ion-radio>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-label>George</ion-label>
|
||||
<ion-radio value="george" disabled slot="start"></ion-radio>
|
||||
</ion-item>
|
||||
|
||||
<ion-item>
|
||||
<ion-button type="submit">Submit</ion-button>
|
||||
</ion-item>
|
||||
</ion-radio-group>
|
||||
</ion-list>
|
||||
</form>
|
||||
|
||||
<p style="margin: 20px">
|
||||
Value:
|
||||
<span id="value"></span>
|
||||
</p>
|
||||
|
||||
<p style="margin: 20px">
|
||||
Changes:
|
||||
<span id="changes">0</span>
|
||||
</p>
|
||||
</ion-content>
|
||||
|
||||
<style>
|
||||
.outer-content {
|
||||
--background: #f2f2f2;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
var changes = 0;
|
||||
|
||||
document.getElementById('group').addEventListener('ionChange', function (ev) {
|
||||
document.getElementById('value').textContent = ev.detail.value;
|
||||
changes++;
|
||||
document.getElementById('changes').textContent = changes;
|
||||
});
|
||||
|
||||
var biff = 0;
|
||||
document.querySelector('[value="biff"]').addEventListener('ionSelect', function (ev) {
|
||||
biff++;
|
||||
document.getElementById('biff').textContent = biff;
|
||||
});
|
||||
|
||||
var griff = 0;
|
||||
document.querySelector('[value="griff"]').addEventListener('ionSelect', function (ev) {
|
||||
griff++;
|
||||
document.getElementById('griff').textContent = griff;
|
||||
});
|
||||
|
||||
var buford = 0;
|
||||
document.querySelector('[value="buford"]').addEventListener('ionSelect', function (ev) {
|
||||
buford++;
|
||||
document.getElementById('buford').textContent = buford;
|
||||
});
|
||||
</script>
|
||||
</ion-app>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,35 @@
|
||||
import { expect } from '@playwright/test';
|
||||
import { configs, test } from '@utils/test/playwright';
|
||||
|
||||
configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
test.describe(title('radio-group: form'), () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/src/components/radio-group/test/legacy/form', config);
|
||||
});
|
||||
|
||||
test('selecting an option should update the value', async ({ page }) => {
|
||||
const radioGroup = page.locator('ion-radio-group');
|
||||
const ionChange = await page.spyOnEvent('ionChange');
|
||||
const griffRadio = page.locator('ion-radio[value="griff"]');
|
||||
await expect(radioGroup).toHaveAttribute('value', 'biff');
|
||||
|
||||
await griffRadio.click();
|
||||
await page.waitForChanges();
|
||||
|
||||
await expect(ionChange).toHaveReceivedEventDetail({ value: 'griff', event: { isTrusted: true } });
|
||||
});
|
||||
|
||||
test('selecting a disabled option should not update the value', async ({ page }) => {
|
||||
const value = page.locator('#value');
|
||||
const disabledRadio = page.locator('ion-radio[value="george"]');
|
||||
|
||||
await expect(value).toHaveText('');
|
||||
await expect(disabledRadio).toHaveAttribute('disabled', '');
|
||||
|
||||
await disabledRadio.click({ force: true });
|
||||
await page.waitForChanges();
|
||||
|
||||
await expect(value).toHaveText('');
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -0,0 +1,82 @@
|
||||
<!DOCTYPE html>
|
||||
<html lang="en" dir="ltr">
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<title>Radio Group - Search</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 nomodule src="../../../../../dist/ionic/ionic.js"></script>
|
||||
<script type="module" src="../../../../../dist/ionic/ionic.esm.js"></script>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<ion-app>
|
||||
<ion-header>
|
||||
<ion-toolbar>
|
||||
<ion-title>Radio Group - Form</ion-title>
|
||||
</ion-toolbar>
|
||||
<ion-toolbar>
|
||||
<ion-searchbar placeholder="Type to filter..." debounce="0"></ion-searchbar>
|
||||
</ion-toolbar>
|
||||
<ion-toolbar>
|
||||
<ion-note id="value">Current value:</ion-note>
|
||||
</ion-toolbar>
|
||||
</ion-header>
|
||||
|
||||
<ion-content class="outer-content">
|
||||
<ion-radio-group allow-empty-selection></ion-radio-group>
|
||||
</ion-content>
|
||||
|
||||
<style>
|
||||
ion-note {
|
||||
padding: 0 10px;
|
||||
}
|
||||
</style>
|
||||
<script>
|
||||
const radioGroup = document.querySelector('ion-radio-group');
|
||||
const searchbar = document.querySelector('ion-searchbar');
|
||||
const currentValue = document.querySelector('#value');
|
||||
|
||||
radioGroup.addEventListener('ionChange', (ev) => {
|
||||
currentValue.innerText = `Current value: ${ev.detail.value}`;
|
||||
});
|
||||
|
||||
searchbar.addEventListener('ionChange', (ev) => {
|
||||
filter(ev.detail.value);
|
||||
});
|
||||
|
||||
const filter = (value) => {
|
||||
const query = value != null ? value.toLowerCase() : '';
|
||||
const data = [
|
||||
{ id: 0, value: 'zero' },
|
||||
{ id: 1, value: 'one' },
|
||||
{ id: 2, value: 'two' },
|
||||
{ id: 3, value: 'three' },
|
||||
];
|
||||
|
||||
let html = '';
|
||||
|
||||
data.forEach((d) => {
|
||||
if (d.value.includes(query)) {
|
||||
html += `
|
||||
<ion-item>
|
||||
<ion-label>Item ${d.value}</ion-label>
|
||||
<ion-radio value="${d.value}"></ion-radio>
|
||||
</ion-item>
|
||||
`;
|
||||
}
|
||||
});
|
||||
|
||||
radioGroup.innerHTML = html;
|
||||
};
|
||||
|
||||
filter();
|
||||
</script>
|
||||
</ion-app>
|
||||
</body>
|
||||
</html>
|
||||
@@ -0,0 +1,42 @@
|
||||
import { expect } from '@playwright/test';
|
||||
import { configs, test } from '@utils/test/playwright';
|
||||
|
||||
/**
|
||||
* This behavior does not var across modes/directions.
|
||||
*/
|
||||
configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
test.describe(title('radio-group'), () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.goto('/src/components/radio-group/test/legacy/search', config);
|
||||
});
|
||||
|
||||
test.describe('radio-group: state', () => {
|
||||
test('radio should remain checked after being removed/readded to the dom', async ({ page }) => {
|
||||
const radioGroup = page.locator('ion-radio-group');
|
||||
const radio = page.locator('ion-radio[value=two]');
|
||||
const searchbarInput = page.locator('ion-searchbar input');
|
||||
|
||||
// select radio
|
||||
await radio.click();
|
||||
await expect(radio.locator('input')).toHaveJSProperty('checked', true);
|
||||
|
||||
// filter radio so it is not in DOM
|
||||
await page.fill('ion-searchbar input', 'zero');
|
||||
await searchbarInput.evaluate((el) => el.blur());
|
||||
await page.waitForChanges();
|
||||
await expect(radio).toBeHidden();
|
||||
|
||||
// ensure radio group has the same value
|
||||
await expect(radioGroup).toHaveJSProperty('value', 'two');
|
||||
|
||||
// clear the search so the radio appears
|
||||
await page.fill('ion-searchbar input', '');
|
||||
await searchbarInput.evaluate((el) => el.blur());
|
||||
await page.waitForChanges();
|
||||
|
||||
// ensure that the new radio instance is still checked
|
||||
await expect(radio.locator('input')).toHaveJSProperty('checked', true);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -65,8 +65,7 @@
|
||||
if (d.value.includes(query)) {
|
||||
html += `
|
||||
<ion-item>
|
||||
<ion-label>Item ${d.value}</ion-label>
|
||||
<ion-radio value="${d.value}"></ion-radio>
|
||||
<ion-radio value="${d.value}">Item ${d.value}</ion-radio>
|
||||
</ion-item>
|
||||
`;
|
||||
}
|
||||
|
||||
@@ -1,42 +1,41 @@
|
||||
import { expect } from '@playwright/test';
|
||||
import { configs, test } from '@utils/test/playwright';
|
||||
|
||||
import { RadioFixture } from '../fixtures';
|
||||
|
||||
/**
|
||||
* This behavior does not var across modes/directions.
|
||||
*/
|
||||
configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
test.describe(title('radio-group'), () => {
|
||||
test.beforeEach(async ({ page }) => {
|
||||
test.describe(title('radio-group: search'), () => {
|
||||
test('radio should remain checked after being removed/readded to the dom', async ({ page }) => {
|
||||
await page.goto('/src/components/radio-group/test/search', config);
|
||||
});
|
||||
|
||||
test.describe('radio-group: state', () => {
|
||||
test('radio should remain checked after being removed/readded to the dom', async ({ page }) => {
|
||||
const radioGroup = page.locator('ion-radio-group');
|
||||
const radio = page.locator('ion-radio[value=two]');
|
||||
const searchbarInput = page.locator('ion-searchbar input');
|
||||
const radioFixture = new RadioFixture(page);
|
||||
|
||||
// select radio
|
||||
await radio.click();
|
||||
await expect(radio.locator('input')).toHaveJSProperty('checked', true);
|
||||
const radioGroup = page.locator('ion-radio-group');
|
||||
const searchbarInput = page.locator('ion-searchbar input');
|
||||
|
||||
// filter radio so it is not in DOM
|
||||
await page.fill('ion-searchbar input', 'zero');
|
||||
await searchbarInput.evaluate((el) => el.blur());
|
||||
await page.waitForChanges();
|
||||
await expect(radio).toBeHidden();
|
||||
// select radio
|
||||
const radio = await radioFixture.checkRadio('mouse', 'ion-radio[value=two]');
|
||||
await radioFixture.expectChecked(true);
|
||||
|
||||
// ensure radio group has the same value
|
||||
await expect(radioGroup).toHaveJSProperty('value', 'two');
|
||||
// filter radio so it is not in DOM
|
||||
await page.fill('ion-searchbar input', 'zero');
|
||||
await searchbarInput.evaluate((el) => el.blur());
|
||||
await page.waitForChanges();
|
||||
await expect(radio).toBeHidden();
|
||||
|
||||
// clear the search so the radio appears
|
||||
await page.fill('ion-searchbar input', '');
|
||||
await searchbarInput.evaluate((el) => el.blur());
|
||||
await page.waitForChanges();
|
||||
// ensure radio group has the same value
|
||||
await expect(radioGroup).toHaveJSProperty('value', 'two');
|
||||
|
||||
// ensure that the new radio instance is still checked
|
||||
await expect(radio.locator('input')).toHaveJSProperty('checked', true);
|
||||
});
|
||||
// clear the search so the radio appears
|
||||
await page.fill('ion-searchbar input', '');
|
||||
await searchbarInput.evaluate((el) => el.blur());
|
||||
await page.waitForChanges();
|
||||
|
||||
// ensure that the new radio instance is still checked
|
||||
await radioFixture.expectChecked(true);
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,8 +2,7 @@ import type { ComponentInterface, EventEmitter } from '@stencil/core';
|
||||
import { Component, Element, Event, Host, Method, Prop, State, Watch, h } from '@stencil/core';
|
||||
import type { LegacyFormController } from '@utils/forms';
|
||||
import { createLegacyFormController } from '@utils/forms';
|
||||
import type { Attributes } from '@utils/helpers';
|
||||
import { addEventListener, getAriaLabel, inheritAriaAttributes, removeEventListener } from '@utils/helpers';
|
||||
import { addEventListener, getAriaLabel, removeEventListener } from '@utils/helpers';
|
||||
import { printIonWarning } from '@utils/logging';
|
||||
import { createColorClasses, hostContext } from '@utils/theme';
|
||||
|
||||
@@ -31,7 +30,6 @@ export class Radio implements ComponentInterface {
|
||||
private radioGroup: HTMLIonRadioGroupElement | null = null;
|
||||
private nativeInput!: HTMLInputElement;
|
||||
private legacyFormController!: LegacyFormController;
|
||||
private inheritedAttributes: Attributes = {};
|
||||
|
||||
// This flag ensures we log the deprecation warning at most once.
|
||||
private hasLoggedDeprecationWarning = false;
|
||||
@@ -135,8 +133,7 @@ export class Radio implements ComponentInterface {
|
||||
ev.stopPropagation();
|
||||
ev.preventDefault();
|
||||
|
||||
const element = this.legacyFormController.hasLegacyControl() ? this.el : this.nativeInput;
|
||||
element.focus();
|
||||
this.el.focus();
|
||||
}
|
||||
|
||||
/** @internal */
|
||||
@@ -167,12 +164,6 @@ export class Radio implements ComponentInterface {
|
||||
|
||||
componentWillLoad() {
|
||||
this.emitStyle();
|
||||
|
||||
if (!this.legacyFormController.hasLegacyControl()) {
|
||||
this.inheritedAttributes = {
|
||||
...inheritAriaAttributes(this.el),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@Watch('checked')
|
||||
@@ -201,7 +192,34 @@ export class Radio implements ComponentInterface {
|
||||
};
|
||||
|
||||
private onClick = () => {
|
||||
this.checked = this.nativeInput.checked;
|
||||
const { radioGroup, checked } = this;
|
||||
|
||||
/**
|
||||
* The legacy control uses a native input inside
|
||||
* of the radio host, so we can set this.checked
|
||||
* to the state of the nativeInput. RadioGroup
|
||||
* will prevent the native input from checking if
|
||||
* allowEmptySelection="false" by calling ev.preventDefault().
|
||||
*/
|
||||
if (this.legacyFormController.hasLegacyControl()) {
|
||||
this.checked = this.nativeInput.checked;
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* The modern control does not use a native input
|
||||
* inside of the radio host, so we cannot rely on the
|
||||
* ev.preventDefault() behavior above. If the radio
|
||||
* is checked and the parent radio group allows for empty
|
||||
* selection, then we can set the checked state to false.
|
||||
* Otherwise, the checked state should always be set
|
||||
* to true because the checked state cannot be toggled.
|
||||
*/
|
||||
if (checked && radioGroup?.allowEmptySelection) {
|
||||
this.checked = false;
|
||||
} else {
|
||||
this.checked = true;
|
||||
}
|
||||
};
|
||||
|
||||
private onFocus = () => {
|
||||
@@ -232,23 +250,14 @@ export class Radio implements ComponentInterface {
|
||||
}
|
||||
|
||||
private renderRadio() {
|
||||
const {
|
||||
checked,
|
||||
disabled,
|
||||
inputId,
|
||||
color,
|
||||
el,
|
||||
justify,
|
||||
labelPlacement,
|
||||
inheritedAttributes,
|
||||
hasLabel,
|
||||
buttonTabindex,
|
||||
} = this;
|
||||
const { checked, disabled, color, el, justify, labelPlacement, hasLabel, buttonTabindex } = this;
|
||||
const mode = getIonMode(this);
|
||||
const inItem = hostContext('ion-item', el);
|
||||
|
||||
return (
|
||||
<Host
|
||||
onFocus={this.onFocus}
|
||||
onBlur={this.onBlur}
|
||||
onClick={this.onClick}
|
||||
class={createColorClasses(color, {
|
||||
[mode]: true,
|
||||
@@ -261,21 +270,12 @@ export class Radio implements ComponentInterface {
|
||||
'ion-activatable': !inItem,
|
||||
'ion-focusable': !inItem,
|
||||
})}
|
||||
role="radio"
|
||||
aria-checked={checked ? 'true' : 'false'}
|
||||
aria-disabled={disabled ? 'true' : null}
|
||||
tabindex={buttonTabindex}
|
||||
>
|
||||
<label class="radio-wrapper">
|
||||
{/*
|
||||
The native control must be rendered
|
||||
before the visible label text due to https://bugs.webkit.org/show_bug.cgi?id=251951
|
||||
*/}
|
||||
<input
|
||||
type="radio"
|
||||
checked={checked}
|
||||
disabled={disabled}
|
||||
id={inputId}
|
||||
tabindex={buttonTabindex}
|
||||
ref={(nativeEl) => (this.nativeInput = nativeEl as HTMLInputElement)}
|
||||
{...inheritedAttributes}
|
||||
/>
|
||||
<div
|
||||
class={{
|
||||
'label-text-wrapper': true,
|
||||
|
||||
@@ -16,10 +16,7 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
|
||||
});
|
||||
|
||||
test.describe(title('radio: keyboard navigation'), () => {
|
||||
test.beforeEach(async ({ page, skip }) => {
|
||||
// TODO (FW-2979)
|
||||
skip.browser('webkit', 'Safari 16 only allows text fields and pop-up menus to be focused.');
|
||||
|
||||
test.beforeEach(async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-app>
|
||||
|
||||
@@ -95,7 +95,7 @@ configs().forEach(({ title, screenshot, config }) => {
|
||||
test('should apply color correctly', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-radio slot="start" value="pepperoni" color="success"></ion-radio>
|
||||
<ion-radio legacy="true" value="pepperoni" color="success"></ion-radio>
|
||||
`,
|
||||
config
|
||||
);
|
||||
@@ -138,7 +138,7 @@ configs({ directions: ['ltr'] }).forEach(({ title, config }) => {
|
||||
test('radio should be checked when activated even without a radio group', async ({ page }) => {
|
||||
await page.setContent(
|
||||
`
|
||||
<ion-radio slot="start" value="pepperoni"></ion-radio>
|
||||
<ion-radio legacy="true" value="pepperoni"></ion-radio>
|
||||
`,
|
||||
config
|
||||
);
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [7.2.1](https://github.com/ionic-team/ionic-framework/compare/v7.2.0...v7.2.1) (2023-07-26)
|
||||
|
||||
**Note:** Version bump only for package @ionic/docs
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [7.2.0](https://github.com/ionic-team/ionic-framework/compare/v7.1.4...v7.2.0) (2023-07-19)
|
||||
|
||||
**Note:** Version bump only for package @ionic/docs
|
||||
|
||||
4
docs/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "@ionic/docs",
|
||||
"version": "7.2.0",
|
||||
"version": "7.2.1",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@ionic/docs",
|
||||
"version": "7.2.0",
|
||||
"version": "7.2.1",
|
||||
"license": "MIT"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/docs",
|
||||
"version": "7.2.0",
|
||||
"version": "7.2.1",
|
||||
"description": "Pre-packaged API documentation for the Ionic docs.",
|
||||
"main": "core.json",
|
||||
"types": "core.d.ts",
|
||||
|
||||
@@ -4,5 +4,5 @@
|
||||
"docs",
|
||||
"packages/*"
|
||||
],
|
||||
"version": "7.2.0"
|
||||
"version": "7.2.1"
|
||||
}
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [7.2.1](https://github.com/ionic-team/ionic-framework/compare/v7.2.0...v7.2.1) (2023-07-26)
|
||||
|
||||
**Note:** Version bump only for package @ionic/angular-server
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [7.2.0](https://github.com/ionic-team/ionic-framework/compare/v7.1.4...v7.2.0) (2023-07-19)
|
||||
|
||||
**Note:** Version bump only for package @ionic/angular-server
|
||||
|
||||
18
packages/angular-server/package-lock.json
generated
@@ -1,15 +1,15 @@
|
||||
{
|
||||
"name": "@ionic/angular-server",
|
||||
"version": "7.2.0",
|
||||
"version": "7.2.1",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@ionic/angular-server",
|
||||
"version": "7.2.0",
|
||||
"version": "7.2.1",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ionic/core": "^7.2.0"
|
||||
"@ionic/core": "^7.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@angular-eslint/eslint-plugin": "^14.0.0",
|
||||
@@ -1060,9 +1060,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@ionic/core": {
|
||||
"version": "7.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.1.4.tgz",
|
||||
"integrity": "sha512-/h32Sc7Jd8csdMZ6BhddoTGC/X7cO0tIOeDuyC/ypMarXajScHc0pgVEBneAA7PVBEVxsoeMDP7yuqJt6Duaiw==",
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.2.1.tgz",
|
||||
"integrity": "sha512-7I3OIGHIhGCXxswphP3vfuyCCjXysAUg4cfKGB2QQ5e073DPsZkMSpVam19nAIjEDyfK2pQZC+SgSkZvvCc+2A==",
|
||||
"dependencies": {
|
||||
"@stencil/core": "^3.4.0",
|
||||
"ionicons": "7.1.0",
|
||||
@@ -7342,9 +7342,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@ionic/core": {
|
||||
"version": "7.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.1.4.tgz",
|
||||
"integrity": "sha512-/h32Sc7Jd8csdMZ6BhddoTGC/X7cO0tIOeDuyC/ypMarXajScHc0pgVEBneAA7PVBEVxsoeMDP7yuqJt6Duaiw==",
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.2.1.tgz",
|
||||
"integrity": "sha512-7I3OIGHIhGCXxswphP3vfuyCCjXysAUg4cfKGB2QQ5e073DPsZkMSpVam19nAIjEDyfK2pQZC+SgSkZvvCc+2A==",
|
||||
"requires": {
|
||||
"@stencil/core": "^3.4.0",
|
||||
"ionicons": "7.1.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/angular-server",
|
||||
"version": "7.2.0",
|
||||
"version": "7.2.1",
|
||||
"description": "Angular SSR Module for Ionic",
|
||||
"keywords": [
|
||||
"ionic",
|
||||
@@ -61,6 +61,6 @@
|
||||
},
|
||||
"prettier": "@ionic/prettier-config",
|
||||
"dependencies": {
|
||||
"@ionic/core": "^7.2.0"
|
||||
"@ionic/core": "^7.2.1"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [7.2.1](https://github.com/ionic-team/ionic-framework/compare/v7.2.0...v7.2.1) (2023-07-26)
|
||||
|
||||
**Note:** Version bump only for package @ionic/angular
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [7.2.0](https://github.com/ionic-team/ionic-framework/compare/v7.1.4...v7.2.0) (2023-07-19)
|
||||
|
||||
|
||||
|
||||
18
packages/angular/package-lock.json
generated
@@ -1,15 +1,15 @@
|
||||
{
|
||||
"name": "@ionic/angular",
|
||||
"version": "7.2.0",
|
||||
"version": "7.2.1",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@ionic/angular",
|
||||
"version": "7.2.0",
|
||||
"version": "7.2.1",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ionic/core": "^7.2.0",
|
||||
"@ionic/core": "^7.2.1",
|
||||
"ionicons": "^7.0.0",
|
||||
"jsonc-parser": "^3.0.0",
|
||||
"tslib": "^2.3.0"
|
||||
@@ -1227,9 +1227,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@ionic/core": {
|
||||
"version": "7.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.1.4.tgz",
|
||||
"integrity": "sha512-/h32Sc7Jd8csdMZ6BhddoTGC/X7cO0tIOeDuyC/ypMarXajScHc0pgVEBneAA7PVBEVxsoeMDP7yuqJt6Duaiw==",
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.2.1.tgz",
|
||||
"integrity": "sha512-7I3OIGHIhGCXxswphP3vfuyCCjXysAUg4cfKGB2QQ5e073DPsZkMSpVam19nAIjEDyfK2pQZC+SgSkZvvCc+2A==",
|
||||
"dependencies": {
|
||||
"@stencil/core": "^3.4.0",
|
||||
"ionicons": "7.1.0",
|
||||
@@ -8104,9 +8104,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@ionic/core": {
|
||||
"version": "7.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.1.4.tgz",
|
||||
"integrity": "sha512-/h32Sc7Jd8csdMZ6BhddoTGC/X7cO0tIOeDuyC/ypMarXajScHc0pgVEBneAA7PVBEVxsoeMDP7yuqJt6Duaiw==",
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.2.1.tgz",
|
||||
"integrity": "sha512-7I3OIGHIhGCXxswphP3vfuyCCjXysAUg4cfKGB2QQ5e073DPsZkMSpVam19nAIjEDyfK2pQZC+SgSkZvvCc+2A==",
|
||||
"requires": {
|
||||
"@stencil/core": "^3.4.0",
|
||||
"ionicons": "7.1.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/angular",
|
||||
"version": "7.2.0",
|
||||
"version": "7.2.1",
|
||||
"description": "Angular specific wrappers for @ionic/core",
|
||||
"keywords": [
|
||||
"ionic",
|
||||
@@ -47,7 +47,7 @@
|
||||
}
|
||||
},
|
||||
"dependencies": {
|
||||
"@ionic/core": "^7.2.0",
|
||||
"@ionic/core": "^7.2.1",
|
||||
"ionicons": "^7.0.0",
|
||||
"jsonc-parser": "^3.0.0",
|
||||
"tslib": "^2.3.0"
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [7.2.1](https://github.com/ionic-team/ionic-framework/compare/v7.2.0...v7.2.1) (2023-07-26)
|
||||
|
||||
**Note:** Version bump only for package @ionic/react-router
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [7.2.0](https://github.com/ionic-team/ionic-framework/compare/v7.1.4...v7.2.0) (2023-07-19)
|
||||
|
||||
**Note:** Version bump only for package @ionic/react-router
|
||||
|
||||
46
packages/react-router/package-lock.json
generated
@@ -1,15 +1,15 @@
|
||||
{
|
||||
"name": "@ionic/react-router",
|
||||
"version": "7.2.0",
|
||||
"version": "7.2.1",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@ionic/react-router",
|
||||
"version": "7.2.0",
|
||||
"version": "7.2.1",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ionic/react": "^7.2.0",
|
||||
"@ionic/react": "^7.2.1",
|
||||
"tslib": "*"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -205,9 +205,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@ionic/core": {
|
||||
"version": "7.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.1.4.tgz",
|
||||
"integrity": "sha512-/h32Sc7Jd8csdMZ6BhddoTGC/X7cO0tIOeDuyC/ypMarXajScHc0pgVEBneAA7PVBEVxsoeMDP7yuqJt6Duaiw==",
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.2.1.tgz",
|
||||
"integrity": "sha512-7I3OIGHIhGCXxswphP3vfuyCCjXysAUg4cfKGB2QQ5e073DPsZkMSpVam19nAIjEDyfK2pQZC+SgSkZvvCc+2A==",
|
||||
"dependencies": {
|
||||
"@stencil/core": "^3.4.0",
|
||||
"ionicons": "7.1.0",
|
||||
@@ -401,11 +401,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@ionic/react": {
|
||||
"version": "7.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/react/-/react-7.1.4.tgz",
|
||||
"integrity": "sha512-sy8a4TXMzS3cfGEAr7gb73PYn+0VsmfUkpAJdH2rd4C9qdcvNqQfL3Yy+Ut9HfsvY6lk3LJsm1+eeqPbKgG94w==",
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/react/-/react-7.2.1.tgz",
|
||||
"integrity": "sha512-z9PSPoBiHsdwotdywGcnln1y01wjLoS09vmCUboc+2qSadVMczcjEuBxfRIvjVbaQt3u8RGHif2+K3AgGNKMeA==",
|
||||
"dependencies": {
|
||||
"@ionic/core": "7.1.4",
|
||||
"@ionic/core": "7.2.1",
|
||||
"ionicons": "^7.0.0",
|
||||
"tslib": "*"
|
||||
},
|
||||
@@ -486,9 +486,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@stencil/core": {
|
||||
"version": "3.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-3.4.1.tgz",
|
||||
"integrity": "sha512-7rjOmM0W9K5op2gtOQRLERGH1155rv2fm6ppxOzYqqG8ISct4m9skp5XgUBYPu+GSPsJFdRuCIQs0IuVsG/7+g==",
|
||||
"version": "3.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-3.4.2.tgz",
|
||||
"integrity": "sha512-FAUhUVaakCy29nU2GwO/HQBRV1ihPRvncz3PUc8oR+UJLAxGabTmP8PLY7wvHfbw+Cvi4VXfJFTBvdfDu6iKPQ==",
|
||||
"bin": {
|
||||
"stencil": "bin/stencil"
|
||||
},
|
||||
@@ -3663,9 +3663,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@ionic/core": {
|
||||
"version": "7.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.1.4.tgz",
|
||||
"integrity": "sha512-/h32Sc7Jd8csdMZ6BhddoTGC/X7cO0tIOeDuyC/ypMarXajScHc0pgVEBneAA7PVBEVxsoeMDP7yuqJt6Duaiw==",
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.2.1.tgz",
|
||||
"integrity": "sha512-7I3OIGHIhGCXxswphP3vfuyCCjXysAUg4cfKGB2QQ5e073DPsZkMSpVam19nAIjEDyfK2pQZC+SgSkZvvCc+2A==",
|
||||
"requires": {
|
||||
"@stencil/core": "^3.4.0",
|
||||
"ionicons": "7.1.0",
|
||||
@@ -3786,11 +3786,11 @@
|
||||
"requires": {}
|
||||
},
|
||||
"@ionic/react": {
|
||||
"version": "7.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/react/-/react-7.1.4.tgz",
|
||||
"integrity": "sha512-sy8a4TXMzS3cfGEAr7gb73PYn+0VsmfUkpAJdH2rd4C9qdcvNqQfL3Yy+Ut9HfsvY6lk3LJsm1+eeqPbKgG94w==",
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/react/-/react-7.2.1.tgz",
|
||||
"integrity": "sha512-z9PSPoBiHsdwotdywGcnln1y01wjLoS09vmCUboc+2qSadVMczcjEuBxfRIvjVbaQt3u8RGHif2+K3AgGNKMeA==",
|
||||
"requires": {
|
||||
"@ionic/core": "7.1.4",
|
||||
"@ionic/core": "7.2.1",
|
||||
"ionicons": "^7.0.0",
|
||||
"tslib": "*"
|
||||
}
|
||||
@@ -3844,9 +3844,9 @@
|
||||
}
|
||||
},
|
||||
"@stencil/core": {
|
||||
"version": "3.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-3.4.1.tgz",
|
||||
"integrity": "sha512-7rjOmM0W9K5op2gtOQRLERGH1155rv2fm6ppxOzYqqG8ISct4m9skp5XgUBYPu+GSPsJFdRuCIQs0IuVsG/7+g=="
|
||||
"version": "3.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-3.4.2.tgz",
|
||||
"integrity": "sha512-FAUhUVaakCy29nU2GwO/HQBRV1ihPRvncz3PUc8oR+UJLAxGabTmP8PLY7wvHfbw+Cvi4VXfJFTBvdfDu6iKPQ=="
|
||||
},
|
||||
"@types/estree": {
|
||||
"version": "0.0.39",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/react-router",
|
||||
"version": "7.2.0",
|
||||
"version": "7.2.1",
|
||||
"description": "React Router wrapper for @ionic/react",
|
||||
"keywords": [
|
||||
"ionic",
|
||||
@@ -37,7 +37,7 @@
|
||||
"dist/"
|
||||
],
|
||||
"dependencies": {
|
||||
"@ionic/react": "^7.2.0",
|
||||
"@ionic/react": "^7.2.1",
|
||||
"tslib": "*"
|
||||
},
|
||||
"peerDependencies": {
|
||||
|
||||
@@ -270,13 +270,13 @@ class IonRouterInner extends React.PureComponent<IonRouteProps, IonRouteState> {
|
||||
const goBack = history.goBack || history.back;
|
||||
goBack();
|
||||
} else {
|
||||
this.handleNavigate(prevInfo.pathname + (prevInfo.search || ''), 'pop', 'back');
|
||||
this.handleNavigate(prevInfo.pathname + (prevInfo.search || ''), 'pop', 'back', routeAnimation);
|
||||
}
|
||||
} else {
|
||||
this.handleNavigate(defaultHref as string, 'pop', 'back');
|
||||
this.handleNavigate(defaultHref as string, 'pop', 'back', routeAnimation);
|
||||
}
|
||||
} else {
|
||||
this.handleNavigate(defaultHref as string, 'pop', 'back');
|
||||
this.handleNavigate(defaultHref as string, 'pop', 'back', routeAnimation);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import type { RouteInfo, StackContextState, ViewItem } from '@ionic/react';
|
||||
import { RouteManagerContext, StackContext, generateId, getConfig } from '@ionic/react';
|
||||
import React from 'react';
|
||||
import type { PropsWithChildren } from 'react';
|
||||
import React, { cloneElement, useContext, useEffect, useMemo, useReducer, useRef, useState } from 'react';
|
||||
import { matchPath } from 'react-router-dom';
|
||||
|
||||
import { clonePageElement } from './clonePageElement';
|
||||
@@ -11,76 +12,93 @@ interface StackManagerProps {
|
||||
routeInfo: RouteInfo;
|
||||
}
|
||||
|
||||
// eslint-disable-next-line @typescript-eslint/no-empty-interface
|
||||
interface StackManagerState {}
|
||||
|
||||
const isViewVisible = (el: HTMLElement) =>
|
||||
!el.classList.contains('ion-page-invisible') && !el.classList.contains('ion-page-hidden');
|
||||
|
||||
export class StackManager extends React.PureComponent<StackManagerProps, StackManagerState> {
|
||||
id: string;
|
||||
context!: React.ContextType<typeof RouteManagerContext>;
|
||||
ionRouterOutlet?: React.ReactElement;
|
||||
routerOutletElement: HTMLIonRouterOutletElement | undefined;
|
||||
prevProps?: StackManagerProps;
|
||||
skipTransition: boolean;
|
||||
export const StackManager = ({ children, ...props }: PropsWithChildren<StackManagerProps>) => {
|
||||
const { routeInfo } = props;
|
||||
const {
|
||||
findViewItemByRouteInfo,
|
||||
findLeavingViewItemByRouteInfo,
|
||||
findViewItemByPathname,
|
||||
createViewItem,
|
||||
addViewItem,
|
||||
goBack,
|
||||
getChildrenToRender,
|
||||
clearOutlet,
|
||||
} = useContext(RouteManagerContext);
|
||||
|
||||
stackContextValue: StackContextState = {
|
||||
registerIonPage: this.registerIonPage.bind(this),
|
||||
isInOutlet: () => true,
|
||||
};
|
||||
const routerOutletRef = useRef<HTMLIonRouterOutletElement>();
|
||||
const ionRouterOutletRef = useRef<React.ReactElement>();
|
||||
const skipTransitionRef = useRef(false);
|
||||
const clearOutletTimeout = useRef(null);
|
||||
const pendingPageTransitionRef = useRef(false);
|
||||
const prevProps = useRef<{ routeInfo: RouteInfo }>();
|
||||
|
||||
private clearOutletTimeout: any;
|
||||
private pendingPageTransition = false;
|
||||
const forceUpdate = useReducer((x) => x + 1, 0)[1];
|
||||
|
||||
constructor(props: StackManagerProps) {
|
||||
super(props);
|
||||
this.registerIonPage = this.registerIonPage.bind(this);
|
||||
this.transitionPage = this.transitionPage.bind(this);
|
||||
this.handlePageTransition = this.handlePageTransition.bind(this);
|
||||
this.id = generateId('routerOutlet');
|
||||
this.prevProps = undefined;
|
||||
this.skipTransition = false;
|
||||
}
|
||||
const [id] = useState(generateId('routerOutlet'));
|
||||
|
||||
componentDidMount() {
|
||||
if (this.clearOutletTimeout) {
|
||||
/**
|
||||
* The clearOutlet integration with React Router is a bit hacky.
|
||||
* It uses a timeout to clear the outlet after a transition.
|
||||
* In React v18, components are mounted and unmounted in development mode
|
||||
* to check for side effects.
|
||||
*
|
||||
* This clearTimeout prevents the outlet from being cleared when the component is re-mounted,
|
||||
* which should only happen in development mode and as a result of a hot reload.
|
||||
*/
|
||||
clearTimeout(this.clearOutletTimeout);
|
||||
const stackContextValue: StackContextState = useMemo(
|
||||
() => ({
|
||||
isInOutlet: () => true,
|
||||
registerIonPage: (page: HTMLElement, routeInfo: RouteInfo) => {
|
||||
const foundView = findViewItemByRouteInfo(routeInfo, id);
|
||||
if (foundView) {
|
||||
const oldPageElement = foundView.ionPageElement;
|
||||
foundView.ionPageElement = page;
|
||||
foundView.ionRoute = true;
|
||||
|
||||
/**
|
||||
* React 18 will unmount and remount IonPage
|
||||
* elements in development mode when using createRoot.
|
||||
* This can cause duplicate page transitions to occur.
|
||||
*/
|
||||
if (oldPageElement === page) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
handlePageTransition(routeInfo);
|
||||
},
|
||||
}),
|
||||
[routerOutletRef.current]
|
||||
);
|
||||
|
||||
useEffect(() => {
|
||||
const routerOutletElement = routerOutletRef.current;
|
||||
if (routerOutletElement) {
|
||||
// Mount behavior for the initial route
|
||||
setupRouterOutlet(routerOutletElement);
|
||||
|
||||
handlePageTransition(routeInfo);
|
||||
}
|
||||
if (this.routerOutletElement) {
|
||||
this.setupRouterOutlet(this.routerOutletElement);
|
||||
this.handlePageTransition(this.props.routeInfo);
|
||||
}, []);
|
||||
|
||||
useEffect(() => {
|
||||
const { pathname } = routeInfo;
|
||||
|
||||
if (pathname !== prevProps.current?.routeInfo.pathname) {
|
||||
prevProps.current = props;
|
||||
handlePageTransition(routeInfo);
|
||||
} else if (pendingPageTransitionRef.current) {
|
||||
handlePageTransition(routeInfo);
|
||||
pendingPageTransitionRef.current = false;
|
||||
}
|
||||
}
|
||||
}, [routeInfo]);
|
||||
|
||||
componentDidUpdate(prevProps: StackManagerProps) {
|
||||
const { pathname } = this.props.routeInfo;
|
||||
const { pathname: prevPathname } = prevProps.routeInfo;
|
||||
useEffect(() => {
|
||||
return () => {
|
||||
clearOutlet(id);
|
||||
if (clearOutletTimeout.current) {
|
||||
clearTimeout(clearOutletTimeout.current);
|
||||
clearOutletTimeout.current = null;
|
||||
}
|
||||
};
|
||||
}, []);
|
||||
|
||||
if (pathname !== prevPathname) {
|
||||
this.prevProps = prevProps;
|
||||
this.handlePageTransition(this.props.routeInfo);
|
||||
} else if (this.pendingPageTransition) {
|
||||
this.handlePageTransition(this.props.routeInfo);
|
||||
this.pendingPageTransition = false;
|
||||
}
|
||||
}
|
||||
|
||||
componentWillUnmount() {
|
||||
this.clearOutletTimeout = this.context.clearOutlet(this.id);
|
||||
}
|
||||
|
||||
async handlePageTransition(routeInfo: RouteInfo) {
|
||||
if (!this.routerOutletElement || !this.routerOutletElement.commit) {
|
||||
const handlePageTransition = (routeInfo: RouteInfo) => {
|
||||
const routerOutletElement = routerOutletRef.current;
|
||||
if (!routerOutletElement || !routerOutletElement.commit) {
|
||||
/**
|
||||
* The route outlet has not mounted yet. We need to wait for it to render
|
||||
* before we can transition the page.
|
||||
@@ -88,142 +106,126 @@ export class StackManager extends React.PureComponent<StackManagerProps, StackMa
|
||||
* Set a flag to indicate that we should transition the page after
|
||||
* the component has updated.
|
||||
*/
|
||||
this.pendingPageTransition = true;
|
||||
} else {
|
||||
let enteringViewItem = this.context.findViewItemByRouteInfo(routeInfo, this.id);
|
||||
let leavingViewItem = this.context.findLeavingViewItemByRouteInfo(routeInfo, this.id);
|
||||
pendingPageTransitionRef.current = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!leavingViewItem && routeInfo.prevRouteLastPathname) {
|
||||
leavingViewItem = this.context.findViewItemByPathname(routeInfo.prevRouteLastPathname, this.id);
|
||||
}
|
||||
let enteringViewItem = findViewItemByRouteInfo(routeInfo, id);
|
||||
let leavingViewItem = findLeavingViewItemByRouteInfo(routeInfo, id);
|
||||
|
||||
// Check if leavingViewItem should be unmounted
|
||||
if (leavingViewItem) {
|
||||
if (routeInfo.routeAction === 'replace') {
|
||||
leavingViewItem.mount = false;
|
||||
} else if (!(routeInfo.routeAction === 'push' && routeInfo.routeDirection === 'forward')) {
|
||||
if (routeInfo.routeDirection !== 'none' && enteringViewItem !== leavingViewItem) {
|
||||
leavingViewItem.mount = false;
|
||||
}
|
||||
} else if (routeInfo.routeOptions?.unmount) {
|
||||
if (!leavingViewItem && routeInfo.prevRouteLastPathname) {
|
||||
leavingViewItem = findViewItemByPathname(routeInfo.prevRouteLastPathname, id);
|
||||
}
|
||||
|
||||
// Check if the leavingViewItem should be unmounted
|
||||
if (leavingViewItem) {
|
||||
if (routeInfo.routeAction === 'replace') {
|
||||
leavingViewItem.mount = false;
|
||||
} else if (!(routeInfo.routeAction === 'push' && routeInfo.routeDirection === 'forward')) {
|
||||
if (routeInfo.routeDirection !== 'none' && enteringViewItem !== leavingViewItem) {
|
||||
leavingViewItem.mount = false;
|
||||
}
|
||||
} else if (routeInfo.routeOptions?.unmount) {
|
||||
leavingViewItem.mount = false;
|
||||
}
|
||||
}
|
||||
|
||||
const enteringRoute = matchRoute(this.ionRouterOutlet?.props.children, routeInfo) as React.ReactElement;
|
||||
const enteringRoute = matchRoute(ionRouterOutletRef.current?.props.children, routeInfo) as React.ReactElement;
|
||||
|
||||
if (enteringViewItem) {
|
||||
enteringViewItem.reactElement = enteringRoute;
|
||||
} else if (enteringRoute) {
|
||||
enteringViewItem = this.context.createViewItem(this.id, enteringRoute, routeInfo);
|
||||
this.context.addViewItem(enteringViewItem);
|
||||
}
|
||||
if (enteringViewItem) {
|
||||
// If the entering view is already in the stack, then we need to clone it
|
||||
enteringViewItem.reactElement = enteringRoute;
|
||||
} else if (enteringRoute) {
|
||||
// Otherwise we need to create a new view item
|
||||
enteringViewItem = createViewItem(id, enteringRoute, routeInfo);
|
||||
addViewItem(enteringViewItem);
|
||||
}
|
||||
|
||||
if (enteringViewItem && enteringViewItem.ionPageElement) {
|
||||
if (enteringViewItem && enteringViewItem.ionPageElement) {
|
||||
/**
|
||||
* If the entering view item is the same as the leaving view item,
|
||||
* then we don't need to transition.
|
||||
*/
|
||||
if (enteringViewItem === leavingViewItem) {
|
||||
/**
|
||||
* If the entering view item is the same as the leaving view item,
|
||||
* then we don't need to transition.
|
||||
* we are either transitioning using parameterized routes to the same view
|
||||
* or a parent router outlet is re-rendering as a result of React props changing.
|
||||
*
|
||||
* If the route data does not match the current path, the parent router outlet
|
||||
* is attempting to transition and we cancel the operation.
|
||||
*/
|
||||
if (enteringViewItem === leavingViewItem) {
|
||||
/**
|
||||
* If the entering view item is the same as the leaving view item,
|
||||
* we are either transitioning using parameterized routes to the same view
|
||||
* or a parent router outlet is re-rendering as a result of React props changing.
|
||||
*
|
||||
* If the route data does not match the current path, the parent router outlet
|
||||
* is attempting to transition and we cancel the operation.
|
||||
*/
|
||||
if (enteringViewItem.routeData.match.url !== routeInfo.pathname) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* If there isn't a leaving view item, but the route info indicates
|
||||
* that the user has routed from a previous path, then we need
|
||||
* to find the leaving view item to transition between.
|
||||
*/
|
||||
if (!leavingViewItem && this.props.routeInfo.prevRouteLastPathname) {
|
||||
leavingViewItem = this.context.findViewItemByPathname(this.props.routeInfo.prevRouteLastPathname, this.id);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the entering view is already visible and the leaving view is not, the transition does not need to occur.
|
||||
*/
|
||||
if (
|
||||
isViewVisible(enteringViewItem.ionPageElement) &&
|
||||
leavingViewItem !== undefined &&
|
||||
!isViewVisible(leavingViewItem.ionPageElement!)
|
||||
) {
|
||||
if (enteringViewItem.routeData.match.url !== routeInfo.pathname) {
|
||||
return;
|
||||
}
|
||||
|
||||
/**
|
||||
* The view should only be transitioned in the following cases:
|
||||
* 1. Performing a replace or pop action, such as a swipe to go back gesture
|
||||
* to animation the leaving view off the screen.
|
||||
*
|
||||
* 2. Navigating between top-level router outlets, such as /page-1 to /page-2;
|
||||
* or navigating within a nested outlet, such as /tabs/tab-1 to /tabs/tab-2.
|
||||
*
|
||||
* 3. The entering view is an ion-router-outlet containing a page
|
||||
* matching the current route and that hasn't already transitioned in.
|
||||
*
|
||||
* This should only happen when navigating directly to a nested router outlet
|
||||
* route or on an initial page load (i.e. refreshing). In cases when loading
|
||||
* /tabs/tab-1, we need to transition the /tabs page element into the view.
|
||||
*/
|
||||
this.transitionPage(routeInfo, enteringViewItem, leavingViewItem);
|
||||
} else if (leavingViewItem && !enteringRoute && !enteringViewItem) {
|
||||
// If we have a leavingView but no entering view/route, we are probably leaving to
|
||||
// another outlet, so hide this leavingView. We do it in a timeout to give time for a
|
||||
// transition to finish.
|
||||
// setTimeout(() => {
|
||||
if (leavingViewItem.ionPageElement) {
|
||||
leavingViewItem.ionPageElement.classList.add('ion-page-hidden');
|
||||
leavingViewItem.ionPageElement.setAttribute('aria-hidden', 'true');
|
||||
}
|
||||
// }, 250);
|
||||
}
|
||||
|
||||
this.forceUpdate();
|
||||
}
|
||||
}
|
||||
|
||||
registerIonPage(page: HTMLElement, routeInfo: RouteInfo) {
|
||||
const foundView = this.context.findViewItemByRouteInfo(routeInfo, this.id);
|
||||
if (foundView) {
|
||||
const oldPageElement = foundView.ionPageElement;
|
||||
foundView.ionPageElement = page;
|
||||
foundView.ionRoute = true;
|
||||
|
||||
/**
|
||||
* React 18 will unmount and remount IonPage
|
||||
* elements in development mode when using createRoot.
|
||||
* This can cause duplicate page transitions to occur.
|
||||
* If there isn't a leaving view item, but the route info indicates
|
||||
* that the user has routed from a previous path, then we need
|
||||
* to find the leaving view item to transition between.
|
||||
*/
|
||||
if (oldPageElement === page) {
|
||||
if (!leavingViewItem && routeInfo.prevRouteLastPathname) {
|
||||
leavingViewItem = findViewItemByPathname(routeInfo.prevRouteLastPathname, id);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the entering view is already visible and the leaving view is not, the transition does not need to occur.
|
||||
*/
|
||||
if (
|
||||
isViewVisible(enteringViewItem.ionPageElement) &&
|
||||
leavingViewItem !== undefined &&
|
||||
!isViewVisible(leavingViewItem.ionPageElement!)
|
||||
) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
this.handlePageTransition(routeInfo);
|
||||
}
|
||||
|
||||
async setupRouterOutlet(routerOutlet: HTMLIonRouterOutletElement) {
|
||||
const canStart = () => {
|
||||
/**
|
||||
* The view should only be transitioned in the following cases:
|
||||
* 1. Performing a replace or pop action, such as a swipe to go back gesture
|
||||
* to animation the leaving view off the screen.
|
||||
*
|
||||
* 2. Navigating between top-level router outlets, such as /page-1 to /page-2;
|
||||
* or navigating within a nested outlet, such as /tabs/tab-1 to /tabs/tab-2.
|
||||
*
|
||||
* 3. The entering view is an ion-router-outlet containing a page
|
||||
* matching the current route and that hasn't already transitioned in.
|
||||
*
|
||||
* This should only happen when navigating directly to a nested router outlet
|
||||
* route or on an initial page load (i.e. refreshing). In cases when loading
|
||||
* /tabs/tab-1, we need to transition the /tabs page element into the view.
|
||||
*/
|
||||
transitionPage(routeInfo, enteringViewItem, leavingViewItem!);
|
||||
} else if (leavingViewItem && !enteringRoute && !enteringViewItem) {
|
||||
// If we have a leavingView but no entering view/route, we are probably leaving to
|
||||
// another outlet, so hide this leavingView.
|
||||
if (leavingViewItem.ionPageElement) {
|
||||
leavingViewItem.ionPageElement.classList.add('ion-page-hidden');
|
||||
leavingViewItem.ionPageElement.setAttribute('aria-hidden', 'true');
|
||||
}
|
||||
}
|
||||
|
||||
// This causes the router outlet to re-render with the updated view items.
|
||||
// Without it, a push navigation will remove the previous route's view item,
|
||||
// but will not render the new route's view item.
|
||||
forceUpdate();
|
||||
};
|
||||
|
||||
const setupRouterOutlet = (routerOutlet: HTMLIonRouterOutletElement) => {
|
||||
const canStart = (): boolean => {
|
||||
const config = getConfig();
|
||||
const swipeEnabled = config && config.get('swipeBackEnabled', routerOutlet.mode === 'ios');
|
||||
const swipeEnabled = config?.getBoolean('swipeBackEnabled', routerOutlet.mode === 'ios');
|
||||
|
||||
if (!swipeEnabled) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const { routeInfo } = this.props;
|
||||
|
||||
const propsToUse =
|
||||
this.prevProps && this.prevProps.routeInfo.pathname === routeInfo.pushedByRoute
|
||||
? this.prevProps.routeInfo
|
||||
prevProps.current?.routeInfo.pathname === routeInfo.pushedByRoute
|
||||
? prevProps.current!.routeInfo
|
||||
: ({ pathname: routeInfo.pushedByRoute || '' } as any);
|
||||
const enteringViewItem = this.context.findViewItemByRouteInfo(propsToUse, this.id, false);
|
||||
|
||||
const enteringViewItem = findViewItemByRouteInfo(propsToUse, id, false);
|
||||
|
||||
return (
|
||||
!!enteringViewItem &&
|
||||
@@ -247,14 +249,12 @@ export class StackManager extends React.PureComponent<StackManagerProps, StackMa
|
||||
};
|
||||
|
||||
const onStart = async () => {
|
||||
const { routeInfo } = this.props;
|
||||
|
||||
const propsToUse =
|
||||
this.prevProps && this.prevProps.routeInfo.pathname === routeInfo.pushedByRoute
|
||||
? this.prevProps.routeInfo
|
||||
prevProps.current?.routeInfo.pathname === routeInfo.pushedByRoute
|
||||
? prevProps.current!.routeInfo
|
||||
: ({ pathname: routeInfo.pushedByRoute || '' } as any);
|
||||
const enteringViewItem = this.context.findViewItemByRouteInfo(propsToUse, this.id, false);
|
||||
const leavingViewItem = this.context.findViewItemByRouteInfo(routeInfo, this.id, false);
|
||||
const enteringViewItem = findViewItemByRouteInfo(propsToUse, id, false);
|
||||
const leavingViewItem = findViewItemByRouteInfo(routeInfo, id, false);
|
||||
|
||||
/**
|
||||
* When the gesture starts, kick off
|
||||
@@ -262,30 +262,28 @@ export class StackManager extends React.PureComponent<StackManagerProps, StackMa
|
||||
* via a swipe gesture.
|
||||
*/
|
||||
if (enteringViewItem && leavingViewItem) {
|
||||
await this.transitionPage(routeInfo, enteringViewItem, leavingViewItem, 'back', true);
|
||||
await transitionPage(routeInfo, enteringViewItem, leavingViewItem, 'back', true);
|
||||
}
|
||||
|
||||
return Promise.resolve();
|
||||
};
|
||||
|
||||
const onEnd = (shouldContinue: boolean) => {
|
||||
if (shouldContinue) {
|
||||
this.skipTransition = true;
|
||||
|
||||
this.context.goBack();
|
||||
skipTransitionRef.current = true;
|
||||
goBack();
|
||||
} else {
|
||||
/**
|
||||
* In the event that the swipe
|
||||
* gesture was aborted, we should
|
||||
* re-hide the page that was going to enter.
|
||||
*/
|
||||
const { routeInfo } = this.props;
|
||||
|
||||
const propsToUse =
|
||||
this.prevProps && this.prevProps.routeInfo.pathname === routeInfo.pushedByRoute
|
||||
? this.prevProps.routeInfo
|
||||
prevProps.current?.routeInfo.pathname === routeInfo.pushedByRoute
|
||||
? prevProps.current!.routeInfo
|
||||
: ({ pathname: routeInfo.pushedByRoute || '' } as any);
|
||||
const enteringViewItem = this.context.findViewItemByRouteInfo(propsToUse, this.id, false);
|
||||
const leavingViewItem = this.context.findViewItemByRouteInfo(routeInfo, this.id, false);
|
||||
const enteringViewItem = findViewItemByRouteInfo(propsToUse, id, false);
|
||||
const leavingViewItem = findViewItemByRouteInfo(routeInfo, id, false);
|
||||
|
||||
/**
|
||||
* Ionic React has a design defect where it
|
||||
@@ -309,17 +307,17 @@ export class StackManager extends React.PureComponent<StackManagerProps, StackMa
|
||||
onStart,
|
||||
onEnd,
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
async transitionPage(
|
||||
const transitionPage = async (
|
||||
routeInfo: RouteInfo,
|
||||
enteringViewItem: ViewItem,
|
||||
leavingViewItem?: ViewItem,
|
||||
leavingViewItem: ViewItem,
|
||||
direction?: 'forward' | 'back',
|
||||
progressAnimation = false
|
||||
) {
|
||||
) => {
|
||||
const runCommit = async (enteringEl: HTMLElement, leavingEl?: HTMLElement) => {
|
||||
const skipTransition = this.skipTransition;
|
||||
const skipTransition = skipTransitionRef.current;
|
||||
|
||||
/**
|
||||
* If the transition was handled
|
||||
@@ -342,102 +340,99 @@ export class StackManager extends React.PureComponent<StackManagerProps, StackMa
|
||||
* transition triggered by handlePageTransition
|
||||
* in componentDidUpdate.
|
||||
*/
|
||||
this.skipTransition = false;
|
||||
skipTransitionRef.current = false;
|
||||
} else {
|
||||
enteringEl.classList.add('ion-page');
|
||||
enteringEl.classList.add('ion-page-invisible');
|
||||
enteringEl.classList.add('ion-page', 'ion-page-invisible');
|
||||
}
|
||||
|
||||
await routerOutlet.commit(enteringEl, leavingEl, {
|
||||
duration: skipTransition || directionToUse === undefined ? 0 : undefined,
|
||||
direction: directionToUse,
|
||||
showGoBack: !!routeInfo.pushedByRoute,
|
||||
progressAnimation,
|
||||
animationBuilder: routeInfo.routeAnimation,
|
||||
});
|
||||
const routerOutletElement = routerOutletRef.current;
|
||||
|
||||
if (routerOutletElement) {
|
||||
await routerOutletElement.commit(enteringEl, leavingEl, {
|
||||
duration: skipTransitionRef.current || directionToUse === undefined ? 0 : undefined,
|
||||
direction: directionToUse,
|
||||
showGoBack: !!routeInfo.pushedByRoute,
|
||||
progressAnimation,
|
||||
animationBuilder: routeInfo.routeAnimation,
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
const routerOutlet = this.routerOutletElement!;
|
||||
|
||||
const routeInfoFallbackDirection =
|
||||
const routerInfoFallbackDirection =
|
||||
routeInfo.routeDirection === 'none' || routeInfo.routeDirection === 'root' ? undefined : routeInfo.routeDirection;
|
||||
const directionToUse = direction ?? routeInfoFallbackDirection;
|
||||
const directionToUse = direction ?? routerInfoFallbackDirection;
|
||||
|
||||
if (enteringViewItem && enteringViewItem.ionPageElement && this.routerOutletElement) {
|
||||
if (leavingViewItem && leavingViewItem.ionPageElement && enteringViewItem === leavingViewItem) {
|
||||
const routerOutletElement = routerOutletRef.current;
|
||||
|
||||
if (enteringViewItem?.ionPageElement && routerOutletElement) {
|
||||
if (leavingViewItem?.ionPageElement && enteringViewItem === leavingViewItem) {
|
||||
// If a page is transitioning to another version of itself
|
||||
// we clone it so we can have an animation to show
|
||||
|
||||
const match = matchComponent(leavingViewItem.reactElement, routeInfo.pathname, true);
|
||||
if (match) {
|
||||
const newLeavingElement = clonePageElement(leavingViewItem.ionPageElement.outerHTML);
|
||||
if (newLeavingElement) {
|
||||
this.routerOutletElement.appendChild(newLeavingElement);
|
||||
routerOutletElement.appendChild(newLeavingElement);
|
||||
await runCommit(enteringViewItem.ionPageElement, newLeavingElement);
|
||||
this.routerOutletElement.removeChild(newLeavingElement);
|
||||
routerOutletElement.removeChild(newLeavingElement);
|
||||
}
|
||||
} else {
|
||||
await runCommit(enteringViewItem.ionPageElement, undefined);
|
||||
}
|
||||
} else {
|
||||
await runCommit(enteringViewItem.ionPageElement, leavingViewItem?.ionPageElement);
|
||||
if (leavingViewItem && leavingViewItem.ionPageElement && !progressAnimation) {
|
||||
leavingViewItem.ionPageElement.classList.add('ion-page-hidden');
|
||||
leavingViewItem.ionPageElement.setAttribute('aria-hidden', 'true');
|
||||
if (leavingViewItem?.ionPageElement && !progressAnimation) {
|
||||
const { ionPageElement } = leavingViewItem;
|
||||
ionPageElement.setAttribute('aria-hidden', 'true');
|
||||
ionPageElement.classList.add('ion-page-hidden');
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
render() {
|
||||
const { children } = this.props;
|
||||
const ionRouterOutlet = React.Children.only(children) as React.ReactElement;
|
||||
this.ionRouterOutlet = ionRouterOutlet;
|
||||
const renderComponents = () => {
|
||||
const ionRouterOutlet = React.Children.only<React.ReactElement>(children as React.ReactElement);
|
||||
ionRouterOutletRef.current = ionRouterOutlet;
|
||||
|
||||
const components = this.context.getChildrenToRender(this.id, this.ionRouterOutlet, this.props.routeInfo, () => {
|
||||
this.forceUpdate();
|
||||
const components = getChildrenToRender(id, ionRouterOutlet, routeInfo, () => {
|
||||
forceUpdate();
|
||||
});
|
||||
|
||||
return (
|
||||
<StackContext.Provider value={this.stackContextValue}>
|
||||
{React.cloneElement(
|
||||
ionRouterOutlet as any,
|
||||
{
|
||||
ref: (node: HTMLIonRouterOutletElement) => {
|
||||
if (ionRouterOutlet.props.setRef) {
|
||||
ionRouterOutlet.props.setRef(node);
|
||||
}
|
||||
if (ionRouterOutlet.props.forwardedRef) {
|
||||
ionRouterOutlet.props.forwardedRef.current = node;
|
||||
}
|
||||
this.routerOutletElement = node;
|
||||
const { ref } = ionRouterOutlet as any;
|
||||
if (typeof ref === 'function') {
|
||||
ref(node);
|
||||
}
|
||||
},
|
||||
},
|
||||
components
|
||||
)}
|
||||
</StackContext.Provider>
|
||||
);
|
||||
}
|
||||
return cloneElement(ionRouterOutlet, {
|
||||
ref: (node: HTMLIonRouterOutletElement) => {
|
||||
if (ionRouterOutlet.props.setRef) {
|
||||
ionRouterOutlet.props.setRef(node);
|
||||
}
|
||||
if (ionRouterOutlet.props.forwardedRef) {
|
||||
ionRouterOutlet.props.forwardedRef.current = node;
|
||||
}
|
||||
|
||||
static get contextType() {
|
||||
return RouteManagerContext;
|
||||
}
|
||||
}
|
||||
routerOutletRef.current = node;
|
||||
|
||||
const { ref } = ionRouterOutlet as any;
|
||||
if (typeof ref === 'function') {
|
||||
ref(node);
|
||||
}
|
||||
},
|
||||
components,
|
||||
});
|
||||
};
|
||||
|
||||
return <StackContext.Provider value={stackContextValue}>{renderComponents()}</StackContext.Provider>;
|
||||
};
|
||||
|
||||
export default StackManager;
|
||||
|
||||
function matchRoute(node: React.ReactNode, routeInfo: RouteInfo) {
|
||||
let matchedNode: React.ReactNode;
|
||||
|
||||
React.Children.forEach(node as React.ReactElement, (child: React.ReactElement) => {
|
||||
const matchProps = {
|
||||
exact: child.props.exact,
|
||||
path: child.props.path || child.props.from,
|
||||
component: child.props.component,
|
||||
};
|
||||
// In React Router v6 the prop arguments are in a different order
|
||||
const match = matchPath(routeInfo.pathname, matchProps);
|
||||
if (match) {
|
||||
matchedNode = child;
|
||||
@@ -464,6 +459,7 @@ function matchComponent(node: React.ReactElement, pathname: string, forceExact?:
|
||||
path: node.props.path || node.props.from,
|
||||
component: node.props.component,
|
||||
};
|
||||
// In React Router v6 the prop arguments are in a different order
|
||||
const match = matchPath(pathname, matchProps);
|
||||
|
||||
return match;
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [7.2.1](https://github.com/ionic-team/ionic-framework/compare/v7.2.0...v7.2.1) (2023-07-26)
|
||||
|
||||
**Note:** Version bump only for package @ionic/react
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [7.2.0](https://github.com/ionic-team/ionic-framework/compare/v7.1.4...v7.2.0) (2023-07-19)
|
||||
|
||||
**Note:** Version bump only for package @ionic/react
|
||||
|
||||
18
packages/react/package-lock.json
generated
@@ -1,15 +1,15 @@
|
||||
{
|
||||
"name": "@ionic/react",
|
||||
"version": "7.2.0",
|
||||
"version": "7.2.1",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@ionic/react",
|
||||
"version": "7.2.0",
|
||||
"version": "7.2.1",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ionic/core": "^7.2.0",
|
||||
"@ionic/core": "^7.2.1",
|
||||
"ionicons": "^7.0.0",
|
||||
"tslib": "*"
|
||||
},
|
||||
@@ -697,9 +697,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@ionic/core": {
|
||||
"version": "7.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.1.4.tgz",
|
||||
"integrity": "sha512-/h32Sc7Jd8csdMZ6BhddoTGC/X7cO0tIOeDuyC/ypMarXajScHc0pgVEBneAA7PVBEVxsoeMDP7yuqJt6Duaiw==",
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.2.1.tgz",
|
||||
"integrity": "sha512-7I3OIGHIhGCXxswphP3vfuyCCjXysAUg4cfKGB2QQ5e073DPsZkMSpVam19nAIjEDyfK2pQZC+SgSkZvvCc+2A==",
|
||||
"dependencies": {
|
||||
"@stencil/core": "^3.4.0",
|
||||
"ionicons": "7.1.0",
|
||||
@@ -11778,9 +11778,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@ionic/core": {
|
||||
"version": "7.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.1.4.tgz",
|
||||
"integrity": "sha512-/h32Sc7Jd8csdMZ6BhddoTGC/X7cO0tIOeDuyC/ypMarXajScHc0pgVEBneAA7PVBEVxsoeMDP7yuqJt6Duaiw==",
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.2.1.tgz",
|
||||
"integrity": "sha512-7I3OIGHIhGCXxswphP3vfuyCCjXysAUg4cfKGB2QQ5e073DPsZkMSpVam19nAIjEDyfK2pQZC+SgSkZvvCc+2A==",
|
||||
"requires": {
|
||||
"@stencil/core": "^3.4.0",
|
||||
"ionicons": "7.1.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/react",
|
||||
"version": "7.2.0",
|
||||
"version": "7.2.1",
|
||||
"description": "React specific wrapper for @ionic/core",
|
||||
"keywords": [
|
||||
"ionic",
|
||||
@@ -41,7 +41,7 @@
|
||||
"css/"
|
||||
],
|
||||
"dependencies": {
|
||||
"@ionic/core": "^7.2.0",
|
||||
"@ionic/core": "^7.2.1",
|
||||
"ionicons": "^7.0.0",
|
||||
"tslib": "*"
|
||||
},
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [7.2.1](https://github.com/ionic-team/ionic-framework/compare/v7.2.0...v7.2.1) (2023-07-26)
|
||||
|
||||
**Note:** Version bump only for package @ionic/vue-router
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [7.2.0](https://github.com/ionic-team/ionic-framework/compare/v7.1.4...v7.2.0) (2023-07-19)
|
||||
|
||||
**Note:** Version bump only for package @ionic/vue-router
|
||||
|
||||
58
packages/vue-router/package-lock.json
generated
@@ -1,15 +1,15 @@
|
||||
{
|
||||
"name": "@ionic/vue-router",
|
||||
"version": "7.2.0",
|
||||
"version": "7.2.1",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@ionic/vue-router",
|
||||
"version": "7.2.0",
|
||||
"version": "7.2.1",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ionic/vue": "^7.2.0"
|
||||
"@ionic/vue": "^7.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ionic/eslint-config": "^0.3.0",
|
||||
@@ -660,9 +660,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@ionic/core": {
|
||||
"version": "7.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.1.4.tgz",
|
||||
"integrity": "sha512-/h32Sc7Jd8csdMZ6BhddoTGC/X7cO0tIOeDuyC/ypMarXajScHc0pgVEBneAA7PVBEVxsoeMDP7yuqJt6Duaiw==",
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.2.1.tgz",
|
||||
"integrity": "sha512-7I3OIGHIhGCXxswphP3vfuyCCjXysAUg4cfKGB2QQ5e073DPsZkMSpVam19nAIjEDyfK2pQZC+SgSkZvvCc+2A==",
|
||||
"dependencies": {
|
||||
"@stencil/core": "^3.4.0",
|
||||
"ionicons": "7.1.0",
|
||||
@@ -871,11 +871,11 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@ionic/vue": {
|
||||
"version": "7.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/vue/-/vue-7.1.4.tgz",
|
||||
"integrity": "sha512-r7UDUteuzCHVNJWlwiiucYVKhRoS6b2SQ8AqBm1rZy/dGghDyGLbIn3jjowUQNIE4qnV1M6+Im6JtzbwctevqQ==",
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/vue/-/vue-7.2.1.tgz",
|
||||
"integrity": "sha512-l9ucLk1NrAZHXdAT8qrJYArklS7cCok6/Qlq52Kg0+C912sfV3IIEMxjfQw8e6MX0aZGkSYMG/BGLEBqxp6gOw==",
|
||||
"dependencies": {
|
||||
"@ionic/core": "7.1.4",
|
||||
"@ionic/core": "7.2.1",
|
||||
"ionicons": "^7.0.0"
|
||||
}
|
||||
},
|
||||
@@ -1323,9 +1323,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@stencil/core": {
|
||||
"version": "3.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-3.4.1.tgz",
|
||||
"integrity": "sha512-7rjOmM0W9K5op2gtOQRLERGH1155rv2fm6ppxOzYqqG8ISct4m9skp5XgUBYPu+GSPsJFdRuCIQs0IuVsG/7+g==",
|
||||
"version": "3.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-3.4.2.tgz",
|
||||
"integrity": "sha512-FAUhUVaakCy29nU2GwO/HQBRV1ihPRvncz3PUc8oR+UJLAxGabTmP8PLY7wvHfbw+Cvi4VXfJFTBvdfDu6iKPQ==",
|
||||
"bin": {
|
||||
"stencil": "bin/stencil"
|
||||
},
|
||||
@@ -6807,9 +6807,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/tslib": {
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.0.tgz",
|
||||
"integrity": "sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA=="
|
||||
"version": "2.6.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz",
|
||||
"integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig=="
|
||||
},
|
||||
"node_modules/tsutils": {
|
||||
"version": "3.21.0",
|
||||
@@ -7697,9 +7697,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@ionic/core": {
|
||||
"version": "7.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.1.4.tgz",
|
||||
"integrity": "sha512-/h32Sc7Jd8csdMZ6BhddoTGC/X7cO0tIOeDuyC/ypMarXajScHc0pgVEBneAA7PVBEVxsoeMDP7yuqJt6Duaiw==",
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.2.1.tgz",
|
||||
"integrity": "sha512-7I3OIGHIhGCXxswphP3vfuyCCjXysAUg4cfKGB2QQ5e073DPsZkMSpVam19nAIjEDyfK2pQZC+SgSkZvvCc+2A==",
|
||||
"requires": {
|
||||
"@stencil/core": "^3.4.0",
|
||||
"ionicons": "7.1.0",
|
||||
@@ -7829,11 +7829,11 @@
|
||||
"requires": {}
|
||||
},
|
||||
"@ionic/vue": {
|
||||
"version": "7.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/vue/-/vue-7.1.4.tgz",
|
||||
"integrity": "sha512-r7UDUteuzCHVNJWlwiiucYVKhRoS6b2SQ8AqBm1rZy/dGghDyGLbIn3jjowUQNIE4qnV1M6+Im6JtzbwctevqQ==",
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/vue/-/vue-7.2.1.tgz",
|
||||
"integrity": "sha512-l9ucLk1NrAZHXdAT8qrJYArklS7cCok6/Qlq52Kg0+C912sfV3IIEMxjfQw8e6MX0aZGkSYMG/BGLEBqxp6gOw==",
|
||||
"requires": {
|
||||
"@ionic/core": "7.1.4",
|
||||
"@ionic/core": "7.2.1",
|
||||
"ionicons": "^7.0.0"
|
||||
}
|
||||
},
|
||||
@@ -8192,9 +8192,9 @@
|
||||
}
|
||||
},
|
||||
"@stencil/core": {
|
||||
"version": "3.4.1",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-3.4.1.tgz",
|
||||
"integrity": "sha512-7rjOmM0W9K5op2gtOQRLERGH1155rv2fm6ppxOzYqqG8ISct4m9skp5XgUBYPu+GSPsJFdRuCIQs0IuVsG/7+g=="
|
||||
"version": "3.4.2",
|
||||
"resolved": "https://registry.npmjs.org/@stencil/core/-/core-3.4.2.tgz",
|
||||
"integrity": "sha512-FAUhUVaakCy29nU2GwO/HQBRV1ihPRvncz3PUc8oR+UJLAxGabTmP8PLY7wvHfbw+Cvi4VXfJFTBvdfDu6iKPQ=="
|
||||
},
|
||||
"@tootallnate/once": {
|
||||
"version": "2.0.0",
|
||||
@@ -12220,9 +12220,9 @@
|
||||
}
|
||||
},
|
||||
"tslib": {
|
||||
"version": "2.6.0",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.0.tgz",
|
||||
"integrity": "sha512-7At1WUettjcSRHXCyYtTselblcHl9PJFFVKiCAy/bY97+BPZXSQ2wbq0P9s8tK2G7dFQfNnlJnPAiArVBVBsfA=="
|
||||
"version": "2.6.1",
|
||||
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.1.tgz",
|
||||
"integrity": "sha512-t0hLfiEKfMUoqhG+U1oid7Pva4bbDPHYfJNiB7BiIjRkj1pyC++4N3huJfqY6aRH6VTB0rvtzQwjM4K6qpfOig=="
|
||||
},
|
||||
"tsutils": {
|
||||
"version": "3.21.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/vue-router",
|
||||
"version": "7.2.0",
|
||||
"version": "7.2.1",
|
||||
"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.2.0"
|
||||
"@ionic/vue": "^7.2.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@ionic/eslint-config": "^0.3.0",
|
||||
|
||||
@@ -186,10 +186,10 @@ export const createIonRouter = (
|
||||
router.go(prevInfo.position - routeInfo.position);
|
||||
}
|
||||
} else {
|
||||
handleNavigate(defaultHref, "pop", "back");
|
||||
handleNavigate(defaultHref, "pop", "back", routerAnimation);
|
||||
}
|
||||
} else {
|
||||
handleNavigate(defaultHref, "pop", "back");
|
||||
handleNavigate(defaultHref, "pop", "back", routerAnimation);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -3,6 +3,14 @@
|
||||
All notable changes to this project will be documented in this file.
|
||||
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
|
||||
|
||||
## [7.2.1](https://github.com/ionic-team/ionic-framework/compare/v7.2.0...v7.2.1) (2023-07-26)
|
||||
|
||||
**Note:** Version bump only for package @ionic/vue
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
# [7.2.0](https://github.com/ionic-team/ionic-framework/compare/v7.1.4...v7.2.0) (2023-07-19)
|
||||
|
||||
|
||||
|
||||
18
packages/vue/package-lock.json
generated
@@ -1,15 +1,15 @@
|
||||
{
|
||||
"name": "@ionic/vue",
|
||||
"version": "7.2.0",
|
||||
"version": "7.2.1",
|
||||
"lockfileVersion": 2,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "@ionic/vue",
|
||||
"version": "7.2.0",
|
||||
"version": "7.2.1",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ionic/core": "^7.2.0",
|
||||
"@ionic/core": "^7.2.1",
|
||||
"ionicons": "^7.0.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
@@ -207,9 +207,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/@ionic/core": {
|
||||
"version": "7.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.1.4.tgz",
|
||||
"integrity": "sha512-/h32Sc7Jd8csdMZ6BhddoTGC/X7cO0tIOeDuyC/ypMarXajScHc0pgVEBneAA7PVBEVxsoeMDP7yuqJt6Duaiw==",
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.2.1.tgz",
|
||||
"integrity": "sha512-7I3OIGHIhGCXxswphP3vfuyCCjXysAUg4cfKGB2QQ5e073DPsZkMSpVam19nAIjEDyfK2pQZC+SgSkZvvCc+2A==",
|
||||
"dependencies": {
|
||||
"@stencil/core": "^3.4.0",
|
||||
"ionicons": "7.1.0",
|
||||
@@ -3746,9 +3746,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"@ionic/core": {
|
||||
"version": "7.1.4",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.1.4.tgz",
|
||||
"integrity": "sha512-/h32Sc7Jd8csdMZ6BhddoTGC/X7cO0tIOeDuyC/ypMarXajScHc0pgVEBneAA7PVBEVxsoeMDP7yuqJt6Duaiw==",
|
||||
"version": "7.2.1",
|
||||
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-7.2.1.tgz",
|
||||
"integrity": "sha512-7I3OIGHIhGCXxswphP3vfuyCCjXysAUg4cfKGB2QQ5e073DPsZkMSpVam19nAIjEDyfK2pQZC+SgSkZvvCc+2A==",
|
||||
"requires": {
|
||||
"@stencil/core": "^3.4.0",
|
||||
"ionicons": "7.1.0",
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"name": "@ionic/vue",
|
||||
"version": "7.2.0",
|
||||
"version": "7.2.1",
|
||||
"description": "Vue specific wrapper for @ionic/core",
|
||||
"scripts": {
|
||||
"eslint": "eslint src",
|
||||
@@ -66,7 +66,7 @@
|
||||
"vue-router": "^4.0.16"
|
||||
},
|
||||
"dependencies": {
|
||||
"@ionic/core": "^7.2.0",
|
||||
"@ionic/core": "^7.2.1",
|
||||
"ionicons": "^7.0.0"
|
||||
},
|
||||
"vetur": {
|
||||
|
||||