Skip to content

Commit 8ee1069

Browse files
committed
Reverting changes to be focused on modal and popover safe area support
1 parent 3b7beca commit 8ee1069

4 files changed

Lines changed: 3 additions & 650 deletions

File tree

core/src/components/content/content.scss

Lines changed: 0 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -235,38 +235,6 @@
235235
}
236236

237237

238-
// Content: Safe Area
239-
// --------------------------------------------------
240-
// When content has no sibling header, offset from top safe-area.
241-
// When content has no sibling footer/tab-bar, offset from bottom safe-area.
242-
// Left/right safe-areas always apply to main content (for landscape notched devices).
243-
// This prevents content from overlapping device safe areas (status bar, nav bar, notch).
244-
245-
:host(.safe-area-top) #background-content,
246-
:host(.safe-area-top) .inner-scroll {
247-
top: var(--ion-safe-area-top, 0px);
248-
}
249-
250-
:host(.safe-area-bottom) #background-content,
251-
:host(.safe-area-bottom) .inner-scroll {
252-
bottom: var(--ion-safe-area-bottom, 0px);
253-
}
254-
255-
:host(.safe-area-left) #background-content,
256-
:host(.safe-area-left) .inner-scroll {
257-
/* stylelint-disable property-disallowed-list */
258-
left: var(--ion-safe-area-left, 0px);
259-
/* stylelint-enable property-disallowed-list */
260-
}
261-
262-
:host(.safe-area-right) #background-content,
263-
:host(.safe-area-right) .inner-scroll {
264-
/* stylelint-disable property-disallowed-list */
265-
right: var(--ion-safe-area-right, 0px);
266-
/* stylelint-enable property-disallowed-list */
267-
}
268-
269-
270238
// Content: Fixed
271239
// --------------------------------------------------
272240

core/src/components/content/content.tsx

Lines changed: 3 additions & 121 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
import type { ComponentInterface, EventEmitter } from '@stencil/core';
22
import { Build, Component, Element, Event, Host, Listen, Method, Prop, forceUpdate, h, readTask } from '@stencil/core';
3-
import { win } from '@utils/browser';
43
import { componentOnReady, hasLazyBuild, inheritAriaAttributes } from '@utils/helpers';
54
import type { Attributes } from '@utils/helpers';
65
import { isPlatform } from '@utils/platform';
@@ -37,19 +36,6 @@ export class Content implements ComponentInterface {
3736
private resizeTimeout: ReturnType<typeof setTimeout> | null = null;
3837
private inheritedAttributes: Attributes = {};
3938

40-
/**
41-
* Track whether this content has sibling header/footer elements.
42-
* When absent, we need to apply safe-area padding directly.
43-
*/
44-
private hasHeader = false;
45-
private hasFooter = false;
46-
47-
/** Watches for dynamic header/footer changes in parent element */
48-
private parentMutationObserver?: MutationObserver;
49-
50-
/** Watches for dynamic tab bar changes in ion-tabs */
51-
private tabsMutationObserver?: MutationObserver;
52-
5339
private tabsElement: HTMLElement | null = null;
5440
private tabsLoadCallback?: () => void;
5541

@@ -146,13 +132,7 @@ export class Content implements ComponentInterface {
146132
}
147133

148134
connectedCallback() {
149-
// Content is "main" if not inside menu/popover/modal and not nested in another ion-content
150-
this.isMainContent =
151-
this.el.closest('ion-menu, ion-popover, ion-modal') === null &&
152-
this.el.parentElement?.closest('ion-content') === null;
153-
154-
// Detect sibling header/footer for safe-area handling
155-
this.detectSiblingElements();
135+
this.isMainContent = this.el.closest('ion-menu, ion-popover, ion-modal') === null;
156136

157137
/**
158138
* The fullscreen content offsets need to be
@@ -184,109 +164,15 @@ export class Content implements ComponentInterface {
184164
* bubbles, we can catch any instances of child tab bars loading by listening
185165
* on IonTabs.
186166
*/
187-
this.tabsLoadCallback = () => {
188-
this.resize();
189-
// Re-detect footer when tab bar loads (it may not exist during initial detection)
190-
this.updateSiblingDetection();
191-
forceUpdate(this);
192-
};
167+
this.tabsLoadCallback = () => this.resize();
193168
closestTabs.addEventListener('ionTabBarLoaded', this.tabsLoadCallback);
194169
}
195170
}
196171
}
197172

198-
/**
199-
* Detects sibling ion-header and ion-footer elements and sets up
200-
* a mutation observer to handle dynamic changes (e.g., conditional rendering).
201-
*/
202-
private detectSiblingElements() {
203-
this.updateSiblingDetection();
204-
205-
// Watch for dynamic header/footer changes (common in React conditional rendering)
206-
const parent = this.el.parentElement;
207-
if (parent && !this.parentMutationObserver && win !== undefined && 'MutationObserver' in win) {
208-
this.parentMutationObserver = new MutationObserver(() => {
209-
const prevHasHeader = this.hasHeader;
210-
const prevHasFooter = this.hasFooter;
211-
this.updateSiblingDetection();
212-
// Only trigger re-render if header/footer detection actually changed
213-
if (prevHasHeader !== this.hasHeader || prevHasFooter !== this.hasFooter) {
214-
forceUpdate(this);
215-
}
216-
});
217-
this.parentMutationObserver.observe(parent, { childList: true });
218-
}
219-
220-
// Watch for dynamic tab bar changes in ion-tabs (common in Angular conditional rendering)
221-
const tabs = this.el.closest('ion-tabs');
222-
if (tabs && !this.tabsMutationObserver && win !== undefined && 'MutationObserver' in win) {
223-
this.tabsMutationObserver = new MutationObserver(() => {
224-
const prevHasFooter = this.hasFooter;
225-
this.updateSiblingDetection();
226-
// Only trigger re-render if footer detection actually changed
227-
if (prevHasFooter !== this.hasFooter) {
228-
forceUpdate(this);
229-
}
230-
});
231-
this.tabsMutationObserver.observe(tabs, { childList: true });
232-
}
233-
}
234-
235-
/**
236-
* Updates hasHeader/hasFooter based on current DOM state.
237-
* Checks both direct siblings and elements wrapped in custom components
238-
* (e.g., <my-header><ion-header>...</ion-header></my-header>).
239-
*/
240-
private updateSiblingDetection() {
241-
const parent = this.el.parentElement;
242-
if (parent) {
243-
// First check for direct ion-header/ion-footer siblings
244-
this.hasHeader = parent.querySelector(':scope > ion-header') !== null;
245-
this.hasFooter = parent.querySelector(':scope > ion-footer') !== null;
246-
247-
// If not found, check if any sibling contains them (wrapped components)
248-
if (!this.hasHeader) {
249-
this.hasHeader = this.siblingContainsElement(parent, 'ion-header');
250-
}
251-
if (!this.hasFooter) {
252-
this.hasFooter = this.siblingContainsElement(parent, 'ion-footer');
253-
}
254-
}
255-
256-
// If no footer found, check if we're inside ion-tabs which has ion-tab-bar
257-
if (!this.hasFooter) {
258-
const tabs = this.el.closest('ion-tabs');
259-
if (tabs) {
260-
this.hasFooter = tabs.querySelector(':scope > ion-tab-bar') !== null;
261-
}
262-
}
263-
}
264-
265-
/**
266-
* Checks if any sibling element of ion-content contains the specified element.
267-
* Only searches one level deep to avoid finding elements in nested pages.
268-
*/
269-
private siblingContainsElement(parent: Element, tagName: string): boolean {
270-
for (const sibling of parent.children) {
271-
// Skip ion-content itself
272-
if (sibling === this.el) continue;
273-
// Check if this sibling contains the target element as an immediate child
274-
if (sibling.querySelector(`:scope > ${tagName}`) !== null) {
275-
return true;
276-
}
277-
}
278-
return false;
279-
}
280-
281173
disconnectedCallback() {
282174
this.onScrollEnd();
283175

284-
// Clean up mutation observers to prevent memory leaks
285-
this.parentMutationObserver?.disconnect();
286-
this.parentMutationObserver = undefined;
287-
this.tabsMutationObserver?.disconnect();
288-
this.tabsMutationObserver = undefined;
289-
290176
if (hasLazyBuild(this.el)) {
291177
/**
292178
* The event listener and tabs caches need to
@@ -563,7 +449,7 @@ export class Content implements ComponentInterface {
563449
}
564450

565451
render() {
566-
const { fixedSlotPlacement, hasFooter, hasHeader, inheritedAttributes, isMainContent, scrollX, scrollY, el } = this;
452+
const { fixedSlotPlacement, inheritedAttributes, isMainContent, scrollX, scrollY, el } = this;
567453
const rtl = isRTL(el) ? 'rtl' : 'ltr';
568454
const mode = getIonMode(this);
569455
const forceOverscroll = this.shouldForceOverscroll();
@@ -579,10 +465,6 @@ export class Content implements ComponentInterface {
579465
'content-sizing': hostContext('ion-popover', this.el),
580466
overscroll: forceOverscroll,
581467
[`content-${rtl}`]: true,
582-
'safe-area-top': isMainContent && !hasHeader,
583-
'safe-area-bottom': isMainContent && !hasFooter,
584-
'safe-area-left': isMainContent,
585-
'safe-area-right': isMainContent,
586468
})}
587469
style={{
588470
'--offset-top': `${this.cTop}px`,

0 commit comments

Comments
 (0)