diff --git a/.github/workflows/assign-issues.yml b/.github/workflows/assign-issues.yml index 2a3266eb751..fc254b78976 100644 --- a/.github/workflows/assign-issues.yml +++ b/.github/workflows/assign-issues.yml @@ -11,7 +11,7 @@ jobs: issues: write steps: - name: 'Auto-assign issue' - uses: pozil/auto-assign-issue@07fe6dc0e9771842b428f5739098d6140734e226 # v4.0.0 + uses: pozil/auto-assign-issue@af6beea6bdf1e8eb373f061c5bc168681fc6d011 # v4.0.1 with: assignees: brandyscarney, thetaPC, ShaneK numOfAssignee: 1 diff --git a/CHANGELOG.md b/CHANGELOG.md index ac4915217ab..538f88377e8 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.8.11](https://github.com/ionic-team/ionic-framework/compare/v8.8.10...v8.8.11) (2026-06-17) + + +### Bug Fixes + +* **react:** remove relocated inline overlays orphaned on unmount ([#31223](https://github.com/ionic-team/ionic-framework/issues/31223)) ([d28d25b](https://github.com/ionic-team/ionic-framework/commit/d28d25b798d32db6148155bb34fdbd13243286d9)) +* **searchbar:** fix search icon sometimes being offset incorrectly ([#31212](https://github.com/ionic-team/ionic-framework/issues/31212)) ([3394c30](https://github.com/ionic-team/ionic-framework/commit/3394c305b5141326cc045132507dff62dd0e4dd6)), closes [#30434](https://github.com/ionic-team/ionic-framework/issues/30434) + + + + + ## [8.8.10](https://github.com/ionic-team/ionic-framework/compare/v8.8.9...v8.8.10) (2026-06-10) diff --git a/core/CHANGELOG.md b/core/CHANGELOG.md index c2bce62e510..3a594bdaad0 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.8.11](https://github.com/ionic-team/ionic-framework/compare/v8.8.10...v8.8.11) (2026-06-17) + + +### Bug Fixes + +* **searchbar:** fix search icon sometimes being offset incorrectly ([#31212](https://github.com/ionic-team/ionic-framework/issues/31212)) ([3394c30](https://github.com/ionic-team/ionic-framework/commit/3394c305b5141326cc045132507dff62dd0e4dd6)), closes [#30434](https://github.com/ionic-team/ionic-framework/issues/30434) + + + + + ## [8.8.10](https://github.com/ionic-team/ionic-framework/compare/v8.8.9...v8.8.10) (2026-06-10) diff --git a/core/Dockerfile b/core/Dockerfile index 46cd18822f2..380dcab8f91 100644 --- a/core/Dockerfile +++ b/core/Dockerfile @@ -1,5 +1,5 @@ # Get Playwright -FROM mcr.microsoft.com/playwright:v1.60.0 +FROM mcr.microsoft.com/playwright:v1.61.0 # Set the working directory WORKDIR /ionic diff --git a/core/package-lock.json b/core/package-lock.json index 35c260e4e0c..b27479af95c 100644 --- a/core/package-lock.json +++ b/core/package-lock.json @@ -1,12 +1,12 @@ { "name": "@ionic/core", - "version": "8.8.10", + "version": "8.8.11", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@ionic/core", - "version": "8.8.10", + "version": "8.8.11", "license": "MIT", "dependencies": { "@stencil/core": "^4.43.5", @@ -21,7 +21,7 @@ "@capacitor/status-bar": "^8.0.0", "@ionic/eslint-config": "^0.3.0", "@ionic/prettier-config": "^2.0.0", - "@playwright/test": "^1.60.0", + "@playwright/test": "^1.61.0", "@rollup/plugin-node-resolve": "^8.4.0", "@rollup/plugin-virtual": "^2.0.3", "@stencil/angular-output-target": "^1.3.2", @@ -42,7 +42,7 @@ "fs-extra": "^9.0.1", "jest": "^29.7.0", "jest-cli": "^29.7.0", - "playwright-core": "^1.60.0", + "playwright-core": "^1.61.0", "prettier": "^2.6.1", "rollup": "^2.26.4", "sass": "^1.33.0", @@ -649,9 +649,9 @@ } }, "node_modules/@capacitor/keyboard": { - "version": "8.0.3", - "resolved": "https://registry.npmjs.org/@capacitor/keyboard/-/keyboard-8.0.3.tgz", - "integrity": "sha512-27Bv5/2w1Ss2njguBgTS98O0Bb8DRJhAARyzXYib0JlT/n6BrJw/EZ0CokM4C8GFUjFDjJnEKF1Ie01buTMEXQ==", + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/@capacitor/keyboard/-/keyboard-8.0.5.tgz", + "integrity": "sha512-oFXygC4eKYA5l2MdpTR06L2M/4x6e2SLD5yS1T9+UBDKTkzyvhWKEhbYLUaTIBPpLKqlfGudJw1X73S1H9eUzQ==", "dev": true, "license": "MIT", "peerDependencies": { @@ -1615,13 +1615,13 @@ } }, "node_modules/@playwright/test": { - "version": "1.60.0", - "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.60.0.tgz", - "integrity": "sha512-O71yZIbAh/PxDMNGns37GHBIfrVkEVyn+AXyIa5dOTfb4/xNvRWV+Vv/NMbNCtODB/pO7vLlF2OTmMVLhmr7Ag==", + "version": "1.61.0", + "resolved": "https://registry.npmjs.org/@playwright/test/-/test-1.61.0.tgz", + "integrity": "sha512-cKA5B6lpFEMyMGjxF54QihfYpB4FkEGH+qZhtArDEG+wezQAJY8Pq6C7T1SjWz+FFzt3TbyoXBQYk/0292TdJA==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright": "1.60.0" + "playwright": "1.61.0" }, "bin": { "playwright": "cli.js" @@ -8256,13 +8256,13 @@ } }, "node_modules/playwright": { - "version": "1.60.0", - "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.60.0.tgz", - "integrity": "sha512-hheHdokM8cdqCb0lcE3s+zT4t4W+vvjpGxsZlDnikarzx8tSzMebh3UiFtgqwFwnTnjYQcsyMF8ei2mCO/tpeA==", + "version": "1.61.0", + "resolved": "https://registry.npmjs.org/playwright/-/playwright-1.61.0.tgz", + "integrity": "sha512-Z+7BeeqQPRRzklHsVFP4KTGIyMxKUmfeRA4WisM6G3/XW6nwGeX6fX9qYaDa+CiUqpOkb2f6X3nar05R3kSuJQ==", "dev": true, "license": "Apache-2.0", "dependencies": { - "playwright-core": "1.60.0" + "playwright-core": "1.61.0" }, "bin": { "playwright": "cli.js" @@ -8275,9 +8275,9 @@ } }, "node_modules/playwright-core": { - "version": "1.60.0", - "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.60.0.tgz", - "integrity": "sha512-9bW6zvX/m0lEbgTKJ6YppOKx8H3VOPBMOCFh2irXFOT4BbHgrx5hPjwJYLT40Lu+4qtD36qKc/Hn56StUW57IA==", + "version": "1.61.0", + "resolved": "https://registry.npmjs.org/playwright-core/-/playwright-core-1.61.0.tgz", + "integrity": "sha512-caX7TrY3Ml6egyDX0WUcTHDxodl/b51y5wJOdCEA36QviK/s2g081hvmGs8eaE3DWb6NYZQ6BjO/QkNRPenoPA==", "dev": true, "license": "Apache-2.0", "bin": { diff --git a/core/package.json b/core/package.json index d0d285588f1..4f6b8119112 100644 --- a/core/package.json +++ b/core/package.json @@ -1,6 +1,6 @@ { "name": "@ionic/core", - "version": "8.8.10", + "version": "8.8.11", "description": "Base components for Ionic", "engines": { "node": ">= 16" @@ -78,7 +78,7 @@ "@capacitor/status-bar": "^8.0.0", "@ionic/eslint-config": "^0.3.0", "@ionic/prettier-config": "^2.0.0", - "@playwright/test": "^1.60.0", + "@playwright/test": "^1.61.0", "@rollup/plugin-node-resolve": "^8.4.0", "@rollup/plugin-virtual": "^2.0.3", "@stencil/angular-output-target": "^1.3.2", @@ -99,7 +99,7 @@ "fs-extra": "^9.0.1", "jest": "^29.7.0", "jest-cli": "^29.7.0", - "playwright-core": "^1.60.0", + "playwright-core": "^1.61.0", "prettier": "^2.6.1", "rollup": "^2.26.4", "sass": "^1.33.0", diff --git a/core/src/components/alert/test/standalone/alert.e2e.ts-snapshots/alert-standalone-ios-ltr-Mobile-Safari-linux.png b/core/src/components/alert/test/standalone/alert.e2e.ts-snapshots/alert-standalone-ios-ltr-Mobile-Safari-linux.png index b05a3d16860..7bb9fb009eb 100644 Binary files a/core/src/components/alert/test/standalone/alert.e2e.ts-snapshots/alert-standalone-ios-ltr-Mobile-Safari-linux.png and b/core/src/components/alert/test/standalone/alert.e2e.ts-snapshots/alert-standalone-ios-ltr-Mobile-Safari-linux.png differ diff --git a/core/src/components/alert/test/standalone/alert.e2e.ts-snapshots/alert-standalone-ios-rtl-Mobile-Safari-linux.png b/core/src/components/alert/test/standalone/alert.e2e.ts-snapshots/alert-standalone-ios-rtl-Mobile-Safari-linux.png index 02820dd91a8..7a7ea03eebe 100644 Binary files a/core/src/components/alert/test/standalone/alert.e2e.ts-snapshots/alert-standalone-ios-rtl-Mobile-Safari-linux.png and b/core/src/components/alert/test/standalone/alert.e2e.ts-snapshots/alert-standalone-ios-rtl-Mobile-Safari-linux.png differ diff --git a/core/src/components/alert/test/standalone/alert.e2e.ts-snapshots/alert-standalone-md-ltr-Mobile-Safari-linux.png b/core/src/components/alert/test/standalone/alert.e2e.ts-snapshots/alert-standalone-md-ltr-Mobile-Safari-linux.png index effe36becf6..a81b5cbc533 100644 Binary files a/core/src/components/alert/test/standalone/alert.e2e.ts-snapshots/alert-standalone-md-ltr-Mobile-Safari-linux.png and b/core/src/components/alert/test/standalone/alert.e2e.ts-snapshots/alert-standalone-md-ltr-Mobile-Safari-linux.png differ diff --git a/core/src/components/alert/test/standalone/alert.e2e.ts-snapshots/alert-standalone-md-rtl-Mobile-Safari-linux.png b/core/src/components/alert/test/standalone/alert.e2e.ts-snapshots/alert-standalone-md-rtl-Mobile-Safari-linux.png index 8811a5009a2..37593c15e62 100644 Binary files a/core/src/components/alert/test/standalone/alert.e2e.ts-snapshots/alert-standalone-md-rtl-Mobile-Safari-linux.png and b/core/src/components/alert/test/standalone/alert.e2e.ts-snapshots/alert-standalone-md-rtl-Mobile-Safari-linux.png differ diff --git a/core/src/components/card/test/basic/card.e2e.ts-snapshots/card-no-content-or-header-md-ltr-Mobile-Chrome-linux.png b/core/src/components/card/test/basic/card.e2e.ts-snapshots/card-no-content-or-header-md-ltr-Mobile-Chrome-linux.png index 747e33643b1..37eca67a82e 100644 Binary files a/core/src/components/card/test/basic/card.e2e.ts-snapshots/card-no-content-or-header-md-ltr-Mobile-Chrome-linux.png and b/core/src/components/card/test/basic/card.e2e.ts-snapshots/card-no-content-or-header-md-ltr-Mobile-Chrome-linux.png differ diff --git a/core/src/components/input-otp/input-otp.tsx b/core/src/components/input-otp/input-otp.tsx index c6b4f394599..7c46ca59d42 100644 --- a/core/src/components/input-otp/input-otp.tsx +++ b/core/src/components/input-otp/input-otp.tsx @@ -1,11 +1,10 @@ import type { ComponentInterface, EventEmitter } from '@stencil/core'; -import { Component, Element, Event, Fragment, Host, Prop, State, h, Watch } from '@stencil/core'; +import { Component, Element, Event, Fragment, Host, Method, Prop, State, h, Watch } from '@stencil/core'; import type { Attributes } from '@utils/helpers'; import { inheritAriaAttributes } from '@utils/helpers'; import { printIonWarning } from '@utils/logging'; import { isRTL } from '@utils/rtl'; import { createColorClasses } from '@utils/theme'; -import { Method } from 'ionicons/dist/types/stencil-public-runtime'; import { getIonMode } from '../../global/ionic-global'; import type { Color } from '../../interface'; diff --git a/core/src/components/popover/test/standalone/popover.e2e.ts-snapshots/popover-standalone-basic-popover-ios-ltr-Mobile-Safari-linux.png b/core/src/components/popover/test/standalone/popover.e2e.ts-snapshots/popover-standalone-basic-popover-ios-ltr-Mobile-Safari-linux.png index b0894575b0e..5c2f116d569 100644 Binary files a/core/src/components/popover/test/standalone/popover.e2e.ts-snapshots/popover-standalone-basic-popover-ios-ltr-Mobile-Safari-linux.png and b/core/src/components/popover/test/standalone/popover.e2e.ts-snapshots/popover-standalone-basic-popover-ios-ltr-Mobile-Safari-linux.png differ diff --git a/core/src/components/popover/test/standalone/popover.e2e.ts-snapshots/popover-standalone-basic-popover-ios-rtl-Mobile-Safari-linux.png b/core/src/components/popover/test/standalone/popover.e2e.ts-snapshots/popover-standalone-basic-popover-ios-rtl-Mobile-Safari-linux.png index 37aec7be624..0f2b81dae8b 100644 Binary files a/core/src/components/popover/test/standalone/popover.e2e.ts-snapshots/popover-standalone-basic-popover-ios-rtl-Mobile-Safari-linux.png and b/core/src/components/popover/test/standalone/popover.e2e.ts-snapshots/popover-standalone-basic-popover-ios-rtl-Mobile-Safari-linux.png differ diff --git a/core/src/components/popover/test/standalone/popover.e2e.ts-snapshots/popover-standalone-basic-popover-md-ltr-Mobile-Safari-linux.png b/core/src/components/popover/test/standalone/popover.e2e.ts-snapshots/popover-standalone-basic-popover-md-ltr-Mobile-Safari-linux.png index ba0cccc7e78..24ae03189b6 100644 Binary files a/core/src/components/popover/test/standalone/popover.e2e.ts-snapshots/popover-standalone-basic-popover-md-ltr-Mobile-Safari-linux.png and b/core/src/components/popover/test/standalone/popover.e2e.ts-snapshots/popover-standalone-basic-popover-md-ltr-Mobile-Safari-linux.png differ diff --git a/core/src/components/popover/test/standalone/popover.e2e.ts-snapshots/popover-standalone-basic-popover-md-rtl-Mobile-Safari-linux.png b/core/src/components/popover/test/standalone/popover.e2e.ts-snapshots/popover-standalone-basic-popover-md-rtl-Mobile-Safari-linux.png index ff9947ec11e..412da91df23 100644 Binary files a/core/src/components/popover/test/standalone/popover.e2e.ts-snapshots/popover-standalone-basic-popover-md-rtl-Mobile-Safari-linux.png and b/core/src/components/popover/test/standalone/popover.e2e.ts-snapshots/popover-standalone-basic-popover-md-rtl-Mobile-Safari-linux.png differ diff --git a/core/src/components/searchbar/searchbar.tsx b/core/src/components/searchbar/searchbar.tsx index 0131db55ca1..b04481be01e 100644 --- a/core/src/components/searchbar/searchbar.tsx +++ b/core/src/components/searchbar/searchbar.tsx @@ -32,6 +32,7 @@ export class Searchbar implements ComponentInterface { private inheritedAttributes: Attributes = {}; private loadTimeout: ReturnType | undefined; private clearTimeout: ReturnType | undefined; + private searchIconResizeObserver?: ResizeObserver; /** * The value of the input when the textarea is focused. @@ -302,6 +303,7 @@ export class Searchbar implements ComponentInterface { if (this.clearTimeout) { clearTimeout(this.clearTimeout); } + this.searchIconResizeObserver?.disconnect(); } private emitStyle() { @@ -539,7 +541,26 @@ export class Searchbar implements ComponentInterface { * such as Dynamic Type on iOS as well as 8px * of padding. */ - const iconLeft = 'calc(50% - ' + (textWidth / 2 + iconEl.clientWidth + 8) + 'px)'; + const iconWidth = iconEl.clientWidth; + + /** + * Fix for https://github.com/ionic-team/ionic-framework/issues/30434: + * iconEl.clientWidth can very briefly be 0 when this is called from componentDidLoad. + * If it is zero, set up a ResizeObserver and call this function when it observes a width greater than 0. + */ + if (iconWidth === 0) { + this.searchIconResizeObserver?.disconnect(); + this.searchIconResizeObserver = new ResizeObserver((entries) => { + if (entries[0].contentRect.width > 0) { + this.searchIconResizeObserver?.disconnect(); + this.positionPlaceholder(); + } + }); + this.searchIconResizeObserver?.observe(iconEl); + return; + } + + const iconLeft = 'calc(50% - ' + (textWidth / 2 + iconWidth + 8) + 'px)'; // Set the input padding start and icon margin start if (rtl) { diff --git a/core/src/components/toggle/test/enable-on-off-labels/toggle.e2e.ts-snapshots/toggle-on-off-labels-color-ios-ltr-Mobile-Chrome-linux.png b/core/src/components/toggle/test/enable-on-off-labels/toggle.e2e.ts-snapshots/toggle-on-off-labels-color-ios-ltr-Mobile-Chrome-linux.png index 41868dc7a7c..e0329b36125 100644 Binary files a/core/src/components/toggle/test/enable-on-off-labels/toggle.e2e.ts-snapshots/toggle-on-off-labels-color-ios-ltr-Mobile-Chrome-linux.png and b/core/src/components/toggle/test/enable-on-off-labels/toggle.e2e.ts-snapshots/toggle-on-off-labels-color-ios-ltr-Mobile-Chrome-linux.png differ diff --git a/core/src/components/toggle/test/enable-on-off-labels/toggle.e2e.ts-snapshots/toggle-on-off-labels-color-ios-ltr-dark-Mobile-Chrome-linux.png b/core/src/components/toggle/test/enable-on-off-labels/toggle.e2e.ts-snapshots/toggle-on-off-labels-color-ios-ltr-dark-Mobile-Chrome-linux.png index 40cf9acb46b..1b9ce49c285 100644 Binary files a/core/src/components/toggle/test/enable-on-off-labels/toggle.e2e.ts-snapshots/toggle-on-off-labels-color-ios-ltr-dark-Mobile-Chrome-linux.png and b/core/src/components/toggle/test/enable-on-off-labels/toggle.e2e.ts-snapshots/toggle-on-off-labels-color-ios-ltr-dark-Mobile-Chrome-linux.png differ diff --git a/core/src/components/toggle/test/enable-on-off-labels/toggle.e2e.ts-snapshots/toggle-on-off-labels-color-ios-rtl-Mobile-Chrome-linux.png b/core/src/components/toggle/test/enable-on-off-labels/toggle.e2e.ts-snapshots/toggle-on-off-labels-color-ios-rtl-Mobile-Chrome-linux.png index 6451895309f..2fda73f438f 100644 Binary files a/core/src/components/toggle/test/enable-on-off-labels/toggle.e2e.ts-snapshots/toggle-on-off-labels-color-ios-rtl-Mobile-Chrome-linux.png and b/core/src/components/toggle/test/enable-on-off-labels/toggle.e2e.ts-snapshots/toggle-on-off-labels-color-ios-rtl-Mobile-Chrome-linux.png differ diff --git a/core/src/components/toggle/test/enable-on-off-labels/toggle.e2e.ts-snapshots/toggle-on-off-labels-color-ios-rtl-dark-Mobile-Chrome-linux.png b/core/src/components/toggle/test/enable-on-off-labels/toggle.e2e.ts-snapshots/toggle-on-off-labels-color-ios-rtl-dark-Mobile-Chrome-linux.png index 5d091d0cf3f..cff9195471b 100644 Binary files a/core/src/components/toggle/test/enable-on-off-labels/toggle.e2e.ts-snapshots/toggle-on-off-labels-color-ios-rtl-dark-Mobile-Chrome-linux.png and b/core/src/components/toggle/test/enable-on-off-labels/toggle.e2e.ts-snapshots/toggle-on-off-labels-color-ios-rtl-dark-Mobile-Chrome-linux.png differ diff --git a/core/src/components/toggle/test/enable-on-off-labels/toggle.e2e.ts-snapshots/toggle-on-off-labels-ios-ltr-Mobile-Chrome-linux.png b/core/src/components/toggle/test/enable-on-off-labels/toggle.e2e.ts-snapshots/toggle-on-off-labels-ios-ltr-Mobile-Chrome-linux.png index 325ce8a11ba..45d2af6358e 100644 Binary files a/core/src/components/toggle/test/enable-on-off-labels/toggle.e2e.ts-snapshots/toggle-on-off-labels-ios-ltr-Mobile-Chrome-linux.png and b/core/src/components/toggle/test/enable-on-off-labels/toggle.e2e.ts-snapshots/toggle-on-off-labels-ios-ltr-Mobile-Chrome-linux.png differ diff --git a/core/src/components/toggle/test/enable-on-off-labels/toggle.e2e.ts-snapshots/toggle-on-off-labels-ios-ltr-dark-Mobile-Chrome-linux.png b/core/src/components/toggle/test/enable-on-off-labels/toggle.e2e.ts-snapshots/toggle-on-off-labels-ios-ltr-dark-Mobile-Chrome-linux.png index fb5eaa52dca..1a0137ea7e1 100644 Binary files a/core/src/components/toggle/test/enable-on-off-labels/toggle.e2e.ts-snapshots/toggle-on-off-labels-ios-ltr-dark-Mobile-Chrome-linux.png and b/core/src/components/toggle/test/enable-on-off-labels/toggle.e2e.ts-snapshots/toggle-on-off-labels-ios-ltr-dark-Mobile-Chrome-linux.png differ diff --git a/core/src/components/toggle/test/enable-on-off-labels/toggle.e2e.ts-snapshots/toggle-on-off-labels-ios-rtl-Mobile-Chrome-linux.png b/core/src/components/toggle/test/enable-on-off-labels/toggle.e2e.ts-snapshots/toggle-on-off-labels-ios-rtl-Mobile-Chrome-linux.png index 200fb61bbc3..9248bcf5636 100644 Binary files a/core/src/components/toggle/test/enable-on-off-labels/toggle.e2e.ts-snapshots/toggle-on-off-labels-ios-rtl-Mobile-Chrome-linux.png and b/core/src/components/toggle/test/enable-on-off-labels/toggle.e2e.ts-snapshots/toggle-on-off-labels-ios-rtl-Mobile-Chrome-linux.png differ diff --git a/core/src/components/toggle/test/enable-on-off-labels/toggle.e2e.ts-snapshots/toggle-on-off-labels-ios-rtl-dark-Mobile-Chrome-linux.png b/core/src/components/toggle/test/enable-on-off-labels/toggle.e2e.ts-snapshots/toggle-on-off-labels-ios-rtl-dark-Mobile-Chrome-linux.png index 1cf8830d5fb..f4949337d98 100644 Binary files a/core/src/components/toggle/test/enable-on-off-labels/toggle.e2e.ts-snapshots/toggle-on-off-labels-ios-rtl-dark-Mobile-Chrome-linux.png and b/core/src/components/toggle/test/enable-on-off-labels/toggle.e2e.ts-snapshots/toggle-on-off-labels-ios-rtl-dark-Mobile-Chrome-linux.png differ diff --git a/lerna.json b/lerna.json index f3c1de76b36..dec4d837282 100644 --- a/lerna.json +++ b/lerna.json @@ -3,5 +3,5 @@ "core", "packages/*" ], - "version": "8.8.10" + "version": "8.8.11" } \ No newline at end of file diff --git a/packages/angular-server/CHANGELOG.md b/packages/angular-server/CHANGELOG.md index a992b74e841..974a5f5215d 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.8.11](https://github.com/ionic-team/ionic-framework/compare/v8.8.10...v8.8.11) (2026-06-17) + +**Note:** Version bump only for package @ionic/angular-server + + + + + ## [8.8.10](https://github.com/ionic-team/ionic-framework/compare/v8.8.9...v8.8.10) (2026-06-10) **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 148f34be2b3..7b6b8e7b5f7 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.10", + "version": "8.8.11", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@ionic/angular-server", - "version": "8.8.10", + "version": "8.8.11", "license": "MIT", "dependencies": { - "@ionic/core": "^8.8.10" + "@ionic/core": "^8.8.11" }, "devDependencies": { "@angular/animations": "^22.0.0", @@ -1039,9 +1039,9 @@ "dev": true }, "node_modules/@ionic/core": { - "version": "8.8.10", - "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.8.10.tgz", - "integrity": "sha512-pNujZuU/vydXKtE3yOqmeOIySbXodspxuK4QcbRitWoikNZhGalqW2JvtEJqeRRvE4KJ4dJ3gXF8i6+rtVSG3Q==", + "version": "8.8.11", + "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.8.11.tgz", + "integrity": "sha512-+/uKZu3+ihAHBXl+EGrln+EW6v57VWqLICOHK4zahGy7SM9soq1PYLtG03DGsxqPt9ET7YwpX1B0ToU8/Ved3w==", "license": "MIT", "dependencies": { "@stencil/core": "4.43.5", @@ -7197,9 +7197,9 @@ "dev": true }, "@ionic/core": { - "version": "8.8.10", - "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.8.10.tgz", - "integrity": "sha512-pNujZuU/vydXKtE3yOqmeOIySbXodspxuK4QcbRitWoikNZhGalqW2JvtEJqeRRvE4KJ4dJ3gXF8i6+rtVSG3Q==", + "version": "8.8.11", + "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.8.11.tgz", + "integrity": "sha512-+/uKZu3+ihAHBXl+EGrln+EW6v57VWqLICOHK4zahGy7SM9soq1PYLtG03DGsxqPt9ET7YwpX1B0ToU8/Ved3w==", "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 7890541ba28..90227daecf8 100644 --- a/packages/angular-server/package.json +++ b/packages/angular-server/package.json @@ -1,6 +1,6 @@ { "name": "@ionic/angular-server", - "version": "8.8.10", + "version": "8.8.11", "description": "Angular SSR Module for Ionic", "keywords": [ "ionic", @@ -66,6 +66,6 @@ }, "prettier": "@ionic/prettier-config", "dependencies": { - "@ionic/core": "^8.8.10" + "@ionic/core": "^8.8.11" } } diff --git a/packages/angular/CHANGELOG.md b/packages/angular/CHANGELOG.md index f8d91e91c4c..4ff12da8dba 100644 --- a/packages/angular/CHANGELOG.md +++ b/packages/angular/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.8.11](https://github.com/ionic-team/ionic-framework/compare/v8.8.10...v8.8.11) (2026-06-17) + +**Note:** Version bump only for package @ionic/angular + + + + + ## [8.8.10](https://github.com/ionic-team/ionic-framework/compare/v8.8.9...v8.8.10) (2026-06-10) **Note:** Version bump only for package @ionic/angular diff --git a/packages/angular/package-lock.json b/packages/angular/package-lock.json index e9242489664..020225456f1 100644 --- a/packages/angular/package-lock.json +++ b/packages/angular/package-lock.json @@ -1,15 +1,15 @@ { "name": "@ionic/angular", - "version": "8.8.10", + "version": "8.8.11", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@ionic/angular", - "version": "8.8.10", + "version": "8.8.11", "license": "MIT", "dependencies": { - "@ionic/core": "^8.8.10", + "@ionic/core": "^8.8.11", "ionicons": "^8.0.13", "jsonc-parser": "^3.0.0", "tslib": "^2.3.0" @@ -2036,9 +2036,9 @@ } }, "node_modules/@ionic/core": { - "version": "8.8.10", - "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.8.10.tgz", - "integrity": "sha512-pNujZuU/vydXKtE3yOqmeOIySbXodspxuK4QcbRitWoikNZhGalqW2JvtEJqeRRvE4KJ4dJ3gXF8i6+rtVSG3Q==", + "version": "8.8.11", + "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.8.11.tgz", + "integrity": "sha512-+/uKZu3+ihAHBXl+EGrln+EW6v57VWqLICOHK4zahGy7SM9soq1PYLtG03DGsxqPt9ET7YwpX1B0ToU8/Ved3w==", "license": "MIT", "dependencies": { "@stencil/core": "4.43.5", diff --git a/packages/angular/package.json b/packages/angular/package.json index 4447f11e536..b0c07b6954e 100644 --- a/packages/angular/package.json +++ b/packages/angular/package.json @@ -1,6 +1,6 @@ { "name": "@ionic/angular", - "version": "8.8.10", + "version": "8.8.11", "description": "Angular specific wrappers for @ionic/core", "keywords": [ "ionic", @@ -48,7 +48,7 @@ } }, "dependencies": { - "@ionic/core": "^8.8.10", + "@ionic/core": "^8.8.11", "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 2f10b5d0085..5917f17868e 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.8.11](https://github.com/ionic-team/ionic-framework/compare/v8.8.10...v8.8.11) (2026-06-17) + +**Note:** Version bump only for package @ionic/docs + + + + + ## [8.8.10](https://github.com/ionic-team/ionic-framework/compare/v8.8.9...v8.8.10) (2026-06-10) **Note:** Version bump only for package @ionic/docs diff --git a/packages/docs/package-lock.json b/packages/docs/package-lock.json index ae6cfc74db0..7a0bbe2011b 100644 --- a/packages/docs/package-lock.json +++ b/packages/docs/package-lock.json @@ -1,12 +1,12 @@ { "name": "@ionic/docs", - "version": "8.8.10", + "version": "8.8.11", "lockfileVersion": 2, "requires": true, "packages": { "": { "name": "@ionic/docs", - "version": "8.8.10", + "version": "8.8.11", "license": "MIT" } } diff --git a/packages/docs/package.json b/packages/docs/package.json index c760e36b802..3e2a99476f8 100644 --- a/packages/docs/package.json +++ b/packages/docs/package.json @@ -1,6 +1,6 @@ { "name": "@ionic/docs", - "version": "8.8.10", + "version": "8.8.11", "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 36b1acb5f22..936acf7b80a 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.8.11](https://github.com/ionic-team/ionic-framework/compare/v8.8.10...v8.8.11) (2026-06-17) + +**Note:** Version bump only for package @ionic/react-router + + + + + ## [8.8.10](https://github.com/ionic-team/ionic-framework/compare/v8.8.9...v8.8.10) (2026-06-10) **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 1a74f5ec16b..17be19923ac 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.10", + "version": "8.8.11", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@ionic/react-router", - "version": "8.8.10", + "version": "8.8.11", "license": "MIT", "dependencies": { - "@ionic/react": "^8.8.10", + "@ionic/react": "^8.8.11", "tslib": "*" }, "devDependencies": { @@ -248,9 +248,9 @@ "license": "BSD-3-Clause" }, "node_modules/@ionic/core": { - "version": "8.8.10", - "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.8.10.tgz", - "integrity": "sha512-pNujZuU/vydXKtE3yOqmeOIySbXodspxuK4QcbRitWoikNZhGalqW2JvtEJqeRRvE4KJ4dJ3gXF8i6+rtVSG3Q==", + "version": "8.8.11", + "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.8.11.tgz", + "integrity": "sha512-+/uKZu3+ihAHBXl+EGrln+EW6v57VWqLICOHK4zahGy7SM9soq1PYLtG03DGsxqPt9ET7YwpX1B0ToU8/Ved3w==", "license": "MIT", "dependencies": { "@stencil/core": "4.43.5", @@ -437,12 +437,12 @@ } }, "node_modules/@ionic/react": { - "version": "8.8.10", - "resolved": "https://registry.npmjs.org/@ionic/react/-/react-8.8.10.tgz", - "integrity": "sha512-jPxh1yIhUjzY8PEErmTAl/yjbnJzLfQ7B/DZy0qhQtmTU33w8frNz9bGFMBpQqaK7XAAkUiAOUrkR33H9h+hqg==", + "version": "8.8.11", + "resolved": "https://registry.npmjs.org/@ionic/react/-/react-8.8.11.tgz", + "integrity": "sha512-ZDuF8ZQNWsZqw2hxlpNqlOWmTf/vvlTiT5c8oSqX4+A7Jw6YHj+E81MM34Z80RecJYNff7BC/Jjb2THVJwbY+g==", "license": "MIT", "dependencies": { - "@ionic/core": "8.8.10", + "@ionic/core": "8.8.11", "ionicons": "^8.0.13", "tslib": "*" }, @@ -666,6 +666,9 @@ "cpu": [ "arm64" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -679,6 +682,9 @@ "cpu": [ "arm64" ], + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ @@ -762,6 +768,9 @@ "cpu": [ "x64" ], + "libc": [ + "glibc" + ], "license": "MIT", "optional": true, "os": [ @@ -775,6 +784,9 @@ "cpu": [ "x64" ], + "libc": [ + "musl" + ], "license": "MIT", "optional": true, "os": [ diff --git a/packages/react-router/package.json b/packages/react-router/package.json index 01250d92294..3550f501b7c 100644 --- a/packages/react-router/package.json +++ b/packages/react-router/package.json @@ -1,6 +1,6 @@ { "name": "@ionic/react-router", - "version": "8.8.10", + "version": "8.8.11", "description": "React Router wrapper for @ionic/react", "keywords": [ "ionic", @@ -36,7 +36,7 @@ "dist/" ], "dependencies": { - "@ionic/react": "^8.8.10", + "@ionic/react": "^8.8.11", "tslib": "*" }, "peerDependencies": { diff --git a/packages/react/CHANGELOG.md b/packages/react/CHANGELOG.md index e382826a167..ad89385c351 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.8.11](https://github.com/ionic-team/ionic-framework/compare/v8.8.10...v8.8.11) (2026-06-17) + + +### Bug Fixes + +* **react:** remove relocated inline overlays orphaned on unmount ([#31223](https://github.com/ionic-team/ionic-framework/issues/31223)) ([d28d25b](https://github.com/ionic-team/ionic-framework/commit/d28d25b798d32db6148155bb34fdbd13243286d9)) + + + + + ## [8.8.10](https://github.com/ionic-team/ionic-framework/compare/v8.8.9...v8.8.10) (2026-06-10) **Note:** Version bump only for package @ionic/react diff --git a/packages/react/package-lock.json b/packages/react/package-lock.json index 4f4ff7b3cb1..7e3997fd897 100644 --- a/packages/react/package-lock.json +++ b/packages/react/package-lock.json @@ -1,15 +1,15 @@ { "name": "@ionic/react", - "version": "8.8.10", + "version": "8.8.11", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@ionic/react", - "version": "8.8.10", + "version": "8.8.11", "license": "MIT", "dependencies": { - "@ionic/core": "^8.8.10", + "@ionic/core": "^8.8.11", "@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.10", - "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.8.10.tgz", - "integrity": "sha512-pNujZuU/vydXKtE3yOqmeOIySbXodspxuK4QcbRitWoikNZhGalqW2JvtEJqeRRvE4KJ4dJ3gXF8i6+rtVSG3Q==", + "version": "8.8.11", + "resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.8.11.tgz", + "integrity": "sha512-+/uKZu3+ihAHBXl+EGrln+EW6v57VWqLICOHK4zahGy7SM9soq1PYLtG03DGsxqPt9ET7YwpX1B0ToU8/Ved3w==", "license": "MIT", "dependencies": { "@stencil/core": "4.43.5", diff --git a/packages/react/package.json b/packages/react/package.json index 0154f86c9c6..da24251b11d 100644 --- a/packages/react/package.json +++ b/packages/react/package.json @@ -1,6 +1,6 @@ { "name": "@ionic/react", - "version": "8.8.10", + "version": "8.8.11", "description": "React specific wrapper for @ionic/core", "keywords": [ "ionic", @@ -40,7 +40,7 @@ "css/" ], "dependencies": { - "@ionic/core": "^8.8.10", + "@ionic/core": "^8.8.11", "@stencil/react-output-target": "^1.5.2", "ionicons": "^8.0.13", "tslib": "*" diff --git a/packages/react/src/components/__tests__/createInlineOverlayComponent.spec.tsx b/packages/react/src/components/__tests__/createInlineOverlayComponent.spec.tsx new file mode 100644 index 00000000000..e2cb8176af8 --- /dev/null +++ b/packages/react/src/components/__tests__/createInlineOverlayComponent.spec.tsx @@ -0,0 +1,155 @@ +/** + * Mock the `@ionic/core/components` ESM boundary so Jest can load the wrapper. + * Jest can't import Ionic's ESM-only custom elements, so we stub the few + * values `createInlineOverlayComponent` reaches: `componentOnReady` (used to + * redirect `cachedOriginalParent` after mount) and `getPlatforms`/`isPlatform` + * (pulled in transitively via `./utils`). + */ +jest.mock('@ionic/core/components', () => ({ + // Delegates to a mutable hook so individual tests can run side effects + // (e.g. teleporting the host) at the moment the overlay comes online. + componentOnReady: (el: HTMLElement, cb: () => void) => mockComponentOnReady(el, cb), + getPlatforms: () => [], + isPlatform: () => false, +})); + +import { act, render } from '@testing-library/react'; +import React from 'react'; + +import { createInlineOverlayComponent } from '../createInlineOverlayComponent'; + +// Default: resolve immediately, no side effects. Reset in `afterEach`. +// `mock` prefix lets the `jest.mock` factory reference it despite hoisting. +const defaultComponentOnReady = (_el: HTMLElement, cb: () => void) => cb(); +let mockComponentOnReady = defaultComponentOnReady; + +// Mirror how `IonModal` is generated: a delegate-host overlay. +const IonModal = createInlineOverlayComponent('ion-modal', undefined, true) as any; +// An overlay rendered inside another overlay observes the nested context. +const IonPopover = createInlineOverlayComponent('ion-popover', undefined, true) as any; + +/** + * Simulate what CoreDelegate does when an overlay presents: it teleports the + * host element out of its portal parent into another in-document container + * (the running app uses ion-app; here we use any sibling). + */ +const teleport = (el: HTMLElement) => { + const dest = document.createElement('div'); + dest.id = 'teleport-destination'; + document.body.appendChild(dest); + dest.appendChild(el); +}; + +afterEach(() => { + document.body.innerHTML = ''; + mockComponentOnReady = defaultComponentOnReady; +}); + +describe('createInlineOverlayComponent: unmount cleanup', () => { + it('removes a relocated overlay on unmount even when it never opened', () => { + const { unmount } = render(); + + const modal = document.body.querySelector('ion-modal') as HTMLElement; + expect(modal).toBeTruthy(); + + // Overlay is teleported while still closed (isOpen === false). + teleport(modal); + + unmount(); + + expect(document.querySelector('ion-modal')).toBeNull(); + }); + + it('removes a normally-portaled overlay on unmount (no relocation)', () => { + const { unmount } = render(); + + expect(document.body.querySelector('ion-modal')).toBeTruthy(); + + unmount(); + + expect(document.querySelector('ion-modal')).toBeNull(); + }); + + it('removes an open, relocated overlay on unmount', () => { + const { unmount } = render(); + const modal = document.body.querySelector('ion-modal') as HTMLElement; + + // Drive the overlay to its open state the way core does, then teleport it. + act(() => { + modal.dispatchEvent(new CustomEvent('willPresent')); + }); + teleport(modal); + + unmount(); + + expect(document.querySelector('ion-modal')).toBeNull(); + }); + + it('does not orphan a relocated overlay across a StrictMode mount/unmount cycle', () => { + /** + * React 18 StrictMode mounts, unmounts, then remounts each component in + * dev to surface unsafe state reuse. CoreDelegate teleports the host out + * of its portal parent as the overlay comes online (simulated here from + * componentOnReady, which fires in componentDidMount). At the first + * StrictMode unmount the host is relocated but still closed - exactly the + * case that previously left an orphan behind, producing a duplicate + * `` in the DOM. + */ + mockComponentOnReady = (el, cb) => { + teleport(el); + cb(); + }; + + render( + + + + ); + + // Only the surviving remount's host should remain. The discarded first + // mount must not leave an orphan. + expect(document.querySelectorAll('ion-modal')).toHaveLength(1); + }); + + it('removes a relocated nested overlay on unmount even when it never opened', () => { + // keepContentsMounted renders the children (and the nested popover) while + // the outer modal is closed, so the popover observes the nested context. + const { unmount } = render( + + + + ); + + const popover = document.body.querySelector('ion-popover') as HTMLElement; + expect(popover).toBeTruthy(); + + // Nested overlay is teleported while still closed. + teleport(popover); + + unmount(); + + expect(document.querySelector('ion-popover')).toBeNull(); + }); + + it('removes an open, relocated nested overlay on unmount', () => { + const { unmount } = render( + + + + ); + + const popover = document.body.querySelector('ion-popover') as HTMLElement; + + // Drive the nested popover open the way core does, then teleport it out of + // its `