@ionic/core 8.7.17-dev.11767796972.148e4bc4 → 8.7.17-dev.11767891829.1a63afa3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -2,6 +2,7 @@
2
2
  * (C) Ionic http://ionicframework.com - MIT License
3
3
  */
4
4
  import { proxyCustomElement, HTMLElement, createEvent, forceUpdate, Build, readTask, h, Host } from '@stencil/core/internal/client';
5
+ import { w as win } from './index9.js';
5
6
  import { i as inheritAriaAttributes, k as hasLazyBuild, c as componentOnReady } from './helpers.js';
6
7
  import { b as getIonMode, a as isPlatform } from './ionic-global.js';
7
8
  import { i as isRTL } from './dir.js';
@@ -88,7 +89,11 @@ const Content = /*@__PURE__*/ proxyCustomElement(class Content extends HTMLEleme
88
89
  this.inheritedAttributes = inheritAriaAttributes(this.el);
89
90
  }
90
91
  connectedCallback() {
91
- this.isMainContent = this.el.closest('ion-menu, ion-popover, ion-modal') === null;
92
+ var _a;
93
+ // Content is "main" if not inside menu/popover/modal and not nested in another ion-content
94
+ this.isMainContent =
95
+ this.el.closest('ion-menu, ion-popover, ion-modal') === null &&
96
+ ((_a = this.el.parentElement) === null || _a === void 0 ? void 0 : _a.closest('ion-content')) === null;
92
97
  // Detect sibling header/footer for safe-area handling
93
98
  this.detectSiblingElements();
94
99
  /**
@@ -121,7 +126,12 @@ const Content = /*@__PURE__*/ proxyCustomElement(class Content extends HTMLEleme
121
126
  * bubbles, we can catch any instances of child tab bars loading by listening
122
127
  * on IonTabs.
123
128
  */
124
- this.tabsLoadCallback = () => this.resize();
129
+ this.tabsLoadCallback = () => {
130
+ this.resize();
131
+ // Re-detect footer when tab bar loads (it may not exist during initial detection)
132
+ this.updateSiblingDetection();
133
+ forceUpdate(this);
134
+ };
125
135
  closestTabs.addEventListener('ionTabBarLoaded', this.tabsLoadCallback);
126
136
  }
127
137
  }
@@ -134,10 +144,15 @@ const Content = /*@__PURE__*/ proxyCustomElement(class Content extends HTMLEleme
134
144
  this.updateSiblingDetection();
135
145
  // Watch for dynamic header/footer changes (common in React conditional rendering)
136
146
  const parent = this.el.parentElement;
137
- if (parent && !this.parentMutationObserver) {
147
+ if (parent && !this.parentMutationObserver && win !== undefined && 'MutationObserver' in win) {
138
148
  this.parentMutationObserver = new MutationObserver(() => {
149
+ const prevHasHeader = this.hasHeader;
150
+ const prevHasFooter = this.hasFooter;
139
151
  this.updateSiblingDetection();
140
- forceUpdate(this);
152
+ // Only trigger re-render if header/footer detection actually changed
153
+ if (prevHasHeader !== this.hasHeader || prevHasFooter !== this.hasFooter) {
154
+ forceUpdate(this);
155
+ }
141
156
  });
142
157
  this.parentMutationObserver.observe(parent, { childList: true });
143
158
  }
@@ -443,7 +458,7 @@ const Content = /*@__PURE__*/ proxyCustomElement(class Content extends HTMLEleme
443
458
  const forceOverscroll = this.shouldForceOverscroll();
444
459
  const transitionShadow = mode === 'ios';
445
460
  this.resize();
446
- return (h(Host, Object.assign({ key: 'c8e3a93e0b1ba6f7aa81a6a6065145ece9a6e2ef', role: isMainContent ? 'main' : undefined, class: createColorClasses(this.color, {
461
+ return (h(Host, Object.assign({ key: 'f7218f733e4022a30875441bd949747537d28aa1', role: isMainContent ? 'main' : undefined, class: createColorClasses(this.color, {
447
462
  [mode]: true,
448
463
  'content-sizing': hostContext('ion-popover', this.el),
449
464
  overscroll: forceOverscroll,
@@ -453,12 +468,12 @@ const Content = /*@__PURE__*/ proxyCustomElement(class Content extends HTMLEleme
453
468
  }), style: {
454
469
  '--offset-top': `${this.cTop}px`,
455
470
  '--offset-bottom': `${this.cBottom}px`,
456
- } }, inheritedAttributes), h("div", { key: '4c0482cda885348eea9eb66d7f076af6b38c52e5', ref: (el) => (this.backgroundContentEl = el), id: "background-content", part: "background" }), fixedSlotPlacement === 'before' ? h("slot", { name: "fixed" }) : null, h("div", { key: '6fbb39bf7ab7120009c56aea9340de45c934eeed', class: {
471
+ } }, inheritedAttributes), h("div", { key: 'b735ec68c18c0b99c3595bb194029830e6542cde', ref: (el) => (this.backgroundContentEl = el), id: "background-content", part: "background" }), fixedSlotPlacement === 'before' ? h("slot", { name: "fixed" }) : null, h("div", { key: 'e76c00d030342d44ade6648c3f9e32ca990787ba', class: {
457
472
  'inner-scroll': true,
458
473
  'scroll-x': scrollX,
459
474
  'scroll-y': scrollY,
460
475
  overscroll: (scrollX || scrollY) && forceOverscroll,
461
- }, ref: (scrollEl) => (this.scrollEl = scrollEl), onScroll: this.scrollEvents ? (ev) => this.onScroll(ev) : undefined, part: "scroll" }, h("slot", { key: '6425bc84edbc0c5b1f2764a1d611df1b46628274' })), transitionShadow ? (h("div", { class: "transition-effect" }, h("div", { class: "transition-cover" }), h("div", { class: "transition-shadow" }))) : null, fixedSlotPlacement === 'after' ? h("slot", { name: "fixed" }) : null));
476
+ }, ref: (scrollEl) => (this.scrollEl = scrollEl), onScroll: this.scrollEvents ? (ev) => this.onScroll(ev) : undefined, part: "scroll" }, h("slot", { key: '9049be4cea9b5da5ec1e1012248b05286fddeb7a' })), transitionShadow ? (h("div", { class: "transition-effect" }, h("div", { class: "transition-cover" }), h("div", { class: "transition-shadow" }))) : null, fixedSlotPlacement === 'after' ? h("slot", { name: "fixed" }) : null));
462
477
  }
463
478
  get el() { return this; }
464
479
  static get style() { return contentCss; }
@@ -2,6 +2,7 @@
2
2
  * (C) Ionic http://ionicframework.com - MIT License
3
3
  */
4
4
  import { proxyCustomElement, HTMLElement, createEvent, writeTask, h, Host } from '@stencil/core/internal/client';
5
+ import { w as win } from './index9.js';
5
6
  import { a as findClosestIonContent, i as isIonContent, d as disableContentScrollY, r as resetContentScrollY, f as findIonContent, p as printIonContentErrorMsg } from './index8.js';
6
7
  import { C as CoreDelegate, a as attachComponent, d as detachComponent } from './framework-delegate.js';
7
8
  import { f as clamp, g as getElementRoot, r as raf, d as inheritAttributes, k as hasLazyBuild } from './helpers.js';
@@ -16,7 +17,6 @@ import { KEYBOARD_DID_OPEN } from './keyboard.js';
16
17
  import { c as createAnimation } from './animation.js';
17
18
  import { g as getTimeGivenProgression } from './cubic-bezier.js';
18
19
  import { createGesture } from './index3.js';
19
- import { w as win } from './index9.js';
20
20
  import { d as defineCustomElement$1 } from './backdrop.js';
21
21
 
22
22
  var Style;
@@ -1724,6 +1724,8 @@ const Modal = /*@__PURE__*/ proxyCustomElement(class Modal extends HTMLElement {
1724
1724
  this.triggerController.removeClickListener();
1725
1725
  this.cleanupViewTransitionListener();
1726
1726
  this.cleanupParentRemovalObserver();
1727
+ // Reset safe-area state to handle removal without dismiss (e.g., framework unmount)
1728
+ this.resetSafeAreaState();
1727
1729
  }
1728
1730
  componentWillLoad() {
1729
1731
  var _a;
@@ -2160,7 +2162,9 @@ const Modal = /*@__PURE__*/ proxyCustomElement(class Modal extends HTMLElement {
2160
2162
  this.skipSafeAreaCoordinateDetection = true;
2161
2163
  this.updateFooterPadding();
2162
2164
  // Watch for dynamic footer additions/removals (e.g., async data loading)
2163
- if (!this.footerObserver) {
2165
+ // Use subtree:true to support wrapped footers in framework components
2166
+ // (e.g., <my-footer><ion-footer>...</ion-footer></my-footer>)
2167
+ if (!this.footerObserver && win !== undefined && 'MutationObserver' in win) {
2164
2168
  this.footerObserver = new MutationObserver(() => this.updateFooterPadding());
2165
2169
  this.footerObserver.observe(this.el, { childList: true, subtree: true });
2166
2170
  }
@@ -2193,6 +2197,30 @@ const Modal = /*@__PURE__*/ proxyCustomElement(class Modal extends HTMLElement {
2193
2197
  style.setProperty('--ion-safe-area-left', '0px');
2194
2198
  style.setProperty('--ion-safe-area-right', '0px');
2195
2199
  }
2200
+ /**
2201
+ * Resets all safe-area related state and styles.
2202
+ * Called during dismiss and disconnectedCallback to ensure clean state
2203
+ * for re-presentation of inline modals.
2204
+ */
2205
+ resetSafeAreaState() {
2206
+ var _a;
2207
+ this.skipSafeAreaCoordinateDetection = false;
2208
+ this.cachedSafeAreas = undefined;
2209
+ this.prevSafeAreaState = { top: false, bottom: false, left: false, right: false };
2210
+ (_a = this.footerObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
2211
+ this.footerObserver = undefined;
2212
+ // Clear wrapper styles that may have been set for safe-area handling
2213
+ if (this.wrapperEl) {
2214
+ this.wrapperEl.style.removeProperty('padding-bottom');
2215
+ this.wrapperEl.style.removeProperty('box-sizing');
2216
+ }
2217
+ // Clear safe-area CSS variable overrides
2218
+ const style = this.el.style;
2219
+ style.removeProperty('--ion-safe-area-top');
2220
+ style.removeProperty('--ion-safe-area-bottom');
2221
+ style.removeProperty('--ion-safe-area-left');
2222
+ style.removeProperty('--ion-safe-area-right');
2223
+ }
2196
2224
  /**
2197
2225
  * Gets the root safe-area values from the document element.
2198
2226
  * Uses cached values during gestures to avoid getComputedStyle calls.
@@ -2284,7 +2312,7 @@ const Modal = /*@__PURE__*/ proxyCustomElement(class Modal extends HTMLElement {
2284
2312
  * For example, `cancel` or `backdrop`.
2285
2313
  */
2286
2314
  async dismiss(data, role) {
2287
- var _a, _b;
2315
+ var _a;
2288
2316
  if (this.gestureAnimationDismissing && role !== GESTURE) {
2289
2317
  return false;
2290
2318
  }
@@ -2347,22 +2375,7 @@ const Modal = /*@__PURE__*/ proxyCustomElement(class Modal extends HTMLElement {
2347
2375
  this.currentBreakpoint = undefined;
2348
2376
  this.animation = undefined;
2349
2377
  // Reset safe-area state for potential re-presentation
2350
- this.skipSafeAreaCoordinateDetection = false;
2351
- this.cachedSafeAreas = undefined;
2352
- this.prevSafeAreaState = { top: false, bottom: false, left: false, right: false };
2353
- (_b = this.footerObserver) === null || _b === void 0 ? void 0 : _b.disconnect();
2354
- this.footerObserver = undefined;
2355
- // Clear styles that may have been set for safe-area handling
2356
- if (this.wrapperEl) {
2357
- this.wrapperEl.style.removeProperty('padding-bottom');
2358
- this.wrapperEl.style.removeProperty('box-sizing');
2359
- }
2360
- // Clear safe-area CSS variable overrides
2361
- const style = this.el.style;
2362
- style.removeProperty('--ion-safe-area-top');
2363
- style.removeProperty('--ion-safe-area-bottom');
2364
- style.removeProperty('--ion-safe-area-left');
2365
- style.removeProperty('--ion-safe-area-right');
2378
+ this.resetSafeAreaState();
2366
2379
  unlock();
2367
2380
  return dismissed;
2368
2381
  }
@@ -2612,20 +2625,20 @@ const Modal = /*@__PURE__*/ proxyCustomElement(class Modal extends HTMLElement {
2612
2625
  const isCardModal = presentingElement !== undefined && mode === 'ios';
2613
2626
  const isHandleCycle = handleBehavior === 'cycle';
2614
2627
  const isSheetModalWithHandle = isSheetModal && showHandle;
2615
- return (h(Host, Object.assign({ key: '11cd16cc481093a38a327abdd94467be3f71718d', "no-router": true,
2628
+ return (h(Host, Object.assign({ key: '44022099fcaf047b97d1c2cb45b9b51c930e707c', "no-router": true,
2616
2629
  // Allow the modal to be navigable when the handle is focusable
2617
2630
  tabIndex: isHandleCycle && isSheetModalWithHandle ? 0 : -1 }, htmlAttributes, { style: {
2618
2631
  zIndex: `${20000 + this.overlayIndex}`,
2619
- }, class: Object.assign({ [mode]: true, ['modal-default']: !isCardModal && !isSheetModal, [`modal-card`]: isCardModal, [`modal-sheet`]: isSheetModal, [`modal-no-expand-scroll`]: isSheetModal && !expandToScroll, 'overlay-hidden': true, [FOCUS_TRAP_DISABLE_CLASS]: focusTrap === false }, getClassMap(this.cssClass)), onIonBackdropTap: this.onBackdropTap, onIonModalDidPresent: this.onLifecycle, onIonModalWillPresent: this.onLifecycle, onIonModalWillDismiss: this.onLifecycle, onIonModalDidDismiss: this.onLifecycle, onFocus: this.onModalFocus }), h("ion-backdrop", { key: '125658fbb071960da3905854668078e15bce56da', ref: (el) => (this.backdropEl = el), visible: this.showBackdrop, tappable: this.backdropDismiss, part: "backdrop" }), mode === 'ios' && h("div", { key: '4a63815ef165e5806fef85ef48bf509813ff55c9', class: "modal-shadow" }), h("div", Object.assign({ key: 'cfc4b20354cbf2c0f873f6aee91c9b8f553de61d',
2632
+ }, class: Object.assign({ [mode]: true, ['modal-default']: !isCardModal && !isSheetModal, [`modal-card`]: isCardModal, [`modal-sheet`]: isSheetModal, [`modal-no-expand-scroll`]: isSheetModal && !expandToScroll, 'overlay-hidden': true, [FOCUS_TRAP_DISABLE_CLASS]: focusTrap === false }, getClassMap(this.cssClass)), onIonBackdropTap: this.onBackdropTap, onIonModalDidPresent: this.onLifecycle, onIonModalWillPresent: this.onLifecycle, onIonModalWillDismiss: this.onLifecycle, onIonModalDidDismiss: this.onLifecycle, onFocus: this.onModalFocus }), h("ion-backdrop", { key: 'ddd7e4f6eef51ac1f62ac70e0af10fb01e707f07', ref: (el) => (this.backdropEl = el), visible: this.showBackdrop, tappable: this.backdropDismiss, part: "backdrop" }), mode === 'ios' && h("div", { key: '58620980e3e4ec273c6787bde026e1c010b904b7', class: "modal-shadow" }), h("div", Object.assign({ key: '3fb7f6218644ba898fc504467775593eb89426a0',
2620
2633
  /*
2621
2634
  role and aria-modal must be used on the
2622
2635
  same element. They must also be set inside the
2623
2636
  shadow DOM otherwise ion-button will not be highlighted
2624
2637
  when using VoiceOver: https://bugs.webkit.org/show_bug.cgi?id=247134
2625
2638
  */
2626
- role: "dialog" }, inheritedAttributes, { "aria-modal": "true", class: "modal-wrapper ion-overlay-wrapper", part: "content", ref: (el) => (this.wrapperEl = el) }), showHandle && (h("button", { key: '33a4ee89bb8b6512883cb8756641c1e27fdb0ebc', class: "modal-handle",
2639
+ role: "dialog" }, inheritedAttributes, { "aria-modal": "true", class: "modal-wrapper ion-overlay-wrapper", part: "content", ref: (el) => (this.wrapperEl = el) }), showHandle && (h("button", { key: '9745cd590fdaa9d023a14b487ec2c87ddbafd7f7', class: "modal-handle",
2627
2640
  // Prevents the handle from receiving keyboard focus when it does not cycle
2628
- tabIndex: !isHandleCycle ? -1 : 0, "aria-label": "Activate to adjust the size of the dialog overlaying the screen", onClick: isHandleCycle ? this.onHandleClick : undefined, part: "handle", ref: (el) => (this.dragHandleEl = el) })), h("slot", { key: '986fafb71234591c96e927f92b7330bb5c76fc2e', onSlotchange: this.onSlotChange }))));
2641
+ tabIndex: !isHandleCycle ? -1 : 0, "aria-label": "Activate to adjust the size of the dialog overlaying the screen", onClick: isHandleCycle ? this.onHandleClick : undefined, part: "handle", ref: (el) => (this.dragHandleEl = el) })), h("slot", { key: 'b9a8b5d2d3d3c9b06f99179f496c9f08907d0bad', onSlotchange: this.onSlotChange }))));
2629
2642
  }
2630
2643
  get el() { return this; }
2631
2644
  static get watchers() { return {
@@ -945,7 +945,7 @@ const mdEnterAnimation = (baseEl, opts) => {
945
945
  };
946
946
  const results = getPopoverPosition(isRTL, contentWidth, contentHeight, 0, 0, reference, side, align, defaultPosition, trigger, ev);
947
947
  const padding = size === 'cover' ? 0 : POPOVER_MD_BODY_PADDING;
948
- const { originX, originY, top, left, bottom, checkSafeAreaTop, checkSafeAreaBottom } = calculateWindowAdjustment(side, results.top, results.left, padding, bodyWidth, bodyHeight, contentWidth, contentHeight, 0, results.originX, results.originY, results.referenceCoordinates);
948
+ const { originX, originY, top, left, bottom, checkSafeAreaTop, checkSafeAreaBottom, checkSafeAreaLeft, checkSafeAreaRight, } = calculateWindowAdjustment(side, results.top, results.left, padding, bodyWidth, bodyHeight, contentWidth, contentHeight, 0, results.originX, results.originY, results.referenceCoordinates);
949
949
  /**
950
950
  * Safe area CSS variable adjustments.
951
951
  * When the popover is positioned near an edge, we add the corresponding
@@ -954,14 +954,23 @@ const mdEnterAnimation = (baseEl, opts) => {
954
954
  */
955
955
  const safeAreaTop = ' + var(--ion-safe-area-top, 0)';
956
956
  const safeAreaBottom = ' + var(--ion-safe-area-bottom, 0)';
957
+ const safeAreaLeft = ' + var(--ion-safe-area-left, 0)';
958
+ const safeAreaRight = ' - var(--ion-safe-area-right, 0)';
957
959
  let topValue = `${top}px`;
958
960
  let bottomValue = bottom !== undefined ? `${bottom}px` : undefined;
961
+ let leftValue = `${left}px`;
959
962
  if (checkSafeAreaTop) {
960
963
  topValue = `${top}px${safeAreaTop}`;
961
964
  }
962
965
  if (checkSafeAreaBottom && bottomValue !== undefined) {
963
966
  bottomValue = `${bottom}px${safeAreaBottom}`;
964
967
  }
968
+ if (checkSafeAreaLeft) {
969
+ leftValue = `${left}px${safeAreaLeft}`;
970
+ }
971
+ if (checkSafeAreaRight) {
972
+ leftValue = `${left}px${safeAreaRight}`;
973
+ }
965
974
  const baseAnimation = createAnimation();
966
975
  const backdropAnimation = createAnimation();
967
976
  const wrapperAnimation = createAnimation();
@@ -979,7 +988,7 @@ const mdEnterAnimation = (baseEl, opts) => {
979
988
  .addElement(contentEl)
980
989
  .beforeStyles({
981
990
  top: `calc(${topValue} + var(--offset-y, 0px))`,
982
- left: `calc(${left}px + var(--offset-x, 0px))`,
991
+ left: `calc(${leftValue} + var(--offset-x, 0px))`,
983
992
  'transform-origin': `${originY} ${originX}`,
984
993
  })
985
994
  .beforeAddWrite(() => {
@@ -6,16 +6,16 @@
6
6
  var index = require('./index-D6Wc6v08.js');
7
7
  var hardwareBackButton = require('./hardware-back-button-VCK4V3mG.js');
8
8
  var ionicGlobal = require('./ionic-global-HMVqOFGO.js');
9
+ var index$1 = require('./index-DkNv4J_i.js');
9
10
  var helpers = require('./helpers-DrTqNghc.js');
10
11
  var dir = require('./dir-Cn0z1rJH.js');
11
12
  var theme = require('./theme-CeDs6Hcv.js');
12
- var index$1 = require('./index-CO6eryBo.js');
13
+ var index$2 = require('./index-CO6eryBo.js');
13
14
  var keyboardController = require('./keyboard-controller-GXBiBRKS.js');
14
15
  var cubicBezier = require('./cubic-bezier-DAjy1V-e.js');
15
16
  var frameworkDelegate = require('./framework-delegate-DMJRBuDi.js');
16
17
  var lockController = require('./lock-controller-aDB9wrEf.js');
17
- var index$2 = require('./index-094mMFB-.js');
18
- require('./index-DkNv4J_i.js');
18
+ var index$3 = require('./index-094mMFB-.js');
19
19
  require('./keyboard-UuAS4D_9.js');
20
20
  require('./capacitor-DmA66EwP.js');
21
21
 
@@ -231,7 +231,11 @@ const Content = class {
231
231
  this.inheritedAttributes = helpers.inheritAriaAttributes(this.el);
232
232
  }
233
233
  connectedCallback() {
234
- this.isMainContent = this.el.closest('ion-menu, ion-popover, ion-modal') === null;
234
+ var _a;
235
+ // Content is "main" if not inside menu/popover/modal and not nested in another ion-content
236
+ this.isMainContent =
237
+ this.el.closest('ion-menu, ion-popover, ion-modal') === null &&
238
+ ((_a = this.el.parentElement) === null || _a === void 0 ? void 0 : _a.closest('ion-content')) === null;
235
239
  // Detect sibling header/footer for safe-area handling
236
240
  this.detectSiblingElements();
237
241
  /**
@@ -264,7 +268,12 @@ const Content = class {
264
268
  * bubbles, we can catch any instances of child tab bars loading by listening
265
269
  * on IonTabs.
266
270
  */
267
- this.tabsLoadCallback = () => this.resize();
271
+ this.tabsLoadCallback = () => {
272
+ this.resize();
273
+ // Re-detect footer when tab bar loads (it may not exist during initial detection)
274
+ this.updateSiblingDetection();
275
+ index.forceUpdate(this);
276
+ };
268
277
  closestTabs.addEventListener('ionTabBarLoaded', this.tabsLoadCallback);
269
278
  }
270
279
  }
@@ -277,10 +286,15 @@ const Content = class {
277
286
  this.updateSiblingDetection();
278
287
  // Watch for dynamic header/footer changes (common in React conditional rendering)
279
288
  const parent = this.el.parentElement;
280
- if (parent && !this.parentMutationObserver) {
289
+ if (parent && !this.parentMutationObserver && index$1.win !== undefined && 'MutationObserver' in index$1.win) {
281
290
  this.parentMutationObserver = new MutationObserver(() => {
291
+ const prevHasHeader = this.hasHeader;
292
+ const prevHasFooter = this.hasFooter;
282
293
  this.updateSiblingDetection();
283
- index.forceUpdate(this);
294
+ // Only trigger re-render if header/footer detection actually changed
295
+ if (prevHasHeader !== this.hasHeader || prevHasFooter !== this.hasFooter) {
296
+ index.forceUpdate(this);
297
+ }
284
298
  });
285
299
  this.parentMutationObserver.observe(parent, { childList: true });
286
300
  }
@@ -586,7 +600,7 @@ const Content = class {
586
600
  const forceOverscroll = this.shouldForceOverscroll();
587
601
  const transitionShadow = mode === 'ios';
588
602
  this.resize();
589
- return (index.h(index.Host, Object.assign({ key: 'c8e3a93e0b1ba6f7aa81a6a6065145ece9a6e2ef', role: isMainContent ? 'main' : undefined, class: theme.createColorClasses(this.color, {
603
+ return (index.h(index.Host, Object.assign({ key: 'f7218f733e4022a30875441bd949747537d28aa1', role: isMainContent ? 'main' : undefined, class: theme.createColorClasses(this.color, {
590
604
  [mode]: true,
591
605
  'content-sizing': theme.hostContext('ion-popover', this.el),
592
606
  overscroll: forceOverscroll,
@@ -596,12 +610,12 @@ const Content = class {
596
610
  }), style: {
597
611
  '--offset-top': `${this.cTop}px`,
598
612
  '--offset-bottom': `${this.cBottom}px`,
599
- } }, inheritedAttributes), index.h("div", { key: '4c0482cda885348eea9eb66d7f076af6b38c52e5', ref: (el) => (this.backgroundContentEl = el), id: "background-content", part: "background" }), fixedSlotPlacement === 'before' ? index.h("slot", { name: "fixed" }) : null, index.h("div", { key: '6fbb39bf7ab7120009c56aea9340de45c934eeed', class: {
613
+ } }, inheritedAttributes), index.h("div", { key: 'b735ec68c18c0b99c3595bb194029830e6542cde', ref: (el) => (this.backgroundContentEl = el), id: "background-content", part: "background" }), fixedSlotPlacement === 'before' ? index.h("slot", { name: "fixed" }) : null, index.h("div", { key: 'e76c00d030342d44ade6648c3f9e32ca990787ba', class: {
600
614
  'inner-scroll': true,
601
615
  'scroll-x': scrollX,
602
616
  'scroll-y': scrollY,
603
617
  overscroll: (scrollX || scrollY) && forceOverscroll,
604
- }, ref: (scrollEl) => (this.scrollEl = scrollEl), onScroll: this.scrollEvents ? (ev) => this.onScroll(ev) : undefined, part: "scroll" }, index.h("slot", { key: '6425bc84edbc0c5b1f2764a1d611df1b46628274' })), transitionShadow ? (index.h("div", { class: "transition-effect" }, index.h("div", { class: "transition-cover" }), index.h("div", { class: "transition-shadow" }))) : null, fixedSlotPlacement === 'after' ? index.h("slot", { name: "fixed" }) : null));
618
+ }, ref: (scrollEl) => (this.scrollEl = scrollEl), onScroll: this.scrollEvents ? (ev) => this.onScroll(ev) : undefined, part: "scroll" }, index.h("slot", { key: '9049be4cea9b5da5ec1e1012248b05286fddeb7a' })), transitionShadow ? (index.h("div", { class: "transition-effect" }, index.h("div", { class: "transition-cover" }), index.h("div", { class: "transition-shadow" }))) : null, fixedSlotPlacement === 'after' ? index.h("slot", { name: "fixed" }) : null));
605
619
  }
606
620
  get el() { return index.getElement(this); }
607
621
  };
@@ -719,16 +733,16 @@ const Footer = class {
719
733
  this.destroyCollapsibleFooter();
720
734
  if (hasFade) {
721
735
  const pageEl = this.el.closest('ion-app,ion-page,.ion-page,page-inner');
722
- const contentEl = pageEl ? index$1.findIonContent(pageEl) : null;
736
+ const contentEl = pageEl ? index$2.findIonContent(pageEl) : null;
723
737
  if (!contentEl) {
724
- index$1.printIonContentErrorMsg(this.el);
738
+ index$2.printIonContentErrorMsg(this.el);
725
739
  return;
726
740
  }
727
741
  this.setupFadeFooter(contentEl);
728
742
  }
729
743
  };
730
744
  this.setupFadeFooter = async (contentEl) => {
731
- const scrollEl = (this.scrollEl = await index$1.getScrollElement(contentEl));
745
+ const scrollEl = (this.scrollEl = await index$2.getScrollElement(contentEl));
732
746
  /**
733
747
  * Handle fading of toolbars on scroll
734
748
  */
@@ -1041,7 +1055,7 @@ const Header = class {
1041
1055
  */
1042
1056
  this.translucent = false;
1043
1057
  this.setupFadeHeader = async (contentEl, condenseHeader) => {
1044
- const scrollEl = (this.scrollEl = await index$1.getScrollElement(contentEl));
1058
+ const scrollEl = (this.scrollEl = await index$2.getScrollElement(contentEl));
1045
1059
  /**
1046
1060
  * Handle fading of toolbars on scroll
1047
1061
  */
@@ -1075,7 +1089,7 @@ const Header = class {
1075
1089
  this.destroyCollapsibleHeader();
1076
1090
  if (hasCondense) {
1077
1091
  const pageEl = this.el.closest('ion-app,ion-page,.ion-page,page-inner');
1078
- const contentEl = pageEl ? index$1.findIonContent(pageEl) : null;
1092
+ const contentEl = pageEl ? index$2.findIonContent(pageEl) : null;
1079
1093
  // Cloned elements are always needed in iOS transition
1080
1094
  index.writeTask(() => {
1081
1095
  const title = cloneElement('ion-title');
@@ -1086,9 +1100,9 @@ const Header = class {
1086
1100
  }
1087
1101
  else if (hasFade) {
1088
1102
  const pageEl = this.el.closest('ion-app,ion-page,.ion-page,page-inner');
1089
- const contentEl = pageEl ? index$1.findIonContent(pageEl) : null;
1103
+ const contentEl = pageEl ? index$2.findIonContent(pageEl) : null;
1090
1104
  if (!contentEl) {
1091
- index$1.printIonContentErrorMsg(this.el);
1105
+ index$2.printIonContentErrorMsg(this.el);
1092
1106
  return;
1093
1107
  }
1094
1108
  const condenseHeader = contentEl.querySelector('ion-header[collapse="condense"]');
@@ -1111,13 +1125,13 @@ const Header = class {
1111
1125
  }
1112
1126
  async setupCondenseHeader(contentEl, pageEl) {
1113
1127
  if (!contentEl || !pageEl) {
1114
- index$1.printIonContentErrorMsg(this.el);
1128
+ index$2.printIonContentErrorMsg(this.el);
1115
1129
  return;
1116
1130
  }
1117
1131
  if (typeof IntersectionObserver === 'undefined') {
1118
1132
  return;
1119
1133
  }
1120
- this.scrollEl = await index$1.getScrollElement(contentEl);
1134
+ this.scrollEl = await index$2.getScrollElement(contentEl);
1121
1135
  const headers = pageEl.querySelectorAll('ion-header');
1122
1136
  this.collapsibleMainHeader = Array.from(headers).find((header) => header.collapse !== 'condense');
1123
1137
  if (!this.collapsibleMainHeader) {
@@ -1315,7 +1329,7 @@ const RouterOutlet = class {
1315
1329
  const { el, mode } = this;
1316
1330
  const animated = this.animated && index.config.getBoolean('animated', true);
1317
1331
  const animationBuilder = opts.animationBuilder || this.animation || index.config.get('navAnimation');
1318
- await index$2.transition(Object.assign(Object.assign({ mode,
1332
+ await index$3.transition(Object.assign(Object.assign({ mode,
1319
1333
  animated,
1320
1334
  enteringEl,
1321
1335
  leavingEl, baseEl: el,
@@ -4,6 +4,7 @@
4
4
  'use strict';
5
5
 
6
6
  var index$3 = require('./index-D6Wc6v08.js');
7
+ var index = require('./index-DkNv4J_i.js');
7
8
  var index$2 = require('./index-CO6eryBo.js');
8
9
  var frameworkDelegate = require('./framework-delegate-DMJRBuDi.js');
9
10
  var helpers = require('./helpers-DrTqNghc.js');
@@ -17,7 +18,6 @@ var keyboard = require('./keyboard-hHzlEQpk.js');
17
18
  var animation = require('./animation-Bt3H9L1C.js');
18
19
  var cubicBezier = require('./cubic-bezier-DAjy1V-e.js');
19
20
  var index$1 = require('./index-CAvQ7Tka.js');
20
- var index = require('./index-DkNv4J_i.js');
21
21
  require('./hardware-back-button-VCK4V3mG.js');
22
22
  require('./gesture-controller-dtqlP_q4.js');
23
23
  require('./keyboard-UuAS4D_9.js');
@@ -1723,6 +1723,8 @@ const Modal = class {
1723
1723
  this.triggerController.removeClickListener();
1724
1724
  this.cleanupViewTransitionListener();
1725
1725
  this.cleanupParentRemovalObserver();
1726
+ // Reset safe-area state to handle removal without dismiss (e.g., framework unmount)
1727
+ this.resetSafeAreaState();
1726
1728
  }
1727
1729
  componentWillLoad() {
1728
1730
  var _a;
@@ -2159,7 +2161,9 @@ const Modal = class {
2159
2161
  this.skipSafeAreaCoordinateDetection = true;
2160
2162
  this.updateFooterPadding();
2161
2163
  // Watch for dynamic footer additions/removals (e.g., async data loading)
2162
- if (!this.footerObserver) {
2164
+ // Use subtree:true to support wrapped footers in framework components
2165
+ // (e.g., <my-footer><ion-footer>...</ion-footer></my-footer>)
2166
+ if (!this.footerObserver && index.win !== undefined && 'MutationObserver' in index.win) {
2163
2167
  this.footerObserver = new MutationObserver(() => this.updateFooterPadding());
2164
2168
  this.footerObserver.observe(this.el, { childList: true, subtree: true });
2165
2169
  }
@@ -2192,6 +2196,30 @@ const Modal = class {
2192
2196
  style.setProperty('--ion-safe-area-left', '0px');
2193
2197
  style.setProperty('--ion-safe-area-right', '0px');
2194
2198
  }
2199
+ /**
2200
+ * Resets all safe-area related state and styles.
2201
+ * Called during dismiss and disconnectedCallback to ensure clean state
2202
+ * for re-presentation of inline modals.
2203
+ */
2204
+ resetSafeAreaState() {
2205
+ var _a;
2206
+ this.skipSafeAreaCoordinateDetection = false;
2207
+ this.cachedSafeAreas = undefined;
2208
+ this.prevSafeAreaState = { top: false, bottom: false, left: false, right: false };
2209
+ (_a = this.footerObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
2210
+ this.footerObserver = undefined;
2211
+ // Clear wrapper styles that may have been set for safe-area handling
2212
+ if (this.wrapperEl) {
2213
+ this.wrapperEl.style.removeProperty('padding-bottom');
2214
+ this.wrapperEl.style.removeProperty('box-sizing');
2215
+ }
2216
+ // Clear safe-area CSS variable overrides
2217
+ const style = this.el.style;
2218
+ style.removeProperty('--ion-safe-area-top');
2219
+ style.removeProperty('--ion-safe-area-bottom');
2220
+ style.removeProperty('--ion-safe-area-left');
2221
+ style.removeProperty('--ion-safe-area-right');
2222
+ }
2195
2223
  /**
2196
2224
  * Gets the root safe-area values from the document element.
2197
2225
  * Uses cached values during gestures to avoid getComputedStyle calls.
@@ -2283,7 +2311,7 @@ const Modal = class {
2283
2311
  * For example, `cancel` or `backdrop`.
2284
2312
  */
2285
2313
  async dismiss(data, role) {
2286
- var _a, _b;
2314
+ var _a;
2287
2315
  if (this.gestureAnimationDismissing && role !== overlays.GESTURE) {
2288
2316
  return false;
2289
2317
  }
@@ -2346,22 +2374,7 @@ const Modal = class {
2346
2374
  this.currentBreakpoint = undefined;
2347
2375
  this.animation = undefined;
2348
2376
  // Reset safe-area state for potential re-presentation
2349
- this.skipSafeAreaCoordinateDetection = false;
2350
- this.cachedSafeAreas = undefined;
2351
- this.prevSafeAreaState = { top: false, bottom: false, left: false, right: false };
2352
- (_b = this.footerObserver) === null || _b === void 0 ? void 0 : _b.disconnect();
2353
- this.footerObserver = undefined;
2354
- // Clear styles that may have been set for safe-area handling
2355
- if (this.wrapperEl) {
2356
- this.wrapperEl.style.removeProperty('padding-bottom');
2357
- this.wrapperEl.style.removeProperty('box-sizing');
2358
- }
2359
- // Clear safe-area CSS variable overrides
2360
- const style = this.el.style;
2361
- style.removeProperty('--ion-safe-area-top');
2362
- style.removeProperty('--ion-safe-area-bottom');
2363
- style.removeProperty('--ion-safe-area-left');
2364
- style.removeProperty('--ion-safe-area-right');
2377
+ this.resetSafeAreaState();
2365
2378
  unlock();
2366
2379
  return dismissed;
2367
2380
  }
@@ -2611,20 +2624,20 @@ const Modal = class {
2611
2624
  const isCardModal = presentingElement !== undefined && mode === 'ios';
2612
2625
  const isHandleCycle = handleBehavior === 'cycle';
2613
2626
  const isSheetModalWithHandle = isSheetModal && showHandle;
2614
- return (index$3.h(index$3.Host, Object.assign({ key: '11cd16cc481093a38a327abdd94467be3f71718d', "no-router": true,
2627
+ return (index$3.h(index$3.Host, Object.assign({ key: '44022099fcaf047b97d1c2cb45b9b51c930e707c', "no-router": true,
2615
2628
  // Allow the modal to be navigable when the handle is focusable
2616
2629
  tabIndex: isHandleCycle && isSheetModalWithHandle ? 0 : -1 }, htmlAttributes, { style: {
2617
2630
  zIndex: `${20000 + this.overlayIndex}`,
2618
- }, class: Object.assign({ [mode]: true, ['modal-default']: !isCardModal && !isSheetModal, [`modal-card`]: isCardModal, [`modal-sheet`]: isSheetModal, [`modal-no-expand-scroll`]: isSheetModal && !expandToScroll, 'overlay-hidden': true, [overlays.FOCUS_TRAP_DISABLE_CLASS]: focusTrap === false }, theme.getClassMap(this.cssClass)), onIonBackdropTap: this.onBackdropTap, onIonModalDidPresent: this.onLifecycle, onIonModalWillPresent: this.onLifecycle, onIonModalWillDismiss: this.onLifecycle, onIonModalDidDismiss: this.onLifecycle, onFocus: this.onModalFocus }), index$3.h("ion-backdrop", { key: '125658fbb071960da3905854668078e15bce56da', ref: (el) => (this.backdropEl = el), visible: this.showBackdrop, tappable: this.backdropDismiss, part: "backdrop" }), mode === 'ios' && index$3.h("div", { key: '4a63815ef165e5806fef85ef48bf509813ff55c9', class: "modal-shadow" }), index$3.h("div", Object.assign({ key: 'cfc4b20354cbf2c0f873f6aee91c9b8f553de61d',
2631
+ }, class: Object.assign({ [mode]: true, ['modal-default']: !isCardModal && !isSheetModal, [`modal-card`]: isCardModal, [`modal-sheet`]: isSheetModal, [`modal-no-expand-scroll`]: isSheetModal && !expandToScroll, 'overlay-hidden': true, [overlays.FOCUS_TRAP_DISABLE_CLASS]: focusTrap === false }, theme.getClassMap(this.cssClass)), onIonBackdropTap: this.onBackdropTap, onIonModalDidPresent: this.onLifecycle, onIonModalWillPresent: this.onLifecycle, onIonModalWillDismiss: this.onLifecycle, onIonModalDidDismiss: this.onLifecycle, onFocus: this.onModalFocus }), index$3.h("ion-backdrop", { key: 'ddd7e4f6eef51ac1f62ac70e0af10fb01e707f07', ref: (el) => (this.backdropEl = el), visible: this.showBackdrop, tappable: this.backdropDismiss, part: "backdrop" }), mode === 'ios' && index$3.h("div", { key: '58620980e3e4ec273c6787bde026e1c010b904b7', class: "modal-shadow" }), index$3.h("div", Object.assign({ key: '3fb7f6218644ba898fc504467775593eb89426a0',
2619
2632
  /*
2620
2633
  role and aria-modal must be used on the
2621
2634
  same element. They must also be set inside the
2622
2635
  shadow DOM otherwise ion-button will not be highlighted
2623
2636
  when using VoiceOver: https://bugs.webkit.org/show_bug.cgi?id=247134
2624
2637
  */
2625
- role: "dialog" }, inheritedAttributes, { "aria-modal": "true", class: "modal-wrapper ion-overlay-wrapper", part: "content", ref: (el) => (this.wrapperEl = el) }), showHandle && (index$3.h("button", { key: '33a4ee89bb8b6512883cb8756641c1e27fdb0ebc', class: "modal-handle",
2638
+ role: "dialog" }, inheritedAttributes, { "aria-modal": "true", class: "modal-wrapper ion-overlay-wrapper", part: "content", ref: (el) => (this.wrapperEl = el) }), showHandle && (index$3.h("button", { key: '9745cd590fdaa9d023a14b487ec2c87ddbafd7f7', class: "modal-handle",
2626
2639
  // Prevents the handle from receiving keyboard focus when it does not cycle
2627
- tabIndex: !isHandleCycle ? -1 : 0, "aria-label": "Activate to adjust the size of the dialog overlaying the screen", onClick: isHandleCycle ? this.onHandleClick : undefined, part: "handle", ref: (el) => (this.dragHandleEl = el) })), index$3.h("slot", { key: '986fafb71234591c96e927f92b7330bb5c76fc2e', onSlotchange: this.onSlotChange }))));
2640
+ tabIndex: !isHandleCycle ? -1 : 0, "aria-label": "Activate to adjust the size of the dialog overlaying the screen", onClick: isHandleCycle ? this.onHandleClick : undefined, part: "handle", ref: (el) => (this.dragHandleEl = el) })), index$3.h("slot", { key: 'b9a8b5d2d3d3c9b06f99179f496c9f08907d0bad', onSlotchange: this.onSlotChange }))));
2628
2641
  }
2629
2642
  get el() { return index$3.getElement(this); }
2630
2643
  static get watchers() { return {
@@ -948,7 +948,7 @@ const mdEnterAnimation = (baseEl, opts) => {
948
948
  };
949
949
  const results = getPopoverPosition(isRTL, contentWidth, contentHeight, 0, 0, reference, side, align, defaultPosition, trigger, ev);
950
950
  const padding = size === 'cover' ? 0 : POPOVER_MD_BODY_PADDING;
951
- const { originX, originY, top, left, bottom, checkSafeAreaTop, checkSafeAreaBottom } = calculateWindowAdjustment(side, results.top, results.left, padding, bodyWidth, bodyHeight, contentWidth, contentHeight, 0, results.originX, results.originY, results.referenceCoordinates);
951
+ const { originX, originY, top, left, bottom, checkSafeAreaTop, checkSafeAreaBottom, checkSafeAreaLeft, checkSafeAreaRight, } = calculateWindowAdjustment(side, results.top, results.left, padding, bodyWidth, bodyHeight, contentWidth, contentHeight, 0, results.originX, results.originY, results.referenceCoordinates);
952
952
  /**
953
953
  * Safe area CSS variable adjustments.
954
954
  * When the popover is positioned near an edge, we add the corresponding
@@ -957,14 +957,23 @@ const mdEnterAnimation = (baseEl, opts) => {
957
957
  */
958
958
  const safeAreaTop = ' + var(--ion-safe-area-top, 0)';
959
959
  const safeAreaBottom = ' + var(--ion-safe-area-bottom, 0)';
960
+ const safeAreaLeft = ' + var(--ion-safe-area-left, 0)';
961
+ const safeAreaRight = ' - var(--ion-safe-area-right, 0)';
960
962
  let topValue = `${top}px`;
961
963
  let bottomValue = bottom !== undefined ? `${bottom}px` : undefined;
964
+ let leftValue = `${left}px`;
962
965
  if (checkSafeAreaTop) {
963
966
  topValue = `${top}px${safeAreaTop}`;
964
967
  }
965
968
  if (checkSafeAreaBottom && bottomValue !== undefined) {
966
969
  bottomValue = `${bottom}px${safeAreaBottom}`;
967
970
  }
971
+ if (checkSafeAreaLeft) {
972
+ leftValue = `${left}px${safeAreaLeft}`;
973
+ }
974
+ if (checkSafeAreaRight) {
975
+ leftValue = `${left}px${safeAreaRight}`;
976
+ }
968
977
  const baseAnimation = animation.createAnimation();
969
978
  const backdropAnimation = animation.createAnimation();
970
979
  const wrapperAnimation = animation.createAnimation();
@@ -982,7 +991,7 @@ const mdEnterAnimation = (baseEl, opts) => {
982
991
  .addElement(contentEl)
983
992
  .beforeStyles({
984
993
  top: `calc(${topValue} + var(--offset-y, 0px))`,
985
- left: `calc(${left}px + var(--offset-x, 0px))`,
994
+ left: `calc(${leftValue} + var(--offset-x, 0px))`,
986
995
  'transform-origin': `${originY} ${originX}`,
987
996
  })
988
997
  .beforeAddWrite(() => {