feat(animation): add animation utility (#18918)

* Add new keyframes proof of concept

* update esm import

* add base before and after methods, add tests

* add base before and after hooks

* update clean up methods, add tests

* add web animations support, change to arrow functions

* remove console logs

* add from, to, fromTo, and other properties

* add more tests, fix onFinish functionality, being testing with nav transitions

* add progress methods, use force linear

* run linter

* Add playSync

* integrate animations with framework components

* onFinish now supports multiple callbacks

* change const to let

* testing reverse

* add support for both animation utilities

* bug fix

* export createAnimation, a few tweaks

* add base tests

* fix issue with onFinish being called out of order. added tests

* fix race conditions in tests

* clean up

* fix bug where onFinish not calling for empty elements array,  update test

* clean up

* fix treeshaking, remove old comments

* remove old tests

* Add test for animationbuilder backwards compat

* update typings for menu controller

* mock web animations in tests

* run build

* fix type errors

* sync with master

* use requestAnimationFrame instead of writeTask

* fix flaky tests, fix menu

* fix ordering

* update webdriver

* fix wrong version

* Revert "fix wrong version"

This reverts commit be91296e9701399f8d784b08d09a3c475ca15df7.

Revert chromedriver update

* Revert "update webdriver"

This reverts commit e49bc9d76e335a0af5828725065399bd6795fa37.

Revert chromedriver update

* expose raw animation object, add tests

* add stylesheet recycling

* finalize before and after hook tests

* a few styling changes

* fix lint warnings

* get rid of old code

* Fix progressStep overflow bug

* disable reuse stylesheet

* small updates

* fix old animation create

* setStyleProperty helper

* reuse keyframe styles

* keyframes

* fix css animation issue with display: none, add tests

* add comment

* fix issue with progress animations and css animations

* clean up

* clean up pt2

* fix tests

* fix linter

* add fill for overlays

* fix swipe to go back

* clean up css animations when done

* fix edge cases with css animations

* fix menu open and close

* add reset function

* clean up reset fn

* Fix issue where animation always being reset

* allow updating animations on the fly

* add clear onfinish method

* fix linter

* add callback options, expand force direction

* ensure opts is defined

* fix css animations open and close for menus

* remove test

* add extra check

* clean up

* fix css anim bug swipe to go back

* fix pause

* setup alt animation to avoid flickering

* clean up

* reset flags on destroy

* add ability to change duration on progressEnd

* fix flicker on duration change for css animations

* fix ios transition

* remove unneeded recursion

* increase durability of updating css animations on the fly

* fix gesture anim

* fix web anim as well. more work for cleanup

* simplify progressEnd for css animations

* fix swipe to go back race condition

* clean up

* Add todo

* fix one more bug
This commit is contained in:
Liam DeBeasi
2019-08-12 10:05:04 -04:00
committed by GitHub
parent e33cf854a9
commit 30ca46ab12
70 changed files with 3974 additions and 762 deletions

View File

@ -1,11 +1,14 @@
import { writeTask } from '@stencil/core';
import { LIFECYCLE_DID_ENTER, LIFECYCLE_DID_LEAVE, LIFECYCLE_WILL_ENTER, LIFECYCLE_WILL_LEAVE } from '../../components/nav/constants';
import { Animation, AnimationBuilder, NavDirection, NavOptions } from '../../interface';
import { Animation, AnimationBuilder, IonicAnimation, NavDirection, NavOptions } from '../../interface';
const iosTransitionAnimation = () => import('./ios.transition');
const mdTransitionAnimation = () => import('./md.transition');
// TODO: Remove when removing AnimationBuilder
export type IonicAnimationInterface = (navEl: HTMLElement, opts: TransitionOptions) => IonicAnimation;
export const transition = (opts: TransitionOptions): Promise<TransitionResult> => {
return new Promise((resolve, reject) => {
writeTask(() => {
@ -43,6 +46,7 @@ const beforeTransition = (opts: TransitionOptions) => {
const runTransition = async (opts: TransitionOptions): Promise<TransitionResult> => {
const animationBuilder = await getAnimationBuilder(opts);
const ani = (animationBuilder)
? animation(animationBuilder, opts)
: noAnimation(opts); // fast path for no animation
@ -59,35 +63,50 @@ const afterTransition = (opts: TransitionOptions) => {
}
};
const getAnimationBuilder = async (opts: TransitionOptions): Promise<AnimationBuilder | undefined> => {
const getAnimationBuilder = async (opts: TransitionOptions): Promise<IonicAnimationInterface | AnimationBuilder | undefined> => {
if (!opts.leavingEl || !opts.animated || opts.duration === 0) {
return undefined;
}
if (opts.animationBuilder) {
return opts.animationBuilder;
}
const builder = (opts.mode === 'ios')
const getAnimation = (opts.mode === 'ios')
? (await iosTransitionAnimation()).iosTransitionAnimation
: (await mdTransitionAnimation()).mdTransitionAnimation;
return builder;
return getAnimation;
};
const animation = async (animationBuilder: AnimationBuilder, opts: TransitionOptions): Promise<TransitionResult> => {
const animation = async (animationBuilder: IonicAnimationInterface | AnimationBuilder, opts: TransitionOptions): Promise<TransitionResult> => {
await waitForReady(opts, true);
const trans = await import('../animation').then(mod => mod.create(animationBuilder, opts.baseEl, opts));
let trans: Animation | IonicAnimation;
try {
trans = await import('../animation/old-animation').then(mod => mod.create(animationBuilder as AnimationBuilder, opts.baseEl, opts));
} catch (err) {
trans = (animationBuilder as IonicAnimationInterface)(opts.baseEl, opts);
}
fireWillEvents(opts.enteringEl, opts.leavingEl);
await playTransition(trans, opts);
const didComplete = await playTransition(trans, opts);
// TODO: Remove AnimationBuilder
(trans as any).hasCompleted = didComplete;
if (opts.progressCallback) {
opts.progressCallback(undefined);
}
if (trans.hasCompleted) {
if ((trans as any).hasCompleted) {
fireDidEvents(opts.enteringEl, opts.leavingEl);
}
return {
hasCompleted: trans.hasCompleted,
hasCompleted: (trans as any).hasCompleted,
animation: trans
};
};
@ -126,15 +145,17 @@ const notifyViewReady = async (viewIsReady: undefined | ((enteringEl: HTMLElemen
}
};
const playTransition = (trans: Animation, opts: TransitionOptions): Promise<Animation> => {
const playTransition = (trans: IonicAnimation | Animation, opts: TransitionOptions): Promise<Animation | boolean> => {
const progressCallback = opts.progressCallback;
const promise = new Promise<Animation>(resolve => trans.onFinish(resolve));
// TODO: Remove AnimationBuilder
const promise = new Promise<Animation | boolean>(resolve => trans.onFinish(resolve));
// cool, let's do this, start the transition
if (progressCallback) {
// this is a swipe to go back, just get the transition progress ready
// kick off the swipe animation start
trans.progressStart();
trans.progressStart(true);
progressCallback(trans);
} else {
@ -214,7 +235,7 @@ const setZIndex = (
};
export interface TransitionOptions extends NavOptions {
progressCallback?: ((ani: Animation | undefined) => void);
progressCallback?: ((ani: IonicAnimation | Animation | undefined) => void);
baseEl: any;
enteringEl: HTMLElement;
leavingEl: HTMLElement | undefined;
@ -222,5 +243,5 @@ export interface TransitionOptions extends NavOptions {
export interface TransitionResult {
hasCompleted: boolean;
animation?: Animation;
animation?: Animation | IonicAnimation;
}