diff --git a/angular/src/directives/navigation/stack-controller.ts b/angular/src/directives/navigation/stack-controller.ts index a1e326ca4a..d89cfcba94 100644 --- a/angular/src/directives/navigation/stack-controller.ts +++ b/angular/src/directives/navigation/stack-controller.ts @@ -271,7 +271,6 @@ export class StackController { if ((containerEl as any).commit) { return containerEl.commit(enteringEl, leavingEl, { - deepWait: true, duration: direction === undefined ? 0 : undefined, direction, showGoBack, diff --git a/core/src/components/modal/modal.tsx b/core/src/components/modal/modal.tsx index 67b744fd94..65a06bf98a 100644 --- a/core/src/components/modal/modal.tsx +++ b/core/src/components/modal/modal.tsx @@ -17,7 +17,7 @@ import type { } from '../../interface'; import { findIonContent, printIonContentErrorMsg } from '../../utils/content'; import { CoreDelegate, attachComponent, detachComponent } from '../../utils/framework-delegate'; -import { raf, inheritAttributes } from '../../utils/helpers'; +import { raf, inheritAttributes, hasLazyBuild } from '../../utils/helpers'; import type { Attributes } from '../../utils/helpers'; import { KEYBOARD_DID_OPEN } from '../../utils/keyboard/keyboard'; import { printIonWarning } from '../../utils/logging'; @@ -436,7 +436,7 @@ export class Modal implements ComponentInterface, OverlayInterface { return; } - const { presentingElement } = this; + const { presentingElement, el } = this; /** * When using an inline modal @@ -462,9 +462,8 @@ export class Modal implements ComponentInterface, OverlayInterface { }; const { inline, delegate } = this.getDelegate(true); - this.usersElement = await attachComponent(delegate, this.el, this.component, ['ion-page'], data, inline); - - await deepReady(this.usersElement); + this.usersElement = await attachComponent(delegate, el, this.component, ['ion-page'], data, inline); + hasLazyBuild(el) && (await deepReady(this.usersElement)); writeTask(() => this.el.classList.add('show-modal')); diff --git a/core/src/components/popover/popover.tsx b/core/src/components/popover/popover.tsx index 97d10594b9..6349ea5ee0 100644 --- a/core/src/components/popover/popover.tsx +++ b/core/src/components/popover/popover.tsx @@ -16,7 +16,7 @@ import type { TriggerAction, } from '../../interface'; import { CoreDelegate, attachComponent, detachComponent } from '../../utils/framework-delegate'; -import { addEventListener, raf } from '../../utils/helpers'; +import { addEventListener, raf, hasLazyBuild } from '../../utils/helpers'; import { BACKDROP, dismiss, eventMethod, focusFirstDescendant, prepareOverlay, present } from '../../utils/overlays'; import { isPlatform } from '../../utils/platform'; import { getClassMap } from '../../utils/theme'; @@ -431,14 +431,16 @@ export class Popover implements ComponentInterface, PopoverInterface { await this.currentTransition; } + const { el } = this; + const data = { ...this.componentProps, popover: this.el, }; const { inline, delegate } = this.getDelegate(true); - this.usersElement = await attachComponent(delegate, this.el, this.component, ['popover-viewport'], data, inline); - await deepReady(this.usersElement); + this.usersElement = await attachComponent(delegate, el, this.component, ['popover-viewport'], data, inline); + hasLazyBuild(el) && (await deepReady(this.usersElement)); if (!this.keyboardEvents) { this.configureKeyboardInteraction(); diff --git a/core/src/components/router-outlet/route-outlet.tsx b/core/src/components/router-outlet/route-outlet.tsx index c1ba068bed..3bf78ec7a4 100644 --- a/core/src/components/router-outlet/route-outlet.tsx +++ b/core/src/components/router-outlet/route-outlet.tsx @@ -19,7 +19,7 @@ import type { } from '../../interface'; import { getTimeGivenProgression } from '../../utils/animation/cubic-bezier'; import { attachComponent, detachComponent } from '../../utils/framework-delegate'; -import { shallowEqualStringMap } from '../../utils/helpers'; +import { shallowEqualStringMap, hasLazyBuild } from '../../utils/helpers'; import { transition } from '../../utils/transition'; @Component({ @@ -238,6 +238,13 @@ export class RouterOutlet implements ComponentInterface, NavOutlet { enteringEl, leavingEl, baseEl: el, + + /** + * We need to wait for all Stencil components + * to be ready only when using the lazy + * loaded bundle. + */ + deepWait: hasLazyBuild(el), progressCallback: opts.progressAnimation ? (ani) => { /** diff --git a/core/src/utils/helpers.ts b/core/src/utils/helpers.ts index b29e7b92f9..1e82284400 100644 --- a/core/src/utils/helpers.ts +++ b/core/src/utils/helpers.ts @@ -76,6 +76,15 @@ export const componentOnReady = (el: any, callback: any) => { } }; +/** + * This functions checks if a Stencil component is using + * the lazy loaded build of Stencil. Returns `true` if + * the component is lazy loaded. Returns `false` otherwise. + */ +export const hasLazyBuild = (stencilEl: HTMLElement) => { + return (stencilEl as any).componentOnReady !== undefined; +}; + export type Attributes = { [key: string]: any }; /** diff --git a/core/src/utils/transition/index.ts b/core/src/utils/transition/index.ts index 2f9cb9c402..7e145235d3 100644 --- a/core/src/utils/transition/index.ts +++ b/core/src/utils/transition/index.ts @@ -7,7 +7,7 @@ import { LIFECYCLE_WILL_LEAVE, } from '../../components/nav/constants'; import type { Animation, AnimationBuilder, NavDirection, NavOptions } from '../../interface'; -import { componentOnReady, raf } from '../helpers'; +import { raf } from '../helpers'; const iosTransitionAnimation = () => import('./ios.transition'); const mdTransitionAnimation = () => import('./md.transition'); @@ -135,11 +135,11 @@ const noAnimation = async (opts: TransitionOptions): Promise = const waitForReady = async (opts: TransitionOptions, defaultDeep: boolean) => { const deep = opts.deepWait !== undefined ? opts.deepWait : defaultDeep; - const promises = deep - ? [deepReady(opts.enteringEl), deepReady(opts.leavingEl)] - : [shallowReady(opts.enteringEl), shallowReady(opts.leavingEl)]; - await Promise.all(promises); + if (deep) { + await Promise.all([deepReady(opts.enteringEl), deepReady(opts.leavingEl)]); + } + await notifyViewReady(opts.viewIsReady, opts.enteringEl); }; @@ -195,13 +195,6 @@ export const lifecycle = (el: HTMLElement | undefined, eventName: string) => { } }; -const shallowReady = (el: Element | undefined): Promise => { - if (el) { - return new Promise((resolve) => componentOnReady(el, resolve)); - } - return Promise.resolve(); -}; - export const deepReady = async (el: any | undefined): Promise => { const element = el as any; if (element) { diff --git a/packages/react-router/src/ReactRouter/StackManager.tsx b/packages/react-router/src/ReactRouter/StackManager.tsx index c21e6e6d51..25d43380d1 100644 --- a/packages/react-router/src/ReactRouter/StackManager.tsx +++ b/packages/react-router/src/ReactRouter/StackManager.tsx @@ -365,7 +365,6 @@ export class StackManager extends React.PureComponent { - return new Promise(resolve => { - if (skipTransition) { - skipTransition = false; - return resolve(false); - } + if (skipTransition) { + skipTransition = false; + return Promise.resolve(false); + } - if (enteringEl === leavingEl) { - return resolve(false); - } + if (enteringEl === leavingEl) { + return Promise.resolve(false); + } - requestAnimationFrame(() => { - requestAnimationFrame(async () => { - enteringEl.classList.add('ion-page-invisible'); + enteringEl.classList.add('ion-page-invisible'); - const hasRootDirection = direction === undefined || direction === 'root' || direction === 'none'; - const result = await ionRouterOutlet.value.commit(enteringEl, leavingEl, { - deepWait: true, - /** - * replace operations result in a direction of none. - * These typically do not have need animations, so we set - * the duration to 0. However, if a developer explicitly - * passes an animationBuilder, we should assume that - * they want an animation to be played even - * though it is a replace operation. - */ - duration: hasRootDirection && animationBuilder === undefined ? 0 : undefined, - direction, - showGoBack, - progressAnimation, - animationBuilder - }); - - return resolve(result); - }); - }); + const hasRootDirection = direction === undefined || direction === 'root' || direction === 'none'; + const result = await ionRouterOutlet.value.commit(enteringEl, leavingEl, { + /** + * replace operations result in a direction of none. + * These typically do not have need animations, so we set + * the duration to 0. However, if a developer explicitly + * passes an animationBuilder, we should assume that + * they want an animation to be played even + * though it is a replace operation. + */ + duration: hasRootDirection && animationBuilder === undefined ? 0 : undefined, + direction, + showGoBack, + progressAnimation, + animationBuilder }); + + return result; } const handlePageTransition = async () => {