diff --git a/angular/src/directives/overlays/popover.ts b/angular/src/directives/overlays/popover.ts index aedbb97f9c..5cee75eecf 100644 --- a/angular/src/directives/overlays/popover.ts +++ b/angular/src/directives/overlays/popover.ts @@ -108,7 +108,7 @@ export class IonPopover { constructor(c: ChangeDetectorRef, r: ElementRef, protected z: NgZone) { this.el = r.nativeElement; - this.el.addEventListener('willPresent', () => { + this.el.addEventListener('ionMount', () => { this.isCmpOpen = true; c.detectChanges(); }); diff --git a/core/src/components.d.ts b/core/src/components.d.ts index dcb41e77fa..22d6ffc4ee 100644 --- a/core/src/components.d.ts +++ b/core/src/components.d.ts @@ -5907,6 +5907,10 @@ declare namespace LocalJSX { * Emitted after the popover has presented. Shorthand for ionPopoverWillDismiss. */ "onDidPresent"?: (event: IonPopoverCustomEvent) => void; + /** + * Emitted before the popover has presented, but after the component has been mounted in the DOM. This event exists for ion-popover to resolve an issue with the popover and the lazy build, that the transition is unable to get the correct dimensions of the popover with auto sizing. This is not required for other overlays, since the existing overlay transitions are not effected by auto sizing content. + */ + "onIonMount"?: (event: IonPopoverCustomEvent) => void; /** * Emitted after the popover has dismissed. */ diff --git a/core/src/components/popover/popover.tsx b/core/src/components/popover/popover.tsx index 79c0ba9c34..5139e4ee0a 100644 --- a/core/src/components/popover/popover.tsx +++ b/core/src/components/popover/popover.tsx @@ -27,7 +27,12 @@ import { iosEnterAnimation } from './animations/ios.enter'; import { iosLeaveAnimation } from './animations/ios.leave'; import { mdEnterAnimation } from './animations/md.enter'; import { mdLeaveAnimation } from './animations/md.leave'; -import { configureDismissInteraction, configureKeyboardInteraction, configureTriggerInteraction } from './utils'; +import { + configureDismissInteraction, + configureKeyboardInteraction, + configureTriggerInteraction, + waitOneFrame, +} from './utils'; /** * @virtualProp {"ios" | "md"} mode - The mode determines which platform styles to use. @@ -310,6 +315,19 @@ export class Popover implements ComponentInterface, PopoverInterface { */ @Event({ eventName: 'didDismiss' }) didDismissShorthand!: EventEmitter; + /** + * Emitted before the popover has presented, but after the component + * has been mounted in the DOM. + * This event exists for ion-popover to resolve an issue with the + * popover and the lazy build, that the transition is unable to get + * the correct dimensions of the popover with auto sizing. + * This is not required for other overlays, since the existing + * overlay transitions are not effected by auto sizing content. + * + * @internal + */ + @Event() ionMount!: EventEmitter; + connectedCallback() { const { configureTriggerInteraction, el } = this; @@ -446,6 +464,20 @@ export class Popover implements ComponentInterface, PopoverInterface { } this.configureDismissInteraction(); + // TODO: FW-2773: Apply this to only the lazy build. + if (inline === true) { + /** + * ionMount only needs to be emitted if the popover is inline. + */ + this.ionMount.emit(); + /** + * Wait one raf before presenting the popover. + * This allows the lazy build enough time to + * calculate the popover dimensions for the animation. + */ + await waitOneFrame(); + } + this.currentTransition = present(this, 'popoverEnter', iosEnterAnimation, mdEnterAnimation, { event: event || this.event, size: this.size, diff --git a/core/src/components/popover/utils.ts b/core/src/components/popover/utils.ts index 363db25c52..6dfad7c08e 100644 --- a/core/src/components/popover/utils.ts +++ b/core/src/components/popover/utils.ts @@ -928,3 +928,7 @@ export const shouldShowArrow = (side: PositionSide, didAdjustBounds = false, ev? return true; }; + +export const waitOneFrame = () => { + return new Promise((resolve) => raf(() => resolve())); +};