diff --git a/.github/actions/publish-npm/action.yml b/.github/actions/publish-npm/action.yml
index 6913b493ef1..cce9c2c235a 100644
--- a/.github/actions/publish-npm/action.yml
+++ b/.github/actions/publish-npm/action.yml
@@ -22,7 +22,7 @@ runs:
using: 'composite'
steps:
- name: π’ Configure Node for Publish
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
+ uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: ${{ inputs.node-version }}
registry-url: 'https://registry.npmjs.org'
diff --git a/.github/workflows/actions/build-angular-server/action.yml b/.github/workflows/actions/build-angular-server/action.yml
index 70c65316883..283a9db0244 100644
--- a/.github/workflows/actions/build-angular-server/action.yml
+++ b/.github/workflows/actions/build-angular-server/action.yml
@@ -3,7 +3,7 @@ description: 'Build Ionic Angular Server'
runs:
using: 'composite'
steps:
- - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
+ - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: 24.x
- uses: ./.github/workflows/actions/download-archive
diff --git a/.github/workflows/actions/build-angular/action.yml b/.github/workflows/actions/build-angular/action.yml
index 121fa6f7da9..7771cb0e879 100644
--- a/.github/workflows/actions/build-angular/action.yml
+++ b/.github/workflows/actions/build-angular/action.yml
@@ -3,7 +3,7 @@ description: 'Build Ionic Angular'
runs:
using: 'composite'
steps:
- - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
+ - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: 24.x
- uses: ./.github/workflows/actions/download-archive
diff --git a/.github/workflows/actions/build-core-stencil-prerelease/action.yml b/.github/workflows/actions/build-core-stencil-prerelease/action.yml
index f1e33c8b55e..0bd78e4adfe 100644
--- a/.github/workflows/actions/build-core-stencil-prerelease/action.yml
+++ b/.github/workflows/actions/build-core-stencil-prerelease/action.yml
@@ -13,7 +13,7 @@ runs:
using: 'composite'
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
+ - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: 24.x
diff --git a/.github/workflows/actions/build-core/action.yml b/.github/workflows/actions/build-core/action.yml
index 068eab5c471..d155d64d4f1 100644
--- a/.github/workflows/actions/build-core/action.yml
+++ b/.github/workflows/actions/build-core/action.yml
@@ -9,7 +9,7 @@ runs:
using: 'composite'
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
+ - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: 24.x
- name: πΈοΈ Install Dependencies
diff --git a/.github/workflows/actions/build-react-router/action.yml b/.github/workflows/actions/build-react-router/action.yml
index bb2cbb27eea..1ef7d916c85 100644
--- a/.github/workflows/actions/build-react-router/action.yml
+++ b/.github/workflows/actions/build-react-router/action.yml
@@ -3,7 +3,7 @@ description: 'Build Ionic React Router'
runs:
using: 'composite'
steps:
- - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
+ - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: 24.x
- uses: ./.github/workflows/actions/download-archive
diff --git a/.github/workflows/actions/build-react/action.yml b/.github/workflows/actions/build-react/action.yml
index b7d3ac6b99a..5e615935ec7 100644
--- a/.github/workflows/actions/build-react/action.yml
+++ b/.github/workflows/actions/build-react/action.yml
@@ -3,7 +3,7 @@ description: 'Build Ionic React'
runs:
using: 'composite'
steps:
- - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
+ - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: 24.x
- uses: ./.github/workflows/actions/download-archive
@@ -43,7 +43,7 @@ runs:
output: packages/react/ReactBuild.zip
paths: packages/react/dist packages/react/css packages/react/package.json
- name: Clean package.json updates
- run: git checkout ./core/package.json ./packages/react/package.json
+ run: git checkout ./core/package.json ./packages/react/package.json ./packages/react/package-lock.json
shell: bash
- name: π Check Diff
run: git diff --exit-code
diff --git a/.github/workflows/actions/build-vue-router/action.yml b/.github/workflows/actions/build-vue-router/action.yml
index 68972ef2324..bc068447da3 100644
--- a/.github/workflows/actions/build-vue-router/action.yml
+++ b/.github/workflows/actions/build-vue-router/action.yml
@@ -3,7 +3,7 @@ description: 'Builds Ionic Vue Router'
runs:
using: 'composite'
steps:
- - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
+ - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: 24.x
- uses: ./.github/workflows/actions/download-archive
diff --git a/.github/workflows/actions/build-vue/action.yml b/.github/workflows/actions/build-vue/action.yml
index 22c731e99ad..69a55fb0727 100644
--- a/.github/workflows/actions/build-vue/action.yml
+++ b/.github/workflows/actions/build-vue/action.yml
@@ -3,7 +3,7 @@ description: 'Build Ionic Vue'
runs:
using: 'composite'
steps:
- - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
+ - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: 24.x
- uses: ./.github/workflows/actions/download-archive
diff --git a/.github/workflows/actions/download-archive/action.yml b/.github/workflows/actions/download-archive/action.yml
index 97f07f8627a..c4da9dd9bca 100644
--- a/.github/workflows/actions/download-archive/action.yml
+++ b/.github/workflows/actions/download-archive/action.yml
@@ -10,7 +10,7 @@ inputs:
runs:
using: 'composite'
steps:
- - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
+ - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
name: ${{ inputs.name }}
path: ${{ inputs.path }}
diff --git a/.github/workflows/actions/test-angular-e2e/action.yml b/.github/workflows/actions/test-angular-e2e/action.yml
index 8a15bfb5037..d3cbf772ad4 100644
--- a/.github/workflows/actions/test-angular-e2e/action.yml
+++ b/.github/workflows/actions/test-angular-e2e/action.yml
@@ -6,7 +6,7 @@ inputs:
runs:
using: 'composite'
steps:
- - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
+ - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: 24.x
- uses: ./.github/workflows/actions/download-archive
diff --git a/.github/workflows/actions/test-angular-package/action.yml b/.github/workflows/actions/test-angular-package/action.yml
index 4f6181a2115..296a34baa56 100644
--- a/.github/workflows/actions/test-angular-package/action.yml
+++ b/.github/workflows/actions/test-angular-package/action.yml
@@ -3,7 +3,7 @@ description: 'Test Ionic Angular Package'
runs:
using: 'composite'
steps:
- - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
+ - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: 24.x
- uses: ./.github/workflows/actions/download-archive
diff --git a/.github/workflows/actions/test-core-clean-build/action.yml b/.github/workflows/actions/test-core-clean-build/action.yml
index f6275acbee5..169bca12c5c 100644
--- a/.github/workflows/actions/test-core-clean-build/action.yml
+++ b/.github/workflows/actions/test-core-clean-build/action.yml
@@ -3,7 +3,7 @@ description: 'Test Core Clean Build'
runs:
using: 'composite'
steps:
- - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
+ - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: 24.x
diff --git a/.github/workflows/actions/test-core-lint/action.yml b/.github/workflows/actions/test-core-lint/action.yml
index 66a3036ef04..d9435780f44 100644
--- a/.github/workflows/actions/test-core-lint/action.yml
+++ b/.github/workflows/actions/test-core-lint/action.yml
@@ -3,7 +3,7 @@ description: 'Test Core Lint'
runs:
using: 'composite'
steps:
- - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
+ - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: 24.x
- name: πΈοΈ Install Dependencies
diff --git a/.github/workflows/actions/test-core-screenshot/action.yml b/.github/workflows/actions/test-core-screenshot/action.yml
index 379ce934edc..ced133401d1 100644
--- a/.github/workflows/actions/test-core-screenshot/action.yml
+++ b/.github/workflows/actions/test-core-screenshot/action.yml
@@ -13,7 +13,7 @@ inputs:
runs:
using: 'composite'
steps:
- - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
+ - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: 24.x
- uses: ./.github/workflows/actions/download-archive
@@ -66,7 +66,7 @@ runs:
working-directory: ./core
- name: π¦ Archive Updated Screenshots
if: inputs.update == 'true' && steps.test-and-update.outputs.hasUpdatedScreenshots == 'true'
- uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
+ uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: updated-screenshots-${{ inputs.shard }}-${{ inputs.totalShards }}
path: UpdatedScreenshots-${{ inputs.shard }}-${{ inputs.totalShards }}.zip
diff --git a/.github/workflows/actions/test-core-spec/action.yml b/.github/workflows/actions/test-core-spec/action.yml
index f33ab0aa3e3..e2d55586215 100644
--- a/.github/workflows/actions/test-core-spec/action.yml
+++ b/.github/workflows/actions/test-core-spec/action.yml
@@ -6,7 +6,7 @@ inputs:
runs:
using: 'composite'
steps:
- - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
+ - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: 24.x
- name: πΈοΈ Install Dependencies
diff --git a/.github/workflows/actions/test-react-e2e/action.yml b/.github/workflows/actions/test-react-e2e/action.yml
index af6100bdb07..5c1e96e4f88 100644
--- a/.github/workflows/actions/test-react-e2e/action.yml
+++ b/.github/workflows/actions/test-react-e2e/action.yml
@@ -6,7 +6,7 @@ inputs:
runs:
using: 'composite'
steps:
- - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
+ - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: 24.x
- uses: ./.github/workflows/actions/download-archive
diff --git a/.github/workflows/actions/test-react-router-e2e/action.yml b/.github/workflows/actions/test-react-router-e2e/action.yml
index beea150b549..13e6ef48ebe 100644
--- a/.github/workflows/actions/test-react-router-e2e/action.yml
+++ b/.github/workflows/actions/test-react-router-e2e/action.yml
@@ -6,7 +6,7 @@ inputs:
runs:
using: 'composite'
steps:
- - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
+ - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: 24.x
- uses: ./.github/workflows/actions/download-archive
diff --git a/.github/workflows/actions/test-vue-e2e/action.yml b/.github/workflows/actions/test-vue-e2e/action.yml
index 2316e019a46..c57ba40064f 100644
--- a/.github/workflows/actions/test-vue-e2e/action.yml
+++ b/.github/workflows/actions/test-vue-e2e/action.yml
@@ -6,7 +6,7 @@ inputs:
runs:
using: 'composite'
steps:
- - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
+ - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: 24.x
- uses: ./.github/workflows/actions/download-archive
diff --git a/.github/workflows/actions/update-reference-screenshots/action.yml b/.github/workflows/actions/update-reference-screenshots/action.yml
index 844f4e6d2ac..c1c8df73ddb 100644
--- a/.github/workflows/actions/update-reference-screenshots/action.yml
+++ b/.github/workflows/actions/update-reference-screenshots/action.yml
@@ -7,10 +7,10 @@ on:
runs:
using: 'composite'
steps:
- - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
+ - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: 24.x
- - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1
+ - uses: actions/download-artifact@9000827ccba6bdab643e8b6fd33ac0654aef8333 # v8.0.2
with:
path: ./artifacts
- name: π Extract Archives
diff --git a/.github/workflows/actions/upload-archive/action.yml b/.github/workflows/actions/upload-archive/action.yml
index 3cfff8853fc..5245f7a48c3 100644
--- a/.github/workflows/actions/upload-archive/action.yml
+++ b/.github/workflows/actions/upload-archive/action.yml
@@ -13,7 +13,7 @@ runs:
- name: ποΈ Create Archive
run: zip -q -r ${{ inputs.output }} ${{ inputs.paths }}
shell: bash
- - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1
+ - uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2
with:
name: ${{ inputs.name }}
path: ${{ inputs.output }}
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index bdb408b3eb9..1fddfeb7fa0 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -15,7 +15,7 @@ jobs:
security-events: write
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- - uses: github/codeql-action/init@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2
+ - uses: github/codeql-action/init@24c54180a607b1449ed407dd24f251e4e9147c8d # v4.38.3
with:
languages: javascript
- - uses: github/codeql-action/analyze@2892aa5e19bbd11bc0cff5427e3b750a04d9e3c2 # v4.38.2
+ - uses: github/codeql-action/analyze@24c54180a607b1449ed407dd24f251e4e9147c8d # v4.38.3
diff --git a/.github/workflows/migrate.yml b/.github/workflows/migrate.yml
index 54990664544..5cd5df3ecb4 100644
--- a/.github/workflows/migrate.yml
+++ b/.github/workflows/migrate.yml
@@ -64,7 +64,7 @@ jobs:
working-directory: ./packages/migrate
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
+ - uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: 24.x
cache: 'npm'
diff --git a/.github/workflows/release-migrate.yml b/.github/workflows/release-migrate.yml
index d119e6830de..0c083240609 100644
--- a/.github/workflows/release-migrate.yml
+++ b/.github/workflows/release-migrate.yml
@@ -21,7 +21,7 @@ jobs:
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
- name: π’ Configure Node for Publish
- uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0
+ uses: actions/setup-node@949feb2413d6458794dcd2491c4babbbce0c15c1 # v7.1.0
with:
node-version: 24.x
registry-url: 'https://registry.npmjs.org'
diff --git a/CHANGELOG.md b/CHANGELOG.md
index cf6be27ea7a..c50200accd0 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -3,6 +3,16 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+## [9.0.8](https://github.com/ionic-team/ionic-framework/compare/v9.0.7...v9.0.8) (2026-10-14)
+
+### Bug Fixes
+
+* **angular, vue:** fire lifecycle events on nested pages ([#31532](https://github.com/ionic-team/ionic-framework/issues/31532)) ([277097e](https://github.com/ionic-team/ionic-framework/commit/277097e1dfa13d8b34a6826aca462843810fc8f1)), closes [#30831](https://github.com/ionic-team/ionic-framework/issues/30831) [#16834](https://github.com/ionic-team/ionic-framework/issues/16834)
+* **angular:** update route snapshot on query param navigation ([#31534](https://github.com/ionic-team/ionic-framework/issues/31534)) ([6b5afec](https://github.com/ionic-team/ionic-framework/commit/6b5afec5b8d2a8df79c014120b5be5b4fbb2a2cb)), closes [#24587](https://github.com/ionic-team/ionic-framework/issues/24587)
+* **modal:** stop sheets dismissing on upward drags ([#31553](https://github.com/ionic-team/ionic-framework/issues/31553)) ([3e3544e](https://github.com/ionic-team/ionic-framework/commit/3e3544e4303d9dd49eb834cddddacd54bbe01fe4))
+* **react-router:** stop hidden views from re-rendering on every navigation ([#31541](https://github.com/ionic-team/ionic-framework/issues/31541)) ([4ae0196](https://github.com/ionic-team/ionic-framework/commit/4ae01961e8ed65e26369e09d478fabeffba5ed6d)), closes [#31528](https://github.com/ionic-team/ionic-framework/issues/31528)
+
+
## [9.0.7](https://github.com/ionic-team/ionic-framework/compare/v9.0.6...v9.0.7) (2026-10-07)
### Bug Fixes
diff --git a/core/CHANGELOG.md b/core/CHANGELOG.md
index 531652cf2e3..84405878558 100644
--- a/core/CHANGELOG.md
+++ b/core/CHANGELOG.md
@@ -3,6 +3,13 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
+## [9.0.8](https://github.com/ionic-team/ionic-framework/compare/v9.0.7...v9.0.8) (2026-10-14)
+
+### Bug Fixes
+
+* **modal:** stop sheets dismissing on upward drags ([#31553](https://github.com/ionic-team/ionic-framework/issues/31553)) ([3e3544e](https://github.com/ionic-team/ionic-framework/commit/3e3544e4303d9dd49eb834cddddacd54bbe01fe4))
+
+
## [9.0.7](https://github.com/ionic-team/ionic-framework/compare/v9.0.6...v9.0.7) (2026-10-07)
### Bug Fixes
diff --git a/core/Dockerfile b/core/Dockerfile
index 702746752ba..966a39a352e 100644
--- a/core/Dockerfile
+++ b/core/Dockerfile
@@ -1,5 +1,5 @@
# Get Playwright
-FROM mcr.microsoft.com/playwright:v1.63.0
+FROM mcr.microsoft.com/playwright:v1.64.0
# Set the working directory
WORKDIR /ionic
diff --git a/core/package-lock.json b/core/package-lock.json
index 97ed7e472fe..14b7aad5b32 100644
--- a/core/package-lock.json
+++ b/core/package-lock.json
@@ -1,12 +1,12 @@
{
"name": "@ionic/core",
- "version": "9.0.7",
+ "version": "9.0.8",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@ionic/core",
- "version": "9.0.7",
+ "version": "9.0.8",
"license": "MIT",
"dependencies": {
"@stencil/core": "^4.44.2",
@@ -23,7 +23,7 @@
"@eslint/js": "^9.0.0",
"@ionic/eslint-config": "^0.3.0",
"@ionic/prettier-config": "^2.0.0",
- "@playwright/test": "^1.63.0",
+ "@playwright/test": "^1.64.0",
"@rollup/plugin-node-resolve": "^8.4.0",
"@rollup/plugin-virtual": "^2.0.3",
"@stencil/angular-output-target": "^1.4.1",
@@ -45,7 +45,7 @@
"fs-extra": "^9.0.1",
"jest": "^29.7.0",
"jest-cli": "^29.7.0",
- "playwright-core": "^1.63.0",
+ "playwright-core": "^1.64.0",
"prettier": "^2.6.1",
"rollup": "^2.26.4",
"sass": "^1.33.0",
@@ -633,9 +633,9 @@
"license": "MIT"
},
"node_modules/@capacitor/core": {
- "version": "8.5.2",
- "resolved": "https://registry.npmjs.org/@capacitor/core/-/core-8.5.2.tgz",
- "integrity": "sha512-agnQbGdhGw/KZFuLf7H9SY2o+oE7upkr/WPQsYaokXP6f9chaE8iVmbKkfN6SVl4w3pmz7oZ3Ur1hbkmy1hx+w==",
+ "version": "8.5.3",
+ "resolved": "https://registry.npmjs.org/@capacitor/core/-/core-8.5.3.tgz",
+ "integrity": "sha512-oBE1oGuYE4ZzYYrulC75OuHdSsD6zLUy7d5o1tFwDLG4govGoubY15cxpiI5l0+q87Lm5p0bhbehMdzJg4aFag==",
"dev": true,
"license": "MIT",
"dependencies": {
@@ -1637,13 +1637,13 @@
}
},
"node_modules/@playwright/test": {
- "version": "1.63.0",
- "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.63.0.tgz",
- "integrity": "sha512-oxMK4vllB9RK5NQ2l1pq1IfOf2AvnEuj/vYGDj0H2nMtmtZpKtCwt/l00GEO6xjGfpBNAvjovvYdCm50dRQkpQ==",
+ "version": "1.64.0",
+ "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.64.0.tgz",
+ "integrity": "sha512-oTN9FNYuN6bqQMwiho6jJKLCG2/QOYCixGXuCjRmzOq23eODeukuY2XiAVoVpAECbuezMt1MHQjAiQxK8F+Y+g==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "playwright": "1.63.0"
+ "playwright": "1.64.0"
},
"bin": {
"playwright": "cli.js"
@@ -9221,13 +9221,13 @@
}
},
"node_modules/playwright": {
- "version": "1.63.0",
- "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.63.0.tgz",
- "integrity": "sha512-+7ziBLidS4NaNCdt57SUDT+wYmmd5fmiQejUic/kb+YsYSCPyOOE9sebzMjNmQrsnNpDJqd4WHvV/8lfKfUDUg==",
+ "version": "1.64.0",
+ "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.64.0.tgz",
+ "integrity": "sha512-kVzTnYFYEyQ9RGzBjNCd2+yEqWmVbxl3AHPynv3qQ6JTjv4a+kwRcnqQwIpuP3NnrnIrE/Q6wWAIAvMfIE2/Yg==",
"dev": true,
"license": "Apache-2.0",
"dependencies": {
- "playwright-core": "1.63.0"
+ "playwright-core": "1.64.0"
},
"bin": {
"playwright": "cli.js"
@@ -9237,9 +9237,9 @@
}
},
"node_modules/playwright-core": {
- "version": "1.63.0",
- "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.63.0.tgz",
- "integrity": "sha512-rYCsBF/M5HjUch52bbtVONEFjv6Xu8sm8h72dNlR5bzIE1fvC/bxgspzkjSfU+MweEMmPM8KJebG6nnyxo5mCg==",
+ "version": "1.64.0",
+ "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.64.0.tgz",
+ "integrity": "sha512-T9r+MZkTECl2+oUcZ26YgZzTrYidTsIhYYkJix+6iDOymOb1FB2RLLSOxRGnZGv5DStt+aduIVbt+E8WygXYpg==",
"dev": true,
"license": "Apache-2.0",
"bin": {
diff --git a/core/package.json b/core/package.json
index 6c255150c0f..6554c74ccd2 100644
--- a/core/package.json
+++ b/core/package.json
@@ -1,6 +1,6 @@
{
"name": "@ionic/core",
- "version": "9.0.7",
+ "version": "9.0.8",
"description": "Base components for Ionic",
"engines": {
"node": ">= 16"
@@ -80,7 +80,7 @@
"@eslint/js": "^9.0.0",
"@ionic/eslint-config": "^0.3.0",
"@ionic/prettier-config": "^2.0.0",
- "@playwright/test": "^1.63.0",
+ "@playwright/test": "^1.64.0",
"@rollup/plugin-node-resolve": "^8.4.0",
"@rollup/plugin-virtual": "^2.0.3",
"@stencil/angular-output-target": "^1.4.1",
@@ -102,7 +102,7 @@
"fs-extra": "^9.0.1",
"jest": "^29.7.0",
"jest-cli": "^29.7.0",
- "playwright-core": "^1.63.0",
+ "playwright-core": "^1.64.0",
"prettier": "^2.6.1",
"rollup": "^2.26.4",
"sass": "^1.33.0",
diff --git a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-ios-ltr-Mobile-Chrome-linux.png b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-ios-ltr-Mobile-Chrome-linux.png
index d9c803dfa7c..4e77dd36c94 100644
Binary files a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-ios-ltr-Mobile-Chrome-linux.png and b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-ios-ltr-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-ios-ltr-Mobile-Firefox-linux.png b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-ios-ltr-Mobile-Firefox-linux.png
index b8c706fb344..b2b830ef953 100644
Binary files a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-ios-ltr-Mobile-Firefox-linux.png and b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-ios-ltr-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-ios-ltr-Mobile-Safari-linux.png b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-ios-ltr-Mobile-Safari-linux.png
index 6d11e95bba2..31a3feced83 100644
Binary files a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-ios-ltr-Mobile-Safari-linux.png and b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-ios-ltr-Mobile-Safari-linux.png differ
diff --git a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-ios-rtl-Mobile-Chrome-linux.png b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-ios-rtl-Mobile-Chrome-linux.png
index ade964c7b27..b7881eb34b4 100644
Binary files a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-ios-rtl-Mobile-Chrome-linux.png and b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-ios-rtl-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-ios-rtl-Mobile-Firefox-linux.png b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-ios-rtl-Mobile-Firefox-linux.png
index 59c03881daf..e98c0ede885 100644
Binary files a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-ios-rtl-Mobile-Firefox-linux.png and b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-ios-rtl-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-ios-rtl-Mobile-Safari-linux.png b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-ios-rtl-Mobile-Safari-linux.png
index 4db55bcfcdc..2a3a4d09722 100644
Binary files a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-ios-rtl-Mobile-Safari-linux.png and b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-ios-rtl-Mobile-Safari-linux.png differ
diff --git a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-md-ltr-Mobile-Chrome-linux.png b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-md-ltr-Mobile-Chrome-linux.png
index e79d6e3c871..f19384016b4 100644
Binary files a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-md-ltr-Mobile-Chrome-linux.png and b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-md-ltr-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-md-ltr-Mobile-Firefox-linux.png b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-md-ltr-Mobile-Firefox-linux.png
index fab77e40ddc..65a04b6f10a 100644
Binary files a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-md-ltr-Mobile-Firefox-linux.png and b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-md-ltr-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-md-ltr-Mobile-Safari-linux.png b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-md-ltr-Mobile-Safari-linux.png
index 1076d64e884..44fa87eb3d5 100644
Binary files a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-md-ltr-Mobile-Safari-linux.png and b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-md-ltr-Mobile-Safari-linux.png differ
diff --git a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-md-rtl-Mobile-Chrome-linux.png b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-md-rtl-Mobile-Chrome-linux.png
index 76e841e42fc..e3357e6a193 100644
Binary files a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-md-rtl-Mobile-Chrome-linux.png and b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-md-rtl-Mobile-Chrome-linux.png differ
diff --git a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-md-rtl-Mobile-Firefox-linux.png b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-md-rtl-Mobile-Firefox-linux.png
index b58450b4c15..8fcbef1cab1 100644
Binary files a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-md-rtl-Mobile-Firefox-linux.png and b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-md-rtl-Mobile-Firefox-linux.png differ
diff --git a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-md-rtl-Mobile-Safari-linux.png b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-md-rtl-Mobile-Safari-linux.png
index 2eb01e783c9..c5da390317f 100644
Binary files a/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-md-rtl-Mobile-Safari-linux.png and b/core/src/components/alert/test/basic/alert.e2e.ts-snapshots/alert-prompt-md-rtl-Mobile-Safari-linux.png differ
diff --git a/core/src/components/alert/test/basic/index.html b/core/src/components/alert/test/basic/index.html
index e9ec5413a04..8c163252e46 100644
--- a/core/src/components/alert/test/basic/index.html
+++ b/core/src/components/alert/test/basic/index.html
@@ -190,11 +190,17 @@
type: 'date',
min: '2017-03-01',
max: '2018-01-12',
+ // WebKit renders today's date in empty date inputs, so set
+ // a value to keep the screenshot from changing every day.
+ value: '2017-06-15',
},
// input date without min nor max
{
name: 'name5',
type: 'date',
+ // WebKit renders today's date in empty date inputs, so set
+ // a value to keep the screenshot from changing every day.
+ value: '2020-09-24',
},
{
name: 'name6',
diff --git a/core/src/components/modal/gestures/sheet.ts b/core/src/components/modal/gestures/sheet.ts
index 5040271018a..deb08cf4046 100644
--- a/core/src/components/modal/gestures/sheet.ts
+++ b/core/src/components/modal/gestures/sheet.ts
@@ -9,6 +9,9 @@ import { getBackdropValueForSheet } from '../utils';
import { calculateSpringStep, canSwipeOnContent, handleCanDismiss } from './utils';
+/** How far ahead, in milliseconds, a drag's velocity is projected when snapping. */
+const FLICK_PROJECTION_MS = 350;
+
export interface MoveSheetToBreakpointOptions {
/**
* The breakpoint value to move the sheet to.
@@ -84,6 +87,11 @@ export const createSheetGesture = (
const contentEl = baseEl.querySelector('ion-content');
// Cache the initial value so the gesture restores it instead of forcing scrolling on.
const initialContentScrollY = contentEl?.scrollY ?? true;
+ /**
+ * The height of the sheet the user actually sees. This comes from the wrapper
+ * rather than the host element, which is stretched to the full viewport no
+ * matter how tall the sheet itself is.
+ */
const height = wrapperEl.clientHeight;
let currentBreakpoint = initialBreakpoint;
let offset = 0;
@@ -419,13 +427,13 @@ export const createSheetGesture = (
offset = clamp(0.0001, processedStep, maxStep);
animation.progressStep(offset);
- const snapBreakpoint = calculateSnapBreakpoint(detail.deltaY);
+ const snapBreakpoint = calculateSnapBreakpoint(detail.deltaY, detail.velocityY);
const eventDetail: ModalDragEventDetail = {
currentY: detail.currentY,
deltaY: detail.deltaY,
velocityY: detail.velocityY,
- progress: calculateProgress(detail.currentY),
+ progress: calculateEventProgress(detail.deltaY),
snapBreakpoint: snapBreakpoint,
};
@@ -433,7 +441,7 @@ export const createSheetGesture = (
};
const onEnd = (detail: GestureDetail) => {
- const snapBreakpoint = calculateSnapBreakpoint(detail.deltaY);
+ const snapBreakpoint = calculateSnapBreakpoint(detail.deltaY, detail.velocityY);
/**
* `snapBreakpoint === 0` is not enough on its own. `canDismiss: false`
@@ -449,7 +457,7 @@ export const createSheetGesture = (
currentY: detail.currentY,
deltaY: detail.deltaY,
velocityY: detail.velocityY,
- progress: calculateProgress(detail.currentY),
+ progress: calculateEventProgress(detail.deltaY),
snapBreakpoint,
isDismissing,
};
@@ -650,24 +658,15 @@ export const createSheetGesture = (
};
/**
- * Calculates the breakpoint based on the current deltaY.
- * This determines where the sheet should snap to when the user releases the
- * gesture.
+ * Decides which breakpoint the sheet should settle on for the current drag.
*
- * @param deltaY The change in Y position since the gesture started.
- * @returns The snap breakpoint value.
+ * @param deltaY The change in Y position since the gesture started
+ * @param velocityY The velocity in pixels per millisecond
+ * @returns The snap breakpoint value
*/
- const calculateSnapBreakpoint = (deltaY: number): number => {
- /**
- * Calculates the real-time vertical position of the modal.
- * We combine the wrapper's current bounding box position with the
- * gesture's deltaY to account for the physical movement during the drag.
- */
- const currentY = wrapperEl.getBoundingClientRect().top + deltaY;
- /**
- * Convert that pixel position back into a 0 to 1 progress value.
- */
- const currentProgress = calculateProgress(currentY);
+ const calculateSnapBreakpoint = (deltaY: number, velocityY: number): number => {
+ // Project the drag forward so a quick flick counts.
+ const currentProgress = calculateProgress(deltaY + velocityY * FLICK_PROJECTION_MS);
/**
* Find and return the defined breakpoint that is closest to the
@@ -681,78 +680,29 @@ export const createSheetGesture = (
};
/**
- * Calculates the progress of the swipe gesture.
- *
- * The progress is a value between 0 and 1 that represents how far
- * the swipe has progressed towards closing the modal.
- *
- * A value closer to 1 means the modal is closer to being opened,
- * while a value closer to 0 means the modal is closer to being closed.
+ * Calculates how open the sheet is part way through a gesture, on the same
+ * 0 to 1 scale as the breakpoints: 1 is fully open and 0 is fully closed.
*
- * @param currentY The current Y position of the gesture
+ * @param deltaY The change in Y position since the gesture started
* @returns The progress of the sheet gesture
*/
- const calculateProgress = (currentY: number): number => {
- const minBreakpoint = breakpoints[0];
- const maxBreakpoint = breakpoints[breakpoints.length - 1];
-
- /**
- * The lowest point the sheet can be dragged to aka the point at which
- * the sheet is fully closed.
- */
- const maxY = convertBreakpointToY(minBreakpoint);
- /**
- * The highest point the sheet can be dragged to aka the point at which
- * the sheet is fully open.
- */
- const minY = convertBreakpointToY(maxBreakpoint);
- // The total distance between the fully open and fully closed positions.
- const totalDistance = maxY - minY;
- // The distance from the current position to the fully closed position.
- const distanceFromBottom = maxY - currentY;
- /**
- * The progress represents how far the sheet is from the bottom relative
- * to the total distance. When the user starts swiping up, the progress
- * should be close to 1, and when the user has swiped all the way down,
- * the progress should be close to 0.
- */
- const progress = distanceFromBottom / totalDistance;
+ const calculateProgress = (deltaY: number): number => {
+ // Mirrors the animation step in onMove, so the snap matches where the sheet is drawn.
+ const progress = currentBreakpoint - deltaY / height;
// Round to the nearest thousandth to avoid returning very small decimal
const roundedProgress = Math.round(progress * 1000) / 1000;
- return Math.max(0, Math.min(1, roundedProgress));
+ return clamp(0, roundedProgress, 1);
};
/**
- * Converts a breakpoint value (0 to 1) into a pixel Y coordinate
- * on the screen.
- *
- * @param breakpoint The breakpoint value (e.g., 0.5 for half-open)
- * @returns The pixel Y coordinate on the screen
+ * Scales the progress from the lowest to the highest breakpoint, so the
+ * drag events report 0 at the lowest breakpoint and 1 at the highest.
*/
- const convertBreakpointToY = (breakpoint: number): number => {
- const rect = baseEl.getBoundingClientRect();
- const modalHeight = rect.height;
- // The bottom of the screen.
- const viewportBottom = window.innerHeight;
- /**
- * The active height is how much of the modal is actually showing
- * on the screen for this specific breakpoint.
- */
- const activeHeight = modalHeight * breakpoint;
+ const calculateEventProgress = (deltaY: number): number => {
+ const progress = (calculateProgress(deltaY) - minBreakpoint) / (maxBreakpoint - minBreakpoint);
- /**
- * To find the Y coordinate, start at the bottom of the screen
- * and move up by the active height of the modal.
- *
- * A breakpoint of 1.0 means the active height is the full modal height
- * (fully open). A breakpoint of 0.0 means the active height is 0
- * (fully closed).
- *
- * Since screen Y coordinates get smaller as you go up, we subtract the
- * active height from the viewport bottom.
- */
- return viewportBottom - activeHeight;
+ return clamp(0, progress, 1);
};
const gesture = createGesture({
diff --git a/core/src/components/modal/test/can-dismiss/modal-sheet.e2e.ts b/core/src/components/modal/test/can-dismiss/modal-sheet.e2e.ts
index 865b5b5a8de..2be21e2c03b 100644
--- a/core/src/components/modal/test/can-dismiss/modal-sheet.e2e.ts
+++ b/core/src/components/modal/test/can-dismiss/modal-sheet.e2e.ts
@@ -112,11 +112,11 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
await ionHandlerDone.next();
- const modal = page.locator('ion-modal');
- expect(modal).not.toBe(null);
+ await expect(page.locator('ion-modal')).toBeVisible();
});
test('should not dismiss on swipe when not attempting to close', async ({ page }) => {
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
+ const ionDragEnd = await page.spyOnEvent('ionDragEnd');
await page.click('#sheet-can-dismiss-promise-true');
@@ -125,8 +125,14 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) =>
const modalHeader = page.locator('#modal-header');
await dragElementBy(modalHeader, page, 0, 30);
- const modal = page.locator('ion-modal');
- expect(modal).not.toBe(null);
+ /**
+ * A drag this small snaps the sheet back open, so canDismiss is never
+ * consulted and the sheet stays where it was.
+ */
+ const dragEndEvent = await ionDragEnd.next();
+
+ expect(dragEndEvent.detail.isDismissing).toBe(false);
+ await expect(page.locator('ion-modal')).toBeVisible();
});
test('should hit the dismiss threshold when swiping', async ({ page }) => {
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
diff --git a/core/src/components/modal/test/sheet/index.html b/core/src/components/modal/test/sheet/index.html
index 91b735edad7..cbf9b3e6cbf 100644
--- a/core/src/components/modal/test/sheet/index.html
+++ b/core/src/components/modal/test/sheet/index.html
@@ -21,6 +21,11 @@
--height: 50%;
}
+ /* Kept below half the viewport so the drag tests catch sheets dismissing on upward drags. */
+ .short-sheet {
+ --height: 40%;
+ }
+
.custom-handle::part(handle) {
top: -16px;
background: rgba(255, 255, 255, 0.53);
@@ -127,6 +132,12 @@
+