chore(git): sync main (#30858)

Syncing Major 9.0 with main
This commit is contained in:
Shane
2025-12-10 14:04:57 -08:00
committed by GitHub
39 changed files with 615 additions and 110 deletions

View File

@@ -3,6 +3,20 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [8.7.12](https://github.com/ionic-team/ionic-framework/compare/v8.7.11...v8.7.12) (2025-12-10)
### Bug Fixes
* **modal:** allow interaction with parent content through sheet modals in child routes ([#30839](https://github.com/ionic-team/ionic-framework/issues/30839)) ([b9e3cf0](https://github.com/ionic-team/ionic-framework/commit/b9e3cf0f5aae79a1f27a07b102c77e51f24825f4)), closes [#30700](https://github.com/ionic-team/ionic-framework/issues/30700)
* **modal:** prevent browser hang when using ModalController in Angular ([#30845](https://github.com/ionic-team/ionic-framework/issues/30845)) ([b164516](https://github.com/ionic-team/ionic-framework/commit/b1645168a7fb9378dc39a081c207b2de0e180089))
* **popover:** recalculate the content dimensions after the header has fully loaded ([#30853](https://github.com/ionic-team/ionic-framework/issues/30853)) ([99dcf38](https://github.com/ionic-team/ionic-framework/commit/99dcf3810a0c32416996d1e992ddf63359965cfc))
* **select, action-sheet:** use radio role for options ([#30769](https://github.com/ionic-team/ionic-framework/issues/30769)) ([1c89cf0](https://github.com/ionic-team/ionic-framework/commit/1c89cf06ac959f9c9a35a66f811227c244d3198b))
## [8.7.11](https://github.com/ionic-team/ionic-framework/compare/v8.7.10...v8.7.11) (2025-11-26)

View File

@@ -3,6 +3,20 @@
All notable changes to this project will be documented in this file.
See [Conventional Commits](https://conventionalcommits.org) for commit guidelines.
## [8.7.12](https://github.com/ionic-team/ionic-framework/compare/v8.7.11...v8.7.12) (2025-12-10)
### Bug Fixes
* **modal:** allow interaction with parent content through sheet modals in child routes ([#30839](https://github.com/ionic-team/ionic-framework/issues/30839)) ([b9e3cf0](https://github.com/ionic-team/ionic-framework/commit/b9e3cf0f5aae79a1f27a07b102c77e51f24825f4)), closes [#30700](https://github.com/ionic-team/ionic-framework/issues/30700)
* **modal:** prevent browser hang when using ModalController in Angular ([#30845](https://github.com/ionic-team/ionic-framework/issues/30845)) ([b164516](https://github.com/ionic-team/ionic-framework/commit/b1645168a7fb9378dc39a081c207b2de0e180089))
* **popover:** recalculate the content dimensions after the header has fully loaded ([#30853](https://github.com/ionic-team/ionic-framework/issues/30853)) ([99dcf38](https://github.com/ionic-team/ionic-framework/commit/99dcf3810a0c32416996d1e992ddf63359965cfc))
* **select, action-sheet:** use radio role for options ([#30769](https://github.com/ionic-team/ionic-framework/issues/30769)) ([1c89cf0](https://github.com/ionic-team/ionic-framework/commit/1c89cf06ac959f9c9a35a66f811227c244d3198b))
## [8.7.11](https://github.com/ionic-team/ionic-framework/compare/v8.7.10...v8.7.11) (2025-11-26)

44
core/package-lock.json generated
View File

@@ -1,12 +1,12 @@
{
"name": "@ionic/core",
"version": "8.7.11",
"version": "8.7.12",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@ionic/core",
"version": "8.7.11",
"version": "8.7.12",
"license": "MIT",
"dependencies": {
"@stencil/core": "4.38.0",
@@ -50,6 +50,9 @@
"serve": "^14.0.1",
"stylelint": "^13.13.1",
"stylelint-order": "^4.1.0"
},
"engines": {
"node": "24.x"
}
},
"custom-rules": {
@@ -91,7 +94,6 @@
"version": "7.16.12",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/code-frame": "^7.16.7",
"@babel/generator": "^7.16.8",
@@ -629,7 +631,6 @@
"version": "7.4.4",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"tslib": "^2.1.0"
}
@@ -861,7 +862,6 @@
"version": "4.33.0",
"dev": true,
"license": "BSD-2-Clause",
"peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "4.33.0",
"@typescript-eslint/types": "4.33.0",
@@ -1799,7 +1799,6 @@
"node_modules/@stencil/core": {
"version": "4.38.0",
"license": "MIT",
"peer": true,
"bin": {
"stencil": "bin/stencil"
},
@@ -2224,7 +2223,6 @@
"version": "6.7.2",
"dev": true,
"license": "BSD-2-Clause",
"peer": true,
"dependencies": {
"@typescript-eslint/scope-manager": "6.7.2",
"@typescript-eslint/types": "6.7.2",
@@ -2450,6 +2448,7 @@
"integrity": "sha512-vay5/oQJdsNHmliWoZfHPoVZZRmnSWhug0BYT34njkYTPqClh3DNWLkZNJBVSjsNMrg0CCrBfoKkjZQPM/QVUw==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/parser": "^7.28.5",
"@vue/shared": "3.5.25",
@@ -2464,6 +2463,7 @@
"integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==",
"dev": true,
"license": "BSD-2-Clause",
"peer": true,
"engines": {
"node": ">=0.12"
},
@@ -2476,7 +2476,8 @@
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
"dev": true,
"license": "MIT"
"license": "MIT",
"peer": true
},
"node_modules/@vue/compiler-dom": {
"version": "3.5.25",
@@ -2484,6 +2485,7 @@
"integrity": "sha512-4We0OAcMZsKgYoGlMjzYvaoErltdFI2/25wqanuTu+S4gismOTRTBPi4IASOjxWdzIwrYSjnqONfKvuqkXzE2Q==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@vue/compiler-core": "3.5.25",
"@vue/shared": "3.5.25"
@@ -2495,6 +2497,7 @@
"integrity": "sha512-PUgKp2rn8fFsI++lF2sO7gwO2d9Yj57Utr5yEsDf3GNaQcowCLKL7sf+LvVFvtJDXUp/03+dC6f2+LCv5aK1ag==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/parser": "^7.28.5",
"@vue/compiler-core": "3.5.25",
@@ -2512,7 +2515,8 @@
"resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz",
"integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==",
"dev": true,
"license": "MIT"
"license": "MIT",
"peer": true
},
"node_modules/@vue/compiler-sfc/node_modules/postcss": {
"version": "8.5.6",
@@ -2534,6 +2538,7 @@
}
],
"license": "MIT",
"peer": true,
"dependencies": {
"nanoid": "^3.3.11",
"picocolors": "^1.1.1",
@@ -2549,6 +2554,7 @@
"integrity": "sha512-ritPSKLBcParnsKYi+GNtbdbrIE1mtuFEJ4U1sWeuOMlIziK5GtOL85t5RhsNy4uWIXPgk+OUdpnXiTdzn8o3A==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@vue/compiler-dom": "3.5.25",
"@vue/shared": "3.5.25"
@@ -2560,6 +2566,7 @@
"integrity": "sha512-5xfAypCQepv4Jog1U4zn8cZIcbKKFka3AgWHEFQeK65OW+Ys4XybP6z2kKgws4YB43KGpqp5D/K3go2UPPunLA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@vue/shared": "3.5.25"
}
@@ -2570,6 +2577,7 @@
"integrity": "sha512-Z751v203YWwYzy460bzsYQISDfPjHTl+6Zzwo/a3CsAf+0ccEjQ8c+0CdX1WsumRTHeywvyUFtW6KvNukT/smA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@vue/reactivity": "3.5.25",
"@vue/shared": "3.5.25"
@@ -2581,6 +2589,7 @@
"integrity": "sha512-a4WrkYFbb19i9pjkz38zJBg8wa/rboNERq3+hRRb0dHiJh13c+6kAbgqCPfMaJ2gg4weWD3APZswASOfmKwamA==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@vue/reactivity": "3.5.25",
"@vue/runtime-core": "3.5.25",
@@ -2594,6 +2603,7 @@
"integrity": "sha512-UJaXR54vMG61i8XNIzTSf2Q7MOqZHpp8+x3XLGtE3+fL+nQd+k7O5+X3D/uWrnQXOdMw5VPih+Uremcw+u1woQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@vue/compiler-ssr": "3.5.25",
"@vue/shared": "3.5.25"
@@ -2607,7 +2617,8 @@
"resolved": "https://registry.npmjs.org/@vue/shared/-/shared-3.5.25.tgz",
"integrity": "sha512-AbOPdQQnAnzs58H2FrrDxYj/TJfmeS2jdfEEhgiKINy+bnOANmVizIEgq1r+C5zsbs6l1CCQxtcj71rwNQ4jWg==",
"dev": true,
"license": "MIT"
"license": "MIT",
"peer": true
},
"node_modules/@zeit/schemas": {
"version": "2.21.0",
@@ -2630,7 +2641,6 @@
"version": "7.4.0",
"dev": true,
"license": "MIT",
"peer": true,
"bin": {
"acorn": "bin/acorn"
},
@@ -3791,7 +3801,8 @@
"resolved": "https://registry.npmjs.org/csstype/-/csstype-3.2.3.tgz",
"integrity": "sha512-z1HGKcYy2xA8AGQfwrn0PAy+PB7X/GSj3UVJW9qKyn43xWa+gl5nXmU4qqLMRzWVLFC8KusUX8T/0kCiOYpAIQ==",
"dev": true,
"license": "MIT"
"license": "MIT",
"peer": true
},
"node_modules/debug": {
"version": "2.6.9",
@@ -4085,7 +4096,6 @@
"version": "7.32.0",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@babel/code-frame": "7.12.11",
"@eslint/eslintrc": "^0.4.3",
@@ -7281,6 +7291,7 @@
"integrity": "sha512-vd2F4YUyEXKGcLHoq+TEyCjxueSeHnFxyyjNp80yg0XV4vUhnDer/lvvlqM/arB5bXQN5K2/3oinyCRyx8T2CQ==",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"@jridgewell/sourcemap-codec": "^1.5.5"
}
@@ -7602,6 +7613,7 @@
}
],
"license": "MIT",
"peer": true,
"bin": {
"nanoid": "bin/nanoid.cjs"
},
@@ -7956,7 +7968,6 @@
"integrity": "sha512-hutraynyn31F+Bifme+Ps9Vq59hKuUCz7H1kDOcBs+2oGguKkWTU50bBWrtz34OUWmIwpBTWDxaRPXrIXkgvmQ==",
"dev": true,
"license": "Apache-2.0",
"peer": true,
"bin": {
"playwright-core": "cli.js"
},
@@ -7968,7 +7979,6 @@
"version": "7.0.35",
"dev": true,
"license": "MIT",
"peer": true,
"dependencies": {
"chalk": "^2.4.2",
"source-map": "^0.6.1",
@@ -8074,7 +8084,6 @@
"version": "0.36.2",
"dev": true,
"license": "MIT",
"peer": true,
"peerDependencies": {
"postcss": ">=5.0.0"
}
@@ -8123,7 +8132,6 @@
"version": "2.6.1",
"dev": true,
"license": "MIT",
"peer": true,
"bin": {
"prettier": "bin-prettier.js"
},
@@ -8481,7 +8489,6 @@
"version": "2.35.1",
"dev": true,
"license": "MIT",
"peer": true,
"bin": {
"rollup": "dist/bin/rollup"
},
@@ -8703,6 +8710,7 @@
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
"dev": true,
"license": "BSD-3-Clause",
"peer": true,
"engines": {
"node": ">=0.10.0"
}

View File

@@ -1,6 +1,6 @@
{
"name": "@ionic/core",
"version": "8.7.11",
"version": "8.7.12",
"description": "Base components for Ionic",
"engines": {
"node": "24.x"

View File

@@ -71,7 +71,7 @@ export class Modal implements ComponentInterface, OverlayInterface {
private gesture?: Gesture;
private coreDelegate: FrameworkDelegate = CoreDelegate();
private sheetTransition?: Promise<any>;
private isSheetModal = false;
@State() private isSheetModal = false;
private currentBreakpoint?: number;
private wrapperEl?: HTMLElement;
private backdropEl?: HTMLIonBackdropElement;
@@ -100,6 +100,8 @@ export class Modal implements ComponentInterface, OverlayInterface {
private parentRemovalObserver?: MutationObserver;
// Cached original parent from before modal is moved to body during presentation
private cachedOriginalParent?: HTMLElement;
// Cached ion-page ancestor for child route passthrough
private cachedPageParent?: HTMLElement | null;
lastFocus?: HTMLElement;
animation?: Animation;
@@ -644,7 +646,14 @@ export class Modal implements ComponentInterface, OverlayInterface {
window.addEventListener(KEYBOARD_DID_OPEN, this.keyboardOpenCallback);
}
if (this.isSheetModal) {
/**
* Recalculate isSheetModal because framework bindings (e.g., Angular)
* may not have been applied when componentWillLoad ran.
*/
const isSheetModal = this.breakpoints !== undefined && this.initialBreakpoint !== undefined;
this.isSheetModal = isSheetModal;
if (isSheetModal) {
this.initSheetGesture();
} else if (hasCardModal) {
this.initSwipeToClose();
@@ -753,6 +762,91 @@ export class Modal implements ComponentInterface, OverlayInterface {
this.moveSheetToBreakpoint = moveSheetToBreakpoint;
this.gesture.enable(true);
/**
* When backdrop interaction is allowed, nested router outlets from child routes
* may block pointer events to parent content. Apply passthrough styles only when
* the modal was the sole content of a child route page.
* See https://github.com/ionic-team/ionic-framework/issues/30700
*/
const backdropNotBlocking = this.showBackdrop === false || this.focusTrap === false || backdropBreakpoint > 0;
if (backdropNotBlocking) {
this.setupChildRoutePassthrough();
}
}
/**
* For sheet modals that allow background interaction, sets up pointer-events
* passthrough on child route page wrappers and nested router outlets.
*/
private setupChildRoutePassthrough() {
// Cache the page parent for cleanup
this.cachedPageParent = this.getOriginalPageParent();
const pageParent = this.cachedPageParent;
// Skip ion-app (controller modals) and pages with visible sibling content next to the modal
if (!pageParent || pageParent.tagName === 'ION-APP') {
return;
}
const hasVisibleContent = Array.from(pageParent.children).some(
(child) =>
child !== this.el &&
!(child instanceof HTMLElement && window.getComputedStyle(child).display === 'none') &&
child.tagName !== 'TEMPLATE' &&
child.tagName !== 'SLOT' &&
!(child.nodeType === Node.TEXT_NODE && !child.textContent?.trim())
);
if (hasVisibleContent) {
return;
}
// Child route case: page only contained the modal
pageParent.classList.add('ion-page-overlay-passthrough');
// Also make nested router outlets passthrough
const routerOutlet = pageParent.parentElement;
if (routerOutlet?.tagName === 'ION-ROUTER-OUTLET' && routerOutlet.parentElement?.tagName !== 'ION-APP') {
routerOutlet.style.setProperty('pointer-events', 'none');
routerOutlet.setAttribute('data-overlay-passthrough', 'true');
}
}
/**
* Finds the ion-page ancestor of the modal's original parent location.
*/
private getOriginalPageParent(): HTMLElement | null {
if (!this.cachedOriginalParent) {
return null;
}
let pageParent: HTMLElement | null = this.cachedOriginalParent;
while (pageParent && !pageParent.classList.contains('ion-page')) {
pageParent = pageParent.parentElement;
}
return pageParent;
}
/**
* Removes passthrough styles added by setupChildRoutePassthrough.
*/
private cleanupChildRoutePassthrough() {
const pageParent = this.cachedPageParent;
if (!pageParent) {
return;
}
pageParent.classList.remove('ion-page-overlay-passthrough');
const routerOutlet = pageParent.parentElement;
if (routerOutlet?.hasAttribute('data-overlay-passthrough')) {
routerOutlet.style.removeProperty('pointer-events');
routerOutlet.removeAttribute('data-overlay-passthrough');
}
// Clear the cached reference
this.cachedPageParent = undefined;
}
private sheetOnDismiss() {
@@ -862,6 +956,8 @@ export class Modal implements ComponentInterface, OverlayInterface {
}
this.cleanupViewTransitionListener();
this.cleanupParentRemovalObserver();
this.cleanupChildRoutePassthrough();
}
this.currentBreakpoint = undefined;
this.animation = undefined;
@@ -1183,6 +1279,20 @@ export class Modal implements ComponentInterface, OverlayInterface {
return;
}
/**
* Don't observe for controller-based modals or when the parent is the
* app root (document.body or ion-app). These parents won't be removed,
* and observing document.body with subtree: true causes performance
* issues with frameworks like Angular during change detection.
*/
if (
this.hasController ||
this.cachedOriginalParent === document.body ||
this.cachedOriginalParent.tagName === 'ION-APP'
) {
return;
}
this.parentRemovalObserver = new MutationObserver((mutations) => {
mutations.forEach((mutation) => {
if (mutation.type === 'childList' && mutation.removedNodes.length > 0) {

View File

@@ -1,6 +1,6 @@
import { expect } from '@playwright/test';
import { configs, test, Viewports } from '@utils/test/playwright';
import type { E2EPage } from '@utils/test/playwright';
import { configs, test, Viewports } from '@utils/test/playwright';
configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => {
test.describe(title('modal: focus trapping'), () => {
@@ -104,6 +104,28 @@ configs().forEach(({ title, screenshot, config }) => {
});
configs({ modes: ['ios'], directions: ['ltr'] }).forEach(({ title, config }) => {
test.describe(title('modal: parent removal observer'), () => {
test('should not set up parentRemovalObserver for controller-created modals', async ({ page }, testInfo) => {
testInfo.annotations.push({
type: 'issue',
description: 'FW-6766',
});
await page.goto('/src/components/modal/test/basic', config);
const ionModalDidPresent = await page.spyOnEvent('ionModalDidPresent');
await page.click('#basic-modal');
await ionModalDidPresent.next();
const modal = page.locator('ion-modal');
const hasObserver = await modal.evaluate((el: any) => {
return el.parentRemovalObserver !== undefined;
});
expect(hasObserver).toBe(false);
});
});
test.describe(title('modal: backdrop'), () => {
test.beforeEach(async ({ page }) => {
await page.goto('/src/components/modal/test/basic', config);

View File

@@ -181,6 +181,15 @@ html.ios ion-modal.modal-card .ion-page {
z-index: $z-index-page-container;
}
/**
* Allows pointer events to pass through child route page wrappers
* when they only contain a sheet modal that permits background interaction.
* https://github.com/ionic-team/ionic-framework/issues/30700
*/
.ion-page.ion-page-overlay-passthrough {
pointer-events: none;
}
/**
* When making custom dialogs, using
* ion-content is not required. As a result,

View File

@@ -38,6 +38,20 @@ let lastId = 0;
export const activeAnimations = new WeakMap<OverlayInterface, Animation[]>();
type OverlayWithFocusTrapProps = HTMLIonOverlayElement & {
focusTrap?: boolean;
showBackdrop?: boolean;
backdropBreakpoint?: number;
};
/**
* Determines if the overlay's backdrop is always blocking (no background interaction).
* Returns false if showBackdrop=false or backdropBreakpoint > 0.
*/
const isBackdropAlwaysBlocking = (el: OverlayWithFocusTrapProps): boolean => {
return el.showBackdrop !== false && !((el.backdropBreakpoint ?? 0) > 0);
};
const createController = <Opts extends object, HTMLElm>(tagName: string) => {
return {
create(options: Opts): Promise<HTMLElm> {
@@ -539,11 +553,9 @@ export const present = async <OverlayPresentOptions>(
* view container subtree, skip adding aria-hidden/inert there
* to avoid disabling the overlay.
*/
const overlayEl = overlay.el as HTMLIonOverlayElement & { focusTrap?: boolean; showBackdrop?: boolean };
const overlayEl = overlay.el as OverlayWithFocusTrapProps;
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;
const shouldLockRoot = shouldTrapFocus && isBackdropAlwaysBlocking(overlayEl);
overlay.presented = true;
overlay.willPresent.emit();
@@ -680,12 +692,12 @@ export const dismiss = async <OverlayDismissOptions>(
* is dismissed.
*/
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 el = o as OverlayWithFocusTrapProps;
return el.tagName !== 'ION-TOAST' && el.focusTrap !== false && isBackdropAlwaysBlocking(el);
});
const overlayEl = overlay.el as HTMLIonOverlayElement & { focusTrap?: boolean; showBackdrop?: boolean };
const overlayEl = overlay.el as OverlayWithFocusTrapProps;
const locksRoot =
overlayEl.tagName !== 'ION-TOAST' && overlayEl.focusTrap !== false && overlayEl.showBackdrop !== false;
overlayEl.tagName !== 'ION-TOAST' && overlayEl.focusTrap !== false && isBackdropAlwaysBlocking(overlayEl);
/**
* If this is the last visible overlay that is trapping focus

View File

@@ -3,5 +3,5 @@
"core",
"packages/*"
],
"version": "8.7.11"
"version": "8.7.12"
}

View File

@@ -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.12](https://github.com/ionic-team/ionic-framework/compare/v8.7.11...v8.7.12) (2025-12-10)
**Note:** Version bump only for package @ionic/angular-server
## [8.7.11](https://github.com/ionic-team/ionic-framework/compare/v8.7.10...v8.7.11) (2025-11-26)
**Note:** Version bump only for package @ionic/angular-server

View File

@@ -1,15 +1,15 @@
{
"name": "@ionic/angular-server",
"version": "8.7.11",
"version": "8.7.12",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@ionic/angular-server",
"version": "8.7.11",
"version": "8.7.12",
"license": "MIT",
"dependencies": {
"@ionic/core": "^8.7.11"
"@ionic/core": "^8.7.12"
},
"devDependencies": {
"@angular-eslint/eslint-plugin": "^16.0.0",
@@ -1031,14 +1031,17 @@
"dev": true
},
"node_modules/@ionic/core": {
"version": "8.7.11",
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.7.11.tgz",
"integrity": "sha512-9UX9IeEztWWXymi+xCUMEBnnY+TbaR8crZLOwFnxPUEq4FFWSUCSv5XeHHQBpgZjBO2MJuDGcNv0GCQumIjVcQ==",
"version": "8.7.12",
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.7.12.tgz",
"integrity": "sha512-+QnytOHsMMDEz45hi/t9AN8ATaWMNZ7jNdx621BGSHi0JkEl1c4NylL3cfYIPJ/78y40ZG5NzprwNiR9sXdswg==",
"license": "MIT",
"dependencies": {
"@stencil/core": "4.38.0",
"ionicons": "^8.0.13",
"tslib": "^2.1.0"
},
"engines": {
"node": "24.x"
}
},
"node_modules/@ionic/eslint-config": {
@@ -7306,9 +7309,9 @@
"dev": true
},
"@ionic/core": {
"version": "8.7.11",
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.7.11.tgz",
"integrity": "sha512-9UX9IeEztWWXymi+xCUMEBnnY+TbaR8crZLOwFnxPUEq4FFWSUCSv5XeHHQBpgZjBO2MJuDGcNv0GCQumIjVcQ==",
"version": "8.7.12",
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.7.12.tgz",
"integrity": "sha512-+QnytOHsMMDEz45hi/t9AN8ATaWMNZ7jNdx621BGSHi0JkEl1c4NylL3cfYIPJ/78y40ZG5NzprwNiR9sXdswg==",
"requires": {
"@stencil/core": "4.38.0",
"ionicons": "^8.0.13",

View File

@@ -1,6 +1,6 @@
{
"name": "@ionic/angular-server",
"version": "8.7.11",
"version": "8.7.12",
"description": "Angular SSR Module for Ionic",
"keywords": [
"ionic",
@@ -62,6 +62,6 @@
},
"prettier": "@ionic/prettier-config",
"dependencies": {
"@ionic/core": "^8.7.11"
"@ionic/core": "^8.7.12"
}
}

View File

@@ -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.12](https://github.com/ionic-team/ionic-framework/compare/v8.7.11...v8.7.12) (2025-12-10)
### Bug Fixes
* **modal:** allow interaction with parent content through sheet modals in child routes ([#30839](https://github.com/ionic-team/ionic-framework/issues/30839)) ([b9e3cf0](https://github.com/ionic-team/ionic-framework/commit/b9e3cf0f5aae79a1f27a07b102c77e51f24825f4)), closes [#30700](https://github.com/ionic-team/ionic-framework/issues/30700)
## [8.7.11](https://github.com/ionic-team/ionic-framework/compare/v8.7.10...v8.7.11) (2025-11-26)
**Note:** Version bump only for package @ionic/angular

View File

@@ -1,15 +1,15 @@
{
"name": "@ionic/angular",
"version": "8.7.11",
"version": "8.7.12",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@ionic/angular",
"version": "8.7.11",
"version": "8.7.12",
"license": "MIT",
"dependencies": {
"@ionic/core": "^8.7.11",
"@ionic/core": "^8.7.12",
"ionicons": "^8.0.13",
"jsonc-parser": "^3.0.0",
"tslib": "^2.3.0"
@@ -1398,14 +1398,17 @@
"dev": true
},
"node_modules/@ionic/core": {
"version": "8.7.11",
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.7.11.tgz",
"integrity": "sha512-9UX9IeEztWWXymi+xCUMEBnnY+TbaR8crZLOwFnxPUEq4FFWSUCSv5XeHHQBpgZjBO2MJuDGcNv0GCQumIjVcQ==",
"version": "8.7.12",
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.7.12.tgz",
"integrity": "sha512-+QnytOHsMMDEz45hi/t9AN8ATaWMNZ7jNdx621BGSHi0JkEl1c4NylL3cfYIPJ/78y40ZG5NzprwNiR9sXdswg==",
"license": "MIT",
"dependencies": {
"@stencil/core": "4.38.0",
"ionicons": "^8.0.13",
"tslib": "^2.1.0"
},
"engines": {
"node": "24.x"
}
},
"node_modules/@ionic/eslint-config": {

View File

@@ -1,6 +1,6 @@
{
"name": "@ionic/angular",
"version": "8.7.11",
"version": "8.7.12",
"description": "Angular specific wrappers for @ionic/core",
"keywords": [
"ionic",
@@ -48,7 +48,7 @@
}
},
"dependencies": {
"@ionic/core": "^8.7.11",
"@ionic/core": "^8.7.12",
"ionicons": "^8.0.13",
"jsonc-parser": "^3.0.0",
"tslib": "^2.3.0"

View File

@@ -0,0 +1,38 @@
import { expect, test } from '@playwright/test';
/**
* Tests for sheet modals in child routes with showBackdrop=false.
* Parent has buttons + nested outlet; child route contains only the modal.
* See https://github.com/ionic-team/ionic-framework/issues/30700
*/
test.describe('Modals: Inline Sheet in Child Route (standalone)', () => {
test.beforeEach(async ({ page }) => {
await page.goto('/standalone/modal-child-route/child');
});
test('should render parent content and child modal', async ({ page }) => {
await expect(page.locator('#increment-btn')).toBeVisible();
await expect(page.locator('#decrement-btn')).toBeVisible();
await expect(page.locator('#background-action-count')).toHaveText('0');
await expect(page.locator('ion-modal.show-modal')).toBeVisible();
await expect(page.locator('#modal-content-loaded')).toBeVisible();
});
test('should allow interacting with parent content while modal is open in child route', async ({ page }) => {
await expect(page.locator('ion-modal.show-modal')).toBeVisible();
await page.locator('#increment-btn').click();
await expect(page.locator('#background-action-count')).toHaveText('1');
});
test('should allow multiple interactions with parent content while modal is open', async ({ page }) => {
await expect(page.locator('ion-modal.show-modal')).toBeVisible();
await page.locator('#increment-btn').click();
await page.locator('#increment-btn').click();
await expect(page.locator('#background-action-count')).toHaveText('2');
await page.locator('#decrement-btn').click();
await expect(page.locator('#background-action-count')).toHaveText('1');
});
});

View File

@@ -13,6 +13,14 @@ export const routes: Routes = [
{ 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: 'modal-child-route', redirectTo: '/standalone/modal-child-route/child', pathMatch: 'full' },
{
path: 'modal-child-route',
loadComponent: () => import('../modal-child-route/modal-child-route-parent.component').then(c => c.ModalChildRouteParentComponent),
children: [
{ path: 'child', loadComponent: () => import('../modal-child-route/modal-child-route-child.component').then(c => c.ModalChildRouteChildComponent) },
]
},
{ 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) },

View File

@@ -100,6 +100,11 @@
Modal Dynamic Wrapper Test
</ion-label>
</ion-item>
<ion-item routerLink="/standalone/modal-child-route">
<ion-label>
Modal Child Route Test
</ion-label>
</ion-item>
<ion-item routerLink="/standalone/programmatic-modal">
<ion-label>
Programmatic Modal Test

View File

@@ -0,0 +1,33 @@
import { CommonModule } from '@angular/common';
import { Component } from '@angular/core';
import { IonContent, IonHeader, IonModal, IonTitle, IonToolbar } from '@ionic/angular/standalone';
/**
* Child route component containing only the sheet modal with showBackdrop=false.
* Verifies issue https://github.com/ionic-team/ionic-framework/issues/30700
*/
@Component({
selector: 'app-modal-child-route-child',
template: `
<ion-modal
[isOpen]="true"
[breakpoints]="[0.2, 0.5, 0.7]"
[initialBreakpoint]="0.5"
[showBackdrop]="false"
>
<ng-template>
<ion-header>
<ion-toolbar>
<ion-title>Modal in Child Route</ion-title>
</ion-toolbar>
</ion-header>
<ion-content class="ion-padding">
<p id="modal-content-loaded">Modal content loaded in child route</p>
</ion-content>
</ng-template>
</ion-modal>
`,
standalone: true,
imports: [CommonModule, IonContent, IonHeader, IonModal, IonTitle, IonToolbar],
})
export class ModalChildRouteChildComponent {}

View File

@@ -0,0 +1,38 @@
import { Component } from '@angular/core';
import { IonButton, IonContent, IonHeader, IonRouterOutlet, IonTitle, IonToolbar } from '@ionic/angular/standalone';
/**
* Parent with interactive buttons and nested outlet for child route modal.
* See https://github.com/ionic-team/ionic-framework/issues/30700
*/
@Component({
selector: 'app-modal-child-route-parent',
template: `
<ion-header>
<ion-toolbar>
<ion-title>Parent Page with Nested Route</ion-title>
</ion-toolbar>
</ion-header>
<ion-content class="ion-padding">
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 20px;">
<ion-button id="decrement-btn" (click)="decrement()">-</ion-button>
<p id="background-action-count">{{ count }}</p>
<ion-button id="increment-btn" (click)="increment()">+</ion-button>
</div>
<ion-router-outlet></ion-router-outlet>
</ion-content>
`,
standalone: true,
imports: [IonButton, IonContent, IonHeader, IonRouterOutlet, IonTitle, IonToolbar],
})
export class ModalChildRouteParentComponent {
count = 0;
increment() {
this.count++;
}
decrement() {
this.count--;
}
}

View File

@@ -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.12](https://github.com/ionic-team/ionic-framework/compare/v8.7.11...v8.7.12) (2025-12-10)
**Note:** Version bump only for package @ionic/docs
## [8.7.11](https://github.com/ionic-team/ionic-framework/compare/v8.7.10...v8.7.11) (2025-11-26)
**Note:** Version bump only for package @ionic/docs

View File

@@ -1,13 +1,13 @@
{
"name": "@ionic/docs",
"version": "8.7.11",
"version": "8.7.12",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@ionic/docs",
"version": "8.7.11",
"version": "8.7.12",
"license": "MIT"
}
}
}
}

View File

@@ -1,6 +1,6 @@
{
"name": "@ionic/docs",
"version": "8.7.11",
"version": "8.7.12",
"description": "Pre-packaged API documentation for the Ionic docs.",
"main": "core.json",
"types": "core.d.ts",

View File

@@ -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.12](https://github.com/ionic-team/ionic-framework/compare/v8.7.11...v8.7.12) (2025-12-10)
**Note:** Version bump only for package @ionic/react-router
## [8.7.11](https://github.com/ionic-team/ionic-framework/compare/v8.7.10...v8.7.11) (2025-11-26)
**Note:** Version bump only for package @ionic/react-router

View File

@@ -1,15 +1,15 @@
{
"name": "@ionic/react-router",
"version": "8.7.11",
"version": "8.7.12",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@ionic/react-router",
"version": "8.7.11",
"version": "8.7.12",
"license": "MIT",
"dependencies": {
"@ionic/react": "^8.7.11",
"@ionic/react": "^8.7.12",
"tslib": "*"
},
"devDependencies": {
@@ -238,14 +238,17 @@
"dev": true
},
"node_modules/@ionic/core": {
"version": "8.7.11",
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.7.11.tgz",
"integrity": "sha512-9UX9IeEztWWXymi+xCUMEBnnY+TbaR8crZLOwFnxPUEq4FFWSUCSv5XeHHQBpgZjBO2MJuDGcNv0GCQumIjVcQ==",
"version": "8.7.12",
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.7.12.tgz",
"integrity": "sha512-+QnytOHsMMDEz45hi/t9AN8ATaWMNZ7jNdx621BGSHi0JkEl1c4NylL3cfYIPJ/78y40ZG5NzprwNiR9sXdswg==",
"license": "MIT",
"dependencies": {
"@stencil/core": "4.38.0",
"ionicons": "^8.0.13",
"tslib": "^2.1.0"
},
"engines": {
"node": "24.x"
}
},
"node_modules/@ionic/eslint-config": {
@@ -415,12 +418,12 @@
}
},
"node_modules/@ionic/react": {
"version": "8.7.11",
"resolved": "https://registry.npmjs.org/@ionic/react/-/react-8.7.11.tgz",
"integrity": "sha512-h4j2SVRMgoxZBdr1bluKGrb0xNYEqEDcjHDuHsok669tKH3RnTMfD276zytfhFh3R8gIKWIqxb76NIsW/hfZcQ==",
"version": "8.7.12",
"resolved": "https://registry.npmjs.org/@ionic/react/-/react-8.7.12.tgz",
"integrity": "sha512-gNm5L++aiwkwJrUFKhcHUUgjqnj9n03gK7UcoL7Oz+271arzmwF/FNd47G85b6PovwiYQXY2CUBvNJ7Nh4qE/A==",
"license": "MIT",
"dependencies": {
"@ionic/core": "8.7.11",
"@ionic/core": "8.7.12",
"ionicons": "^8.0.13",
"tslib": "*"
},
@@ -4175,9 +4178,9 @@
"dev": true
},
"@ionic/core": {
"version": "8.7.11",
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.7.11.tgz",
"integrity": "sha512-9UX9IeEztWWXymi+xCUMEBnnY+TbaR8crZLOwFnxPUEq4FFWSUCSv5XeHHQBpgZjBO2MJuDGcNv0GCQumIjVcQ==",
"version": "8.7.12",
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.7.12.tgz",
"integrity": "sha512-+QnytOHsMMDEz45hi/t9AN8ATaWMNZ7jNdx621BGSHi0JkEl1c4NylL3cfYIPJ/78y40ZG5NzprwNiR9sXdswg==",
"requires": {
"@stencil/core": "4.38.0",
"ionicons": "^8.0.13",
@@ -4281,11 +4284,11 @@
"requires": {}
},
"@ionic/react": {
"version": "8.7.11",
"resolved": "https://registry.npmjs.org/@ionic/react/-/react-8.7.11.tgz",
"integrity": "sha512-h4j2SVRMgoxZBdr1bluKGrb0xNYEqEDcjHDuHsok669tKH3RnTMfD276zytfhFh3R8gIKWIqxb76NIsW/hfZcQ==",
"version": "8.7.12",
"resolved": "https://registry.npmjs.org/@ionic/react/-/react-8.7.12.tgz",
"integrity": "sha512-gNm5L++aiwkwJrUFKhcHUUgjqnj9n03gK7UcoL7Oz+271arzmwF/FNd47G85b6PovwiYQXY2CUBvNJ7Nh4qE/A==",
"requires": {
"@ionic/core": "8.7.11",
"@ionic/core": "8.7.12",
"ionicons": "^8.0.13",
"tslib": "*"
}

View File

@@ -1,6 +1,6 @@
{
"name": "@ionic/react-router",
"version": "8.7.11",
"version": "8.7.12",
"description": "React Router wrapper for @ionic/react",
"keywords": [
"ionic",
@@ -36,7 +36,7 @@
"dist/"
],
"dependencies": {
"@ionic/react": "^8.7.11",
"@ionic/react": "^8.7.12",
"tslib": "*"
},
"peerDependencies": {

View File

@@ -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.12](https://github.com/ionic-team/ionic-framework/compare/v8.7.11...v8.7.12) (2025-12-10)
### Bug Fixes
* **modal:** allow interaction with parent content through sheet modals in child routes ([#30839](https://github.com/ionic-team/ionic-framework/issues/30839)) ([b9e3cf0](https://github.com/ionic-team/ionic-framework/commit/b9e3cf0f5aae79a1f27a07b102c77e51f24825f4)), closes [#30700](https://github.com/ionic-team/ionic-framework/issues/30700)
## [8.7.11](https://github.com/ionic-team/ionic-framework/compare/v8.7.10...v8.7.11) (2025-11-26)
**Note:** Version bump only for package @ionic/react

View File

@@ -1,15 +1,15 @@
{
"name": "@ionic/react",
"version": "8.7.11",
"version": "8.7.12",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@ionic/react",
"version": "8.7.11",
"version": "8.7.12",
"license": "MIT",
"dependencies": {
"@ionic/core": "^8.7.11",
"@ionic/core": "^8.7.12",
"ionicons": "^8.0.13",
"tslib": "*"
},
@@ -736,14 +736,17 @@
"dev": true
},
"node_modules/@ionic/core": {
"version": "8.7.11",
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.7.11.tgz",
"integrity": "sha512-9UX9IeEztWWXymi+xCUMEBnnY+TbaR8crZLOwFnxPUEq4FFWSUCSv5XeHHQBpgZjBO2MJuDGcNv0GCQumIjVcQ==",
"version": "8.7.12",
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.7.12.tgz",
"integrity": "sha512-+QnytOHsMMDEz45hi/t9AN8ATaWMNZ7jNdx621BGSHi0JkEl1c4NylL3cfYIPJ/78y40ZG5NzprwNiR9sXdswg==",
"license": "MIT",
"dependencies": {
"@stencil/core": "4.38.0",
"ionicons": "^8.0.13",
"tslib": "^2.1.0"
},
"engines": {
"node": "24.x"
}
},
"node_modules/@ionic/eslint-config": {

View File

@@ -1,6 +1,6 @@
{
"name": "@ionic/react",
"version": "8.7.11",
"version": "8.7.12",
"description": "React specific wrapper for @ionic/core",
"keywords": [
"ionic",
@@ -40,7 +40,7 @@
"css/"
],
"dependencies": {
"@ionic/core": "^8.7.11",
"@ionic/core": "^8.7.12",
"ionicons": "^8.0.13",
"tslib": "*"
},

View File

@@ -0,0 +1,69 @@
import React, { useState } from 'react';
import {
IonButton,
IonContent,
IonHeader,
IonModal,
IonPage,
IonRouterOutlet,
IonTitle,
IonToolbar,
} from '@ionic/react';
import { Route } from 'react-router';
/**
* Parent component with counter buttons and nested router outlet.
* This reproduces the issue from https://github.com/ionic-team/ionic-framework/issues/30700
* where sheet modals in child routes with showBackdrop=false block interaction with parent content.
*/
const ModalSheetChildRouteParent: React.FC = () => {
const [count, setCount] = useState(0);
return (
<IonPage>
<IonHeader>
<IonToolbar>
<IonTitle>Parent Page with Nested Route</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent className="ion-padding">
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '20px' }}>
<IonButton id="decrement-btn" onClick={() => setCount((c) => c - 1)}>
-
</IonButton>
<p id="background-action-count">{count}</p>
<IonButton id="increment-btn" onClick={() => setCount((c) => c + 1)}>
+
</IonButton>
</div>
</IonContent>
<IonRouterOutlet>
<Route path="/overlay-components/modal-sheet-child-route/child" component={ModalSheetChildRouteChild} />
</IonRouterOutlet>
</IonPage>
);
};
const ModalSheetChildRouteChild: React.FC = () => {
return (
<IonPage>
<IonModal
isOpen={true}
breakpoints={[0.2, 0.5, 0.7]}
initialBreakpoint={0.5}
showBackdrop={false}
>
<IonHeader>
<IonToolbar>
<IonTitle>Modal in Child Route</IonTitle>
</IonToolbar>
</IonHeader>
<IonContent className="ion-padding">
<p id="modal-content-loaded">Modal content loaded in child route</p>
</IonContent>
</IonModal>
</IonPage>
);
};
export default ModalSheetChildRouteParent;

View File

@@ -15,6 +15,7 @@ import AlertComponent from './AlertComponent';
import LoadingComponent from './LoadingComponent';
import ModalComponent from './ModalComponent';
import ModalFocusTrap from './ModalFocusTrap';
import ModalSheetChildRoute from './ModalSheetChildRoute';
import ModalTeleport from './ModalTeleport';
import PickerComponent from './PickerComponent';
import PopoverComponent from './PopoverComponent';
@@ -32,6 +33,7 @@ const OverlayHooks: React.FC<OverlayHooksProps> = () => {
<Route path="/overlay-components/loading" component={LoadingComponent} />
<Route path="/overlay-components/modal-basic" component={ModalComponent} />
<Route path="/overlay-components/modal-focus-trap" component={ModalFocusTrap} />
<Route path="/overlay-components/modal-sheet-child-route" component={ModalSheetChildRoute} />
<Route path="/overlay-components/modal-teleport" component={ModalTeleport} />
<Route path="/overlay-components/picker" component={PickerComponent} />
<Route path="/overlay-components/popover" component={PopoverComponent} />
@@ -62,6 +64,10 @@ const OverlayHooks: React.FC<OverlayHooksProps> = () => {
<IonIcon icon={star} />
<IonLabel>Modal Teleport</IonLabel>
</IonTabButton>
<IonTabButton tab="modalSheetChildRoute" href="/overlay-components/modal-sheet-child-route/child">
<IonIcon icon={star} />
<IonLabel>Sheet Child</IonLabel>
</IonTabButton>
<IonTabButton tab="picker" href="/overlay-components/picker">
<IonIcon icon={logoIonic} />
<IonLabel>Picker</IonLabel>

View File

@@ -5,7 +5,9 @@ describe('IonModal: focusTrap regression', () => {
it('should allow interacting with background when focusTrap=false', () => {
cy.get('#open-non-trapped-modal').click();
cy.get('ion-modal').should('be.visible');
// Use 'exist' instead of 'be.visible' because the modal has pointer-events: none
// to allow background interaction, which Cypress interprets as "covered"
cy.get('ion-modal.show-modal').should('exist');
cy.get('#background-action').click();
cy.get('#background-action-count').should('have.text', '1');
@@ -13,7 +15,7 @@ describe('IonModal: focusTrap regression', () => {
it('should prevent interacting with background when focusTrap=true', () => {
cy.get('#open-trapped-modal').click();
cy.get('ion-modal').should('be.visible');
cy.get('ion-modal.show-modal').should('be.visible');
// Ensure backdrop is active and capturing pointer events
cy.get('ion-backdrop').should('exist');

View File

@@ -0,0 +1,37 @@
/**
* Tests for sheet modals in child routes with showBackdrop=false.
* See https://github.com/ionic-team/ionic-framework/issues/30700
*/
describe('IonModal: Sheet in Child Route with Nested Routing', () => {
beforeEach(() => {
cy.visit('/overlay-components/modal-sheet-child-route/child');
});
it('should render parent content and child modal', () => {
cy.get('#increment-btn').should('exist');
cy.get('#decrement-btn').should('exist');
cy.get('#background-action-count').should('have.text', '0');
cy.get('ion-modal.show-modal').should('exist');
cy.get('#modal-content-loaded').should('exist');
});
it('should allow interacting with parent content while modal is open in child route', () => {
// Wait for modal to be presented
cy.get('ion-modal.show-modal').should('exist');
// Click the increment button in the parent content
cy.get('#increment-btn').click();
cy.get('#background-action-count').should('have.text', '1');
});
it('should allow multiple interactions with parent content while modal is open', () => {
cy.get('ion-modal.show-modal').should('exist');
cy.get('#increment-btn').click();
cy.get('#increment-btn').click();
cy.get('#background-action-count').should('have.text', '2');
cy.get('#decrement-btn').click();
cy.get('#background-action-count').should('have.text', '1');
});
});

View File

@@ -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.12](https://github.com/ionic-team/ionic-framework/compare/v8.7.11...v8.7.12) (2025-12-10)
**Note:** Version bump only for package @ionic/vue-router
## [8.7.11](https://github.com/ionic-team/ionic-framework/compare/v8.7.10...v8.7.11) (2025-11-26)
**Note:** Version bump only for package @ionic/vue-router

View File

@@ -1,15 +1,15 @@
{
"name": "@ionic/vue-router",
"version": "8.7.11",
"version": "8.7.12",
"lockfileVersion": 2,
"requires": true,
"packages": {
"": {
"name": "@ionic/vue-router",
"version": "8.7.11",
"version": "8.7.12",
"license": "MIT",
"dependencies": {
"@ionic/vue": "^8.7.11"
"@ionic/vue": "^8.7.12"
},
"devDependencies": {
"@ionic/eslint-config": "^0.3.0",
@@ -673,14 +673,17 @@
"dev": true
},
"node_modules/@ionic/core": {
"version": "8.7.11",
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.7.11.tgz",
"integrity": "sha512-9UX9IeEztWWXymi+xCUMEBnnY+TbaR8crZLOwFnxPUEq4FFWSUCSv5XeHHQBpgZjBO2MJuDGcNv0GCQumIjVcQ==",
"version": "8.7.12",
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.7.12.tgz",
"integrity": "sha512-+QnytOHsMMDEz45hi/t9AN8ATaWMNZ7jNdx621BGSHi0JkEl1c4NylL3cfYIPJ/78y40ZG5NzprwNiR9sXdswg==",
"license": "MIT",
"dependencies": {
"@stencil/core": "4.38.0",
"ionicons": "^8.0.13",
"tslib": "^2.1.0"
},
"engines": {
"node": "24.x"
}
},
"node_modules/@ionic/eslint-config": {
@@ -865,12 +868,12 @@
}
},
"node_modules/@ionic/vue": {
"version": "8.7.11",
"resolved": "https://registry.npmjs.org/@ionic/vue/-/vue-8.7.11.tgz",
"integrity": "sha512-HDEcjhxWfimVQxvXfghrqlAWpXnJvcUDTIVE2Mvq8ul+s7gL/OZCpXTAODJOfFCBAGJ0o9QXyC7OPjyN4UbO8Q==",
"version": "8.7.12",
"resolved": "https://registry.npmjs.org/@ionic/vue/-/vue-8.7.12.tgz",
"integrity": "sha512-fH/acQ7dYYd1XY1HFqKf0Th6klbfNNzhlnYUf9kNQpkHqUpMamSzA8TWDOV5f4PNKYq6X4oKAPPeIQA4DOayUQ==",
"license": "MIT",
"dependencies": {
"@ionic/core": "8.7.11",
"@ionic/core": "8.7.12",
"@stencil/vue-output-target": "0.10.7",
"ionicons": "^8.0.13"
}
@@ -8041,9 +8044,9 @@
"dev": true
},
"@ionic/core": {
"version": "8.7.11",
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.7.11.tgz",
"integrity": "sha512-9UX9IeEztWWXymi+xCUMEBnnY+TbaR8crZLOwFnxPUEq4FFWSUCSv5XeHHQBpgZjBO2MJuDGcNv0GCQumIjVcQ==",
"version": "8.7.12",
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.7.12.tgz",
"integrity": "sha512-+QnytOHsMMDEz45hi/t9AN8ATaWMNZ7jNdx621BGSHi0JkEl1c4NylL3cfYIPJ/78y40ZG5NzprwNiR9sXdswg==",
"requires": {
"@stencil/core": "4.38.0",
"ionicons": "^8.0.13",
@@ -8156,11 +8159,11 @@
"requires": {}
},
"@ionic/vue": {
"version": "8.7.11",
"resolved": "https://registry.npmjs.org/@ionic/vue/-/vue-8.7.11.tgz",
"integrity": "sha512-HDEcjhxWfimVQxvXfghrqlAWpXnJvcUDTIVE2Mvq8ul+s7gL/OZCpXTAODJOfFCBAGJ0o9QXyC7OPjyN4UbO8Q==",
"version": "8.7.12",
"resolved": "https://registry.npmjs.org/@ionic/vue/-/vue-8.7.12.tgz",
"integrity": "sha512-fH/acQ7dYYd1XY1HFqKf0Th6klbfNNzhlnYUf9kNQpkHqUpMamSzA8TWDOV5f4PNKYq6X4oKAPPeIQA4DOayUQ==",
"requires": {
"@ionic/core": "8.7.11",
"@ionic/core": "8.7.12",
"@stencil/vue-output-target": "0.10.7",
"ionicons": "^8.0.13"
}

View File

@@ -1,6 +1,6 @@
{
"name": "@ionic/vue-router",
"version": "8.7.11",
"version": "8.7.12",
"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.11"
"@ionic/vue": "^8.7.12"
},
"devDependencies": {
"@ionic/eslint-config": "^0.3.0",

View File

@@ -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.12](https://github.com/ionic-team/ionic-framework/compare/v8.7.11...v8.7.12) (2025-12-10)
**Note:** Version bump only for package @ionic/vue
## [8.7.11](https://github.com/ionic-team/ionic-framework/compare/v8.7.10...v8.7.11) (2025-11-26)
**Note:** Version bump only for package @ionic/vue

View File

@@ -1,15 +1,15 @@
{
"name": "@ionic/vue",
"version": "8.7.11",
"version": "8.7.12",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "@ionic/vue",
"version": "8.7.11",
"version": "8.7.12",
"license": "MIT",
"dependencies": {
"@ionic/core": "^8.7.11",
"@ionic/core": "^8.7.12",
"@stencil/vue-output-target": "0.10.7",
"ionicons": "^8.0.13"
},
@@ -222,14 +222,17 @@
"dev": true
},
"node_modules/@ionic/core": {
"version": "8.7.11",
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.7.11.tgz",
"integrity": "sha512-9UX9IeEztWWXymi+xCUMEBnnY+TbaR8crZLOwFnxPUEq4FFWSUCSv5XeHHQBpgZjBO2MJuDGcNv0GCQumIjVcQ==",
"version": "8.7.12",
"resolved": "https://registry.npmjs.org/@ionic/core/-/core-8.7.12.tgz",
"integrity": "sha512-+QnytOHsMMDEz45hi/t9AN8ATaWMNZ7jNdx621BGSHi0JkEl1c4NylL3cfYIPJ/78y40ZG5NzprwNiR9sXdswg==",
"license": "MIT",
"dependencies": {
"@stencil/core": "4.38.0",
"ionicons": "^8.0.13",
"tslib": "^2.1.0"
},
"engines": {
"node": "24.x"
}
},
"node_modules/@ionic/core/node_modules/tslib": {

View File

@@ -1,6 +1,6 @@
{
"name": "@ionic/vue",
"version": "8.7.11",
"version": "8.7.12",
"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.11",
"@ionic/core": "^8.7.12",
"@stencil/vue-output-target": "0.10.7",
"ionicons": "^8.0.13"
},