From 2847681f7bf5ac53a1b0f93d96e4cd2590485132 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 22 Sep 2025 11:40:19 -0400 Subject: [PATCH 01/10] chore(deps): update dependency chalk to v5.6.2 (#30672) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | Age | Confidence | |---|---|---|---| | [chalk](https://redirect.github.com/chalk/chalk) | [`5.6.0` -> `5.6.2`](https://renovatebot.com/diffs/npm/chalk/5.6.0/5.6.2) | [![age](https://developer.mend.io/api/mc/badges/age/npm/chalk/5.6.2?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/chalk/5.6.0/5.6.2?slim=true)](https://docs.renovatebot.com/merge-confidence/) | --- ### Release Notes
chalk/chalk (chalk) ### [`v5.6.2`](https://redirect.github.com/chalk/chalk/releases/tag/v5.6.2) [Compare Source](https://redirect.github.com/chalk/chalk/compare/v5.6.0...v5.6.2) - Fix incorrect publish
--- ### Configuration 📅 **Schedule**: Branch creation - "every weekday before 11am" (UTC), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Never, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/ionic-team/ionic-framework). Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- core/package-lock.json | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/core/package-lock.json b/core/package-lock.json index 6e4a7454a3..29d34a9297 100644 --- a/core/package-lock.json +++ b/core/package-lock.json @@ -3474,9 +3474,9 @@ ] }, "node_modules/chalk": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.0.tgz", - "integrity": "sha512-46QrSQFyVSEyYAgQ22hQ+zDa60YHA4fBstHmtSApj1Y5vKtG27fWowW03jCk5KcbXEWPZUIR894aARCA/G1kfQ==", + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", "dev": true, "engines": { "node": "^12.17.0 || ^14.13 || >=16.0.0" @@ -13076,9 +13076,9 @@ "dev": true }, "chalk": { - "version": "5.6.0", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.0.tgz", - "integrity": "sha512-46QrSQFyVSEyYAgQ22hQ+zDa60YHA4fBstHmtSApj1Y5vKtG27fWowW03jCk5KcbXEWPZUIR894aARCA/G1kfQ==", + "version": "5.6.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.6.2.tgz", + "integrity": "sha512-7NzBL0rN6fMUW+f7A6Io4h40qQlG+xGmtMxfbnH/K7TAtt8JQWVQK+6g0UXKMeVJoyV5EkkNsErQ8pVD3bLHbA==", "dev": true }, "chalk-template": { From 6d4cb0f4e260906691210aff1007ceaa3719cd91 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 22 Sep 2025 11:40:51 -0400 Subject: [PATCH 02/10] chore(deps): update capacitor to v7.0.3 (#30671) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Change | Age | Confidence | |---|---|---|---| | [@capacitor/keyboard](https://redirect.github.com/ionic-team/capacitor-plugins) | [`7.0.2` -> `7.0.3`](https://renovatebot.com/diffs/npm/@capacitor%2fkeyboard/7.0.2/7.0.3) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@capacitor%2fkeyboard/7.0.3?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@capacitor%2fkeyboard/7.0.2/7.0.3?slim=true)](https://docs.renovatebot.com/merge-confidence/) | | [@capacitor/status-bar](https://redirect.github.com/ionic-team/capacitor-plugins) | [`7.0.2` -> `7.0.3`](https://renovatebot.com/diffs/npm/@capacitor%2fstatus-bar/7.0.2/7.0.3) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@capacitor%2fstatus-bar/7.0.3?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@capacitor%2fstatus-bar/7.0.2/7.0.3?slim=true)](https://docs.renovatebot.com/merge-confidence/) | --- ### Release Notes
ionic-team/capacitor-plugins (@​capacitor/keyboard) ### [`v7.0.3`](https://redirect.github.com/ionic-team/capacitor-plugins/releases/tag/%40capacitor/keyboard%407.0.3) [Compare Source](https://redirect.github.com/ionic-team/capacitor-plugins/compare/@capacitor/keyboard@7.0.2...@capacitor/keyboard@7.0.3) **Note:** Version bump only for package [@​capacitor/keyboard](https://redirect.github.com/capacitor/keyboard)
--- ### Configuration 📅 **Schedule**: Branch creation - "every weekday before 11am" (UTC), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Never, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about these updates again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/ionic-team/ionic-framework). Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- core/package-lock.json | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/core/package-lock.json b/core/package-lock.json index 29d34a9297..1a02ff866e 100644 --- a/core/package-lock.json +++ b/core/package-lock.json @@ -681,18 +681,18 @@ } }, "node_modules/@capacitor/keyboard": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@capacitor/keyboard/-/keyboard-7.0.2.tgz", - "integrity": "sha512-9We5BY1mu+QWOReDukr+6HxA4Bh0mKBU0txFtwXJdjBohttMYWJzB+dQf4oHrX8odiU2Cm/BfDdAU2wV06Cyig==", + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@capacitor/keyboard/-/keyboard-7.0.3.tgz", + "integrity": "sha512-BIBKjmky5rOYNhvYhNeDi0MMvjwYZ6YF9JoCYcGKvKY+XLJKtezsEL78XfOlgWZBkbfR8uq3tzktY6PqgoYLKA==", "dev": true, "peerDependencies": { "@capacitor/core": ">=7.0.0" } }, "node_modules/@capacitor/status-bar": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@capacitor/status-bar/-/status-bar-7.0.2.tgz", - "integrity": "sha512-fYYkkdzCbQV+MjZVnaQTFl5I4bddnFW8ZrPVxDjNoGVPTUG7H58Ij1+NcuNxHLXjJvZOoZeYJ3w3I16Wb2zssw==", + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@capacitor/status-bar/-/status-bar-7.0.3.tgz", + "integrity": "sha512-JyRpVnKwHij9hgPWolF6PK+HT3e2HSPjN11/h2OmKxq8GAdPGARFLv+97eZl0pvuvm0Kka/LpiLb5whXISBg7Q==", "dev": true, "peerDependencies": { "@capacitor/core": ">=7.0.0" @@ -11118,16 +11118,16 @@ "requires": {} }, "@capacitor/keyboard": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@capacitor/keyboard/-/keyboard-7.0.2.tgz", - "integrity": "sha512-9We5BY1mu+QWOReDukr+6HxA4Bh0mKBU0txFtwXJdjBohttMYWJzB+dQf4oHrX8odiU2Cm/BfDdAU2wV06Cyig==", + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@capacitor/keyboard/-/keyboard-7.0.3.tgz", + "integrity": "sha512-BIBKjmky5rOYNhvYhNeDi0MMvjwYZ6YF9JoCYcGKvKY+XLJKtezsEL78XfOlgWZBkbfR8uq3tzktY6PqgoYLKA==", "dev": true, "requires": {} }, "@capacitor/status-bar": { - "version": "7.0.2", - "resolved": "https://registry.npmjs.org/@capacitor/status-bar/-/status-bar-7.0.2.tgz", - "integrity": "sha512-fYYkkdzCbQV+MjZVnaQTFl5I4bddnFW8ZrPVxDjNoGVPTUG7H58Ij1+NcuNxHLXjJvZOoZeYJ3w3I16Wb2zssw==", + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/@capacitor/status-bar/-/status-bar-7.0.3.tgz", + "integrity": "sha512-JyRpVnKwHij9hgPWolF6PK+HT3e2HSPjN11/h2OmKxq8GAdPGARFLv+97eZl0pvuvm0Kka/LpiLb5whXISBg7Q==", "dev": true, "requires": {} }, From 9e361727b86c327bdeed199c47767c0c2f580028 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 22 Sep 2025 11:41:13 -0400 Subject: [PATCH 03/10] chore(deps): update actions/labeler action to v6 (#30668) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [actions/labeler](https://redirect.github.com/actions/labeler) | action | major | `v5` -> `v6` | --- ### Release Notes
actions/labeler (actions/labeler) ### [`v6`](https://redirect.github.com/actions/labeler/compare/v5...v6) [Compare Source](https://redirect.github.com/actions/labeler/compare/v5...v6)
--- ### Configuration 📅 **Schedule**: Branch creation - "every weekday before 11am" (UTC), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Never, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/ionic-team/ionic-framework). Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/label.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/label.yml b/.github/workflows/label.yml index a4e35060df..7f5d8de978 100644 --- a/.github/workflows/label.yml +++ b/.github/workflows/label.yml @@ -13,7 +13,7 @@ jobs: triage: runs-on: ubuntu-latest steps: - - uses: actions/labeler@v5 + - uses: actions/labeler@v6 with: repo-token: "${{ secrets.GITHUB_TOKEN }}" sync-labels: true From 36c56e71b6e2cf144910d56df9b039010518f1b9 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Mon, 22 Sep 2025 11:41:34 -0400 Subject: [PATCH 04/10] chore(deps): update actions/setup-node action to v5 (#30664) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This PR contains the following updates: | Package | Type | Update | Change | |---|---|---|---| | [actions/setup-node](https://redirect.github.com/actions/setup-node) | action | major | `v4` -> `v5` | --- ### Release Notes
actions/setup-node (actions/setup-node) ### [`v5`](https://redirect.github.com/actions/setup-node/compare/v4...v5) [Compare Source](https://redirect.github.com/actions/setup-node/compare/v4...v5)
--- ### Configuration 📅 **Schedule**: Branch creation - "every weekday before 11am" (UTC), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Never, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/ionic-team/ionic-framework). Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- .github/workflows/actions/build-angular-server/action.yml | 2 +- .github/workflows/actions/build-angular/action.yml | 2 +- .../workflows/actions/build-core-stencil-prerelease/action.yml | 2 +- .github/workflows/actions/build-core/action.yml | 2 +- .github/workflows/actions/build-react-router/action.yml | 2 +- .github/workflows/actions/build-react/action.yml | 2 +- .github/workflows/actions/build-vue-router/action.yml | 2 +- .github/workflows/actions/build-vue/action.yml | 2 +- .github/workflows/actions/publish-npm/action.yml | 2 +- .github/workflows/actions/test-angular-e2e/action.yml | 2 +- .github/workflows/actions/test-core-clean-build/action.yml | 2 +- .github/workflows/actions/test-core-lint/action.yml | 2 +- .github/workflows/actions/test-core-screenshot/action.yml | 2 +- .github/workflows/actions/test-core-spec/action.yml | 2 +- .github/workflows/actions/test-react-e2e/action.yml | 2 +- .github/workflows/actions/test-react-router-e2e/action.yml | 2 +- .github/workflows/actions/test-vue-e2e/action.yml | 2 +- .../workflows/actions/update-reference-screenshots/action.yml | 2 +- 18 files changed, 18 insertions(+), 18 deletions(-) diff --git a/.github/workflows/actions/build-angular-server/action.yml b/.github/workflows/actions/build-angular-server/action.yml index b530d30078..c48d1dcb3b 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@v4 + - uses: actions/setup-node@v5 with: node-version: 22.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 80da1c353d..349c6734e4 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@v4 + - uses: actions/setup-node@v5 with: node-version: 22.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 d35a2914bd..878265178a 100644 --- a/.github/workflows/actions/build-core-stencil-prerelease/action.yml +++ b/.github/workflows/actions/build-core-stencil-prerelease/action.yml @@ -9,7 +9,7 @@ runs: using: 'composite' steps: - uses: actions/checkout@v5 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@v5 with: node-version: 22.x diff --git a/.github/workflows/actions/build-core/action.yml b/.github/workflows/actions/build-core/action.yml index 5d036175a1..f64f564620 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@v5 - - uses: actions/setup-node@v4 + - uses: actions/setup-node@v5 with: node-version: 22.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 390378cb12..61d5f6b2d4 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@v4 + - uses: actions/setup-node@v5 with: node-version: 22.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 3ea565d62e..6b8b9f7417 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@v4 + - uses: actions/setup-node@v5 with: node-version: 22.x - uses: ./.github/workflows/actions/download-archive diff --git a/.github/workflows/actions/build-vue-router/action.yml b/.github/workflows/actions/build-vue-router/action.yml index 623bdc4c7a..e1c7716f5e 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@v4 + - uses: actions/setup-node@v5 with: node-version: 22.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 f2be91e109..bc8a47facc 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@v4 + - uses: actions/setup-node@v5 with: node-version: 22.x - uses: ./.github/workflows/actions/download-archive diff --git a/.github/workflows/actions/publish-npm/action.yml b/.github/workflows/actions/publish-npm/action.yml index 6bd557db3b..5c5b49d56c 100644 --- a/.github/workflows/actions/publish-npm/action.yml +++ b/.github/workflows/actions/publish-npm/action.yml @@ -19,7 +19,7 @@ inputs: runs: using: 'composite' steps: - - uses: actions/setup-node@v4 + - uses: actions/setup-node@v5 with: node-version: 22.x # Provenance requires npm 9.5.0+ diff --git a/.github/workflows/actions/test-angular-e2e/action.yml b/.github/workflows/actions/test-angular-e2e/action.yml index 705d6e27cf..cd7ebfe0ae 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@v4 + - uses: actions/setup-node@v5 with: node-version: 22.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 d822e69468..ea6da763fd 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@v4 + - uses: actions/setup-node@v5 with: node-version: 22.x diff --git a/.github/workflows/actions/test-core-lint/action.yml b/.github/workflows/actions/test-core-lint/action.yml index a4298c2c0a..b0e45abdae 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@v4 + - uses: actions/setup-node@v5 with: node-version: 22.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 588c310b46..f3d599f02c 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@v4 + - uses: actions/setup-node@v5 with: node-version: 22.x - uses: ./.github/workflows/actions/download-archive diff --git a/.github/workflows/actions/test-core-spec/action.yml b/.github/workflows/actions/test-core-spec/action.yml index f624666406..cdec48fabf 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@v4 + - uses: actions/setup-node@v5 with: node-version: 22.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 ab056ac667..3cf40c29b8 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@v4 + - uses: actions/setup-node@v5 with: node-version: 22.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 cf71e4da5a..f1f0150de1 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@v4 + - uses: actions/setup-node@v5 with: node-version: 22.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 93a21db785..905cb319a7 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@v4 + - uses: actions/setup-node@v5 with: node-version: 22.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 d454b2e2a3..95d0c7b726 100644 --- a/.github/workflows/actions/update-reference-screenshots/action.yml +++ b/.github/workflows/actions/update-reference-screenshots/action.yml @@ -7,7 +7,7 @@ on: runs: using: 'composite' steps: - - uses: actions/setup-node@v4 + - uses: actions/setup-node@v5 with: node-version: 22.x - uses: actions/download-artifact@v5 From 024d090122548e26ec2cdcfae4637dde8f288278 Mon Sep 17 00:00:00 2001 From: Shane Date: Tue, 23 Sep 2025 10:22:48 -0700 Subject: [PATCH 05/10] fix(vue): emit component-specific overlay events (#30688) Issue number: resolves #30641 --------- ## What is the current behavior? Currently, Vue modals do not emit `ionModal...` events. This happened due to a change in the way the stencil output targets for Vue changed. Christian [updated the overlays](https://github.com/ionic-team/ionic-framework/pull/30227/files#diff-7e46aba01094c4917cd55e8eebd263fc4a297a2d62143f1ae30959ec4e023b6f) to support the base events, but not the component-specific events. ## What is the new behavior? With this change, you'll be able to bind to the events as described in the Ionic documentation. ## Does this introduce a breaking change? - [ ] Yes - [X] No ## Other information Current dev build: ``` 8.7.5-dev.11758311583.14f4e9d9 ``` --- packages/vue/src/utils/overlays.ts | 13 +- packages/vue/test/base/src/views/Overlays.vue | 37 ++++ .../test/base/tests/e2e/specs/overlays.cy.js | 159 +++++++++++++++++- 3 files changed, 201 insertions(+), 8 deletions(-) diff --git a/packages/vue/src/utils/overlays.ts b/packages/vue/src/utils/overlays.ts index 91133e3490..b917e75054 100644 --- a/packages/vue/src/utils/overlays.ts +++ b/packages/vue/src/utils/overlays.ts @@ -1,5 +1,5 @@ -import type { VNode, ComponentOptions } from "vue"; -import { defineComponent, h, ref, onMounted } from "vue"; +import type { ComponentOptions, VNode } from "vue"; +import { defineComponent, h, onMounted, ref } from "vue"; // TODO(FW-2969): types @@ -147,23 +147,32 @@ export const defineOverlayContainer = ( const elementRef = ref(); onMounted(() => { + // Convert name from kebab-case to camelCase + const componentName = name.replace(/-([a-z])/g, (_, letter) => + letter.toUpperCase() + ); elementRef.value.addEventListener("ionMount", (ev: Event) => { emit("ionMount", ev); + emit(componentName + "IonMount", ev); isOpen.value = true; }); elementRef.value.addEventListener("willPresent", (ev: Event) => { emit("willPresent", ev); + emit(componentName + "WillPresent", ev); isOpen.value = true; }); elementRef.value.addEventListener("didDismiss", (ev: Event) => { emit("didDismiss", ev); + emit(componentName + "DidDismiss", ev); isOpen.value = false; }); elementRef.value.addEventListener("willDismiss", (ev: Event) => { emit("willDismiss", ev); + emit(componentName + "WillDismiss", ev); }); elementRef.value.addEventListener("didPresent", (ev: Event) => { emit("didPresent", ev); + emit(componentName + "DidPresent", ev); }); }); diff --git a/packages/vue/test/base/src/views/Overlays.vue b/packages/vue/test/base/src/views/Overlays.vue index 49b956e0dd..0b382b94b4 100644 --- a/packages/vue/test/base/src/views/Overlays.vue +++ b/packages/vue/test/base/src/views/Overlays.vue @@ -64,6 +64,10 @@ Modal onDidPresent:
{{ didPresent }}

Modal onWillDismiss:
{{ willDismiss }}

Modal onDidDismiss:
{{ didDismiss }}

+ Modal ionModalWillPresent:
{{ ionModalWillPresent }}

+ Modal ionModalDidPresent:
{{ ionModalDidPresent }}

+ Modal ionModalWillDismiss:
{{ ionModalWillDismiss }}

+ Modal ionModalDidDismiss:
{{ ionModalDidDismiss }}

@@ -266,6 +274,19 @@ export default defineComponent({ const openModal = async () => { const modal = await modalController.create({ cssClass: "ion-modal-controller", component: ModalContent, componentProps: overlayProps }); + + // Attach lifecycle listeners for controller-created modal + modal.addEventListener('willPresent', () => { willPresent.value += 1; }); + modal.addEventListener('didPresent', () => { didPresent.value += 1; }); + modal.addEventListener('willDismiss', () => { willDismiss.value += 1; }); + modal.addEventListener('didDismiss', () => { didDismiss.value += 1; }); + + // Long-form event names + modal.addEventListener('ionModalWillPresent', () => { ionModalWillPresent.value += 1; }); + modal.addEventListener('ionModalDidPresent', () => { ionModalDidPresent.value += 1; }); + modal.addEventListener('ionModalWillDismiss', () => { ionModalWillDismiss.value += 1; }); + modal.addEventListener('ionModalDidDismiss', () => { ionModalDidDismiss.value += 1; }); + await modal.present(); } @@ -335,21 +356,37 @@ export default defineComponent({ const didPresent = ref(0); const willDismiss = ref(0); const didDismiss = ref(0); + const ionModalWillPresent = ref(0); + const ionModalDidPresent = ref(0); + const ionModalWillDismiss = ref(0); + const ionModalDidDismiss = ref(0); const onModalWillPresent = () => willPresent.value += 1; const onModalDidPresent = () => { didPresent.value += 1; setModalRef(true); } const onModalWillDismiss = () => willDismiss.value += 1; const onModalDidDismiss = () => { didDismiss.value += 1; setModalRef(false); } + const onIonModalWillPresent = () => ionModalWillPresent.value += 1; + const onIonModalDidPresent = () => ionModalDidPresent.value += 1; + const onIonModalWillDismiss = () => ionModalWillDismiss.value += 1; + const onIonModalDidDismiss = () => ionModalDidDismiss.value += 1; return { onModalWillPresent, onModalDidPresent, onModalWillDismiss, onModalDidDismiss, + onIonModalWillPresent, + onIonModalDidPresent, + onIonModalWillDismiss, + onIonModalDidDismiss, willPresent, didPresent, willDismiss, didDismiss, + ionModalWillPresent, + ionModalDidPresent, + ionModalWillDismiss, + ionModalDidDismiss, changeLoadingProps, overlayProps, present, diff --git a/packages/vue/test/base/tests/e2e/specs/overlays.cy.js b/packages/vue/test/base/tests/e2e/specs/overlays.cy.js index 79f4ff4efb..8d34036799 100644 --- a/packages/vue/test/base/tests/e2e/specs/overlays.cy.js +++ b/packages/vue/test/base/tests/e2e/specs/overlays.cy.js @@ -1,7 +1,11 @@ const testController = (overlay, shadow = false) => { const selector = `.${overlay}-controller`; - cy.get(`ion-radio#${overlay}`).click(); - cy.get('ion-radio#controller').click(); + cy.get(`ion-radio#${overlay}`) + .scrollIntoView({ offset: { top: -100, left: 0 } }) + .click({ force: true }); + cy.get('ion-radio#controller') + .scrollIntoView({ offset: { top: -100, left: 0 } }) + .click({ force: true }); cy.get('ion-button#present-overlay').click(); cy.get(selector).should('exist').should('be.visible'); @@ -16,8 +20,12 @@ const testController = (overlay, shadow = false) => { } const testComponent = (overlay, shadow = false) => { - cy.get(`ion-radio#${overlay}`).click(); - cy.get('ion-radio#component').click(); + cy.get(`ion-radio#${overlay}`) + .scrollIntoView({ offset: { top: -100, left: 0 } }) + .click({ force: true }); + cy.get('ion-radio#component') + .scrollIntoView({ offset: { top: -100, left: 0 } }) + .click({ force: true }); cy.get('ion-button#present-overlay').click(); cy.get(overlay).should('exist').should('be.visible'); @@ -40,8 +48,12 @@ const testComponent = (overlay, shadow = false) => { } const testInlineOverlay = (overlay, shadow = false) => { - cy.get(`ion-radio#${overlay}`).click(); - cy.get('ion-radio#component').click(); + cy.get(`ion-radio#${overlay}`) + .scrollIntoView({ offset: { top: -100, left: 0 } }) + .click({ force: true }); + cy.get('ion-radio#component') + .scrollIntoView({ offset: { top: -100, left: 0 } }) + .click({ force: true }); cy.get('ion-button#present-overlay').click(); cy.get(overlay).should('exist').should('be.visible'); @@ -214,6 +226,135 @@ describe('Overlays', () => { }); }); + it('should fire long-form lifecycle events on overlays', () => { + cy.get('ion-radio#ion-modal').click(); + cy.get('ion-radio#component').click(); + + cy.get('ion-button#present-overlay').click(); + cy.get('ion-modal').should('exist'); + + testLongLifecycle('overlays', { + willPresent: 1, + didPresent: 1, + willDismiss: 0, + didDismiss: 0 + }); + + cy.get('ion-modal #dismiss').click(); + + testLongLifecycle('overlays', { + willPresent: 1, + didPresent: 1, + willDismiss: 1, + didDismiss: 1 + }); + + cy.get('ion-button#present-overlay').click(); + cy.get('ion-modal').should('exist'); + + testLongLifecycle('overlays', { + willPresent: 2, + didPresent: 2, + willDismiss: 1, + didDismiss: 1 + }); + + cy.get('ion-modal #dismiss').click(); + + testLongLifecycle('overlays', { + willPresent: 2, + didPresent: 2, + willDismiss: 2, + didDismiss: 2 + }); + }); + + it('should fire lifecycle events on controller overlays', () => { + cy.get('ion-radio#ion-modal').click(); + cy.get('ion-radio#controller').click(); + + cy.get('ion-button#present-overlay').click(); + cy.get('ion-modal').should('exist'); + + testLifecycle('overlays', { + willPresent: 1, + didPresent: 1, + willDismiss: 0, + didDismiss: 0 + }); + + cy.get('ion-modal #dismiss').click(); + + testLifecycle('overlays', { + willPresent: 1, + didPresent: 1, + willDismiss: 1, + didDismiss: 1 + }); + + cy.get('ion-button#present-overlay').click(); + cy.get('ion-modal').should('exist'); + + testLifecycle('overlays', { + willPresent: 2, + didPresent: 2, + willDismiss: 1, + didDismiss: 1 + }); + + cy.get('ion-modal #dismiss').click(); + + testLifecycle('overlays', { + willPresent: 2, + didPresent: 2, + willDismiss: 2, + didDismiss: 2 + }); + }); + + it('should fire long-form lifecycle events on controller overlays', () => { + cy.get('ion-radio#ion-modal').click(); + cy.get('ion-radio#controller').click(); + + cy.get('ion-button#present-overlay').click(); + cy.get('ion-modal').should('exist'); + + testLongLifecycle('overlays', { + willPresent: 1, + didPresent: 1, + willDismiss: 0, + didDismiss: 0 + }); + + cy.get('ion-modal #dismiss').click(); + + testLongLifecycle('overlays', { + willPresent: 1, + didPresent: 1, + willDismiss: 1, + didDismiss: 1 + }); + + cy.get('ion-button#present-overlay').click(); + cy.get('ion-modal').should('exist'); + + testLongLifecycle('overlays', { + willPresent: 2, + didPresent: 2, + willDismiss: 1, + didDismiss: 1 + }); + + cy.get('ion-modal #dismiss').click(); + + testLongLifecycle('overlays', { + willPresent: 2, + didPresent: 2, + willDismiss: 2, + didDismiss: 2 + }); + }); + it('should unmount modal via component', () => { cy.get('ion-radio#ion-modal').click(); cy.get('ion-radio#component').click(); @@ -260,3 +401,9 @@ const testLifecycle = (selector, expected = {}) => { cy.get(`[data-pageid=${selector}] #didDismiss`).should('have.text', expected.didDismiss); } +const testLongLifecycle = (selector, expected = {}) => { + cy.get(`[data-pageid=${selector}] #ionModalWillPresent`).should('have.text', expected.willPresent); + cy.get(`[data-pageid=${selector}] #ionModalDidPresent`).should('have.text', expected.didPresent); + cy.get(`[data-pageid=${selector}] #ionModalWillDismiss`).should('have.text', expected.willDismiss); + cy.get(`[data-pageid=${selector}] #ionModalDidDismiss`).should('have.text', expected.didDismiss); +} From 49f7cc770416914322d12d880b32620d46e1d987 Mon Sep 17 00:00:00 2001 From: Maria Hutt Date: Tue, 23 Sep 2025 12:04:25 -0700 Subject: [PATCH 06/10] chore: add Maria back (#30691) Issue number: N/A --------- ## What is the current behavior? I was out of office so I was removed from the auto assign. ## What is the new behavior? - Add Maria back to the auto assign. ## Does this introduce a breaking change? - [ ] Yes - [x] No ## Other information N/A --- .github/workflows/assign-issues.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/assign-issues.yml b/.github/workflows/assign-issues.yml index 4608d2323d..d06c1f52e1 100644 --- a/.github/workflows/assign-issues.yml +++ b/.github/workflows/assign-issues.yml @@ -13,6 +13,6 @@ jobs: - name: 'Auto-assign issue' uses: pozil/auto-assign-issue@39c06395cbac76e79afc4ad4e5c5c6db6ecfdd2e # v2.2.0 with: - assignees: brandyscarney, ShaneK + assignees: brandyscarney, thetaPC, ShaneK numOfAssignee: 1 allowSelfAssign: false From 5a06503d4a82937da43a7f3547f6a5c9625bc278 Mon Sep 17 00:00:00 2001 From: "renovate[bot]" <29139614+renovate[bot]@users.noreply.github.com> Date: Wed, 24 Sep 2025 08:24:30 -0700 Subject: [PATCH 07/10] chore(deps): update playwright (#30693) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Coming soon: The Renovate bot (GitHub App) will be renamed to Mend. PRs from Renovate will soon appear from 'Mend'. Learn more [here](https://redirect.github.com/renovatebot/renovate/discussions/37842). This PR contains the following updates: | Package | Change | Age | Confidence | Type | Update | |---|---|---|---|---|---| | [@playwright/test](https://playwright.dev) ([source](https://redirect.github.com/microsoft/playwright)) | [`^1.55.0` -> `^1.55.1`](https://renovatebot.com/diffs/npm/@playwright%2ftest/1.55.0/1.55.1) | [![age](https://developer.mend.io/api/mc/badges/age/npm/@playwright%2ftest/1.55.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/@playwright%2ftest/1.55.0/1.55.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | devDependencies | patch | | mcr.microsoft.com/playwright | `v1.55.0` -> `v1.55.1` | [![age](https://developer.mend.io/api/mc/badges/age/docker/mcr.microsoft.com%2fplaywright/v1.55.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/docker/mcr.microsoft.com%2fplaywright/v1.55.0/v1.55.1?slim=true)](https://docs.renovatebot.com/merge-confidence/) | final | patch | --- ### Release Notes
microsoft/playwright (@​playwright/test) ### [`v1.55.1`](https://redirect.github.com/microsoft/playwright/releases/tag/v1.55.1) [Compare Source](https://redirect.github.com/microsoft/playwright/compare/v1.55.0...v1.55.1) ##### Highlights [#​37479](https://redirect.github.com/microsoft/playwright/issues/37479) - \[Bug]: Upgrade Chromium to 140.0.7339.186. [#​37147](https://redirect.github.com/microsoft/playwright/issues/37147) - \[Regression]: Internal error: step id not found. [#​37146](https://redirect.github.com/microsoft/playwright/issues/37146) - \[Regression]: HTML reporter displays a broken chip link when there are no projects. [#​37137](https://redirect.github.com/microsoft/playwright/pull/37137) - Revert "fix(a11y): track inert elements as hidden". #### Browser Versions - Chromium 140.0.7339.186 - Mozilla Firefox 141.0 - WebKit 26.0 This version was also tested against the following stable channels: - Google Chrome 139 - Microsoft Edge 139
--- ### Configuration 📅 **Schedule**: Branch creation - "every weekday before 11am" (UTC), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Never, or you tick the rebase/retry checkbox. 👻 **Immortal**: This PR will be recreated if closed unmerged. Get [config help](https://redirect.github.com/renovatebot/renovate/discussions) if that's undesired. --- - [ ] If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/ionic-team/ionic-framework). Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com> --- core/Dockerfile | 2 +- core/package-lock.json | 46 +++++++++++++++++++++--------------------- core/package.json | 2 +- 3 files changed, 25 insertions(+), 25 deletions(-) diff --git a/core/Dockerfile b/core/Dockerfile index 6ccd28e99b..095cde63a4 100644 --- a/core/Dockerfile +++ b/core/Dockerfile @@ -1,5 +1,5 @@ # Get Playwright -FROM mcr.microsoft.com/playwright:v1.55.0 +FROM mcr.microsoft.com/playwright:v1.55.1 # Set the working directory WORKDIR /ionic diff --git a/core/package-lock.json b/core/package-lock.json index 1a02ff866e..cd76d92da1 100644 --- a/core/package-lock.json +++ b/core/package-lock.json @@ -22,7 +22,7 @@ "@clack/prompts": "^0.11.0", "@ionic/eslint-config": "^0.3.0", "@ionic/prettier-config": "^2.0.0", - "@playwright/test": "^1.55.0", + "@playwright/test": "^1.55.1", "@rollup/plugin-node-resolve": "^8.4.0", "@rollup/plugin-virtual": "^2.0.3", "@stencil/angular-output-target": "^0.10.0", @@ -1715,12 +1715,12 @@ } }, "node_modules/@playwright/test": { - "version": "1.55.0", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.55.0.tgz", - "integrity": "sha512-04IXzPwHrW69XusN/SIdDdKZBzMfOT9UNT/YiJit/xpy2VuAoB8NHc8Aplb96zsWDddLnbkPL3TsmrS04ZU2xQ==", + "version": "1.55.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.55.1.tgz", + "integrity": "sha512-IVAh/nOJaw6W9g+RJVlIQJ6gSiER+ae6mKQ5CX1bERzQgbC1VSeBlwdvczT7pxb0GWiyrxH4TGKbMfDb4Sq/ig==", "dev": true, "dependencies": { - "playwright": "1.55.0" + "playwright": "1.55.1" }, "bin": { "playwright": "cli.js" @@ -8593,12 +8593,12 @@ } }, "node_modules/playwright": { - "version": "1.55.0", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.55.0.tgz", - "integrity": "sha512-sdCWStblvV1YU909Xqx0DhOjPZE4/5lJsIS84IfN9dAZfcl/CIZ5O8l3o0j7hPMjDvqoTF8ZUcc+i/GL5erstA==", + "version": "1.55.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.55.1.tgz", + "integrity": "sha512-cJW4Xd/G3v5ovXtJJ52MAOclqeac9S/aGGgRzLabuF8TnIb6xHvMzKIa6JmrRzUkeXJgfL1MhukP0NK6l39h3A==", "dev": true, "dependencies": { - "playwright-core": "1.55.0" + "playwright-core": "1.55.1" }, "bin": { "playwright": "cli.js" @@ -8611,9 +8611,9 @@ } }, "node_modules/playwright-core": { - "version": "1.55.0", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.55.0.tgz", - "integrity": "sha512-GvZs4vU3U5ro2nZpeiwyb0zuFaqb9sUiAJuyrWpcGouD8y9/HLgGbNRjIph7zU9D3hnPaisMl9zG9CgFi/biIg==", + "version": "1.55.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.55.1.tgz", + "integrity": "sha512-Z6Mh9mkwX+zxSlHqdr5AOcJnfp+xUWLCt9uKV18fhzA8eyxUd8NUWzAjxUh55RZKSYwDGX0cfaySdhZJGMoJ+w==", "dev": true, "bin": { "playwright-core": "cli.js" @@ -11863,12 +11863,12 @@ } }, "@playwright/test": { - "version": "1.55.0", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.55.0.tgz", - "integrity": "sha512-04IXzPwHrW69XusN/SIdDdKZBzMfOT9UNT/YiJit/xpy2VuAoB8NHc8Aplb96zsWDddLnbkPL3TsmrS04ZU2xQ==", + "version": "1.55.1", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.55.1.tgz", + "integrity": "sha512-IVAh/nOJaw6W9g+RJVlIQJ6gSiER+ae6mKQ5CX1bERzQgbC1VSeBlwdvczT7pxb0GWiyrxH4TGKbMfDb4Sq/ig==", "dev": true, "requires": { - "playwright": "1.55.0" + "playwright": "1.55.1" } }, "@rollup/plugin-node-resolve": { @@ -16812,19 +16812,19 @@ } }, "playwright": { - "version": "1.55.0", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.55.0.tgz", - "integrity": "sha512-sdCWStblvV1YU909Xqx0DhOjPZE4/5lJsIS84IfN9dAZfcl/CIZ5O8l3o0j7hPMjDvqoTF8ZUcc+i/GL5erstA==", + "version": "1.55.1", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.55.1.tgz", + "integrity": "sha512-cJW4Xd/G3v5ovXtJJ52MAOclqeac9S/aGGgRzLabuF8TnIb6xHvMzKIa6JmrRzUkeXJgfL1MhukP0NK6l39h3A==", "dev": true, "requires": { "fsevents": "2.3.2", - "playwright-core": "1.55.0" + "playwright-core": "1.55.1" } }, "playwright-core": { - "version": "1.55.0", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.55.0.tgz", - "integrity": "sha512-GvZs4vU3U5ro2nZpeiwyb0zuFaqb9sUiAJuyrWpcGouD8y9/HLgGbNRjIph7zU9D3hnPaisMl9zG9CgFi/biIg==", + "version": "1.55.1", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.55.1.tgz", + "integrity": "sha512-Z6Mh9mkwX+zxSlHqdr5AOcJnfp+xUWLCt9uKV18fhzA8eyxUd8NUWzAjxUh55RZKSYwDGX0cfaySdhZJGMoJ+w==", "dev": true }, "postcss": { diff --git a/core/package.json b/core/package.json index c37e0c2bd7..b343a65e06 100644 --- a/core/package.json +++ b/core/package.json @@ -44,7 +44,7 @@ "@clack/prompts": "^0.11.0", "@ionic/eslint-config": "^0.3.0", "@ionic/prettier-config": "^2.0.0", - "@playwright/test": "^1.55.0", + "@playwright/test": "^1.55.1", "@rollup/plugin-node-resolve": "^8.4.0", "@rollup/plugin-virtual": "^2.0.3", "@stencil/angular-output-target": "^0.10.0", From a40d957ad9c1897af365a91b45b00228a00d614c Mon Sep 17 00:00:00 2001 From: Shane Date: Wed, 24 Sep 2025 12:29:58 -0700 Subject: [PATCH 08/10] fix(modal): allow sheet modals to skip focus trap (#30689) Issue number: resolves #30684 --------- ## What is the current behavior? Recently, we [fixed some issues with aria-hidden in modals](https://github.com/ionic-team/ionic-framework/pull/30563), unfortunately at this time we neglected modals that opt out of focus trapping. As a result, a lot of modals that disable focus trapping still have it happening and it doesn't get cleaned up properly on dismiss. ## What is the new behavior? We're now properly checking for and skipping focus traps on modals that do not want them. ## Does this introduce a breaking change? - [ ] Yes - [X] No ## Other information I created regression tests for Angular in this to prevent this from happening again. I initially tried to do this with core, but the issue doesn't seem to reproduce with core. Current dev build: ``` 8.7.5-dev.11758652700.103435a3 ``` --- core/src/components/modal/gestures/sheet.ts | 16 ++- core/src/utils/overlays.ts | 62 ++++++++--- .../src/lazy/modal-dynamic-wrapper.spec.ts | 38 +++++++ .../e2e/src/lazy/modal-sheet-inline.spec.ts | 34 ++++++ .../standalone/modal-dynamic-wrapper.spec.ts | 38 +++++++ .../src/standalone/modal-sheet-inline.spec.ts | 34 ++++++ .../base/src/app/lazy/app-lazy/app.routes.ts | 3 +- .../lazy/home-page/home-page.component.html | 10 ++ .../dynamic-component-wrapper.component.ts | 26 +++++ .../dynamic-modal-content.component.ts | 20 ++++ .../app/lazy/modal-dynamic-wrapper/index.ts | 2 + .../modal-dynamic-wrapper-routing.module.ts | 16 +++ .../modal-dynamic-wrapper.component.html | 8 ++ .../modal-dynamic-wrapper.component.ts | 104 ++++++++++++++++++ .../modal-dynamic-wrapper.module.ts | 14 +++ .../src/app/lazy/modal-sheet-inline/index.ts | 2 + .../modal-sheet-inline-routing.module.ts | 16 +++ .../modal-sheet-inline.component.html | 46 ++++++++ .../modal-sheet-inline.component.ts | 79 +++++++++++++ .../modal-sheet-inline.module.ts | 12 ++ .../standalone/app-standalone/app.routes.ts | 2 + .../home-page/home-page.component.html | 10 ++ .../dynamic-component-wrapper.component.ts | 27 +++++ .../dynamic-modal-content.component.ts | 28 +++++ .../modal-dynamic-wrapper.component.html | 8 ++ .../modal-dynamic-wrapper.component.ts | 103 +++++++++++++++++ .../modal-sheet-inline.component.html | 46 ++++++++ .../modal-sheet-inline.component.ts | 100 +++++++++++++++++ .../overlay-components/ModalFocusTrap.tsx | 61 ++++++++++ .../overlay-components/ModalTeleport.tsx | 71 ++++++++++++ .../overlay-components/OverlayComponents.tsx | 16 ++- .../specs/overlay-components/IonModal.cy.ts | 2 +- .../IonModalFocusTrap.cy.ts | 36 ++++++ .../overlay-components/IonModalTeleport.cy.ts | 27 +++++ .../KeepContentsMounted.cy.ts | 2 +- 35 files changed, 1094 insertions(+), 25 deletions(-) create mode 100644 packages/angular/test/base/e2e/src/lazy/modal-dynamic-wrapper.spec.ts create mode 100644 packages/angular/test/base/e2e/src/lazy/modal-sheet-inline.spec.ts create mode 100644 packages/angular/test/base/e2e/src/standalone/modal-dynamic-wrapper.spec.ts create mode 100644 packages/angular/test/base/e2e/src/standalone/modal-sheet-inline.spec.ts create mode 100644 packages/angular/test/base/src/app/lazy/modal-dynamic-wrapper/dynamic-component-wrapper.component.ts create mode 100644 packages/angular/test/base/src/app/lazy/modal-dynamic-wrapper/dynamic-modal-content.component.ts create mode 100644 packages/angular/test/base/src/app/lazy/modal-dynamic-wrapper/index.ts create mode 100644 packages/angular/test/base/src/app/lazy/modal-dynamic-wrapper/modal-dynamic-wrapper-routing.module.ts create mode 100644 packages/angular/test/base/src/app/lazy/modal-dynamic-wrapper/modal-dynamic-wrapper.component.html create mode 100644 packages/angular/test/base/src/app/lazy/modal-dynamic-wrapper/modal-dynamic-wrapper.component.ts create mode 100644 packages/angular/test/base/src/app/lazy/modal-dynamic-wrapper/modal-dynamic-wrapper.module.ts create mode 100644 packages/angular/test/base/src/app/lazy/modal-sheet-inline/index.ts create mode 100644 packages/angular/test/base/src/app/lazy/modal-sheet-inline/modal-sheet-inline-routing.module.ts create mode 100644 packages/angular/test/base/src/app/lazy/modal-sheet-inline/modal-sheet-inline.component.html create mode 100644 packages/angular/test/base/src/app/lazy/modal-sheet-inline/modal-sheet-inline.component.ts create mode 100644 packages/angular/test/base/src/app/lazy/modal-sheet-inline/modal-sheet-inline.module.ts create mode 100644 packages/angular/test/base/src/app/standalone/modal-dynamic-wrapper/dynamic-component-wrapper.component.ts create mode 100644 packages/angular/test/base/src/app/standalone/modal-dynamic-wrapper/dynamic-modal-content.component.ts create mode 100644 packages/angular/test/base/src/app/standalone/modal-dynamic-wrapper/modal-dynamic-wrapper.component.html create mode 100644 packages/angular/test/base/src/app/standalone/modal-dynamic-wrapper/modal-dynamic-wrapper.component.ts create mode 100644 packages/angular/test/base/src/app/standalone/modal-sheet-inline/modal-sheet-inline.component.html create mode 100644 packages/angular/test/base/src/app/standalone/modal-sheet-inline/modal-sheet-inline.component.ts create mode 100644 packages/react/test/base/src/pages/overlay-components/ModalFocusTrap.tsx create mode 100644 packages/react/test/base/src/pages/overlay-components/ModalTeleport.tsx create mode 100644 packages/react/test/base/tests/e2e/specs/overlay-components/IonModalFocusTrap.cy.ts create mode 100644 packages/react/test/base/tests/e2e/specs/overlay-components/IonModalTeleport.cy.ts diff --git a/core/src/components/modal/gestures/sheet.ts b/core/src/components/modal/gestures/sheet.ts index 219769e487..afac8f3d3e 100644 --- a/core/src/components/modal/gestures/sheet.ts +++ b/core/src/components/modal/gestures/sheet.ts @@ -95,6 +95,12 @@ export const createSheetGesture = ( const contentAnimation = animation.childAnimations.find((ani) => ani.id === 'contentAnimation'); const enableBackdrop = () => { + // Respect explicit opt-out of focus trapping/backdrop interactions + // If focusTrap is false or showBackdrop is false, do not enable the backdrop or re-enable focus trap + const el = baseEl as HTMLIonModalElement & { focusTrap?: boolean; showBackdrop?: boolean }; + if (el.focusTrap === false || el.showBackdrop === false) { + return; + } baseEl.style.setProperty('pointer-events', 'auto'); backdropEl.style.setProperty('pointer-events', 'auto'); @@ -235,7 +241,10 @@ export const createSheetGesture = ( * ion-backdrop and .modal-wrapper always have pointer-events: auto * applied, so the modal content can still be interacted with. */ - const shouldEnableBackdrop = currentBreakpoint > backdropBreakpoint; + const shouldEnableBackdrop = + currentBreakpoint > backdropBreakpoint && + (baseEl as HTMLIonModalElement & { focusTrap?: boolean }).focusTrap !== false && + (baseEl as HTMLIonModalElement & { showBackdrop?: boolean }).showBackdrop !== false; if (shouldEnableBackdrop) { enableBackdrop(); } else { @@ -582,7 +591,10 @@ export const createSheetGesture = ( * Backdrop should become enabled * after the backdropBreakpoint value */ - const shouldEnableBackdrop = currentBreakpoint > backdropBreakpoint; + const shouldEnableBackdrop = + currentBreakpoint > backdropBreakpoint && + (baseEl as HTMLIonModalElement & { focusTrap?: boolean }).focusTrap !== false && + (baseEl as HTMLIonModalElement & { showBackdrop?: boolean }).showBackdrop !== false; if (shouldEnableBackdrop) { enableBackdrop(); } else { diff --git a/core/src/utils/overlays.ts b/core/src/utils/overlays.ts index 0a362a6f8f..5b983158aa 100644 --- a/core/src/utils/overlays.ts +++ b/core/src/utils/overlays.ts @@ -494,10 +494,8 @@ export const setRootAriaHidden = (hidden = false) => { if (hidden) { viewContainer.setAttribute('aria-hidden', 'true'); - viewContainer.setAttribute('inert', ''); } else { viewContainer.removeAttribute('aria-hidden'); - viewContainer.removeAttribute('inert'); } }; @@ -529,15 +527,37 @@ export const present = async ( * focus traps. * * All other overlays should have focus traps to prevent - * the keyboard focus from leaving the overlay. + * the keyboard focus from leaving the overlay unless + * developers explicitly opt out (for example, sheet + * modals that should permit background interaction). + * + * Note: Some apps move inline overlays to a specific container + * during the willPresent lifecycle (e.g., React portals via + * onWillPresent). Defer applying aria-hidden/inert to the app + * root until after willPresent so we can detect where the + * overlay is finally inserted. If the overlay is inside the + * view container subtree, skip adding aria-hidden/inert there + * to avoid disabling the overlay. */ - if (overlay.el.tagName !== 'ION-TOAST') { - setRootAriaHidden(true); - document.body.classList.add(BACKDROP_NO_SCROLL); - } + const overlayEl = overlay.el as HTMLIonOverlayElement & { focusTrap?: boolean; showBackdrop?: boolean }; + const shouldTrapFocus = overlayEl.tagName !== 'ION-TOAST' && overlayEl.focusTrap !== false; + // Only lock out root content when backdrop is active. Developers relying on showBackdrop=false + // expect background interaction to remain enabled. + const shouldLockRoot = shouldTrapFocus && overlayEl.showBackdrop !== false; overlay.presented = true; overlay.willPresent.emit(); + + if (shouldLockRoot) { + const root = getAppRoot(document); + const viewContainer = root.querySelector('ion-router-outlet, #ion-view-container-root'); + const overlayInsideViewContainer = viewContainer ? viewContainer.contains(overlayEl) : false; + + if (!overlayInsideViewContainer) { + setRootAriaHidden(true); + } + document.body.classList.add(BACKDROP_NO_SCROLL); + } overlay.willPresentShorthand?.emit(); const mode = getIonMode(overlay); @@ -653,22 +673,28 @@ export const dismiss = async ( * For accessibility, toasts lack focus traps and don't receive * `aria-hidden` on the root element when presented. * - * All other overlays use focus traps to keep keyboard focus - * within the overlay, setting `aria-hidden` on the root element - * to enhance accessibility. - * - * Therefore, we must remove `aria-hidden` from the root element - * when the last non-toast overlay is dismissed. + * Overlays that opt into focus trapping set `aria-hidden` + * on the root element to keep keyboard focus and pointer + * events inside the overlay. We must remove `aria-hidden` + * from the root element when the last focus-trapping overlay + * is dismissed. */ - const overlaysNotToast = presentedOverlays.filter((o) => o.tagName !== 'ION-TOAST'); - - const lastOverlayNotToast = overlaysNotToast.length === 1 && overlaysNotToast[0].id === overlay.el.id; + const overlaysLockingRoot = presentedOverlays.filter((o) => { + const el = o as HTMLIonOverlayElement & { focusTrap?: boolean; showBackdrop?: boolean }; + return el.tagName !== 'ION-TOAST' && el.focusTrap !== false && el.showBackdrop !== false; + }); + const overlayEl = overlay.el as HTMLIonOverlayElement & { focusTrap?: boolean; showBackdrop?: boolean }; + const locksRoot = + overlayEl.tagName !== 'ION-TOAST' && overlayEl.focusTrap !== false && overlayEl.showBackdrop !== false; /** - * If this is the last visible overlay that is not a toast + * If this is the last visible overlay that is trapping focus * then we want to re-add the root to the accessibility tree. */ - if (lastOverlayNotToast) { + const lastOverlayTrappingFocus = + locksRoot && overlaysLockingRoot.length === 1 && overlaysLockingRoot[0].id === overlayEl.id; + + if (lastOverlayTrappingFocus) { setRootAriaHidden(false); document.body.classList.remove(BACKDROP_NO_SCROLL); } diff --git a/packages/angular/test/base/e2e/src/lazy/modal-dynamic-wrapper.spec.ts b/packages/angular/test/base/e2e/src/lazy/modal-dynamic-wrapper.spec.ts new file mode 100644 index 0000000000..b76f16015b --- /dev/null +++ b/packages/angular/test/base/e2e/src/lazy/modal-dynamic-wrapper.spec.ts @@ -0,0 +1,38 @@ +import { expect, test } from '@playwright/test'; + +test.describe('Modals: Dynamic Wrapper', () => { + test.beforeEach(async ({ page }) => { + await page.goto('/lazy/modal-dynamic-wrapper'); + }); + + test('should render dynamic component inside modal', async ({ page }) => { + await page.locator('#open-dynamic-modal').click(); + + await expect(page.locator('ion-modal')).toBeVisible(); + await expect(page.locator('#dynamic-component-loaded')).toBeVisible(); + }); + + test('should allow interacting with background content while sheet is open', async ({ page }) => { + await page.locator('#open-dynamic-modal').click(); + + await expect(page.locator('ion-modal')).toBeVisible(); + + await page.locator('#background-action').click(); + + await expect(page.locator('#background-action-count')).toHaveText('1'); + }); + + test('should prevent interacting with background content when focus is trapped', async ({ page }) => { + await page.locator('#open-focused-modal').click(); + + await expect(page.locator('ion-modal')).toBeVisible(); + + // Attempt to click the background button via coordinates; click should be intercepted by backdrop + const box = await page.locator('#background-action').boundingBox(); + if (box) { + await page.mouse.click(box.x + box.width / 2, box.y + box.height / 2); + } + + await expect(page.locator('#background-action-count')).toHaveText('0'); + }); +}); diff --git a/packages/angular/test/base/e2e/src/lazy/modal-sheet-inline.spec.ts b/packages/angular/test/base/e2e/src/lazy/modal-sheet-inline.spec.ts new file mode 100644 index 0000000000..0e23c057d0 --- /dev/null +++ b/packages/angular/test/base/e2e/src/lazy/modal-sheet-inline.spec.ts @@ -0,0 +1,34 @@ +import { expect, test } from '@playwright/test'; + +test.describe('Modals: Inline Sheet', () => { + test.beforeEach(async ({ page }) => { + await page.goto('/lazy/modal-sheet-inline'); + }); + + test('should open inline sheet modal', async ({ page }) => { + await page.locator('#present-inline-sheet-modal').click(); + + await expect(page.locator('ion-modal')).toBeVisible(); + await expect(page.locator('#current-breakpoint')).toHaveText('0.2'); + await expect(page.locator('ion-modal ion-item')).toHaveCount(4); + }); + + test('should expand to 0.75 breakpoint when searchbar is clicked', async ({ page }) => { + await page.locator('#present-inline-sheet-modal').click(); + await expect(page.locator('#current-breakpoint')).toHaveText('0.2'); + + await page.locator('ion-modal ion-searchbar').click(); + + await expect(page.locator('#current-breakpoint')).toHaveText('0.75'); + }); + + test('should allow interacting with background content while sheet is open', async ({ page }) => { + await page.locator('#present-inline-sheet-modal').click(); + + await expect(page.locator('ion-modal')).toBeVisible(); + + await page.locator('#background-action').click(); + + await expect(page.locator('#background-action-count')).toHaveText('1'); + }); +}); diff --git a/packages/angular/test/base/e2e/src/standalone/modal-dynamic-wrapper.spec.ts b/packages/angular/test/base/e2e/src/standalone/modal-dynamic-wrapper.spec.ts new file mode 100644 index 0000000000..6f3e0c6a03 --- /dev/null +++ b/packages/angular/test/base/e2e/src/standalone/modal-dynamic-wrapper.spec.ts @@ -0,0 +1,38 @@ +import { expect, test } from '@playwright/test'; + +test.describe('Modals: Dynamic Wrapper (standalone)', () => { + test.beforeEach(async ({ page }) => { + await page.goto('/standalone/modal-dynamic-wrapper'); + }); + + test('should render dynamic component inside modal', async ({ page }) => { + await page.locator('#open-dynamic-modal').click(); + + await expect(page.locator('ion-modal')).toBeVisible(); + await expect(page.locator('#dynamic-component-loaded')).toBeVisible(); + }); + + test('should allow interacting with background content while sheet is open', async ({ page }) => { + await page.locator('#open-dynamic-modal').click(); + + await expect(page.locator('ion-modal')).toBeVisible(); + + await page.locator('#background-action').click(); + + await expect(page.locator('#background-action-count')).toHaveText('1'); + }); + + test('should prevent interacting with background content when focus is trapped', async ({ page }) => { + await page.locator('#open-focused-modal').click(); + + await expect(page.locator('ion-modal')).toBeVisible(); + + // Attempt to click the background button via coordinates; click should be intercepted by backdrop + const box = await page.locator('#background-action').boundingBox(); + if (box) { + await page.mouse.click(box.x + box.width / 2, box.y + box.height / 2); + } + + await expect(page.locator('#background-action-count')).toHaveText('0'); + }); +}); diff --git a/packages/angular/test/base/e2e/src/standalone/modal-sheet-inline.spec.ts b/packages/angular/test/base/e2e/src/standalone/modal-sheet-inline.spec.ts new file mode 100644 index 0000000000..3bebd5173c --- /dev/null +++ b/packages/angular/test/base/e2e/src/standalone/modal-sheet-inline.spec.ts @@ -0,0 +1,34 @@ +import { expect, test } from '@playwright/test'; + +test.describe('Modals: Inline Sheet (standalone)', () => { + test.beforeEach(async ({ page }) => { + await page.goto('/standalone/modal-sheet-inline'); + }); + + test('should open inline sheet modal', async ({ page }) => { + await page.locator('#present-inline-sheet-modal').click(); + + await expect(page.locator('ion-modal')).toBeVisible(); + await expect(page.locator('#current-breakpoint')).toHaveText('0.2'); + await expect(page.locator('ion-modal ion-item')).toHaveCount(4); + }); + + test('should expand to 0.75 breakpoint when searchbar is clicked', async ({ page }) => { + await page.locator('#present-inline-sheet-modal').click(); + await expect(page.locator('#current-breakpoint')).toHaveText('0.2'); + + await page.locator('ion-modal ion-searchbar').click(); + + await expect(page.locator('#current-breakpoint')).toHaveText('0.75'); + }); + + test('should allow interacting with background content while sheet is open', async ({ page }) => { + await page.locator('#present-inline-sheet-modal').click(); + + await expect(page.locator('ion-modal')).toBeVisible(); + + await page.locator('#background-action').click(); + + await expect(page.locator('#background-action-count')).toHaveText('1'); + }); +}); diff --git a/packages/angular/test/base/src/app/lazy/app-lazy/app.routes.ts b/packages/angular/test/base/src/app/lazy/app-lazy/app.routes.ts index 1a46992f92..35a77b19cf 100644 --- a/packages/angular/test/base/src/app/lazy/app-lazy/app.routes.ts +++ b/packages/angular/test/base/src/app/lazy/app-lazy/app.routes.ts @@ -37,6 +37,8 @@ export const routes: Routes = [ { path: 'template-form', component: TemplateFormComponent }, { path: 'modals', component: ModalComponent }, { path: 'modal-inline', loadChildren: () => import('../modal-inline').then(m => m.ModalInlineModule) }, + { path: 'modal-sheet-inline', loadChildren: () => import('../modal-sheet-inline').then(m => m.ModalSheetInlineModule) }, + { path: 'modal-dynamic-wrapper', loadChildren: () => import('../modal-dynamic-wrapper').then(m => m.ModalDynamicWrapperModule) }, { path: 'view-child', component: ViewChildComponent }, { path: 'keep-contents-mounted', loadChildren: () => import('../keep-contents-mounted').then(m => m.OverlayAutoMountModule) }, { path: 'overlays-inline', loadChildren: () => import('../overlays-inline').then(m => m.OverlaysInlineModule) }, @@ -90,4 +92,3 @@ export const routes: Routes = [ ] }, ]; - diff --git a/packages/angular/test/base/src/app/lazy/home-page/home-page.component.html b/packages/angular/test/base/src/app/lazy/home-page/home-page.component.html index 136a0119d3..c3ac265915 100644 --- a/packages/angular/test/base/src/app/lazy/home-page/home-page.component.html +++ b/packages/angular/test/base/src/app/lazy/home-page/home-page.component.html @@ -35,6 +35,16 @@ Modals Test + + + Modal Sheet Inline Test + + + + + Modal Dynamic Wrapper Test + + Router link Test diff --git a/packages/angular/test/base/src/app/lazy/modal-dynamic-wrapper/dynamic-component-wrapper.component.ts b/packages/angular/test/base/src/app/lazy/modal-dynamic-wrapper/dynamic-component-wrapper.component.ts new file mode 100644 index 0000000000..f4304c03a5 --- /dev/null +++ b/packages/angular/test/base/src/app/lazy/modal-dynamic-wrapper/dynamic-component-wrapper.component.ts @@ -0,0 +1,26 @@ +import { Component, ComponentRef, Input, OnDestroy, OnInit, ViewChild, ViewContainerRef } from "@angular/core"; + +@Component({ + selector: 'app-dynamic-component-wrapper', + template: ` + + + + `, + standalone: false +}) +export class DynamicComponentWrapperComponent implements OnInit, OnDestroy { + + @Input() componentRef?: ComponentRef; + @ViewChild('container', { read: ViewContainerRef, static: true }) container!: ViewContainerRef; + + ngOnInit(): void { + if (this.componentRef) { + this.container.insert(this.componentRef.hostView); + } + } + + ngOnDestroy(): void { + this.componentRef?.destroy(); + } +} diff --git a/packages/angular/test/base/src/app/lazy/modal-dynamic-wrapper/dynamic-modal-content.component.ts b/packages/angular/test/base/src/app/lazy/modal-dynamic-wrapper/dynamic-modal-content.component.ts new file mode 100644 index 0000000000..ad1b76c05a --- /dev/null +++ b/packages/angular/test/base/src/app/lazy/modal-dynamic-wrapper/dynamic-modal-content.component.ts @@ -0,0 +1,20 @@ +import { Component, EventEmitter, Output } from "@angular/core"; + +@Component({ + selector: 'app-dynamic-modal-content', + template: ` + + + Dynamic Sheet Content + + + +

Dynamic component rendered inside wrapper.

+ Close +
+ `, + standalone: false +}) +export class DynamicModalContentComponent { + @Output() dismiss = new EventEmitter(); +} diff --git a/packages/angular/test/base/src/app/lazy/modal-dynamic-wrapper/index.ts b/packages/angular/test/base/src/app/lazy/modal-dynamic-wrapper/index.ts new file mode 100644 index 0000000000..ca0da1dfbe --- /dev/null +++ b/packages/angular/test/base/src/app/lazy/modal-dynamic-wrapper/index.ts @@ -0,0 +1,2 @@ +export * from './modal-dynamic-wrapper.component'; +export * from './modal-dynamic-wrapper.module'; diff --git a/packages/angular/test/base/src/app/lazy/modal-dynamic-wrapper/modal-dynamic-wrapper-routing.module.ts b/packages/angular/test/base/src/app/lazy/modal-dynamic-wrapper/modal-dynamic-wrapper-routing.module.ts new file mode 100644 index 0000000000..a8ef812c71 --- /dev/null +++ b/packages/angular/test/base/src/app/lazy/modal-dynamic-wrapper/modal-dynamic-wrapper-routing.module.ts @@ -0,0 +1,16 @@ +import { NgModule } from "@angular/core"; +import { RouterModule } from "@angular/router"; +import { ModalDynamicWrapperComponent } from "."; + +@NgModule({ + imports: [ + RouterModule.forChild([ + { + path: '', + component: ModalDynamicWrapperComponent + } + ]) + ], + exports: [RouterModule] +}) +export class ModalDynamicWrapperRoutingModule { } diff --git a/packages/angular/test/base/src/app/lazy/modal-dynamic-wrapper/modal-dynamic-wrapper.component.html b/packages/angular/test/base/src/app/lazy/modal-dynamic-wrapper/modal-dynamic-wrapper.component.html new file mode 100644 index 0000000000..c3655c5625 --- /dev/null +++ b/packages/angular/test/base/src/app/lazy/modal-dynamic-wrapper/modal-dynamic-wrapper.component.html @@ -0,0 +1,8 @@ +Open Dynamic Sheet Modal +Open Focus-Trapped Sheet Modal +Background Action +

+ Background action count: {{ backgroundActionCount }} +

+ + diff --git a/packages/angular/test/base/src/app/lazy/modal-dynamic-wrapper/modal-dynamic-wrapper.component.ts b/packages/angular/test/base/src/app/lazy/modal-dynamic-wrapper/modal-dynamic-wrapper.component.ts new file mode 100644 index 0000000000..dd05d3c6f1 --- /dev/null +++ b/packages/angular/test/base/src/app/lazy/modal-dynamic-wrapper/modal-dynamic-wrapper.component.ts @@ -0,0 +1,104 @@ +import { Component, ComponentRef, OnDestroy, ViewChild, ViewContainerRef } from "@angular/core"; +import { ModalController } from "@ionic/angular"; +import { DynamicComponentWrapperComponent } from "./dynamic-component-wrapper.component"; +import { DynamicModalContentComponent } from "./dynamic-modal-content.component"; + +@Component({ + selector: 'app-modal-dynamic-wrapper', + templateUrl: './modal-dynamic-wrapper.component.html', + standalone: false +}) +export class ModalDynamicWrapperComponent implements OnDestroy { + + @ViewChild('modalHost', { read: ViewContainerRef, static: true }) modalHost!: ViewContainerRef; + + backgroundActionCount = 0; + + private currentModal?: HTMLIonModalElement; + private currentComponentRef?: ComponentRef; + + constructor(private modalCtrl: ModalController) {} + + async openModal() { + await this.closeModal(); + + const componentRef = this.modalHost.createComponent(DynamicModalContentComponent); + this.modalHost.detach(); + componentRef.instance.dismiss.subscribe(() => this.closeModal()); + + this.currentComponentRef = componentRef; + + const modal = await this.modalCtrl.create({ + component: DynamicComponentWrapperComponent, + componentProps: { + componentRef + }, + breakpoints: [0, 0.2, 0.75, 1], + initialBreakpoint: 0.2, + backdropDismiss: false, + focusTrap: false, + handleBehavior: 'cycle' + }); + + this.currentModal = modal; + + modal.onWillDismiss().then(() => this.destroyComponent()); + + await modal.present(); + } + + async openFocusedModal() { + await this.closeModal(); + + const componentRef = this.modalHost.createComponent(DynamicModalContentComponent); + this.modalHost.detach(); + componentRef.instance.dismiss.subscribe(() => this.closeModal()); + + this.currentComponentRef = componentRef; + + const modal = await this.modalCtrl.create({ + component: DynamicComponentWrapperComponent, + componentProps: { + componentRef, + }, + // Choose a higher initial breakpoint to ensure backdrop is active immediately + breakpoints: [0, 0.25, 0.5, 0.75, 1], + initialBreakpoint: 0.5, + // Keep backdrop active but do not dismiss on tap to avoid interfering with assertions + backdropDismiss: false, + // Explicitly enable focus trapping to block background interaction + focusTrap: true, + handleBehavior: 'cycle', + }); + + this.currentModal = modal; + + modal.onWillDismiss().then(() => this.destroyComponent()); + + await modal.present(); + } + + async closeModal() { + if (this.currentModal) { + await this.currentModal.dismiss(); + this.currentModal = undefined; + } + + this.destroyComponent(); + } + + private destroyComponent() { + if (this.currentComponentRef) { + this.currentComponentRef.destroy(); + this.currentComponentRef = undefined; + } + } + + onBackgroundActionClick() { + this.backgroundActionCount++; + } + + ngOnDestroy(): void { + this.destroyComponent(); + } +} diff --git a/packages/angular/test/base/src/app/lazy/modal-dynamic-wrapper/modal-dynamic-wrapper.module.ts b/packages/angular/test/base/src/app/lazy/modal-dynamic-wrapper/modal-dynamic-wrapper.module.ts new file mode 100644 index 0000000000..2ab22c5aca --- /dev/null +++ b/packages/angular/test/base/src/app/lazy/modal-dynamic-wrapper/modal-dynamic-wrapper.module.ts @@ -0,0 +1,14 @@ +import { CommonModule } from "@angular/common"; +import { NgModule } from "@angular/core"; +import { IonicModule } from "@ionic/angular"; +import { DynamicComponentWrapperComponent } from "./dynamic-component-wrapper.component"; +import { DynamicModalContentComponent } from "./dynamic-modal-content.component"; +import { ModalDynamicWrapperRoutingModule } from "./modal-dynamic-wrapper-routing.module"; +import { ModalDynamicWrapperComponent } from "./modal-dynamic-wrapper.component"; + +@NgModule({ + imports: [CommonModule, IonicModule, ModalDynamicWrapperRoutingModule], + declarations: [ModalDynamicWrapperComponent, DynamicComponentWrapperComponent, DynamicModalContentComponent], + exports: [ModalDynamicWrapperComponent] +}) +export class ModalDynamicWrapperModule { } diff --git a/packages/angular/test/base/src/app/lazy/modal-sheet-inline/index.ts b/packages/angular/test/base/src/app/lazy/modal-sheet-inline/index.ts new file mode 100644 index 0000000000..0283c2cd95 --- /dev/null +++ b/packages/angular/test/base/src/app/lazy/modal-sheet-inline/index.ts @@ -0,0 +1,2 @@ +export * from './modal-sheet-inline.component'; +export * from './modal-sheet-inline.module'; diff --git a/packages/angular/test/base/src/app/lazy/modal-sheet-inline/modal-sheet-inline-routing.module.ts b/packages/angular/test/base/src/app/lazy/modal-sheet-inline/modal-sheet-inline-routing.module.ts new file mode 100644 index 0000000000..54c208d702 --- /dev/null +++ b/packages/angular/test/base/src/app/lazy/modal-sheet-inline/modal-sheet-inline-routing.module.ts @@ -0,0 +1,16 @@ +import { NgModule } from "@angular/core"; +import { RouterModule } from "@angular/router"; +import { ModalSheetInlineComponent } from "."; + +@NgModule({ + imports: [ + RouterModule.forChild([ + { + path: '', + component: ModalSheetInlineComponent + } + ]) + ], + exports: [RouterModule] +}) +export class ModalSheetInlineRoutingModule { } diff --git a/packages/angular/test/base/src/app/lazy/modal-sheet-inline/modal-sheet-inline.component.html b/packages/angular/test/base/src/app/lazy/modal-sheet-inline/modal-sheet-inline.component.html new file mode 100644 index 0000000000..6224ed1091 --- /dev/null +++ b/packages/angular/test/base/src/app/lazy/modal-sheet-inline/modal-sheet-inline.component.html @@ -0,0 +1,46 @@ + + Present Inline Sheet Modal + + +

+ Current breakpoint: {{ currentBreakpoint }} +

+ + + Background Action + + +

+ Background action count: {{ backgroundActionCount }} +

+ + + + + + + + + + + +

{{ contact.name }}

+

{{ contact.title }}

+
+
+
+
+
+
diff --git a/packages/angular/test/base/src/app/lazy/modal-sheet-inline/modal-sheet-inline.component.ts b/packages/angular/test/base/src/app/lazy/modal-sheet-inline/modal-sheet-inline.component.ts new file mode 100644 index 0000000000..2e0dc32e08 --- /dev/null +++ b/packages/angular/test/base/src/app/lazy/modal-sheet-inline/modal-sheet-inline.component.ts @@ -0,0 +1,79 @@ +import { Component, ViewChild } from "@angular/core"; +import { IonModal } from "@ionic/angular"; + +interface Contact { + name: string; + title: string; + avatar: string; +} + +@Component({ + selector: 'app-modal-sheet-inline', + templateUrl: './modal-sheet-inline.component.html', + standalone: false +}) +export class ModalSheetInlineComponent { + + @ViewChild('inlineSheetModal', { read: IonModal }) inlineSheetModal?: IonModal; + + readonly breakpoints: number[] = [0, 0.2, 0.75, 1]; + + readonly contacts: Contact[] = [ + { + name: 'Connor Smith', + title: 'Sales Rep', + avatar: 'https://i.pravatar.cc/300?u=b' + }, + { + name: 'Daniel Smith', + title: 'Product Designer', + avatar: 'https://i.pravatar.cc/300?u=a' + }, + { + name: 'Greg Smith', + title: 'Director of Operations', + avatar: 'https://i.pravatar.cc/300?u=d' + }, + { + name: 'Zoey Smith', + title: 'CEO', + avatar: 'https://i.pravatar.cc/300?u=e' + } + ]; + + isSheetOpen = false; + + currentBreakpoint = 'closed'; + + backgroundActionCount = 0; + + presentInlineSheetModal() { + this.isSheetOpen = true; + this.currentBreakpoint = '0.2'; + } + + async expandInlineSheet() { + const modal = this.inlineSheetModal; + + if (!modal) { + return; + } + + await modal.setCurrentBreakpoint(0.75); + this.currentBreakpoint = '0.75'; + } + + onSheetDidDismiss() { + this.isSheetOpen = false; + this.currentBreakpoint = 'closed'; + } + + onSheetBreakpointDidChange(event: CustomEvent<{ breakpoint: number }>) { + this.currentBreakpoint = event.detail.breakpoint.toString(); + } + + onBackgroundActionClick() { + this.backgroundActionCount++; + } + +} diff --git a/packages/angular/test/base/src/app/lazy/modal-sheet-inline/modal-sheet-inline.module.ts b/packages/angular/test/base/src/app/lazy/modal-sheet-inline/modal-sheet-inline.module.ts new file mode 100644 index 0000000000..9dd75b0a53 --- /dev/null +++ b/packages/angular/test/base/src/app/lazy/modal-sheet-inline/modal-sheet-inline.module.ts @@ -0,0 +1,12 @@ +import { CommonModule } from "@angular/common"; +import { NgModule } from "@angular/core"; +import { IonicModule } from "@ionic/angular"; +import { ModalSheetInlineRoutingModule } from "./modal-sheet-inline-routing.module"; +import { ModalSheetInlineComponent } from "./modal-sheet-inline.component"; + +@NgModule({ + imports: [CommonModule, IonicModule, ModalSheetInlineRoutingModule], + declarations: [ModalSheetInlineComponent], + exports: [ModalSheetInlineComponent] +}) +export class ModalSheetInlineModule { } diff --git a/packages/angular/test/base/src/app/standalone/app-standalone/app.routes.ts b/packages/angular/test/base/src/app/standalone/app-standalone/app.routes.ts index fafb69c62a..ed9628ae7c 100644 --- a/packages/angular/test/base/src/app/standalone/app-standalone/app.routes.ts +++ b/packages/angular/test/base/src/app/standalone/app-standalone/app.routes.ts @@ -11,6 +11,8 @@ export const routes: Routes = [ { path: 'action-sheet-controller', loadComponent: () => import('../action-sheet-controller/action-sheet-controller.component').then(c => c.ActionSheetControllerComponent) }, { path: 'popover', loadComponent: () => import('../popover/popover.component').then(c => c.PopoverComponent) }, { path: 'modal', loadComponent: () => import('../modal/modal.component').then(c => c.ModalComponent) }, + { path: 'modal-sheet-inline', loadComponent: () => import('../modal-sheet-inline/modal-sheet-inline.component').then(c => c.ModalSheetInlineComponent) }, + { path: 'modal-dynamic-wrapper', loadComponent: () => import('../modal-dynamic-wrapper/modal-dynamic-wrapper.component').then(c => c.ModalDynamicWrapperComponent) }, { path: 'programmatic-modal', loadComponent: () => import('../programmatic-modal/programmatic-modal.component').then(c => c.ProgrammaticModalComponent) }, { path: 'router-outlet', loadComponent: () => import('../router-outlet/router-outlet.component').then(c => c.RouterOutletComponent) }, { path: 'back-button', loadComponent: () => import('../back-button/back-button.component').then(c => c.BackButtonComponent) }, diff --git a/packages/angular/test/base/src/app/standalone/home-page/home-page.component.html b/packages/angular/test/base/src/app/standalone/home-page/home-page.component.html index 7900bdfb64..fd6ae409a3 100644 --- a/packages/angular/test/base/src/app/standalone/home-page/home-page.component.html +++ b/packages/angular/test/base/src/app/standalone/home-page/home-page.component.html @@ -90,6 +90,16 @@ Modal Test
+ + + Modal Sheet Inline Test + + + + + Modal Dynamic Wrapper Test + + Programmatic Modal Test diff --git a/packages/angular/test/base/src/app/standalone/modal-dynamic-wrapper/dynamic-component-wrapper.component.ts b/packages/angular/test/base/src/app/standalone/modal-dynamic-wrapper/dynamic-component-wrapper.component.ts new file mode 100644 index 0000000000..d79ec4abff --- /dev/null +++ b/packages/angular/test/base/src/app/standalone/modal-dynamic-wrapper/dynamic-component-wrapper.component.ts @@ -0,0 +1,27 @@ +import { Component, ComponentRef, Input, OnDestroy, OnInit, ViewChild, ViewContainerRef } from '@angular/core'; +import { IonContent } from '@ionic/angular/standalone'; + +@Component({ + selector: 'app-dynamic-component-wrapper', + template: ` + + + + `, + standalone: true, + imports: [IonContent], +}) +export class DynamicComponentWrapperComponent implements OnInit, OnDestroy { + @Input() componentRef?: ComponentRef; + @ViewChild('container', { read: ViewContainerRef, static: true }) container!: ViewContainerRef; + + ngOnInit(): void { + if (this.componentRef) { + this.container.insert(this.componentRef.hostView); + } + } + + ngOnDestroy(): void { + this.componentRef?.destroy(); + } +} diff --git a/packages/angular/test/base/src/app/standalone/modal-dynamic-wrapper/dynamic-modal-content.component.ts b/packages/angular/test/base/src/app/standalone/modal-dynamic-wrapper/dynamic-modal-content.component.ts new file mode 100644 index 0000000000..4022f65b5e --- /dev/null +++ b/packages/angular/test/base/src/app/standalone/modal-dynamic-wrapper/dynamic-modal-content.component.ts @@ -0,0 +1,28 @@ +import { Component, EventEmitter, Output } from '@angular/core'; +import { + IonButton, + IonContent, + IonHeader, + IonTitle, + IonToolbar, +} from '@ionic/angular/standalone'; + +@Component({ + selector: 'app-dynamic-modal-content', + template: ` + + + Dynamic Sheet Content + + + +

Dynamic component rendered inside wrapper.

+ Close +
+ `, + standalone: true, + imports: [IonButton, IonContent, IonHeader, IonTitle, IonToolbar], +}) +export class DynamicModalContentComponent { + @Output() dismiss = new EventEmitter(); +} diff --git a/packages/angular/test/base/src/app/standalone/modal-dynamic-wrapper/modal-dynamic-wrapper.component.html b/packages/angular/test/base/src/app/standalone/modal-dynamic-wrapper/modal-dynamic-wrapper.component.html new file mode 100644 index 0000000000..c3655c5625 --- /dev/null +++ b/packages/angular/test/base/src/app/standalone/modal-dynamic-wrapper/modal-dynamic-wrapper.component.html @@ -0,0 +1,8 @@ +Open Dynamic Sheet Modal +Open Focus-Trapped Sheet Modal +Background Action +

+ Background action count: {{ backgroundActionCount }} +

+ + diff --git a/packages/angular/test/base/src/app/standalone/modal-dynamic-wrapper/modal-dynamic-wrapper.component.ts b/packages/angular/test/base/src/app/standalone/modal-dynamic-wrapper/modal-dynamic-wrapper.component.ts new file mode 100644 index 0000000000..a88f18ef3e --- /dev/null +++ b/packages/angular/test/base/src/app/standalone/modal-dynamic-wrapper/modal-dynamic-wrapper.component.ts @@ -0,0 +1,103 @@ +import { CommonModule } from '@angular/common'; +import { Component, ComponentRef, OnDestroy, ViewChild, ViewContainerRef } from '@angular/core'; +import { IonButton, ModalController } from '@ionic/angular/standalone'; + +import { DynamicComponentWrapperComponent } from './dynamic-component-wrapper.component'; +import { DynamicModalContentComponent } from './dynamic-modal-content.component'; + +@Component({ + selector: 'app-modal-dynamic-wrapper', + templateUrl: './modal-dynamic-wrapper.component.html', + standalone: true, + imports: [CommonModule, IonButton], +}) +export class ModalDynamicWrapperComponent implements OnDestroy { + @ViewChild('modalHost', { read: ViewContainerRef, static: true }) modalHost!: ViewContainerRef; + + backgroundActionCount = 0; + + private currentModal?: HTMLIonModalElement; + private currentComponentRef?: ComponentRef; + + constructor(private modalCtrl: ModalController) {} + + async openModal() { + await this.closeModal(); + + const componentRef = this.modalHost.createComponent(DynamicModalContentComponent); + this.modalHost.detach(); + componentRef.instance.dismiss.subscribe(() => this.closeModal()); + + this.currentComponentRef = componentRef; + + const modal = await this.modalCtrl.create({ + component: DynamicComponentWrapperComponent, + componentProps: { + componentRef, + }, + breakpoints: [0, 0.2, 0.75, 1], + initialBreakpoint: 0.2, + backdropDismiss: false, + focusTrap: false, + handleBehavior: 'cycle', + }); + + this.currentModal = modal; + + modal.onWillDismiss().then(() => this.destroyComponent()); + + await modal.present(); + } + + async openFocusedModal() { + await this.closeModal(); + + const componentRef = this.modalHost.createComponent(DynamicModalContentComponent); + this.modalHost.detach(); + componentRef.instance.dismiss.subscribe(() => this.closeModal()); + + this.currentComponentRef = componentRef; + + const modal = await this.modalCtrl.create({ + component: DynamicComponentWrapperComponent, + componentProps: { + componentRef, + }, + breakpoints: [0, 0.25, 0.5, 0.75, 1], + initialBreakpoint: 0.5, + backdropDismiss: false, + focusTrap: true, + handleBehavior: 'cycle', + }); + + this.currentModal = modal; + + modal.onWillDismiss().then(() => this.destroyComponent()); + + await modal.present(); + } + + async closeModal() { + if (this.currentModal) { + await this.currentModal.dismiss(); + this.currentModal = undefined; + } + + this.destroyComponent(); + } + + private destroyComponent() { + if (this.currentComponentRef) { + this.currentComponentRef.destroy(); + this.currentComponentRef = undefined; + } + } + + onBackgroundActionClick() { + this.backgroundActionCount++; + } + + ngOnDestroy(): void { + this.destroyComponent(); + } +} diff --git a/packages/angular/test/base/src/app/standalone/modal-sheet-inline/modal-sheet-inline.component.html b/packages/angular/test/base/src/app/standalone/modal-sheet-inline/modal-sheet-inline.component.html new file mode 100644 index 0000000000..6224ed1091 --- /dev/null +++ b/packages/angular/test/base/src/app/standalone/modal-sheet-inline/modal-sheet-inline.component.html @@ -0,0 +1,46 @@ + + Present Inline Sheet Modal + + +

+ Current breakpoint: {{ currentBreakpoint }} +

+ + + Background Action + + +

+ Background action count: {{ backgroundActionCount }} +

+ + + + + + + + + + + +

{{ contact.name }}

+

{{ contact.title }}

+
+
+
+
+
+
diff --git a/packages/angular/test/base/src/app/standalone/modal-sheet-inline/modal-sheet-inline.component.ts b/packages/angular/test/base/src/app/standalone/modal-sheet-inline/modal-sheet-inline.component.ts new file mode 100644 index 0000000000..2cdee8df09 --- /dev/null +++ b/packages/angular/test/base/src/app/standalone/modal-sheet-inline/modal-sheet-inline.component.ts @@ -0,0 +1,100 @@ +import { CommonModule } from '@angular/common'; +import { Component, ViewChild } from '@angular/core'; +import { + IonAvatar, + IonButton, + IonContent, + IonImg, + IonItem, + IonLabel, + IonList, + IonModal, + IonSearchbar, +} from '@ionic/angular/standalone'; + +interface Contact { + name: string; + title: string; + avatar: string; +} + +@Component({ + selector: 'app-modal-sheet-inline', + templateUrl: './modal-sheet-inline.component.html', + standalone: true, + imports: [ + CommonModule, + IonAvatar, + IonButton, + IonContent, + IonImg, + IonItem, + IonLabel, + IonList, + IonModal, + IonSearchbar, + ], +}) +export class ModalSheetInlineComponent { + @ViewChild('inlineSheetModal', { read: IonModal }) inlineSheetModal?: IonModal; + + readonly breakpoints: number[] = [0, 0.2, 0.75, 1]; + + readonly contacts: Contact[] = [ + { + name: 'Connor Smith', + title: 'Sales Rep', + avatar: 'https://i.pravatar.cc/300?u=b', + }, + { + name: 'Daniel Smith', + title: 'Product Designer', + avatar: 'https://i.pravatar.cc/300?u=a', + }, + { + name: 'Greg Smith', + title: 'Director of Operations', + avatar: 'https://i.pravatar.cc/300?u=d', + }, + { + name: 'Zoey Smith', + title: 'CEO', + avatar: 'https://i.pravatar.cc/300?u=e', + }, + ]; + + isSheetOpen = false; + + currentBreakpoint = 'closed'; + + backgroundActionCount = 0; + + presentInlineSheetModal() { + this.isSheetOpen = true; + this.currentBreakpoint = '0.2'; + } + + async expandInlineSheet() { + const modal = this.inlineSheetModal; + + if (!modal) { + return; + } + + await modal.setCurrentBreakpoint(0.75); + this.currentBreakpoint = '0.75'; + } + + onSheetDidDismiss() { + this.isSheetOpen = false; + this.currentBreakpoint = 'closed'; + } + + onSheetBreakpointDidChange(event: CustomEvent<{ breakpoint: number }>) { + this.currentBreakpoint = event.detail.breakpoint.toString(); + } + + onBackgroundActionClick() { + this.backgroundActionCount++; + } +} diff --git a/packages/react/test/base/src/pages/overlay-components/ModalFocusTrap.tsx b/packages/react/test/base/src/pages/overlay-components/ModalFocusTrap.tsx new file mode 100644 index 0000000000..7227946b77 --- /dev/null +++ b/packages/react/test/base/src/pages/overlay-components/ModalFocusTrap.tsx @@ -0,0 +1,61 @@ +import React, { useState } from 'react'; +import { IonButton, IonContent, IonModal, IonPage } from '@ionic/react'; + +const ModalFocusTrap: React.FC = () => { + const [showNonTrapped, setShowNonTrapped] = useState(false); + const [showTrapped, setShowTrapped] = useState(false); + const [count, setCount] = useState(0); + + return ( + + + setShowNonTrapped(true)}> + Open Non-Trapped Sheet Modal + + setShowTrapped(true)}> + Open Focus-Trapped Sheet Modal + + + setCount((c) => c + 1)}> + Background Action + +
+ Background action count: {count} +
+ + setShowNonTrapped(false)} + breakpoints={[0, 0.25, 0.5, 0.75, 1]} + initialBreakpoint={0.25} + backdropDismiss={false} + focusTrap={false} + handleBehavior="cycle" + > + +

Non-trapped modal content

+ setShowNonTrapped(false)}>Close +
+
+ + setShowTrapped(false)} + breakpoints={[0, 0.25, 0.5, 0.75, 1]} + initialBreakpoint={0.5} + backdropDismiss={false} + focusTrap={true} + handleBehavior="cycle" + > + +

Focus-trapped modal content

+ setShowTrapped(false)}>Close +
+
+
+
+ ); +}; + +export default ModalFocusTrap; + diff --git a/packages/react/test/base/src/pages/overlay-components/ModalTeleport.tsx b/packages/react/test/base/src/pages/overlay-components/ModalTeleport.tsx new file mode 100644 index 0000000000..bd9028f842 --- /dev/null +++ b/packages/react/test/base/src/pages/overlay-components/ModalTeleport.tsx @@ -0,0 +1,71 @@ +import React, { useState } from 'react'; +import { + IonButton, + IonButtons, + IonContent, + IonHeader, + IonModal, + IonPage, + IonTitle, + IonToolbar, +} from '@ionic/react'; + +const ModalTeleport: React.FC = () => { + const [isOpen, setIsOpen] = useState(false); + const [count, setCount] = useState(0); + + return ( + + +
+ + setCount((c) => c + 1)}> + Background Action + +
+ Background action count: {count} +
+ + setIsOpen(true)}> + Open Teleported Modal + + + {isOpen && ( + setIsOpen(false)} + onWillPresent={(event) => { + const container = document.getElementById('example'); + if (container) { + container.appendChild(event.target as HTMLElement); + } + }} + breakpoints={[0.2, 0.5, 0.7]} + initialBreakpoint={0.5} + showBackdrop={false} + > + + + Modal + + setIsOpen(false)}> + Close + + + + + +

+ Lorem ipsum dolor sit amet consectetur adipisicing elit. Magni illum quidem recusandae ducimus quos + reprehenderit. Veniam, molestias quos, dolorum consequuntur nisi deserunt omnis id illo sit cum qui. + Eaque, dicta. +

+
+
+ )} +
+
+ ); +}; + +export default ModalTeleport; diff --git a/packages/react/test/base/src/pages/overlay-components/OverlayComponents.tsx b/packages/react/test/base/src/pages/overlay-components/OverlayComponents.tsx index cd9a4ff104..19aebc9081 100644 --- a/packages/react/test/base/src/pages/overlay-components/OverlayComponents.tsx +++ b/packages/react/test/base/src/pages/overlay-components/OverlayComponents.tsx @@ -14,6 +14,8 @@ import ActionSheetComponent from './ActionSheetComponent'; import AlertComponent from './AlertComponent'; import LoadingComponent from './LoadingComponent'; import ModalComponent from './ModalComponent'; +import ModalFocusTrap from './ModalFocusTrap'; +import ModalTeleport from './ModalTeleport'; import PickerComponent from './PickerComponent'; import PopoverComponent from './PopoverComponent'; import ToastComponent from './ToastComponent'; @@ -28,7 +30,9 @@ const OverlayHooks: React.FC = () => { - + + + @@ -46,10 +50,18 @@ const OverlayHooks: React.FC = () => { Loading - + Modal + + + Modal Focus + + + + Modal Teleport + Picker diff --git a/packages/react/test/base/tests/e2e/specs/overlay-components/IonModal.cy.ts b/packages/react/test/base/tests/e2e/specs/overlay-components/IonModal.cy.ts index b3dc847074..bf6ce5aca3 100644 --- a/packages/react/test/base/tests/e2e/specs/overlay-components/IonModal.cy.ts +++ b/packages/react/test/base/tests/e2e/specs/overlay-components/IonModal.cy.ts @@ -1,6 +1,6 @@ describe('IonModal', () => { beforeEach(() => { - cy.visit('/overlay-components/modal'); + cy.visit('/overlay-components/modal-basic'); }); it('display modal', () => { diff --git a/packages/react/test/base/tests/e2e/specs/overlay-components/IonModalFocusTrap.cy.ts b/packages/react/test/base/tests/e2e/specs/overlay-components/IonModalFocusTrap.cy.ts new file mode 100644 index 0000000000..395c642dcc --- /dev/null +++ b/packages/react/test/base/tests/e2e/specs/overlay-components/IonModalFocusTrap.cy.ts @@ -0,0 +1,36 @@ +describe('IonModal: focusTrap regression', () => { + beforeEach(() => { + cy.visit('/overlay-components/modal-focus-trap'); + }); + + it('should allow interacting with background when focusTrap=false', () => { + cy.get('#open-non-trapped-modal').click(); + cy.get('ion-modal').should('be.visible'); + + cy.get('#background-action').click(); + cy.get('#background-action-count').should('have.text', '1'); + }); + + it('should prevent interacting with background when focusTrap=true', () => { + cy.get('#open-trapped-modal').click(); + cy.get('ion-modal').should('be.visible'); + + // Ensure backdrop is active and capturing pointer events + cy.get('ion-backdrop').should('exist'); + cy.get('ion-backdrop').should('have.css', 'pointer-events', 'auto'); + + // Baseline: counter is 0 + cy.get('#background-action-count').should('have.text', '0'); + + // Click the center of the background button via body coordinates (topmost element will receive it) + cy.get('#background-action').then(($btn) => { + const rect = $btn[0].getBoundingClientRect(); + const x = rect.left + rect.width / 2; + const y = rect.top + rect.height / 2; + cy.get('body').click(x, y); + }); + + // Counter should remain unchanged + cy.get('#background-action-count').should('have.text', '0'); + }); +}); diff --git a/packages/react/test/base/tests/e2e/specs/overlay-components/IonModalTeleport.cy.ts b/packages/react/test/base/tests/e2e/specs/overlay-components/IonModalTeleport.cy.ts new file mode 100644 index 0000000000..738f2cd985 --- /dev/null +++ b/packages/react/test/base/tests/e2e/specs/overlay-components/IonModalTeleport.cy.ts @@ -0,0 +1,27 @@ +describe('IonModal: inline teleport with showBackdrop=false', () => { + beforeEach(() => { + cy.visit('/overlay-components/modal-teleport'); + }); + + it('should render and remain interactive when appended into a page container', () => { + cy.get('#open-teleport-modal').click(); + cy.get('ion-modal').should('be.visible'); + + // Verify modal content is interactable: close button should dismiss the modal + cy.get('#close-teleport-modal').click(); + cy.get('ion-modal').should('not.exist'); + }); + + it('should allow background interaction when showBackdrop=false', () => { + cy.get('#open-teleport-modal').click(); + cy.get('ion-modal').should('be.visible'); + + // Ensure the background button is clickable while modal is open + cy.get('#teleport-background-action').click(); + cy.get('#teleport-background-action-count').should('have.text', '1'); + + // Cleanup + cy.get('#close-teleport-modal').click(); + cy.get('ion-modal').should('not.exist'); + }); +}); diff --git a/packages/react/test/base/tests/e2e/specs/overlay-components/KeepContentsMounted.cy.ts b/packages/react/test/base/tests/e2e/specs/overlay-components/KeepContentsMounted.cy.ts index 8e4b0bdf83..ee5086d2f1 100644 --- a/packages/react/test/base/tests/e2e/specs/overlay-components/KeepContentsMounted.cy.ts +++ b/packages/react/test/base/tests/e2e/specs/overlay-components/KeepContentsMounted.cy.ts @@ -1,7 +1,7 @@ describe('keepContentsMounted', () => { describe('modal', () => { it('should not mount component if false', () => { - cy.visit('/overlay-components/modal'); + cy.visit('/overlay-components/modal-basic'); cy.get('ion-modal ion-content').should('not.exist'); }); From 515249d2c312dbcc2f4a5f0dbcd8cc312566f17e Mon Sep 17 00:00:00 2001 From: ionitron Date: Wed, 24 Sep 2025 19:51:40 +0000 Subject: [PATCH 09/10] v8.7.5 --- CHANGELOG.md | 12 ++++++++++++ core/CHANGELOG.md | 11 +++++++++++ core/package-lock.json | 6 +++--- core/package.json | 2 +- lerna.json | 2 +- packages/angular-server/CHANGELOG.md | 8 ++++++++ packages/angular-server/package-lock.json | 8 ++++---- packages/angular-server/package.json | 4 ++-- packages/angular/CHANGELOG.md | 11 +++++++++++ packages/angular/package-lock.json | 8 ++++---- packages/angular/package.json | 4 ++-- packages/docs/CHANGELOG.md | 8 ++++++++ packages/docs/package-lock.json | 6 +++--- packages/docs/package.json | 2 +- packages/react-router/CHANGELOG.md | 8 ++++++++ packages/react-router/package-lock.json | 8 ++++---- packages/react-router/package.json | 4 ++-- packages/react/CHANGELOG.md | 11 +++++++++++ packages/react/package-lock.json | 8 ++++---- packages/react/package.json | 4 ++-- packages/vue-router/CHANGELOG.md | 8 ++++++++ packages/vue-router/package-lock.json | 8 ++++---- packages/vue-router/package.json | 4 ++-- packages/vue/CHANGELOG.md | 11 +++++++++++ packages/vue/package-lock.json | 8 ++++---- packages/vue/package.json | 4 ++-- 26 files changed, 133 insertions(+), 45 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 9bf71d444b..47210c4bf2 100644 --- a/CHANGELOG.md +++ b/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. +## [8.7.5](https://github.com/ionic-team/ionic-framework/compare/v8.7.4...v8.7.5) (2025-09-24) + + +### Bug Fixes + +* **modal:** allow sheet modals to skip focus trap ([#30689](https://github.com/ionic-team/ionic-framework/issues/30689)) ([a40d957](https://github.com/ionic-team/ionic-framework/commit/a40d957ad9c1897af365a91b45b00228a00d614c)), closes [#30684](https://github.com/ionic-team/ionic-framework/issues/30684) +* **vue:** emit component-specific overlay events ([#30688](https://github.com/ionic-team/ionic-framework/issues/30688)) ([024d090](https://github.com/ionic-team/ionic-framework/commit/024d090122548e26ec2cdcfae4637dde8f288278)), closes [#30641](https://github.com/ionic-team/ionic-framework/issues/30641) + + + + + ## [8.7.4](https://github.com/ionic-team/ionic-framework/compare/v8.7.3...v8.7.4) (2025-09-17) diff --git a/core/CHANGELOG.md b/core/CHANGELOG.md index 8e9e8ba985..5be7265795 100644 --- a/core/CHANGELOG.md +++ b/core/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [8.7.5](https://github.com/ionic-team/ionic-framework/compare/v8.7.4...v8.7.5) (2025-09-24) + + +### Bug Fixes + +* **modal:** allow sheet modals to skip focus trap ([#30689](https://github.com/ionic-team/ionic-framework/issues/30689)) ([a40d957](https://github.com/ionic-team/ionic-framework/commit/a40d957ad9c1897af365a91b45b00228a00d614c)), closes [#30684](https://github.com/ionic-team/ionic-framework/issues/30684) + + + + + ## [8.7.4](https://github.com/ionic-team/ionic-framework/compare/v8.7.3...v8.7.4) (2025-09-17) diff --git a/core/package-lock.json b/core/package-lock.json index cd76d92da1..dbcd4dcb25 100644 --- a/core/package-lock.json +++ b/core/package-lock.json @@ -1,12 +1,12 @@ { "name": "@ionic/core", - "version": "8.7.4", + "version": "8.7.5", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@ionic/core", - "version": "8.7.4", + "version": "8.7.5", "license": "MIT", "dependencies": { "@stencil/core": "4.36.2", @@ -18338,4 +18338,4 @@ "dev": true } } -} +} \ No newline at end of file diff --git a/core/package.json b/core/package.json index b343a65e06..d4f495595d 100644 --- a/core/package.json +++ b/core/package.json @@ -1,6 +1,6 @@ { "name": "@ionic/core", - "version": "8.7.4", + "version": "8.7.5", "description": "Base components for Ionic", "keywords": [ "ionic", diff --git a/lerna.json b/lerna.json index 29cdc617c1..283bc5a42e 100644 --- a/lerna.json +++ b/lerna.json @@ -3,5 +3,5 @@ "core", "packages/*" ], - "version": "8.7.4" + "version": "8.7.5" } \ No newline at end of file diff --git a/packages/angular-server/CHANGELOG.md b/packages/angular-server/CHANGELOG.md index a8b9fd6f83..2286ed5513 100644 --- a/packages/angular-server/CHANGELOG.md +++ b/packages/angular-server/CHANGELOG.md @@ -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. +## [8.7.5](https://github.com/ionic-team/ionic-framework/compare/v8.7.4...v8.7.5) (2025-09-24) + +**Note:** Version bump only for package @ionic/angular-server + + + + + ## [8.7.4](https://github.com/ionic-team/ionic-framework/compare/v8.7.3...v8.7.4) (2025-09-17) **Note:** Version bump only for package @ionic/angular-server diff --git a/packages/angular-server/package-lock.json b/packages/angular-server/package-lock.json index 0566250203..acd69e46eb 100644 --- a/packages/angular-server/package-lock.json +++ b/packages/angular-server/package-lock.json @@ -1,15 +1,15 @@ { "name": "@ionic/angular-server", - "version": "8.7.4", + "version": "8.7.5", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@ionic/angular-server", - "version": "8.7.4", + "version": "8.7.5", "license": "MIT", "dependencies": { - "@ionic/core": "^8.7.4" + "@ionic/core": "^8.7.5" }, "devDependencies": { "@angular-eslint/eslint-plugin": "^16.0.0", @@ -11286,4 +11286,4 @@ } } } -} +} \ No newline at end of file diff --git a/packages/angular-server/package.json b/packages/angular-server/package.json index 5fd65a465f..f17037d02b 100644 --- a/packages/angular-server/package.json +++ b/packages/angular-server/package.json @@ -1,6 +1,6 @@ { "name": "@ionic/angular-server", - "version": "8.7.4", + "version": "8.7.5", "description": "Angular SSR Module for Ionic", "keywords": [ "ionic", @@ -62,6 +62,6 @@ }, "prettier": "@ionic/prettier-config", "dependencies": { - "@ionic/core": "^8.7.4" + "@ionic/core": "^8.7.5" } } diff --git a/packages/angular/CHANGELOG.md b/packages/angular/CHANGELOG.md index b5df3e3df8..79e9b64e6d 100644 --- a/packages/angular/CHANGELOG.md +++ b/packages/angular/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [8.7.5](https://github.com/ionic-team/ionic-framework/compare/v8.7.4...v8.7.5) (2025-09-24) + + +### Bug Fixes + +* **modal:** allow sheet modals to skip focus trap ([#30689](https://github.com/ionic-team/ionic-framework/issues/30689)) ([a40d957](https://github.com/ionic-team/ionic-framework/commit/a40d957ad9c1897af365a91b45b00228a00d614c)), closes [#30684](https://github.com/ionic-team/ionic-framework/issues/30684) + + + + + ## [8.7.4](https://github.com/ionic-team/ionic-framework/compare/v8.7.3...v8.7.4) (2025-09-17) diff --git a/packages/angular/package-lock.json b/packages/angular/package-lock.json index 31ceaa1a29..136b2cb17e 100644 --- a/packages/angular/package-lock.json +++ b/packages/angular/package-lock.json @@ -1,15 +1,15 @@ { "name": "@ionic/angular", - "version": "8.7.4", + "version": "8.7.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@ionic/angular", - "version": "8.7.4", + "version": "8.7.5", "license": "MIT", "dependencies": { - "@ionic/core": "^8.7.4", + "@ionic/core": "^8.7.5", "ionicons": "^8.0.13", "jsonc-parser": "^3.0.0", "tslib": "^2.3.0" @@ -9079,4 +9079,4 @@ } } } -} +} \ No newline at end of file diff --git a/packages/angular/package.json b/packages/angular/package.json index fc9a71b4e3..bfdef31fd6 100644 --- a/packages/angular/package.json +++ b/packages/angular/package.json @@ -1,6 +1,6 @@ { "name": "@ionic/angular", - "version": "8.7.4", + "version": "8.7.5", "description": "Angular specific wrappers for @ionic/core", "keywords": [ "ionic", @@ -48,7 +48,7 @@ } }, "dependencies": { - "@ionic/core": "^8.7.4", + "@ionic/core": "^8.7.5", "ionicons": "^8.0.13", "jsonc-parser": "^3.0.0", "tslib": "^2.3.0" diff --git a/packages/docs/CHANGELOG.md b/packages/docs/CHANGELOG.md index d732ce1da4..942e882931 100644 --- a/packages/docs/CHANGELOG.md +++ b/packages/docs/CHANGELOG.md @@ -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. +## [8.7.5](https://github.com/ionic-team/ionic-framework/compare/v8.7.4...v8.7.5) (2025-09-24) + +**Note:** Version bump only for package @ionic/docs + + + + + ## [8.7.4](https://github.com/ionic-team/ionic-framework/compare/v8.7.3...v8.7.4) (2025-09-17) **Note:** Version bump only for package @ionic/docs diff --git a/packages/docs/package-lock.json b/packages/docs/package-lock.json index 84681be496..65bb7a6e6e 100644 --- a/packages/docs/package-lock.json +++ b/packages/docs/package-lock.json @@ -1,13 +1,13 @@ { "name": "@ionic/docs", - "version": "8.7.4", + "version": "8.7.5", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@ionic/docs", - "version": "8.7.4", + "version": "8.7.5", "license": "MIT" } } -} +} \ No newline at end of file diff --git a/packages/docs/package.json b/packages/docs/package.json index 0ef9ba6e49..3b1eec2020 100644 --- a/packages/docs/package.json +++ b/packages/docs/package.json @@ -1,6 +1,6 @@ { "name": "@ionic/docs", - "version": "8.7.4", + "version": "8.7.5", "description": "Pre-packaged API documentation for the Ionic docs.", "main": "core.json", "types": "core.d.ts", diff --git a/packages/react-router/CHANGELOG.md b/packages/react-router/CHANGELOG.md index 96ce86fdad..dcff3c6e95 100644 --- a/packages/react-router/CHANGELOG.md +++ b/packages/react-router/CHANGELOG.md @@ -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. +## [8.7.5](https://github.com/ionic-team/ionic-framework/compare/v8.7.4...v8.7.5) (2025-09-24) + +**Note:** Version bump only for package @ionic/react-router + + + + + ## [8.7.4](https://github.com/ionic-team/ionic-framework/compare/v8.7.3...v8.7.4) (2025-09-17) **Note:** Version bump only for package @ionic/react-router diff --git a/packages/react-router/package-lock.json b/packages/react-router/package-lock.json index 9a00aa0b8f..cffbdb89ac 100644 --- a/packages/react-router/package-lock.json +++ b/packages/react-router/package-lock.json @@ -1,15 +1,15 @@ { "name": "@ionic/react-router", - "version": "8.7.4", + "version": "8.7.5", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@ionic/react-router", - "version": "8.7.4", + "version": "8.7.5", "license": "MIT", "dependencies": { - "@ionic/react": "^8.7.4", + "@ionic/react": "^8.7.5", "tslib": "*" }, "devDependencies": { @@ -6844,4 +6844,4 @@ "dev": true } } -} +} \ No newline at end of file diff --git a/packages/react-router/package.json b/packages/react-router/package.json index 3442afabbc..840cfe017a 100644 --- a/packages/react-router/package.json +++ b/packages/react-router/package.json @@ -1,6 +1,6 @@ { "name": "@ionic/react-router", - "version": "8.7.4", + "version": "8.7.5", "description": "React Router wrapper for @ionic/react", "keywords": [ "ionic", @@ -36,7 +36,7 @@ "dist/" ], "dependencies": { - "@ionic/react": "^8.7.4", + "@ionic/react": "^8.7.5", "tslib": "*" }, "peerDependencies": { diff --git a/packages/react/CHANGELOG.md b/packages/react/CHANGELOG.md index e88df89c73..6c7b05c0a3 100644 --- a/packages/react/CHANGELOG.md +++ b/packages/react/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [8.7.5](https://github.com/ionic-team/ionic-framework/compare/v8.7.4...v8.7.5) (2025-09-24) + + +### Bug Fixes + +* **modal:** allow sheet modals to skip focus trap ([#30689](https://github.com/ionic-team/ionic-framework/issues/30689)) ([a40d957](https://github.com/ionic-team/ionic-framework/commit/a40d957ad9c1897af365a91b45b00228a00d614c)), closes [#30684](https://github.com/ionic-team/ionic-framework/issues/30684) + + + + + ## [8.7.4](https://github.com/ionic-team/ionic-framework/compare/v8.7.3...v8.7.4) (2025-09-17) diff --git a/packages/react/package-lock.json b/packages/react/package-lock.json index 576713eff5..c3d44e163a 100644 --- a/packages/react/package-lock.json +++ b/packages/react/package-lock.json @@ -1,15 +1,15 @@ { "name": "@ionic/react", - "version": "8.7.4", + "version": "8.7.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@ionic/react", - "version": "8.7.4", + "version": "8.7.5", "license": "MIT", "dependencies": { - "@ionic/core": "^8.7.4", + "@ionic/core": "^8.7.5", "ionicons": "^8.0.13", "tslib": "*" }, @@ -11913,4 +11913,4 @@ } } } -} +} \ No newline at end of file diff --git a/packages/react/package.json b/packages/react/package.json index cd0b987ca1..bfb5516c65 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -1,6 +1,6 @@ { "name": "@ionic/react", - "version": "8.7.4", + "version": "8.7.5", "description": "React specific wrapper for @ionic/core", "keywords": [ "ionic", @@ -40,7 +40,7 @@ "css/" ], "dependencies": { - "@ionic/core": "^8.7.4", + "@ionic/core": "^8.7.5", "ionicons": "^8.0.13", "tslib": "*" }, diff --git a/packages/vue-router/CHANGELOG.md b/packages/vue-router/CHANGELOG.md index 9845def7cb..cf6cdfedb4 100644 --- a/packages/vue-router/CHANGELOG.md +++ b/packages/vue-router/CHANGELOG.md @@ -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. +## [8.7.5](https://github.com/ionic-team/ionic-framework/compare/v8.7.4...v8.7.5) (2025-09-24) + +**Note:** Version bump only for package @ionic/vue-router + + + + + ## [8.7.4](https://github.com/ionic-team/ionic-framework/compare/v8.7.3...v8.7.4) (2025-09-17) **Note:** Version bump only for package @ionic/vue-router diff --git a/packages/vue-router/package-lock.json b/packages/vue-router/package-lock.json index 6e25076d3d..b6d81671c6 100644 --- a/packages/vue-router/package-lock.json +++ b/packages/vue-router/package-lock.json @@ -1,15 +1,15 @@ { "name": "@ionic/vue-router", - "version": "8.7.4", + "version": "8.7.5", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@ionic/vue-router", - "version": "8.7.4", + "version": "8.7.5", "license": "MIT", "dependencies": { - "@ionic/vue": "^8.7.4" + "@ionic/vue": "^8.7.5" }, "devDependencies": { "@ionic/eslint-config": "^0.3.0", @@ -12991,4 +12991,4 @@ "dev": true } } -} +} \ No newline at end of file diff --git a/packages/vue-router/package.json b/packages/vue-router/package.json index 199ff019ea..ba2858d5e3 100644 --- a/packages/vue-router/package.json +++ b/packages/vue-router/package.json @@ -1,6 +1,6 @@ { "name": "@ionic/vue-router", - "version": "8.7.4", + "version": "8.7.5", "description": "Vue Router integration for @ionic/vue", "scripts": { "test.spec": "jest", @@ -44,7 +44,7 @@ }, "homepage": "https://github.com/ionic-team/ionic-framework#readme", "dependencies": { - "@ionic/vue": "^8.7.4" + "@ionic/vue": "^8.7.5" }, "devDependencies": { "@ionic/eslint-config": "^0.3.0", diff --git a/packages/vue/CHANGELOG.md b/packages/vue/CHANGELOG.md index 67a9704e54..d0850bccee 100644 --- a/packages/vue/CHANGELOG.md +++ b/packages/vue/CHANGELOG.md @@ -3,6 +3,17 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [8.7.5](https://github.com/ionic-team/ionic-framework/compare/v8.7.4...v8.7.5) (2025-09-24) + + +### Bug Fixes + +* **vue:** emit component-specific overlay events ([#30688](https://github.com/ionic-team/ionic-framework/issues/30688)) ([024d090](https://github.com/ionic-team/ionic-framework/commit/024d090122548e26ec2cdcfae4637dde8f288278)), closes [#30641](https://github.com/ionic-team/ionic-framework/issues/30641) + + + + + ## [8.7.4](https://github.com/ionic-team/ionic-framework/compare/v8.7.3...v8.7.4) (2025-09-17) diff --git a/packages/vue/package-lock.json b/packages/vue/package-lock.json index c4ee7d7891..50b4459c4e 100644 --- a/packages/vue/package-lock.json +++ b/packages/vue/package-lock.json @@ -1,15 +1,15 @@ { "name": "@ionic/vue", - "version": "8.7.4", + "version": "8.7.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@ionic/vue", - "version": "8.7.4", + "version": "8.7.5", "license": "MIT", "dependencies": { - "@ionic/core": "^8.7.4", + "@ionic/core": "^8.7.5", "@stencil/vue-output-target": "0.10.7", "ionicons": "^8.0.13" }, @@ -4019,4 +4019,4 @@ "dev": true } } -} +} \ No newline at end of file diff --git a/packages/vue/package.json b/packages/vue/package.json index 2aeb7b572d..d3469d121f 100644 --- a/packages/vue/package.json +++ b/packages/vue/package.json @@ -1,6 +1,6 @@ { "name": "@ionic/vue", - "version": "8.7.4", + "version": "8.7.5", "description": "Vue specific wrapper for @ionic/core", "scripts": { "eslint": "eslint src", @@ -68,7 +68,7 @@ "vue-router": "^4.0.16" }, "dependencies": { - "@ionic/core": "^8.7.4", + "@ionic/core": "^8.7.5", "@stencil/vue-output-target": "0.10.7", "ionicons": "^8.0.13" }, From 99d2b731f5abc7f53b1fd40421b8561664731e6a Mon Sep 17 00:00:00 2001 From: ionitron Date: Wed, 24 Sep 2025 19:52:26 +0000 Subject: [PATCH 10/10] chore(): update package lock files --- core/package-lock.json | 2 +- packages/angular-server/package-lock.json | 14 +++++------ packages/angular/package-lock.json | 8 +++--- packages/docs/package-lock.json | 2 +- packages/react-router/package-lock.json | 30 +++++++++++------------ packages/react/package-lock.json | 8 +++--- packages/vue-router/package-lock.json | 30 +++++++++++------------ packages/vue/package-lock.json | 8 +++--- 8 files changed, 51 insertions(+), 51 deletions(-) diff --git a/core/package-lock.json b/core/package-lock.json index dbcd4dcb25..d21a9c4180 100644 --- a/core/package-lock.json +++ b/core/package-lock.json @@ -18338,4 +18338,4 @@ "dev": true } } -} \ No newline at end of file +} diff --git a/packages/angular-server/package-lock.json b/packages/angular-server/package-lock.json index acd69e46eb..58d98508f3 100644 --- a/packages/angular-server/package-lock.json +++ b/packages/angular-server/package-lock.json @@ -1031,9 +1031,9 @@ "dev": true }, "node_modules/@ionic/core": { - "version": "8.7.4", - "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.7.4.tgz", - "integrity": "sha512-ZCJYKLWdxq+x4OmEDvodqR+y/FSDJYkkFHozWe1+b/p0l9lNN13lLuSZVs0AEOgPtO89Atl67rTbpGE2ad/SCw==", + "version": "8.7.5", + "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.7.5.tgz", + "integrity": "sha512-Uk1qdGPoLHaVhd2FnYSAvRehd3VwwcPIfXaR51qiC7C2L5VhD27VyLSgDetc15G4U+VAIFjgUSR/pKdLFEuMPA==", "license": "MIT", "dependencies": { "@stencil/core": "4.36.2", @@ -7306,9 +7306,9 @@ "dev": true }, "@ionic/core": { - "version": "8.7.4", - "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.7.4.tgz", - "integrity": "sha512-ZCJYKLWdxq+x4OmEDvodqR+y/FSDJYkkFHozWe1+b/p0l9lNN13lLuSZVs0AEOgPtO89Atl67rTbpGE2ad/SCw==", + "version": "8.7.5", + "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.7.5.tgz", + "integrity": "sha512-Uk1qdGPoLHaVhd2FnYSAvRehd3VwwcPIfXaR51qiC7C2L5VhD27VyLSgDetc15G4U+VAIFjgUSR/pKdLFEuMPA==", "requires": { "@stencil/core": "4.36.2", "ionicons": "^8.0.13", @@ -11286,4 +11286,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/angular/package-lock.json b/packages/angular/package-lock.json index 136b2cb17e..e840282dae 100644 --- a/packages/angular/package-lock.json +++ b/packages/angular/package-lock.json @@ -1398,9 +1398,9 @@ "dev": true }, "node_modules/@ionic/core": { - "version": "8.7.4", - "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.7.4.tgz", - "integrity": "sha512-ZCJYKLWdxq+x4OmEDvodqR+y/FSDJYkkFHozWe1+b/p0l9lNN13lLuSZVs0AEOgPtO89Atl67rTbpGE2ad/SCw==", + "version": "8.7.5", + "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.7.5.tgz", + "integrity": "sha512-Uk1qdGPoLHaVhd2FnYSAvRehd3VwwcPIfXaR51qiC7C2L5VhD27VyLSgDetc15G4U+VAIFjgUSR/pKdLFEuMPA==", "license": "MIT", "dependencies": { "@stencil/core": "4.36.2", @@ -9079,4 +9079,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/docs/package-lock.json b/packages/docs/package-lock.json index 65bb7a6e6e..0ea9a4f739 100644 --- a/packages/docs/package-lock.json +++ b/packages/docs/package-lock.json @@ -10,4 +10,4 @@ "license": "MIT" } } -} \ No newline at end of file +} diff --git a/packages/react-router/package-lock.json b/packages/react-router/package-lock.json index cffbdb89ac..b0abc70ecd 100644 --- a/packages/react-router/package-lock.json +++ b/packages/react-router/package-lock.json @@ -238,9 +238,9 @@ "dev": true }, "node_modules/@ionic/core": { - "version": "8.7.4", - "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.7.4.tgz", - "integrity": "sha512-ZCJYKLWdxq+x4OmEDvodqR+y/FSDJYkkFHozWe1+b/p0l9lNN13lLuSZVs0AEOgPtO89Atl67rTbpGE2ad/SCw==", + "version": "8.7.5", + "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.7.5.tgz", + "integrity": "sha512-Uk1qdGPoLHaVhd2FnYSAvRehd3VwwcPIfXaR51qiC7C2L5VhD27VyLSgDetc15G4U+VAIFjgUSR/pKdLFEuMPA==", "license": "MIT", "dependencies": { "@stencil/core": "4.36.2", @@ -415,12 +415,12 @@ } }, "node_modules/@ionic/react": { - "version": "8.7.4", - "resolved": "https://registry.npmjs.org/@ionic/react/-/react-8.7.4.tgz", - "integrity": "sha512-ImJo4VLT687nGS72zGo87b+aaaD4tWWFGtpbmM21rnh2xkWQJKjvZQRAgA6AK9tdMMYHqy0bJvAkykFpzV68XA==", + "version": "8.7.5", + "resolved": "https://registry.npmjs.org/@ionic/react/-/react-8.7.5.tgz", + "integrity": "sha512-ID1in1YhmjlpLUF1aMv9zSEVc+ZiXs1fNWKJLK4U02LRQoNxmKagwYLxItAuls0KqduCErcqfC5pOcBJDtMl4Q==", "license": "MIT", "dependencies": { - "@ionic/core": "8.7.4", + "@ionic/core": "8.7.5", "ionicons": "^8.0.13", "tslib": "*" }, @@ -4175,9 +4175,9 @@ "dev": true }, "@ionic/core": { - "version": "8.7.4", - "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.7.4.tgz", - "integrity": "sha512-ZCJYKLWdxq+x4OmEDvodqR+y/FSDJYkkFHozWe1+b/p0l9lNN13lLuSZVs0AEOgPtO89Atl67rTbpGE2ad/SCw==", + "version": "8.7.5", + "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.7.5.tgz", + "integrity": "sha512-Uk1qdGPoLHaVhd2FnYSAvRehd3VwwcPIfXaR51qiC7C2L5VhD27VyLSgDetc15G4U+VAIFjgUSR/pKdLFEuMPA==", "requires": { "@stencil/core": "4.36.2", "ionicons": "^8.0.13", @@ -4281,11 +4281,11 @@ "requires": {} }, "@ionic/react": { - "version": "8.7.4", - "resolved": "https://registry.npmjs.org/@ionic/react/-/react-8.7.4.tgz", - "integrity": "sha512-ImJo4VLT687nGS72zGo87b+aaaD4tWWFGtpbmM21rnh2xkWQJKjvZQRAgA6AK9tdMMYHqy0bJvAkykFpzV68XA==", + "version": "8.7.5", + "resolved": "https://registry.npmjs.org/@ionic/react/-/react-8.7.5.tgz", + "integrity": "sha512-ID1in1YhmjlpLUF1aMv9zSEVc+ZiXs1fNWKJLK4U02LRQoNxmKagwYLxItAuls0KqduCErcqfC5pOcBJDtMl4Q==", "requires": { - "@ionic/core": "8.7.4", + "@ionic/core": "8.7.5", "ionicons": "^8.0.13", "tslib": "*" } @@ -6844,4 +6844,4 @@ "dev": true } } -} \ No newline at end of file +} diff --git a/packages/react/package-lock.json b/packages/react/package-lock.json index c3d44e163a..68c8d93aab 100644 --- a/packages/react/package-lock.json +++ b/packages/react/package-lock.json @@ -736,9 +736,9 @@ "dev": true }, "node_modules/@ionic/core": { - "version": "8.7.4", - "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.7.4.tgz", - "integrity": "sha512-ZCJYKLWdxq+x4OmEDvodqR+y/FSDJYkkFHozWe1+b/p0l9lNN13lLuSZVs0AEOgPtO89Atl67rTbpGE2ad/SCw==", + "version": "8.7.5", + "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.7.5.tgz", + "integrity": "sha512-Uk1qdGPoLHaVhd2FnYSAvRehd3VwwcPIfXaR51qiC7C2L5VhD27VyLSgDetc15G4U+VAIFjgUSR/pKdLFEuMPA==", "license": "MIT", "dependencies": { "@stencil/core": "4.36.2", @@ -11913,4 +11913,4 @@ } } } -} \ No newline at end of file +} diff --git a/packages/vue-router/package-lock.json b/packages/vue-router/package-lock.json index b6d81671c6..5c9e6036d5 100644 --- a/packages/vue-router/package-lock.json +++ b/packages/vue-router/package-lock.json @@ -673,9 +673,9 @@ "dev": true }, "node_modules/@ionic/core": { - "version": "8.7.4", - "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.7.4.tgz", - "integrity": "sha512-ZCJYKLWdxq+x4OmEDvodqR+y/FSDJYkkFHozWe1+b/p0l9lNN13lLuSZVs0AEOgPtO89Atl67rTbpGE2ad/SCw==", + "version": "8.7.5", + "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.7.5.tgz", + "integrity": "sha512-Uk1qdGPoLHaVhd2FnYSAvRehd3VwwcPIfXaR51qiC7C2L5VhD27VyLSgDetc15G4U+VAIFjgUSR/pKdLFEuMPA==", "license": "MIT", "dependencies": { "@stencil/core": "4.36.2", @@ -865,12 +865,12 @@ } }, "node_modules/@ionic/vue": { - "version": "8.7.4", - "resolved": "https://registry.npmjs.org/@ionic/vue/-/vue-8.7.4.tgz", - "integrity": "sha512-Gof5oHUfyCMBA5VvvtHaLmP4OX+on4nSxCrrDXCFFbgE3b9CXUJGSpBqPwzvrVxkpbPHfkbkgJXhoIWlls4zXA==", + "version": "8.7.5", + "resolved": "https://registry.npmjs.org/@ionic/vue/-/vue-8.7.5.tgz", + "integrity": "sha512-wx7o+ABDDTWLM47CIjxueoZtKbvMQ9AolqGY4/2JvAJds/JlSs4kOEes/AzQ/1dREEp+4sOapmTtJnyauErY3A==", "license": "MIT", "dependencies": { - "@ionic/core": "8.7.4", + "@ionic/core": "8.7.5", "@stencil/vue-output-target": "0.10.7", "ionicons": "^8.0.13" } @@ -8041,9 +8041,9 @@ "dev": true }, "@ionic/core": { - "version": "8.7.4", - "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.7.4.tgz", - "integrity": "sha512-ZCJYKLWdxq+x4OmEDvodqR+y/FSDJYkkFHozWe1+b/p0l9lNN13lLuSZVs0AEOgPtO89Atl67rTbpGE2ad/SCw==", + "version": "8.7.5", + "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.7.5.tgz", + "integrity": "sha512-Uk1qdGPoLHaVhd2FnYSAvRehd3VwwcPIfXaR51qiC7C2L5VhD27VyLSgDetc15G4U+VAIFjgUSR/pKdLFEuMPA==", "requires": { "@stencil/core": "4.36.2", "ionicons": "^8.0.13", @@ -8156,11 +8156,11 @@ "requires": {} }, "@ionic/vue": { - "version": "8.7.4", - "resolved": "https://registry.npmjs.org/@ionic/vue/-/vue-8.7.4.tgz", - "integrity": "sha512-Gof5oHUfyCMBA5VvvtHaLmP4OX+on4nSxCrrDXCFFbgE3b9CXUJGSpBqPwzvrVxkpbPHfkbkgJXhoIWlls4zXA==", + "version": "8.7.5", + "resolved": "https://registry.npmjs.org/@ionic/vue/-/vue-8.7.5.tgz", + "integrity": "sha512-wx7o+ABDDTWLM47CIjxueoZtKbvMQ9AolqGY4/2JvAJds/JlSs4kOEes/AzQ/1dREEp+4sOapmTtJnyauErY3A==", "requires": { - "@ionic/core": "8.7.4", + "@ionic/core": "8.7.5", "@stencil/vue-output-target": "0.10.7", "ionicons": "^8.0.13" } @@ -12991,4 +12991,4 @@ "dev": true } } -} \ No newline at end of file +} diff --git a/packages/vue/package-lock.json b/packages/vue/package-lock.json index 50b4459c4e..29f867b789 100644 --- a/packages/vue/package-lock.json +++ b/packages/vue/package-lock.json @@ -222,9 +222,9 @@ "dev": true }, "node_modules/@ionic/core": { - "version": "8.7.4", - "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.7.4.tgz", - "integrity": "sha512-ZCJYKLWdxq+x4OmEDvodqR+y/FSDJYkkFHozWe1+b/p0l9lNN13lLuSZVs0AEOgPtO89Atl67rTbpGE2ad/SCw==", + "version": "8.7.5", + "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.7.5.tgz", + "integrity": "sha512-Uk1qdGPoLHaVhd2FnYSAvRehd3VwwcPIfXaR51qiC7C2L5VhD27VyLSgDetc15G4U+VAIFjgUSR/pKdLFEuMPA==", "license": "MIT", "dependencies": { "@stencil/core": "4.36.2", @@ -4019,4 +4019,4 @@ "dev": true } } -} \ No newline at end of file +}