diff --git a/.github/actions/publish-npm/action.yml b/.github/actions/publish-npm/action.yml index d3e06d5fb01..6913b493ef1 100644 --- a/.github/actions/publish-npm/action.yml +++ b/.github/actions/publish-npm/action.yml @@ -22,7 +22,7 @@ runs: using: 'composite' steps: - name: 🟒 Configure Node for Publish - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: ${{ inputs.node-version }} registry-url: 'https://registry.npmjs.org' diff --git a/.github/workflows/actions/build-angular-server/action.yml b/.github/workflows/actions/build-angular-server/action.yml index b5d37c5a9ac..e21a39669bf 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@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 24.x - uses: ./.github/workflows/actions/download-archive diff --git a/.github/workflows/actions/build-angular/action.yml b/.github/workflows/actions/build-angular/action.yml index 5224f9741e0..12e1db1f5dc 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@v6 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 24.x - uses: ./.github/workflows/actions/download-archive diff --git a/.github/workflows/actions/build-core-stencil-prerelease/action.yml b/.github/workflows/actions/build-core-stencil-prerelease/action.yml index c105ecccfa4..28e0c54d775 100644 --- a/.github/workflows/actions/build-core-stencil-prerelease/action.yml +++ b/.github/workflows/actions/build-core-stencil-prerelease/action.yml @@ -13,7 +13,7 @@ runs: using: 'composite' steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 24.x diff --git a/.github/workflows/actions/build-core/action.yml b/.github/workflows/actions/build-core/action.yml index 8056f964b98..113a1ebe3b7 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@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 24.x - name: πŸ•ΈοΈ Install Dependencies diff --git a/.github/workflows/actions/build-react-router/action.yml b/.github/workflows/actions/build-react-router/action.yml index c8083494b0a..b104ebd429d 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@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 24.x - uses: ./.github/workflows/actions/download-archive diff --git a/.github/workflows/actions/build-react/action.yml b/.github/workflows/actions/build-react/action.yml index 48f634d2389..8069483deb1 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@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 24.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 c952de0b299..1f74aa2db80 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@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 24.x - uses: ./.github/workflows/actions/download-archive diff --git a/.github/workflows/actions/build-vue/action.yml b/.github/workflows/actions/build-vue/action.yml index 3c31ee94dd4..527250863b8 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@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 24.x - uses: ./.github/workflows/actions/download-archive diff --git a/.github/workflows/actions/download-archive/action.yml b/.github/workflows/actions/download-archive/action.yml index 2acddf9713f..97f07f8627a 100644 --- a/.github/workflows/actions/download-archive/action.yml +++ b/.github/workflows/actions/download-archive/action.yml @@ -10,7 +10,7 @@ inputs: runs: using: 'composite' steps: - - uses: actions/download-artifact@v8 + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: name: ${{ inputs.name }} path: ${{ inputs.path }} diff --git a/.github/workflows/actions/test-angular-e2e/action.yml b/.github/workflows/actions/test-angular-e2e/action.yml index f12fee784e8..8a15bfb5037 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@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 24.x - uses: ./.github/workflows/actions/download-archive diff --git a/.github/workflows/actions/test-core-clean-build/action.yml b/.github/workflows/actions/test-core-clean-build/action.yml index d2000b28ce7..f6275acbee5 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@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 24.x diff --git a/.github/workflows/actions/test-core-lint/action.yml b/.github/workflows/actions/test-core-lint/action.yml index f9f0011719a..66a3036ef04 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@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 24.x - name: πŸ•ΈοΈ Install Dependencies diff --git a/.github/workflows/actions/test-core-screenshot/action.yml b/.github/workflows/actions/test-core-screenshot/action.yml index 1f8699e66d4..379ce934edc 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@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 24.x - uses: ./.github/workflows/actions/download-archive @@ -66,7 +66,7 @@ runs: working-directory: ./core - name: πŸ“¦ Archive Updated Screenshots if: inputs.update == 'true' && steps.test-and-update.outputs.hasUpdatedScreenshots == 'true' - uses: actions/upload-artifact@v7 + uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: updated-screenshots-${{ inputs.shard }}-${{ inputs.totalShards }} path: UpdatedScreenshots-${{ inputs.shard }}-${{ inputs.totalShards }}.zip diff --git a/.github/workflows/actions/test-core-spec/action.yml b/.github/workflows/actions/test-core-spec/action.yml index 2aab4b1be94..f33ab0aa3e3 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@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 24.x - name: πŸ•ΈοΈ Install Dependencies diff --git a/.github/workflows/actions/test-react-e2e/action.yml b/.github/workflows/actions/test-react-e2e/action.yml index a1bcbf7a4db..af6100bdb07 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@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 24.x - uses: ./.github/workflows/actions/download-archive diff --git a/.github/workflows/actions/test-react-router-e2e/action.yml b/.github/workflows/actions/test-react-router-e2e/action.yml index b983878b661..d75c9675fed 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@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 24.x - uses: ./.github/workflows/actions/download-archive diff --git a/.github/workflows/actions/test-vue-e2e/action.yml b/.github/workflows/actions/test-vue-e2e/action.yml index 22c484a7939..2316e019a46 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@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 24.x - uses: ./.github/workflows/actions/download-archive diff --git a/.github/workflows/actions/update-reference-screenshots/action.yml b/.github/workflows/actions/update-reference-screenshots/action.yml index 6ee56689b10..844f4e6d2ac 100644 --- a/.github/workflows/actions/update-reference-screenshots/action.yml +++ b/.github/workflows/actions/update-reference-screenshots/action.yml @@ -7,10 +7,10 @@ on: runs: using: 'composite' steps: - - uses: actions/setup-node@48b55a011bda9f5d6aeb4c2d9c7362e8dae4041e # v6.4.0 + - uses: actions/setup-node@820762786026740c76f36085b0efc47a31fe5020 # v7.0.0 with: node-version: 24.x - - uses: actions/download-artifact@v8 + - uses: actions/download-artifact@3e5f45b2cfb9172054b4087a40e8e0b5a5461e7c # v8.0.1 with: path: ./artifacts - name: πŸ”Ž Extract Archives diff --git a/.github/workflows/actions/upload-archive/action.yml b/.github/workflows/actions/upload-archive/action.yml index c09397345f9..3cfff8853fc 100644 --- a/.github/workflows/actions/upload-archive/action.yml +++ b/.github/workflows/actions/upload-archive/action.yml @@ -13,7 +13,7 @@ runs: - name: πŸ—„οΈ Create Archive run: zip -q -r ${{ inputs.output }} ${{ inputs.paths }} shell: bash - - uses: actions/upload-artifact@v7 + - uses: actions/upload-artifact@043fb46d1a93c77aae656e7c1c64a875d1fc6a0a # v7.0.1 with: name: ${{ inputs.name }} path: ${{ inputs.output }} diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml index ccdc9b996d2..74f504e7317 100644 --- a/.github/workflows/codeql-analysis.yml +++ b/.github/workflows/codeql-analysis.yml @@ -15,7 +15,7 @@ jobs: security-events: write steps: - uses: actions/checkout@9c091bb21b7c1c1d1991bb908d89e4e9dddfe3e0 # v7.0.0 - - uses: github/codeql-action/init@v4 + - uses: github/codeql-action/init@7188fc363630916deb702c7fdcf4e481b751f97a # v4.37.1 with: languages: javascript - - uses: github/codeql-action/analyze@v4 + - uses: github/codeql-action/analyze@7188fc363630916deb702c7fdcf4e481b751f97a # v4.37.1 diff --git a/.github/workflows/conventional-commit.yml b/.github/workflows/conventional-commit.yml index 8c0bbdebb37..65c026de5eb 100644 --- a/.github/workflows/conventional-commit.yml +++ b/.github/workflows/conventional-commit.yml @@ -12,7 +12,7 @@ jobs: if: | !contains(github.event.pull_request.title, 'release') && !contains(github.event.pull_request.title, 'chore') - uses: amannn/action-semantic-pull-request@v6 + uses: amannn/action-semantic-pull-request@48f256284bd46cdaab1048c3721360e808335d50 # v6.1.1 env: GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} with: diff --git a/.github/workflows/label.yml b/.github/workflows/label.yml index 7f5d8de9787..b6014addef1 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@v6 + - uses: actions/labeler@b8dd2d9be0f68b860e7dae5dae7d772984eacd6d # v6.2.0 with: repo-token: "${{ secrets.GITHUB_TOKEN }}" sync-labels: true diff --git a/CHANGELOG.md b/CHANGELOG.md index e16c678580a..996f23da565 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,6 +3,29 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [8.8.15](https://github.com/ionic-team/ionic-framework/compare/v8.8.14...v8.8.15) (2026-07-22) + + +### Bug Fixes + +* **angular-server:** fallback to scoped+annotations when SSR DOM lacks attachShadow ([#30967](https://github.com/ionic-team/ionic-framework/issues/30967)) ([ae6911f](https://github.com/ionic-team/ionic-framework/commit/ae6911f6c8d46467ae54114295688bbba5ccbf5e)), closes [#29751](https://github.com/ionic-team/ionic-framework/issues/29751) +* **modal:** focus the dialog wrapper on present so screen readers can enter the modal ([#31260](https://github.com/ionic-team/ionic-framework/issues/31260)) ([6251eb8](https://github.com/ionic-team/ionic-framework/commit/6251eb85db0e5b43b9e09604248dc8451e1664c0)) + + + + + +## [8.8.14](https://github.com/ionic-team/ionic-framework/compare/v8.8.13...v8.8.14) (2026-07-15) + + +### Bug Fixes + +* **tab-bar:** fire tab change events on tab click ([#31262](https://github.com/ionic-team/ionic-framework/issues/31262)) ([44461dd](https://github.com/ionic-team/ionic-framework/commit/44461ddda5ef44030f477931dd94cce4674801a6)), closes [#30145](https://github.com/ionic-team/ionic-framework/issues/30145) + + + + + ## [8.8.13](https://github.com/ionic-team/ionic-framework/compare/v8.8.12...v8.8.13) (2026-07-01) diff --git a/core/CHANGELOG.md b/core/CHANGELOG.md index 5e125fe6772..a7596c353cc 100644 --- a/core/CHANGELOG.md +++ b/core/CHANGELOG.md @@ -3,6 +3,25 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [8.8.15](https://github.com/ionic-team/ionic-framework/compare/v8.8.14...v8.8.15) (2026-07-22) + + +### Bug Fixes + +* **modal:** focus the dialog wrapper on present so screen readers can enter the modal ([#31260](https://github.com/ionic-team/ionic-framework/issues/31260)) ([6251eb8](https://github.com/ionic-team/ionic-framework/commit/6251eb85db0e5b43b9e09604248dc8451e1664c0)) + + + + + +## [8.8.14](https://github.com/ionic-team/ionic-framework/compare/v8.8.13...v8.8.14) (2026-07-15) + +**Note:** Version bump only for package @ionic/core + + + + + ## [8.8.13](https://github.com/ionic-team/ionic-framework/compare/v8.8.12...v8.8.13) (2026-07-01) diff --git a/core/package-lock.json b/core/package-lock.json index 04192f3795e..d5e316b9e9a 100644 --- a/core/package-lock.json +++ b/core/package-lock.json @@ -1,12 +1,12 @@ { "name": "@ionic/core", - "version": "8.8.13", + "version": "8.8.15", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@ionic/core", - "version": "8.8.13", + "version": "8.8.15", "license": "MIT", "dependencies": { "@stencil/core": "^4.43.5", diff --git a/core/package.json b/core/package.json index bb80ba7e419..6b28bff1ede 100644 --- a/core/package.json +++ b/core/package.json @@ -1,6 +1,6 @@ { "name": "@ionic/core", - "version": "8.8.13", + "version": "8.8.15", "description": "Base components for Ionic", "engines": { "node": ">= 16" diff --git a/core/src/components/modal/gestures/sheet.ts b/core/src/components/modal/gestures/sheet.ts index 13dadc34e81..cacf61c5b43 100644 --- a/core/src/components/modal/gestures/sheet.ts +++ b/core/src/components/modal/gestures/sheet.ts @@ -299,6 +299,13 @@ export const createSheetGesture = ( }; const onStart = (detail: GestureDetail) => { + /** + * Firefox automatically selects the header text during drag + * due to the focusable wrapper (tabindex="-1"). Remove any + * selection that may have occurred. + */ + window.getSelection()?.removeAllRanges(); + /** * If canDismiss is anything other than `true` * then users should be able to swipe down diff --git a/core/src/components/modal/gestures/swipe-to-close.ts b/core/src/components/modal/gestures/swipe-to-close.ts index 2b66e7eac24..d04220c88e7 100644 --- a/core/src/components/modal/gestures/swipe-to-close.ts +++ b/core/src/components/modal/gestures/swipe-to-close.ts @@ -116,6 +116,13 @@ export const createSwipeToCloseGesture = ( const onStart = (detail: GestureDetail) => { const { deltaY } = detail; + /** + * Firefox automatically selects the header text during drag + * due to the focusable wrapper (tabindex="-1"). Remove any + * selection that may have occurred. + */ + window.getSelection()?.removeAllRanges(); + /** * Get the initial scrollY value so * that we can correctly reset the scrollY diff --git a/core/src/components/modal/modal.scss b/core/src/components/modal/modal.scss index 160468f5792..0df4a448cd3 100644 --- a/core/src/components/modal/modal.scss +++ b/core/src/components/modal/modal.scss @@ -84,6 +84,14 @@ ion-backdrop { z-index: 10; } +/** + * The wrapper receives programmatic focus for screen readers but should not + * show a visible focus ring, which is meant only for keyboard navigation. + */ +.modal-wrapper { + outline: none; +} + .modal-shadow { position: absolute; diff --git a/core/src/components/modal/modal.tsx b/core/src/components/modal/modal.tsx index 443fd892181..84ac8181d15 100644 --- a/core/src/components/modal/modal.tsx +++ b/core/src/components/modal/modal.tsx @@ -1188,8 +1188,16 @@ export class Modal implements ComponentInterface, OverlayInterface { */ private onModalFocus = (ev: FocusEvent) => { const { dragHandleEl, el } = this; - // Only handle focus if the modal itself was focused (not a child element) - if (ev.target === el && dragHandleEl && dragHandleEl.tabIndex !== -1) { + /** + * Focus events from inside the shadow DOM are retargeted to the host, so + * `ev.target === el` is also true when a shadow child (e.g. the dialog + * wrapper that present() focuses for screen readers) receives focus. Use + * the shadow root's activeElement to tell the two apart: it is `null` only + * when the host itself was focused directly (e.g. tabbing into the modal). + * Only then do we redirect to the handle, so the wrapper focus set on + * present() is left intact. + */ + if (ev.target === el && el.shadowRoot?.activeElement == null && dragHandleEl && dragHandleEl.tabIndex !== -1) { dragHandleEl.focus(); } }; @@ -1657,10 +1665,17 @@ export class Modal implements ComponentInterface, OverlayInterface { same element. They must also be set inside the shadow DOM otherwise ion-button will not be highlighted when using VoiceOver: https://bugs.webkit.org/show_bug.cgi?id=247134 + + tabIndex={-1} is required so present() can move focus to this + element (which carries the dialog role) instead of the role-less + host. role="dialog" alone does not make an element focusable, so + without the tabindex focus() would be a no-op and screen readers + may not properly announce the dialog and its content when it opens. */ role="dialog" {...inheritedAttributes} aria-modal="true" + tabIndex={-1} class="modal-wrapper ion-overlay-wrapper" part="content" ref={(el) => (this.wrapperEl = el)} diff --git a/core/src/components/modal/test/a11y/modal.e2e.ts b/core/src/components/modal/test/a11y/modal.e2e.ts index 5aef2cda0d8..0cacc470903 100644 --- a/core/src/components/modal/test/a11y/modal.e2e.ts +++ b/core/src/components/modal/test/a11y/modal.e2e.ts @@ -19,5 +19,22 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => const results = await new AxeBuilder({ page }).analyze(); expect(results.violations).toEqual([]); }); + + // The focused wrapper must not show a focus ring when opened via keyboard. + test('should not render a focus ring on the wrapper when presented via keyboard', async ({ page }) => { + await page.goto(`/src/components/modal/test/a11y`, config); + + const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent'); + const button = page.locator('#open-modal'); + const wrapper = page.locator('ion-modal .modal-wrapper'); + + // Open with the keyboard so :focus-visible applies to the wrapper. + await button.focus(); + await page.keyboard.press('Enter'); + await ionModalDidPresent.next(); + + await expect(wrapper).toBeFocused(); + await expect(wrapper).toHaveCSS('outline-style', 'none'); + }); }); }); diff --git a/core/src/utils/overlays.ts b/core/src/utils/overlays.ts index 89b81e28a83..8a3459fb9c2 100644 --- a/core/src/utils/overlays.ts +++ b/core/src/utils/overlays.ts @@ -609,7 +609,29 @@ export const present = async ( * to the overlay container. */ if (overlay.keyboardClose && (document.activeElement === null || !overlay.el.contains(document.activeElement))) { - overlay.el.focus(); + /** + * Some overlays (e.g. modal) put the dialog role and accessible label + * on the `.ion-overlay-wrapper` instead of the host. Screen readers + * need focus on the element with `role="dialog"` to properly announce + * and navigate the dialog. + * + * We only target wrappers with `tabindex`, since `role="dialog"` alone + * does not make an element focusable. If no focusable dialog wrapper + * exists (e.g. picker-legacy), we fall back to the host. + */ + const overlayWrapper = getElementRoot(overlay.el).querySelector('[role="dialog"][tabindex]'); + const focusTarget = overlayWrapper ?? overlay.el; + /** + * `preventScroll` keeps this a pure focus move so the viewport does not + * jump when the wrapper is partially off-screen (e.g. a sheet modal). + * Guard the options call so an older engine that mishandles it can never + * reject present(); we fall back to a plain focus() in that case. + */ + try { + focusTarget.focus({ preventScroll: true }); + } catch { + focusTarget.focus(); + } } /** diff --git a/core/src/utils/test/overlays/overlays.e2e.ts b/core/src/utils/test/overlays/overlays.e2e.ts index ebe7d25a273..de73fd2f011 100644 --- a/core/src/utils/test/overlays/overlays.e2e.ts +++ b/core/src/utils/test/overlays/overlays.e2e.ts @@ -421,5 +421,87 @@ configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => // verify focus is in correct location await expect(input).toBeFocused(); }); + + // Focus the role="dialog" wrapper on present so screen readers can enter. + test('should focus the modal wrapper on present', async ({ page }, testInfo) => { + testInfo.annotations.push({ + type: 'issue', + description: 'FW-7611', + }); + await page.setContent( + ` + + Modal Content + + `, + config + ); + + const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent'); + const modal = page.locator('ion-modal'); + const wrapper = page.locator('ion-modal .modal-wrapper'); + + await modal.evaluate((el: HTMLIonModalElement) => el.present()); + await ionModalDidPresent.next(); + + await expect(wrapper).toHaveAttribute('role', 'dialog'); + await expect(wrapper).toBeFocused(); + }); + + test('should focus the sheet modal wrapper on present', async ({ page }, testInfo) => { + testInfo.annotations.push({ + type: 'issue', + description: 'FW-7611', + }); + await page.setContent( + ` + + Sheet Modal Content + + `, + config + ); + + const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent'); + const modal = page.locator('ion-modal'); + const wrapper = page.locator('ion-modal .modal-wrapper'); + + await modal.evaluate((el: HTMLIonModalElement) => el.present()); + await ionModalDidPresent.next(); + + await expect(wrapper).toHaveAttribute('role', 'dialog'); + await expect(wrapper).toBeFocused(); + }); + + test('should focus the card modal wrapper on present', async ({ page }, testInfo) => { + testInfo.annotations.push({ + type: 'issue', + description: 'FW-7611', + }); + await page.setContent( + ` +
+ Root Content +
+ + Card Modal Content + + `, + config + ); + + const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent'); + const modal = page.locator('ion-modal'); + const wrapper = page.locator('ion-modal .modal-wrapper'); + + await modal.evaluate((el: HTMLIonModalElement) => { + el.presentingElement = document.querySelector('.ion-page')!; + return el.present(); + }); + await ionModalDidPresent.next(); + + await expect(wrapper).toHaveAttribute('role', 'dialog'); + await expect(wrapper).toBeFocused(); + }); }); }); diff --git a/core/src/utils/test/playwright/drag-element.ts b/core/src/utils/test/playwright/drag-element.ts index ec0a8d9ce83..febff65078e 100644 --- a/core/src/utils/test/playwright/drag-element.ts +++ b/core/src/utils/test/playwright/drag-element.ts @@ -35,6 +35,12 @@ export const dragElementBy = async ( await page.mouse.down(); + // Firefox treats focusable elements (tabindex="-1") as draggable text and + // initiates text selection on mouse.down(). In Playwright, this selection + // locks in before the gesture detector fires, blocking pointer events. + // Clearing it here allows the drag gesture to proceed normally. + await page.evaluate(() => window.getSelection()?.removeAllRanges()); + // Drag the element. await moveElement(page, startX, startY, dragByX, dragByY); diff --git a/lerna.json b/lerna.json index c1ff80a0f28..c1999229e99 100644 --- a/lerna.json +++ b/lerna.json @@ -3,5 +3,5 @@ "core", "packages/*" ], - "version": "8.8.13" + "version": "8.8.15" } \ No newline at end of file diff --git a/packages/angular-server/CHANGELOG.md b/packages/angular-server/CHANGELOG.md index 3238fb0800f..4ccbf22bbce 100644 --- a/packages/angular-server/CHANGELOG.md +++ b/packages/angular-server/CHANGELOG.md @@ -3,6 +3,25 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [8.8.15](https://github.com/ionic-team/ionic-framework/compare/v8.8.14...v8.8.15) (2026-07-22) + + +### Bug Fixes + +* **angular-server:** fallback to scoped+annotations when SSR DOM lacks attachShadow ([#30967](https://github.com/ionic-team/ionic-framework/issues/30967)) ([ae6911f](https://github.com/ionic-team/ionic-framework/commit/ae6911f6c8d46467ae54114295688bbba5ccbf5e)), closes [#29751](https://github.com/ionic-team/ionic-framework/issues/29751) + + + + + +## [8.8.14](https://github.com/ionic-team/ionic-framework/compare/v8.8.13...v8.8.14) (2026-07-15) + +**Note:** Version bump only for package @ionic/angular-server + + + + + ## [8.8.13](https://github.com/ionic-team/ionic-framework/compare/v8.8.12...v8.8.13) (2026-07-01) **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 a986c49ee96..742722e560d 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.8.13", + "version": "8.8.15", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@ionic/angular-server", - "version": "8.8.13", + "version": "8.8.15", "license": "MIT", "dependencies": { - "@ionic/core": "^8.8.13" + "@ionic/core": "^8.8.15" }, "devDependencies": { "@angular/animations": "^22.0.0", @@ -1039,9 +1039,9 @@ "dev": true }, "node_modules/@ionic/core": { - "version": "8.8.13", - "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.8.13.tgz", - "integrity": "sha512-f09pRxmOLxPvLeCK9kTTBiByaPeCrApwABAwkqeax08e1b4kDSyXD1nMGDT6ChTvUGxyt4/cPxLsEP68ku4+HQ==", + "version": "8.8.15", + "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.8.15.tgz", + "integrity": "sha512-iEREpxWYEakK3ZVGdFVi6Vm+MIpVhNlfy5qds5IjVnZqUPKaD8ynN/2LPfgQiLO/e8eEo40KJj+QuW97uMW53Q==", "license": "MIT", "dependencies": { "@stencil/core": "4.43.5", @@ -7197,9 +7197,9 @@ "dev": true }, "@ionic/core": { - "version": "8.8.13", - "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.8.13.tgz", - "integrity": "sha512-f09pRxmOLxPvLeCK9kTTBiByaPeCrApwABAwkqeax08e1b4kDSyXD1nMGDT6ChTvUGxyt4/cPxLsEP68ku4+HQ==", + "version": "8.8.15", + "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.8.15.tgz", + "integrity": "sha512-iEREpxWYEakK3ZVGdFVi6Vm+MIpVhNlfy5qds5IjVnZqUPKaD8ynN/2LPfgQiLO/e8eEo40KJj+QuW97uMW53Q==", "requires": { "@stencil/core": "4.43.5", "ionicons": "^8.0.13", diff --git a/packages/angular-server/package.json b/packages/angular-server/package.json index 308f6c33e08..f5d5aa327b8 100644 --- a/packages/angular-server/package.json +++ b/packages/angular-server/package.json @@ -1,6 +1,6 @@ { "name": "@ionic/angular-server", - "version": "8.8.13", + "version": "8.8.15", "description": "Angular SSR Module for Ionic", "keywords": [ "ionic", @@ -66,6 +66,6 @@ }, "prettier": "@ionic/prettier-config", "dependencies": { - "@ionic/core": "^8.8.13" + "@ionic/core": "^8.8.15" } } diff --git a/packages/angular-server/src/ionic-server-module.ts b/packages/angular-server/src/ionic-server-module.ts index 49b93ea5b81..3d446b1b098 100644 --- a/packages/angular-server/src/ionic-server-module.ts +++ b/packages/angular-server/src/ionic-server-module.ts @@ -20,8 +20,17 @@ export class IonicServerModule {} export function hydrateIonicComponents(doc: any, appId: any) { // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types return () => { + const supportsNativeAttachShadow = + typeof doc?.createElement?.('div')?.attachShadow === 'function'; + return hydrateDocument(doc, { - clientHydrateAnnotations: false, + // Fallback for SSR DOMs (e.g. Domino) that do not implement attachShadow. + ...(supportsNativeAttachShadow + ? { clientHydrateAnnotations: false } + : { + serializeShadowRoot: 'scoped', + clientHydrateAnnotations: true, + }), excludeComponents: [ // overlays 'ion-action-sheet', diff --git a/packages/angular/CHANGELOG.md b/packages/angular/CHANGELOG.md index 29461963d67..20ab7d5ba4c 100644 --- a/packages/angular/CHANGELOG.md +++ b/packages/angular/CHANGELOG.md @@ -3,6 +3,22 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [8.8.15](https://github.com/ionic-team/ionic-framework/compare/v8.8.14...v8.8.15) (2026-07-22) + +**Note:** Version bump only for package @ionic/angular + + + + + +## [8.8.14](https://github.com/ionic-team/ionic-framework/compare/v8.8.13...v8.8.14) (2026-07-15) + +**Note:** Version bump only for package @ionic/angular + + + + + ## [8.8.13](https://github.com/ionic-team/ionic-framework/compare/v8.8.12...v8.8.13) (2026-07-01) **Note:** Version bump only for package @ionic/angular diff --git a/packages/angular/package-lock.json b/packages/angular/package-lock.json index c857c63e7db..f8320ad909d 100644 --- a/packages/angular/package-lock.json +++ b/packages/angular/package-lock.json @@ -1,15 +1,15 @@ { "name": "@ionic/angular", - "version": "8.8.13", + "version": "8.8.15", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@ionic/angular", - "version": "8.8.13", + "version": "8.8.15", "license": "MIT", "dependencies": { - "@ionic/core": "^8.8.13", + "@ionic/core": "^8.8.15", "ionicons": "^8.0.13", "jsonc-parser": "^3.0.0", "tslib": "^2.3.0" @@ -2044,9 +2044,9 @@ } }, "node_modules/@ionic/core": { - "version": "8.8.13", - "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.8.13.tgz", - "integrity": "sha512-f09pRxmOLxPvLeCK9kTTBiByaPeCrApwABAwkqeax08e1b4kDSyXD1nMGDT6ChTvUGxyt4/cPxLsEP68ku4+HQ==", + "version": "8.8.15", + "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.8.15.tgz", + "integrity": "sha512-iEREpxWYEakK3ZVGdFVi6Vm+MIpVhNlfy5qds5IjVnZqUPKaD8ynN/2LPfgQiLO/e8eEo40KJj+QuW97uMW53Q==", "license": "MIT", "dependencies": { "@stencil/core": "4.43.5", diff --git a/packages/angular/package.json b/packages/angular/package.json index 7310ffc679c..6b977903c6a 100644 --- a/packages/angular/package.json +++ b/packages/angular/package.json @@ -1,6 +1,6 @@ { "name": "@ionic/angular", - "version": "8.8.13", + "version": "8.8.15", "description": "Angular specific wrappers for @ionic/core", "keywords": [ "ionic", @@ -48,7 +48,7 @@ } }, "dependencies": { - "@ionic/core": "^8.8.13", + "@ionic/core": "^8.8.15", "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 69a91d7e43b..15c703ffa25 100644 --- a/packages/docs/CHANGELOG.md +++ b/packages/docs/CHANGELOG.md @@ -3,6 +3,22 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [8.8.15](https://github.com/ionic-team/ionic-framework/compare/v8.8.14...v8.8.15) (2026-07-22) + +**Note:** Version bump only for package @ionic/docs + + + + + +## [8.8.14](https://github.com/ionic-team/ionic-framework/compare/v8.8.13...v8.8.14) (2026-07-15) + +**Note:** Version bump only for package @ionic/docs + + + + + ## [8.8.13](https://github.com/ionic-team/ionic-framework/compare/v8.8.12...v8.8.13) (2026-07-01) **Note:** Version bump only for package @ionic/docs diff --git a/packages/docs/package-lock.json b/packages/docs/package-lock.json index 32b6c60cc7f..2f96d120cbd 100644 --- a/packages/docs/package-lock.json +++ b/packages/docs/package-lock.json @@ -1,12 +1,12 @@ { "name": "@ionic/docs", - "version": "8.8.13", + "version": "8.8.15", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@ionic/docs", - "version": "8.8.13", + "version": "8.8.15", "license": "MIT" } } diff --git a/packages/docs/package.json b/packages/docs/package.json index 5eb602d6513..262e89331b3 100644 --- a/packages/docs/package.json +++ b/packages/docs/package.json @@ -1,6 +1,6 @@ { "name": "@ionic/docs", - "version": "8.8.13", + "version": "8.8.15", "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 cf601872233..119692c6d83 100644 --- a/packages/react-router/CHANGELOG.md +++ b/packages/react-router/CHANGELOG.md @@ -3,6 +3,22 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [8.8.15](https://github.com/ionic-team/ionic-framework/compare/v8.8.14...v8.8.15) (2026-07-22) + +**Note:** Version bump only for package @ionic/react-router + + + + + +## [8.8.14](https://github.com/ionic-team/ionic-framework/compare/v8.8.13...v8.8.14) (2026-07-15) + +**Note:** Version bump only for package @ionic/react-router + + + + + ## [8.8.13](https://github.com/ionic-team/ionic-framework/compare/v8.8.12...v8.8.13) (2026-07-01) **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 b9c7771dd3c..439c471aae3 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.8.13", + "version": "8.8.15", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@ionic/react-router", - "version": "8.8.13", + "version": "8.8.15", "license": "MIT", "dependencies": { - "@ionic/react": "^8.8.13", + "@ionic/react": "^8.8.15", "tslib": "*" }, "devDependencies": { @@ -248,9 +248,9 @@ "license": "BSD-3-Clause" }, "node_modules/@ionic/core": { - "version": "8.8.13", - "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.8.13.tgz", - "integrity": "sha512-f09pRxmOLxPvLeCK9kTTBiByaPeCrApwABAwkqeax08e1b4kDSyXD1nMGDT6ChTvUGxyt4/cPxLsEP68ku4+HQ==", + "version": "8.8.15", + "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.8.15.tgz", + "integrity": "sha512-iEREpxWYEakK3ZVGdFVi6Vm+MIpVhNlfy5qds5IjVnZqUPKaD8ynN/2LPfgQiLO/e8eEo40KJj+QuW97uMW53Q==", "license": "MIT", "dependencies": { "@stencil/core": "4.43.5", @@ -437,12 +437,12 @@ } }, "node_modules/@ionic/react": { - "version": "8.8.13", - "resolved": "https://registry.npmjs.org/@ionic/react/-/react-8.8.13.tgz", - "integrity": "sha512-xKevvpmTfi2ZtOcmwEsw3EE6fm+TqKYIHKvgkIwAUz/bnRcMmGA9b474WxJcLQ5Twv8ynj/C1iDQcDA+jR0/pw==", + "version": "8.8.15", + "resolved": "https://registry.npmjs.org/@ionic/react/-/react-8.8.15.tgz", + "integrity": "sha512-8bjys95dICAfJMwA0iuKIYfg5pbz2lY56eQpIG6In+796PvMNVXE9eFLhIZ15jjpRE1O/HZHxO2OFV/pL3NVdA==", "license": "MIT", "dependencies": { - "@ionic/core": "8.8.13", + "@ionic/core": "8.8.15", "ionicons": "^8.0.13", "tslib": "*" }, diff --git a/packages/react-router/package.json b/packages/react-router/package.json index b5626d0beb9..cbed62429f7 100644 --- a/packages/react-router/package.json +++ b/packages/react-router/package.json @@ -1,6 +1,6 @@ { "name": "@ionic/react-router", - "version": "8.8.13", + "version": "8.8.15", "description": "React Router wrapper for @ionic/react", "keywords": [ "ionic", @@ -36,7 +36,7 @@ "dist/" ], "dependencies": { - "@ionic/react": "^8.8.13", + "@ionic/react": "^8.8.15", "tslib": "*" }, "peerDependencies": { diff --git a/packages/react/CHANGELOG.md b/packages/react/CHANGELOG.md index 61282f1918e..e0e3c9aeba1 100644 --- a/packages/react/CHANGELOG.md +++ b/packages/react/CHANGELOG.md @@ -3,6 +3,25 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [8.8.15](https://github.com/ionic-team/ionic-framework/compare/v8.8.14...v8.8.15) (2026-07-22) + +**Note:** Version bump only for package @ionic/react + + + + + +## [8.8.14](https://github.com/ionic-team/ionic-framework/compare/v8.8.13...v8.8.14) (2026-07-15) + + +### Bug Fixes + +* **tab-bar:** fire tab change events on tab click ([#31262](https://github.com/ionic-team/ionic-framework/issues/31262)) ([44461dd](https://github.com/ionic-team/ionic-framework/commit/44461ddda5ef44030f477931dd94cce4674801a6)), closes [#30145](https://github.com/ionic-team/ionic-framework/issues/30145) + + + + + ## [8.8.13](https://github.com/ionic-team/ionic-framework/compare/v8.8.12...v8.8.13) (2026-07-01) **Note:** Version bump only for package @ionic/react diff --git a/packages/react/package-lock.json b/packages/react/package-lock.json index feb308cd8b0..15ccdf26c64 100644 --- a/packages/react/package-lock.json +++ b/packages/react/package-lock.json @@ -1,15 +1,15 @@ { "name": "@ionic/react", - "version": "8.8.13", + "version": "8.8.15", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@ionic/react", - "version": "8.8.13", + "version": "8.8.15", "license": "MIT", "dependencies": { - "@ionic/core": "^8.8.13", + "@ionic/core": "^8.8.15", "@stencil/react-output-target": "^1.5.2", "ionicons": "^8.0.13", "tslib": "*" @@ -742,9 +742,9 @@ "dev": true }, "node_modules/@ionic/core": { - "version": "8.8.13", - "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.8.13.tgz", - "integrity": "sha512-f09pRxmOLxPvLeCK9kTTBiByaPeCrApwABAwkqeax08e1b4kDSyXD1nMGDT6ChTvUGxyt4/cPxLsEP68ku4+HQ==", + "version": "8.8.15", + "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.8.15.tgz", + "integrity": "sha512-iEREpxWYEakK3ZVGdFVi6Vm+MIpVhNlfy5qds5IjVnZqUPKaD8ynN/2LPfgQiLO/e8eEo40KJj+QuW97uMW53Q==", "license": "MIT", "dependencies": { "@stencil/core": "4.43.5", diff --git a/packages/react/package.json b/packages/react/package.json index 2a2fe96cfba..075f55c8185 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -1,6 +1,6 @@ { "name": "@ionic/react", - "version": "8.8.13", + "version": "8.8.15", "description": "React specific wrapper for @ionic/core", "keywords": [ "ionic", @@ -40,7 +40,7 @@ "css/" ], "dependencies": { - "@ionic/core": "^8.8.13", + "@ionic/core": "^8.8.15", "@stencil/react-output-target": "^1.5.2", "ionicons": "^8.0.13", "tslib": "*" diff --git a/packages/react/src/components/navigation/IonTabBar.tsx b/packages/react/src/components/navigation/IonTabBar.tsx index 0c5da8dd383..e267c218d54 100644 --- a/packages/react/src/components/navigation/IonTabBar.tsx +++ b/packages/react/src/components/navigation/IonTabBar.tsx @@ -227,12 +227,20 @@ class IonTabBarUnwrapped extends React.PureComponent { /** * Verifies that tabs with similar route prefixes (e.g., /home, /home2, /home3) * correctly select the matching tab instead of the first prefix match. - * + * * @see https://github.com/ionic-team/ionic-framework/issues/30448 */ describe('Similar Route Prefixes', () => { @@ -58,7 +58,11 @@ describe('IonTabs', () => { describe('Without IonRouterOutlet', () => { beforeEach(() => { - cy.visit('/tabs-basic'); + cy.visit('/tabs-basic', { + onBeforeLoad(win) { + cy.spy(win.console, 'log').as('consoleLog'); + }, + }); }); it.skip('should show correct tab when clicking the tab button', () => { @@ -83,5 +87,12 @@ describe('IonTabs', () => { cy.url().should('include', '/tabs-basic'); }); + + it('should fire tab change events on tab click', () => { + cy.get('ion-tab-button[tab="tab2"]').click(); + + cy.get('@consoleLog').should('be.calledWith', 'onIonTabsWillChange', 'tab2'); + cy.get('@consoleLog').should('be.calledWith', 'onIonTabsDidChange:', 'tab2'); + }); }); }); diff --git a/packages/vue-router/CHANGELOG.md b/packages/vue-router/CHANGELOG.md index 9697a53d608..3f626505934 100644 --- a/packages/vue-router/CHANGELOG.md +++ b/packages/vue-router/CHANGELOG.md @@ -3,6 +3,22 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [8.8.15](https://github.com/ionic-team/ionic-framework/compare/v8.8.14...v8.8.15) (2026-07-22) + +**Note:** Version bump only for package @ionic/vue-router + + + + + +## [8.8.14](https://github.com/ionic-team/ionic-framework/compare/v8.8.13...v8.8.14) (2026-07-15) + +**Note:** Version bump only for package @ionic/vue-router + + + + + ## [8.8.13](https://github.com/ionic-team/ionic-framework/compare/v8.8.12...v8.8.13) (2026-07-01) **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 d3cececf797..72943eb71b6 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.8.13", + "version": "8.8.15", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@ionic/vue-router", - "version": "8.8.13", + "version": "8.8.15", "license": "MIT", "dependencies": { - "@ionic/vue": "^8.8.13" + "@ionic/vue": "^8.8.15" }, "devDependencies": { "@ionic/eslint-config": "^0.3.0", @@ -279,9 +279,9 @@ "license": "BSD-3-Clause" }, "node_modules/@ionic/core": { - "version": "8.8.13", - "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.8.13.tgz", - "integrity": "sha512-f09pRxmOLxPvLeCK9kTTBiByaPeCrApwABAwkqeax08e1b4kDSyXD1nMGDT6ChTvUGxyt4/cPxLsEP68ku4+HQ==", + "version": "8.8.15", + "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.8.15.tgz", + "integrity": "sha512-iEREpxWYEakK3ZVGdFVi6Vm+MIpVhNlfy5qds5IjVnZqUPKaD8ynN/2LPfgQiLO/e8eEo40KJj+QuW97uMW53Q==", "license": "MIT", "dependencies": { "@stencil/core": "4.43.5", @@ -468,12 +468,12 @@ } }, "node_modules/@ionic/vue": { - "version": "8.8.13", - "resolved": "https://registry.npmjs.org/@ionic/vue/-/vue-8.8.13.tgz", - "integrity": "sha512-PgpuoQInVBAmBwn12Wg7nvZ471khG++3UGlEsOAFZ6D6BFEvv8OMz90MTE5j6gnT//lzP2GIs/msG+LS8FV5vQ==", + "version": "8.8.15", + "resolved": "https://registry.npmjs.org/@ionic/vue/-/vue-8.8.15.tgz", + "integrity": "sha512-WYM51Qlh1PES6Xst+085ueGj4iars2AhBnTboQBLxS9knU6hHQ90/5/pNjOl3WyFkmWV7/kL8iQaR7o+qESLxQ==", "license": "MIT", "dependencies": { - "@ionic/core": "8.8.13", + "@ionic/core": "8.8.15", "@stencil/vue-output-target": "0.10.7", "ionicons": "^8.0.13" } diff --git a/packages/vue-router/package.json b/packages/vue-router/package.json index 9064ff94397..730d23d3300 100644 --- a/packages/vue-router/package.json +++ b/packages/vue-router/package.json @@ -1,6 +1,6 @@ { "name": "@ionic/vue-router", - "version": "8.8.13", + "version": "8.8.15", "description": "Vue Router integration for @ionic/vue", "scripts": { "eslint": "eslint src", @@ -43,7 +43,7 @@ }, "homepage": "https://github.com/ionic-team/ionic-framework#readme", "dependencies": { - "@ionic/vue": "^8.8.13" + "@ionic/vue": "^8.8.15" }, "devDependencies": { "@ionic/eslint-config": "^0.3.0", diff --git a/packages/vue/CHANGELOG.md b/packages/vue/CHANGELOG.md index b9d622271a2..060691a3ca7 100644 --- a/packages/vue/CHANGELOG.md +++ b/packages/vue/CHANGELOG.md @@ -3,6 +3,22 @@ All notable changes to this project will be documented in this file. See [Conventional Commits](https://conventionalcommits.org) for commit guidelines. +## [8.8.15](https://github.com/ionic-team/ionic-framework/compare/v8.8.14...v8.8.15) (2026-07-22) + +**Note:** Version bump only for package @ionic/vue + + + + + +## [8.8.14](https://github.com/ionic-team/ionic-framework/compare/v8.8.13...v8.8.14) (2026-07-15) + +**Note:** Version bump only for package @ionic/vue + + + + + ## [8.8.13](https://github.com/ionic-team/ionic-framework/compare/v8.8.12...v8.8.13) (2026-07-01) **Note:** Version bump only for package @ionic/vue diff --git a/packages/vue/package-lock.json b/packages/vue/package-lock.json index a82b503747e..69d8a8a28c3 100644 --- a/packages/vue/package-lock.json +++ b/packages/vue/package-lock.json @@ -1,15 +1,15 @@ { "name": "@ionic/vue", - "version": "8.8.13", + "version": "8.8.15", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@ionic/vue", - "version": "8.8.13", + "version": "8.8.15", "license": "MIT", "dependencies": { - "@ionic/core": "^8.8.13", + "@ionic/core": "^8.8.15", "@stencil/vue-output-target": "0.13.1", "ionicons": "^8.0.13" }, @@ -239,9 +239,9 @@ "dev": true }, "node_modules/@ionic/core": { - "version": "8.8.13", - "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.8.13.tgz", - "integrity": "sha512-f09pRxmOLxPvLeCK9kTTBiByaPeCrApwABAwkqeax08e1b4kDSyXD1nMGDT6ChTvUGxyt4/cPxLsEP68ku4+HQ==", + "version": "8.8.15", + "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.8.15.tgz", + "integrity": "sha512-iEREpxWYEakK3ZVGdFVi6Vm+MIpVhNlfy5qds5IjVnZqUPKaD8ynN/2LPfgQiLO/e8eEo40KJj+QuW97uMW53Q==", "license": "MIT", "dependencies": { "@stencil/core": "4.43.5", diff --git a/packages/vue/package.json b/packages/vue/package.json index d1d493dd678..e308acb4353 100644 --- a/packages/vue/package.json +++ b/packages/vue/package.json @@ -1,6 +1,6 @@ { "name": "@ionic/vue", - "version": "8.8.13", + "version": "8.8.15", "description": "Vue specific wrapper for @ionic/core", "scripts": { "eslint": "eslint src", @@ -68,7 +68,7 @@ "vue-router": "^5.0.6" }, "dependencies": { - "@ionic/core": "^8.8.13", + "@ionic/core": "^8.8.15", "@stencil/vue-output-target": "0.13.1", "ionicons": "^8.0.13" },