mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2026-03-13 10:22:08 +08:00
fix(popover): recalculate the content dimensions after the header has fully loaded (#30853)
Issue number: internal --------- ## What is the current behavior? A translucent header in a popover does not consistently render as translucent upon presenting due to the `offset-top` of the content being set to `0`. ## What is the new behavior? Watch the header for height changes using `ResizeObserver` and recalculate the content dimensions when the header height is greater than `0`. ## Does this introduce a breaking change? - [ ] Yes - [x] No --------- Co-authored-by: Brandy Smith <6577830+brandyscarney@users.noreply.github.com>
This commit is contained in:
4
core/src/components.d.ts
vendored
4
core/src/components.d.ts
vendored
@@ -868,6 +868,10 @@ export namespace Components {
|
||||
* Get the element where the actual scrolling takes place. This element can be used to subscribe to `scroll` events or manually modify `scrollTop`. However, it's recommended to use the API provided by `ion-content`: i.e. Using `ionScroll`, `ionScrollStart`, `ionScrollEnd` for scrolling events and `scrollToPoint()` to scroll the content into a certain point.
|
||||
*/
|
||||
"getScrollElement": () => Promise<HTMLElement>;
|
||||
/**
|
||||
* Recalculate content dimensions. Called by overlays (e.g., popover) when sibling elements like headers or footers have finished rendering and their heights are available, ensuring accurate offset-top calculations.
|
||||
*/
|
||||
"recalculateDimensions": () => Promise<void>;
|
||||
/**
|
||||
* Scroll by a specified X/Y distance in the component.
|
||||
* @param x The amount to scroll by on the horizontal axis.
|
||||
|
||||
@@ -254,6 +254,17 @@ export class Content implements ComponentInterface {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Recalculate content dimensions. Called by overlays (e.g., popover) when
|
||||
* sibling elements like headers or footers have finished rendering and their
|
||||
* heights are available, ensuring accurate offset-top calculations.
|
||||
* @internal
|
||||
*/
|
||||
@Method()
|
||||
async recalculateDimensions(): Promise<void> {
|
||||
readTask(() => this.readDimensions());
|
||||
}
|
||||
|
||||
private readDimensions() {
|
||||
const page = getPageElement(this.el);
|
||||
const top = Math.max(this.el.offsetTop, 0);
|
||||
|
||||
@@ -64,6 +64,7 @@ export class Popover implements ComponentInterface, PopoverInterface {
|
||||
private destroyTriggerInteraction?: () => void;
|
||||
private destroyKeyboardInteraction?: () => void;
|
||||
private destroyDismissInteraction?: () => void;
|
||||
private headerResizeObserver?: ResizeObserver;
|
||||
|
||||
private inline = false;
|
||||
private workingDelegate?: FrameworkDelegate;
|
||||
@@ -361,6 +362,11 @@ export class Popover implements ComponentInterface, PopoverInterface {
|
||||
if (destroyTriggerInteraction) {
|
||||
destroyTriggerInteraction();
|
||||
}
|
||||
|
||||
if (this.headerResizeObserver) {
|
||||
this.headerResizeObserver.disconnect();
|
||||
this.headerResizeObserver = undefined;
|
||||
}
|
||||
}
|
||||
|
||||
componentWillLoad() {
|
||||
@@ -491,6 +497,8 @@ export class Popover implements ComponentInterface, PopoverInterface {
|
||||
inline
|
||||
);
|
||||
|
||||
this.recalculateContentOnHeaderReady();
|
||||
|
||||
if (!this.keyboardEvents) {
|
||||
this.configureKeyboardInteraction();
|
||||
}
|
||||
@@ -540,6 +548,39 @@ export class Popover implements ComponentInterface, PopoverInterface {
|
||||
unlock();
|
||||
}
|
||||
|
||||
/**
|
||||
* Watch the header for height changes and trigger content dimension
|
||||
* recalculation when the header has a height > 0. This sets the offset-top
|
||||
* of the content to the height of the header correctly.
|
||||
*/
|
||||
private recalculateContentOnHeaderReady() {
|
||||
const popoverContent = this.el.shadowRoot?.querySelector('.popover-content');
|
||||
if (!popoverContent) {
|
||||
return;
|
||||
}
|
||||
|
||||
const contentContainer = this.usersElement || popoverContent;
|
||||
|
||||
const header = contentContainer.querySelector('ion-header') as HTMLElement | null;
|
||||
const contentElements = contentContainer.querySelectorAll('ion-content');
|
||||
|
||||
if (!header || contentElements.length === 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.headerResizeObserver = new ResizeObserver(async () => {
|
||||
if (header.offsetHeight > 0) {
|
||||
this.headerResizeObserver?.disconnect();
|
||||
this.headerResizeObserver = undefined;
|
||||
for (const contentEl of contentElements) {
|
||||
await contentEl.recalculateDimensions();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
this.headerResizeObserver.observe(header);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dismiss the popover overlay after it has been presented.
|
||||
* This is a no-op if the overlay has not been presented yet. If you want
|
||||
|
||||
Reference in New Issue
Block a user