Skip to content

Commit

Permalink
perf(many): reduce delay when performing overlay or page transitions (#…
Browse files Browse the repository at this point in the history
…26189)

resolves #24346
  • Loading branch information
liamdebeasi committed Nov 1, 2022
1 parent eea6ba9 commit 30e3a14
Show file tree
Hide file tree
Showing 8 changed files with 58 additions and 57 deletions.
1 change: 0 additions & 1 deletion angular/src/directives/navigation/stack-controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down
9 changes: 4 additions & 5 deletions core/src/components/modal/modal.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -436,7 +436,7 @@ export class Modal implements ComponentInterface, OverlayInterface {
return;
}

const { presentingElement } = this;
const { presentingElement, el } = this;

/**
* When using an inline modal
Expand All @@ -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'));

Expand Down
8 changes: 5 additions & 3 deletions core/src/components/popover/popover.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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';
Expand Down Expand Up @@ -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();
Expand Down
9 changes: 8 additions & 1 deletion core/src/components/router-outlet/route-outlet.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -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({
Expand Down Expand Up @@ -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) => {
/**
Expand Down
9 changes: 9 additions & 0 deletions core/src/utils/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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 };

/**
Expand Down
17 changes: 5 additions & 12 deletions core/src/utils/transition/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -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');
Expand Down Expand Up @@ -135,11 +135,11 @@ const noAnimation = async (opts: TransitionOptions): Promise<TransitionResult> =

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);
};

Expand Down Expand Up @@ -195,13 +195,6 @@ export const lifecycle = (el: HTMLElement | undefined, eventName: string) => {
}
};

const shallowReady = (el: Element | undefined): Promise<any> => {
if (el) {
return new Promise((resolve) => componentOnReady(el, resolve));
}
return Promise.resolve();
};

export const deepReady = async (el: any | undefined): Promise<void> => {
const element = el as any;
if (element) {
Expand Down
1 change: 0 additions & 1 deletion packages/react-router/src/ReactRouter/StackManager.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -365,7 +365,6 @@ export class StackManager extends React.PureComponent<StackManagerProps, StackMa
}

await routerOutlet.commit(enteringEl, leavingEl, {
deepWait: true,
duration: skipTransition || directionToUse === undefined ? 0 : undefined,
direction: directionToUse,
showGoBack: !!routeInfo.pushedByRoute,
Expand Down
61 changes: 27 additions & 34 deletions packages/vue/src/components/IonRouterOutlet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -195,50 +195,43 @@ export const IonRouterOutlet = /*@__PURE__*/ defineComponent({
}
});

const transition = (
const transition = async (
enteringEl: HTMLElement,
leavingEl: HTMLElement,
direction: any, // TODO types
showGoBack: boolean,
progressAnimation: boolean,
animationBuilder?: AnimationBuilder
) => {
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');

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);
});
});
enteringEl.classList.add('ion-page-invisible');

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 () => {
Expand Down

0 comments on commit 30e3a14

Please sign in to comment.