@ionic/core 8.7.17-dev.11767895575.16ea7cef → 8.7.17-dev.11767980394.1d9266a9

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.
Files changed (42) hide show
  1. package/components/content.js +111 -8
  2. package/components/ion-tab-bar.js +3 -23
  3. package/components/modal.js +213 -12
  4. package/components/popover.js +83 -11
  5. package/dist/cjs/ion-app_8.cjs.entry.js +122 -20
  6. package/dist/cjs/ion-modal.cjs.entry.js +213 -12
  7. package/dist/cjs/ion-popover.cjs.entry.js +83 -11
  8. package/dist/cjs/ion-tab-bar_2.cjs.entry.js +3 -23
  9. package/dist/collection/components/content/content.css +10 -0
  10. package/dist/collection/components/content/content.js +109 -6
  11. package/dist/collection/components/modal/gestures/sheet.js +3 -1
  12. package/dist/collection/components/modal/gestures/swipe-to-close.js +3 -1
  13. package/dist/collection/components/modal/modal.ios.css +0 -4
  14. package/dist/collection/components/modal/modal.js +205 -7
  15. package/dist/collection/components/modal/modal.md.css +0 -4
  16. package/dist/collection/components/popover/animations/ios.enter.js +21 -5
  17. package/dist/collection/components/popover/animations/md.enter.js +30 -5
  18. package/dist/collection/components/popover/utils.js +32 -1
  19. package/dist/collection/components/tab-bar/tab-bar.js +3 -23
  20. package/dist/docs.json +1 -1
  21. package/dist/esm/ion-app_8.entry.js +111 -9
  22. package/dist/esm/ion-modal.entry.js +213 -12
  23. package/dist/esm/ion-popover.entry.js +83 -11
  24. package/dist/esm/ion-tab-bar_2.entry.js +3 -23
  25. package/dist/ionic/ionic.esm.js +1 -1
  26. package/dist/ionic/p-7268efa5.entry.js +4 -0
  27. package/dist/ionic/p-968a55d1.entry.js +4 -0
  28. package/dist/ionic/p-b55c44c8.entry.js +4 -0
  29. package/dist/ionic/p-ec9ca3fe.entry.js +4 -0
  30. package/dist/types/components/content/content.d.ts +26 -0
  31. package/dist/types/components/modal/gestures/sheet.d.ts +1 -1
  32. package/dist/types/components/modal/gestures/swipe-to-close.d.ts +1 -1
  33. package/dist/types/components/modal/modal.d.ts +45 -0
  34. package/dist/types/components/popover/utils.d.ts +2 -0
  35. package/dist/types/components/tab-bar/tab-bar.d.ts +0 -1
  36. package/hydrate/index.js +395 -52
  37. package/hydrate/index.mjs +395 -52
  38. package/package.json +1 -1
  39. package/dist/ionic/p-172a579f.entry.js +0 -4
  40. package/dist/ionic/p-732b2fd6.entry.js +0 -4
  41. package/dist/ionic/p-91840a80.entry.js +0 -4
  42. package/dist/ionic/p-f9061316.entry.js +0 -4
@@ -648,6 +648,8 @@ export const calculateWindowAdjustment = (side, coordTop, coordLeft, bodyPadding
648
648
  let bottom;
649
649
  let originX = contentOriginX;
650
650
  let originY = contentOriginY;
651
+ let checkSafeAreaTop = false;
652
+ let checkSafeAreaBottom = false;
651
653
  let checkSafeAreaLeft = false;
652
654
  let checkSafeAreaRight = false;
653
655
  const triggerTop = triggerCoordinates
@@ -692,10 +694,18 @@ export const calculateWindowAdjustment = (side, coordTop, coordLeft, bodyPadding
692
694
  * We chose 12 here so that the popover position looks a bit nicer as
693
695
  * it is not right up against the edge of the screen.
694
696
  */
695
- top = Math.max(12, triggerTop - contentHeight - triggerHeight - (arrowHeight - 1));
697
+ top = Math.max(bodyPadding, triggerTop - contentHeight - triggerHeight - (arrowHeight - 1));
696
698
  arrowTop = top + contentHeight;
697
699
  originY = 'bottom';
698
700
  addPopoverBottomClass = true;
701
+ /**
702
+ * If the popover is positioned near the top edge, account for safe area.
703
+ * This ensures the popover doesn't overlap with status bars or notches.
704
+ */
705
+ if (top <= bodyPadding + safeAreaMargin) {
706
+ checkSafeAreaTop = true;
707
+ top = bodyPadding;
708
+ }
699
709
  /**
700
710
  * If not enough room for popover to appear
701
711
  * above trigger, then cut it off.
@@ -703,14 +713,35 @@ export const calculateWindowAdjustment = (side, coordTop, coordLeft, bodyPadding
703
713
  }
704
714
  else {
705
715
  bottom = bodyPadding;
716
+ /**
717
+ * When the popover is pinned to the bottom, account for safe area.
718
+ * This ensures the popover doesn't overlap with home indicators
719
+ * or navigation bars (e.g., Android API 36+ edge-to-edge).
720
+ */
721
+ checkSafeAreaBottom = true;
706
722
  }
707
723
  }
724
+ /**
725
+ * Final check: If the popover extends into any safe-area region,
726
+ * ensure the corresponding flag is set regardless of side.
727
+ * This handles cases where a side-positioned popover (left/right)
728
+ * still needs bottom safe-area padding because it extends into that region.
729
+ */
730
+ const popoverBottom = bottom !== undefined ? bodyHeight - bottom : top + contentHeight;
731
+ if (popoverBottom + safeAreaMargin > bodyHeight) {
732
+ checkSafeAreaBottom = true;
733
+ }
734
+ if (top < safeAreaMargin) {
735
+ checkSafeAreaTop = true;
736
+ }
708
737
  return {
709
738
  top,
710
739
  left,
711
740
  bottom,
712
741
  originX,
713
742
  originY,
743
+ checkSafeAreaTop,
744
+ checkSafeAreaBottom,
714
745
  checkSafeAreaLeft,
715
746
  checkSafeAreaRight,
716
747
  arrowTop,
@@ -11,7 +11,6 @@ import { getIonMode } from "../../global/ionic-global";
11
11
  export class TabBar {
12
12
  constructor() {
13
13
  this.keyboardCtrl = null;
14
- this.keyboardCtrlPromise = null;
15
14
  this.didLoad = false;
16
15
  this.keyboardVisible = false;
17
16
  /**
@@ -47,7 +46,7 @@ export class TabBar {
47
46
  }
48
47
  }
49
48
  async connectedCallback() {
50
- const promise = createKeyboardController(async (keyboardOpen, waitForResize) => {
49
+ this.keyboardCtrl = await createKeyboardController(async (keyboardOpen, waitForResize) => {
51
50
  /**
52
51
  * If the keyboard is hiding, then we need to wait
53
52
  * for the webview to resize. Otherwise, the tab bar
@@ -58,40 +57,21 @@ export class TabBar {
58
57
  }
59
58
  this.keyboardVisible = keyboardOpen; // trigger re-render by updating state
60
59
  });
61
- this.keyboardCtrlPromise = promise;
62
- const keyboardCtrl = await promise;
63
- /**
64
- * Only assign if this is still the current promise.
65
- * Otherwise, a new connectedCallback has started or
66
- * disconnectedCallback was called, so destroy this instance.
67
- */
68
- if (this.keyboardCtrlPromise === promise) {
69
- this.keyboardCtrl = keyboardCtrl;
70
- this.keyboardCtrlPromise = null;
71
- }
72
- else {
73
- keyboardCtrl.destroy();
74
- }
75
60
  }
76
61
  disconnectedCallback() {
77
- if (this.keyboardCtrlPromise) {
78
- this.keyboardCtrlPromise.then((ctrl) => ctrl.destroy());
79
- this.keyboardCtrlPromise = null;
80
- }
81
62
  if (this.keyboardCtrl) {
82
63
  this.keyboardCtrl.destroy();
83
- this.keyboardCtrl = null;
84
64
  }
85
65
  }
86
66
  render() {
87
67
  const { color, translucent, keyboardVisible } = this;
88
68
  const mode = getIonMode(this);
89
69
  const shouldHide = keyboardVisible && this.el.getAttribute('slot') !== 'top';
90
- return (h(Host, { key: '9daf4e2acaff6e3ce3878cf9dd5109fb1afbbebe', role: "tablist", "aria-hidden": shouldHide ? 'true' : null, class: createColorClasses(color, {
70
+ return (h(Host, { key: '388ec37ce308035bab78d6c9a016bb616e9517a9', role: "tablist", "aria-hidden": shouldHide ? 'true' : null, class: createColorClasses(color, {
91
71
  [mode]: true,
92
72
  'tab-bar-translucent': translucent,
93
73
  'tab-bar-hidden': shouldHide,
94
- }) }, h("slot", { key: '1d15aa2da8501e8e7eff11ad4a491478be845c43' })));
74
+ }) }, h("slot", { key: 'ce10ade2b86725e24f3254516483eeedd8ecb16a' })));
95
75
  }
96
76
  static get is() { return "ion-tab-bar"; }
97
77
  static get encapsulation() { return "shadow"; }
package/dist/docs.json CHANGED
@@ -1,5 +1,5 @@
1
1
  {
2
- "timestamp": "2026-01-08T18:08:20",
2
+ "timestamp": "2026-01-09T17:41:47",
3
3
  "compiler": {
4
4
  "name": "@stencil/core",
5
5
  "version": "4.38.0",
@@ -1,9 +1,10 @@
1
1
  /*!
2
2
  * (C) Ionic http://ionicframework.com - MIT License
3
3
  */
4
- import { r as registerInstance, h, e as config, d as Host, g as getElement, f as printIonWarning, c as createEvent, a as readTask, i as forceUpdate, w as writeTask, j as printIonError } from './index-C8IsBmNU.js';
4
+ import { r as registerInstance, h, e as config, d as Host, g as getElement, f as printIonWarning, c as createEvent, i as forceUpdate, a as readTask, w as writeTask, j as printIonError } from './index-C8IsBmNU.js';
5
5
  import { shouldUseCloseWatcher } from './hardware-back-button-CPLxO-Ev.js';
6
6
  import { b as getIonMode, a as isPlatform } from './ionic-global-CDrldh-5.js';
7
+ import { w as win } from './index-ZjP4CjeZ.js';
7
8
  import { i as inheritAriaAttributes, h as hasLazyBuild, c as componentOnReady, e as clamp, s as shallowEqualStringMap } from './helpers-DEn3pfjm.js';
8
9
  import { i as isRTL } from './dir-C53feagD.js';
9
10
  import { c as createColorClasses, h as hostContext } from './theme-DiVJyqlX.js';
@@ -13,7 +14,6 @@ import { g as getTimeGivenProgression } from './cubic-bezier-hHmYLOfE.js';
13
14
  import { a as attachComponent, d as detachComponent } from './framework-delegate-BYawdMXj.js';
14
15
  import { c as createLockController } from './lock-controller-B-hirT0v.js';
15
16
  import { t as transition } from './index-r2D9DEro.js';
16
- import './index-ZjP4CjeZ.js';
17
17
  import './keyboard-CUw4ekVy.js';
18
18
  import './capacitor-CFERIeaU.js';
19
19
 
@@ -152,7 +152,7 @@ Buttons.style = {
152
152
  md: buttonsMdCss
153
153
  };
154
154
 
155
- const contentCss = ":host{--background:var(--ion-background-color, #fff);--color:var(--ion-text-color, #000);--padding-top:0px;--padding-bottom:0px;--padding-start:0px;--padding-end:0px;--keyboard-offset:0px;--offset-top:0px;--offset-bottom:0px;--overflow:auto;display:block;position:relative;-ms-flex:1;flex:1;width:100%;height:100%;margin:0 !important;padding:0 !important;font-family:var(--ion-font-family, inherit);contain:size style}:host(.ion-color) .inner-scroll{background:var(--ion-color-base);color:var(--ion-color-contrast)}#background-content{left:0px;right:0px;top:calc(var(--offset-top) * -1);bottom:calc(var(--offset-bottom) * -1);position:absolute;background:var(--background)}.inner-scroll{left:0px;right:0px;top:calc(var(--offset-top) * -1);bottom:calc(var(--offset-bottom) * -1);-webkit-padding-start:var(--padding-start);padding-inline-start:var(--padding-start);-webkit-padding-end:var(--padding-end);padding-inline-end:var(--padding-end);padding-top:calc(var(--padding-top) + var(--offset-top));padding-bottom:calc(var(--padding-bottom) + var(--keyboard-offset) + var(--offset-bottom));position:absolute;color:var(--color);-webkit-box-sizing:border-box;box-sizing:border-box;overflow:hidden;-ms-touch-action:pan-x pan-y pinch-zoom;touch-action:pan-x pan-y pinch-zoom}.scroll-y,.scroll-x{-webkit-overflow-scrolling:touch;z-index:0;will-change:scroll-position}.scroll-y{overflow-y:var(--overflow);overscroll-behavior-y:contain}.scroll-x{overflow-x:var(--overflow);overscroll-behavior-x:contain}.overscroll::before,.overscroll::after{position:absolute;width:1px;height:1px;content:\"\"}.overscroll::before{bottom:-1px}.overscroll::after{top:-1px}:host(.content-sizing){display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;min-height:0;contain:none}:host(.content-sizing) .inner-scroll{position:relative;top:0;bottom:0;margin-top:calc(var(--offset-top) * -1);margin-bottom:calc(var(--offset-bottom) * -1)}.transition-effect{display:none;position:absolute;width:100%;height:100vh;opacity:0;pointer-events:none}:host(.content-ltr) .transition-effect{left:-100%;}:host(.content-rtl) .transition-effect{right:-100%;}.transition-cover{position:absolute;right:0;width:100%;height:100%;background:black;opacity:0.1}.transition-shadow{display:block;position:absolute;width:100%;height:100%;-webkit-box-shadow:inset -9px 0 9px 0 rgba(0, 0, 100, 0.03);box-shadow:inset -9px 0 9px 0 rgba(0, 0, 100, 0.03)}:host(.content-ltr) .transition-shadow{right:0;}:host(.content-rtl) .transition-shadow{left:0;-webkit-transform:scaleX(-1);transform:scaleX(-1)}::slotted([slot=fixed]){position:absolute;-webkit-transform:translateZ(0);transform:translateZ(0)}";
155
+ const contentCss = ":host{--background:var(--ion-background-color, #fff);--color:var(--ion-text-color, #000);--padding-top:0px;--padding-bottom:0px;--padding-start:0px;--padding-end:0px;--keyboard-offset:0px;--offset-top:0px;--offset-bottom:0px;--overflow:auto;display:block;position:relative;-ms-flex:1;flex:1;width:100%;height:100%;margin:0 !important;padding:0 !important;font-family:var(--ion-font-family, inherit);contain:size style}:host(.ion-color) .inner-scroll{background:var(--ion-color-base);color:var(--ion-color-contrast)}#background-content{left:0px;right:0px;top:calc(var(--offset-top) * -1);bottom:calc(var(--offset-bottom) * -1);position:absolute;background:var(--background)}.inner-scroll{left:0px;right:0px;top:calc(var(--offset-top) * -1);bottom:calc(var(--offset-bottom) * -1);-webkit-padding-start:var(--padding-start);padding-inline-start:var(--padding-start);-webkit-padding-end:var(--padding-end);padding-inline-end:var(--padding-end);padding-top:calc(var(--padding-top) + var(--offset-top));padding-bottom:calc(var(--padding-bottom) + var(--keyboard-offset) + var(--offset-bottom));position:absolute;color:var(--color);-webkit-box-sizing:border-box;box-sizing:border-box;overflow:hidden;-ms-touch-action:pan-x pan-y pinch-zoom;touch-action:pan-x pan-y pinch-zoom}.scroll-y,.scroll-x{-webkit-overflow-scrolling:touch;z-index:0;will-change:scroll-position}.scroll-y{overflow-y:var(--overflow);overscroll-behavior-y:contain}.scroll-x{overflow-x:var(--overflow);overscroll-behavior-x:contain}.overscroll::before,.overscroll::after{position:absolute;width:1px;height:1px;content:\"\"}.overscroll::before{bottom:-1px}.overscroll::after{top:-1px}:host(.content-sizing){display:-ms-flexbox;display:flex;-ms-flex-direction:column;flex-direction:column;min-height:0;contain:none}:host(.content-sizing) .inner-scroll{position:relative;top:0;bottom:0;margin-top:calc(var(--offset-top) * -1);margin-bottom:calc(var(--offset-bottom) * -1)}.transition-effect{display:none;position:absolute;width:100%;height:100vh;opacity:0;pointer-events:none}:host(.content-ltr) .transition-effect{left:-100%;}:host(.content-rtl) .transition-effect{right:-100%;}.transition-cover{position:absolute;right:0;width:100%;height:100%;background:black;opacity:0.1}.transition-shadow{display:block;position:absolute;width:100%;height:100%;-webkit-box-shadow:inset -9px 0 9px 0 rgba(0, 0, 100, 0.03);box-shadow:inset -9px 0 9px 0 rgba(0, 0, 100, 0.03)}:host(.content-ltr) .transition-shadow{right:0;}:host(.content-rtl) .transition-shadow{left:0;-webkit-transform:scaleX(-1);transform:scaleX(-1)}:host(.safe-area-top) #background-content,:host(.safe-area-top) .inner-scroll{top:var(--ion-safe-area-top, 0px)}:host(.safe-area-bottom) #background-content,:host(.safe-area-bottom) .inner-scroll{bottom:var(--ion-safe-area-bottom, 0px)}::slotted([slot=fixed]){position:absolute;-webkit-transform:translateZ(0);transform:translateZ(0)}";
156
156
 
157
157
  const Content = class {
158
158
  constructor(hostRef) {
@@ -169,6 +169,12 @@ const Content = class {
169
169
  this.isMainContent = true;
170
170
  this.resizeTimeout = null;
171
171
  this.inheritedAttributes = {};
172
+ /**
173
+ * Track whether this content has sibling header/footer elements.
174
+ * When absent, we need to apply safe-area padding directly.
175
+ */
176
+ this.hasHeader = false;
177
+ this.hasFooter = false;
172
178
  this.tabsElement = null;
173
179
  // Detail is used in a hot loop in the scroll event, by allocating it here
174
180
  // V8 will be able to inline any read/write to it since it's a monomorphic class.
@@ -223,7 +229,13 @@ const Content = class {
223
229
  this.inheritedAttributes = inheritAriaAttributes(this.el);
224
230
  }
225
231
  connectedCallback() {
226
- this.isMainContent = this.el.closest('ion-menu, ion-popover, ion-modal') === null;
232
+ var _a;
233
+ // Content is "main" if not inside menu/popover/modal and not nested in another ion-content
234
+ this.isMainContent =
235
+ this.el.closest('ion-menu, ion-popover, ion-modal') === null &&
236
+ ((_a = this.el.parentElement) === null || _a === void 0 ? void 0 : _a.closest('ion-content')) === null;
237
+ // Detect sibling header/footer for safe-area handling
238
+ this.detectSiblingElements();
227
239
  /**
228
240
  * The fullscreen content offsets need to be
229
241
  * computed after the tab bar has loaded. Since
@@ -254,13 +266,101 @@ const Content = class {
254
266
  * bubbles, we can catch any instances of child tab bars loading by listening
255
267
  * on IonTabs.
256
268
  */
257
- this.tabsLoadCallback = () => this.resize();
269
+ this.tabsLoadCallback = () => {
270
+ this.resize();
271
+ // Re-detect footer when tab bar loads (it may not exist during initial detection)
272
+ this.updateSiblingDetection();
273
+ forceUpdate(this);
274
+ };
258
275
  closestTabs.addEventListener('ionTabBarLoaded', this.tabsLoadCallback);
259
276
  }
260
277
  }
261
278
  }
279
+ /**
280
+ * Detects sibling ion-header and ion-footer elements and sets up
281
+ * a mutation observer to handle dynamic changes (e.g., conditional rendering).
282
+ */
283
+ detectSiblingElements() {
284
+ this.updateSiblingDetection();
285
+ // Watch for dynamic header/footer changes (common in React conditional rendering)
286
+ const parent = this.el.parentElement;
287
+ if (parent && !this.parentMutationObserver && win !== undefined && 'MutationObserver' in win) {
288
+ this.parentMutationObserver = new MutationObserver(() => {
289
+ const prevHasHeader = this.hasHeader;
290
+ const prevHasFooter = this.hasFooter;
291
+ this.updateSiblingDetection();
292
+ // Only trigger re-render if header/footer detection actually changed
293
+ if (prevHasHeader !== this.hasHeader || prevHasFooter !== this.hasFooter) {
294
+ forceUpdate(this);
295
+ }
296
+ });
297
+ this.parentMutationObserver.observe(parent, { childList: true });
298
+ }
299
+ // Watch for dynamic tab bar changes in ion-tabs (common in Angular conditional rendering)
300
+ const tabs = this.el.closest('ion-tabs');
301
+ if (tabs && !this.tabsMutationObserver && win !== undefined && 'MutationObserver' in win) {
302
+ this.tabsMutationObserver = new MutationObserver(() => {
303
+ const prevHasFooter = this.hasFooter;
304
+ this.updateSiblingDetection();
305
+ // Only trigger re-render if footer detection actually changed
306
+ if (prevHasFooter !== this.hasFooter) {
307
+ forceUpdate(this);
308
+ }
309
+ });
310
+ this.tabsMutationObserver.observe(tabs, { childList: true });
311
+ }
312
+ }
313
+ /**
314
+ * Updates hasHeader/hasFooter based on current DOM state.
315
+ * Checks both direct siblings and elements wrapped in custom components
316
+ * (e.g., <my-header><ion-header>...</ion-header></my-header>).
317
+ */
318
+ updateSiblingDetection() {
319
+ const parent = this.el.parentElement;
320
+ if (parent) {
321
+ // First check for direct ion-header/ion-footer siblings
322
+ this.hasHeader = parent.querySelector(':scope > ion-header') !== null;
323
+ this.hasFooter = parent.querySelector(':scope > ion-footer') !== null;
324
+ // If not found, check if any sibling contains them (wrapped components)
325
+ if (!this.hasHeader) {
326
+ this.hasHeader = this.siblingContainsElement(parent, 'ion-header');
327
+ }
328
+ if (!this.hasFooter) {
329
+ this.hasFooter = this.siblingContainsElement(parent, 'ion-footer');
330
+ }
331
+ }
332
+ // If no footer found, check if we're inside ion-tabs which has ion-tab-bar
333
+ if (!this.hasFooter) {
334
+ const tabs = this.el.closest('ion-tabs');
335
+ if (tabs) {
336
+ this.hasFooter = tabs.querySelector(':scope > ion-tab-bar') !== null;
337
+ }
338
+ }
339
+ }
340
+ /**
341
+ * Checks if any sibling element of ion-content contains the specified element.
342
+ * Only searches one level deep to avoid finding elements in nested pages.
343
+ */
344
+ siblingContainsElement(parent, tagName) {
345
+ for (const sibling of parent.children) {
346
+ // Skip ion-content itself
347
+ if (sibling === this.el)
348
+ continue;
349
+ // Check if this sibling contains the target element as an immediate child
350
+ if (sibling.querySelector(`:scope > ${tagName}`) !== null) {
351
+ return true;
352
+ }
353
+ }
354
+ return false;
355
+ }
262
356
  disconnectedCallback() {
357
+ var _a, _b;
263
358
  this.onScrollEnd();
359
+ // Clean up mutation observers to prevent memory leaks
360
+ (_a = this.parentMutationObserver) === null || _a === void 0 ? void 0 : _a.disconnect();
361
+ this.parentMutationObserver = undefined;
362
+ (_b = this.tabsMutationObserver) === null || _b === void 0 ? void 0 : _b.disconnect();
363
+ this.tabsMutationObserver = undefined;
264
364
  if (hasLazyBuild(this.el)) {
265
365
  /**
266
366
  * The event listener and tabs caches need to
@@ -507,26 +607,28 @@ const Content = class {
507
607
  }
508
608
  }
509
609
  render() {
510
- const { fixedSlotPlacement, inheritedAttributes, isMainContent, scrollX, scrollY, el } = this;
610
+ const { fixedSlotPlacement, hasFooter, hasHeader, inheritedAttributes, isMainContent, scrollX, scrollY, el } = this;
511
611
  const rtl = isRTL(el) ? 'rtl' : 'ltr';
512
612
  const mode = getIonMode(this);
513
613
  const forceOverscroll = this.shouldForceOverscroll();
514
614
  const transitionShadow = mode === 'ios';
515
615
  this.resize();
516
- return (h(Host, Object.assign({ key: 'cd8781f848d8dc926fe66f43d43c49564425a507', role: isMainContent ? 'main' : undefined, class: createColorClasses(this.color, {
616
+ return (h(Host, Object.assign({ key: '8b40855d7b3257fac16b0c945dc54b75a8a36b1f', role: isMainContent ? 'main' : undefined, class: createColorClasses(this.color, {
517
617
  [mode]: true,
518
618
  'content-sizing': hostContext('ion-popover', this.el),
519
619
  overscroll: forceOverscroll,
520
620
  [`content-${rtl}`]: true,
621
+ 'safe-area-top': isMainContent && !hasHeader,
622
+ 'safe-area-bottom': isMainContent && !hasFooter,
521
623
  }), style: {
522
624
  '--offset-top': `${this.cTop}px`,
523
625
  '--offset-bottom': `${this.cBottom}px`,
524
- } }, inheritedAttributes), h("div", { key: '95b112d7cae30f22ef778ceffb88edb4d941c170', ref: (el) => (this.backgroundContentEl = el), id: "background-content", part: "background" }), fixedSlotPlacement === 'before' ? h("slot", { name: "fixed" }) : null, h("div", { key: '2fdfcbc39fb66f11b6191911f2941c660f4c12e5', class: {
626
+ } }, inheritedAttributes), h("div", { key: '1ec3de99f33ed7a252a637c14887043c96046536', ref: (el) => (this.backgroundContentEl = el), id: "background-content", part: "background" }), fixedSlotPlacement === 'before' ? h("slot", { name: "fixed" }) : null, h("div", { key: 'dae33d14c489a55fcb6eceabbec3cb3b04726f34', class: {
525
627
  'inner-scroll': true,
526
628
  'scroll-x': scrollX,
527
629
  'scroll-y': scrollY,
528
630
  overscroll: (scrollX || scrollY) && forceOverscroll,
529
- }, ref: (scrollEl) => (this.scrollEl = scrollEl), onScroll: this.scrollEvents ? (ev) => this.onScroll(ev) : undefined, part: "scroll" }, h("slot", { key: '6bc77e0054ec8e21635a7f2abfe0ca46e0962e03' })), transitionShadow ? (h("div", { class: "transition-effect" }, h("div", { class: "transition-cover" }), h("div", { class: "transition-shadow" }))) : null, fixedSlotPlacement === 'after' ? h("slot", { name: "fixed" }) : null));
631
+ }, ref: (scrollEl) => (this.scrollEl = scrollEl), onScroll: this.scrollEvents ? (ev) => this.onScroll(ev) : undefined, part: "scroll" }, h("slot", { key: 'e99873d5fcc573e5d6ccad0f7c79192e99f4b749' })), transitionShadow ? (h("div", { class: "transition-effect" }, h("div", { class: "transition-cover" }), h("div", { class: "transition-shadow" }))) : null, fixedSlotPlacement === 'after' ? h("slot", { name: "fixed" }) : null));
530
632
  }
531
633
  get el() { return getElement(this); }
532
634
  };