mirror of
https://github.com/ionic-team/ionic-framework.git
synced 2025-08-18 11:17:19 +08:00
fix(animation): properly update Web Animation, clean up types (#19964)
Co-authored-by: manucorporat <manu.mtza@gmail.com>
This commit is contained in:
@ -2,7 +2,7 @@
|
||||
|
||||
import { raf } from '../helpers';
|
||||
|
||||
import { Animation, AnimationCallbackOptions, AnimationDirection, AnimationFill, AnimationKeyFrame, AnimationKeyFrames, AnimationLifecycle, AnimationPlayOptions } from './animation-interface';
|
||||
import { Animation, AnimationCallbackOptions, AnimationDirection, AnimationFill, AnimationKeyFrame, AnimationKeyFrameEdge, AnimationKeyFrames, AnimationLifecycle, AnimationPlayOptions } from './animation-interface';
|
||||
import { addClassToArray, animationEnd, createKeyframeStylesheet, generateKeyframeName, generateKeyframeRules, removeStyleProperty, setStyleProperty } from './animation-utils';
|
||||
|
||||
interface AnimationOnFinishCallback {
|
||||
@ -32,8 +32,6 @@ export const createAnimation = (animationId?: string): Animation => {
|
||||
let _fill: AnimationFill | undefined;
|
||||
let _direction: AnimationDirection | undefined;
|
||||
let _keyframes: AnimationKeyFrames = [];
|
||||
const id: string | undefined = animationId;
|
||||
|
||||
let beforeAddClasses: string[] = [];
|
||||
let beforeRemoveClasses: string[] = [];
|
||||
let initialized = false;
|
||||
@ -55,6 +53,7 @@ export const createAnimation = (animationId?: string): Animation => {
|
||||
let keyframeName: string | undefined;
|
||||
let ani: AnimationInternal;
|
||||
|
||||
const id: string | undefined = animationId;
|
||||
const onFinishCallbacks: AnimationOnFinishCallback[] = [];
|
||||
const onFinishOneTimeCallbacks: AnimationOnFinishCallback[] = [];
|
||||
const elements: HTMLElement[] = [];
|
||||
@ -402,80 +401,20 @@ export const createAnimation = (animationId?: string): Animation => {
|
||||
return ani;
|
||||
};
|
||||
|
||||
/**
|
||||
* Runs all before read callbacks
|
||||
*/
|
||||
const runBeforeRead = () => {
|
||||
_beforeAddReadFunctions.forEach(callback => {
|
||||
callback();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Runs all before write callbacks
|
||||
*/
|
||||
const runBeforeWrite = () => {
|
||||
_beforeAddWriteFunctions.forEach(callback => {
|
||||
callback();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates styles and classes before animation runs
|
||||
*/
|
||||
const runBeforeStyles = () => {
|
||||
const addClasses = beforeAddClasses;
|
||||
const removeClasses = beforeRemoveClasses;
|
||||
const styles = beforeStylesValue;
|
||||
|
||||
elements.forEach(el => {
|
||||
const elementClassList = el.classList;
|
||||
|
||||
addClasses.forEach(c => elementClassList.add(c));
|
||||
removeClasses.forEach(c => elementClassList.remove(c));
|
||||
|
||||
for (const property in styles) {
|
||||
if (styles.hasOwnProperty(property)) {
|
||||
setStyleProperty(el, property, styles[property]);
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Run all "before" animation hooks.
|
||||
*/
|
||||
const beforeAnimation = () => {
|
||||
runBeforeRead();
|
||||
runBeforeWrite();
|
||||
runBeforeStyles();
|
||||
};
|
||||
// Runs all before read callbacks
|
||||
_beforeAddReadFunctions.forEach(callback => callback());
|
||||
|
||||
/**
|
||||
* Runs all after read callbacks
|
||||
*/
|
||||
const runAfterRead = () => {
|
||||
_afterAddReadFunctions.forEach(callback => {
|
||||
callback();
|
||||
});
|
||||
};
|
||||
// Runs all before write callbacks
|
||||
_beforeAddWriteFunctions.forEach(callback => callback());
|
||||
|
||||
/**
|
||||
* Runs all after write callbacks
|
||||
*/
|
||||
const runAfterWrite = () => {
|
||||
_afterAddWriteFunctions.forEach(callback => {
|
||||
callback();
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Updates styles and classes before animation ends
|
||||
*/
|
||||
const runAfterStyles = () => {
|
||||
const addClasses = afterAddClasses;
|
||||
const removeClasses = afterRemoveClasses;
|
||||
const styles = afterStylesValue;
|
||||
// Updates styles and classes before animation runs
|
||||
const addClasses = beforeAddClasses;
|
||||
const removeClasses = beforeRemoveClasses;
|
||||
const styles = beforeStylesValue;
|
||||
|
||||
elements.forEach(el => {
|
||||
const elementClassList = el.classList;
|
||||
@ -496,11 +435,31 @@ export const createAnimation = (animationId?: string): Animation => {
|
||||
*/
|
||||
const afterAnimation = () => {
|
||||
clearCSSAnimationsTimeout();
|
||||
runAfterRead();
|
||||
runAfterWrite();
|
||||
runAfterStyles();
|
||||
|
||||
// Runs all after read callbacks
|
||||
_afterAddReadFunctions.forEach(callback => callback());
|
||||
|
||||
// Runs all after write callbacks
|
||||
_afterAddWriteFunctions.forEach(callback => callback());
|
||||
|
||||
// Updates styles and classes before animation ends
|
||||
const currentStep = willComplete ? 1 : 0;
|
||||
const addClasses = afterAddClasses;
|
||||
const removeClasses = afterRemoveClasses;
|
||||
const styles = afterStylesValue;
|
||||
|
||||
elements.forEach(el => {
|
||||
const elementClassList = el.classList;
|
||||
|
||||
addClasses.forEach(c => elementClassList.add(c));
|
||||
removeClasses.forEach(c => elementClassList.remove(c));
|
||||
|
||||
for (const property in styles) {
|
||||
if (styles.hasOwnProperty(property)) {
|
||||
setStyleProperty(el, property, styles[property]);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
onFinishCallbacks.forEach(onFinishCallback => {
|
||||
return onFinishCallback.c(currentStep, ani);
|
||||
@ -513,7 +472,10 @@ export const createAnimation = (animationId?: string): Animation => {
|
||||
onFinishOneTimeCallbacks.length = 0;
|
||||
|
||||
shouldCalculateNumAnimations = true;
|
||||
finished = true;
|
||||
if (willComplete) {
|
||||
finished = true;
|
||||
}
|
||||
willComplete = true;
|
||||
};
|
||||
|
||||
const animationFinish = () => {
|
||||
@ -606,12 +568,12 @@ export const createAnimation = (animationId?: string): Animation => {
|
||||
step = Math.min(Math.max(step, 0), 0.999);
|
||||
if (supportsWebAnimations) {
|
||||
webAnimations.forEach(animation => {
|
||||
animation.currentTime = animation.effect.getComputedTiming().delay + (getDuration()! * step);
|
||||
animation.currentTime = animation.effect.getComputedTiming().delay + (getDuration() * step);
|
||||
animation.pause();
|
||||
});
|
||||
|
||||
} else {
|
||||
const animationDuration = `-${getDuration()! * step}ms`;
|
||||
const animationDuration = `-${getDuration() * step}ms`;
|
||||
|
||||
elements.forEach(element => {
|
||||
if (_keyframes.length > 0) {
|
||||
@ -720,36 +682,45 @@ export const createAnimation = (animationId?: string): Animation => {
|
||||
|
||||
finished = false;
|
||||
|
||||
willComplete = playTo === 1;
|
||||
// tslint:disable-next-line: strict-boolean-conditions
|
||||
willComplete = true;
|
||||
|
||||
if (!willComplete) {
|
||||
if (playTo === 0) {
|
||||
forceDirectionValue = (getDirection() === 'reverse') ? 'normal' : 'reverse';
|
||||
|
||||
if (forceDirectionValue === 'reverse') {
|
||||
willComplete = false;
|
||||
}
|
||||
|
||||
if (supportsWebAnimations) {
|
||||
update();
|
||||
setAnimationStep(1 - step);
|
||||
} else {
|
||||
forceDelayValue = ((1 - step) * getDuration()!) * -1;
|
||||
forceDelayValue = ((1 - step) * getDuration()) * -1;
|
||||
update(false, false);
|
||||
}
|
||||
} else {
|
||||
if (!supportsWebAnimations) {
|
||||
forceDelayValue = (step * getDuration()!) * -1;
|
||||
} else if (playTo === 1) {
|
||||
if (supportsWebAnimations) {
|
||||
update();
|
||||
setAnimationStep(step);
|
||||
} else {
|
||||
forceDelayValue = (step * getDuration()) * -1;
|
||||
update(false, false);
|
||||
}
|
||||
}
|
||||
|
||||
onFinish(() => {
|
||||
willComplete = true;
|
||||
forceDurationValue = undefined;
|
||||
forceDirectionValue = undefined;
|
||||
forceDelayValue = undefined;
|
||||
}, {
|
||||
oneTimeCallback: true
|
||||
});
|
||||
if (playTo !== undefined) {
|
||||
onFinish(() => {
|
||||
forceDurationValue = undefined;
|
||||
forceDirectionValue = undefined;
|
||||
forceDelayValue = undefined;
|
||||
}, {
|
||||
oneTimeCallback: true
|
||||
});
|
||||
|
||||
if (!parentAnimation) {
|
||||
play();
|
||||
if (!parentAnimation) {
|
||||
play();
|
||||
}
|
||||
}
|
||||
|
||||
return ani;
|
||||
@ -874,6 +845,7 @@ export const createAnimation = (animationId?: string): Animation => {
|
||||
const resetAnimation = () => {
|
||||
if (supportsWebAnimations) {
|
||||
setAnimationStep(0);
|
||||
updateWebAnimation();
|
||||
} else {
|
||||
updateCSSAnimation();
|
||||
}
|
||||
@ -926,30 +898,30 @@ export const createAnimation = (animationId?: string): Animation => {
|
||||
};
|
||||
|
||||
const from = (property: string, value: any) => {
|
||||
const firstFrame = _keyframes[0] as AnimationKeyFrame | undefined;
|
||||
const firstFrame = _keyframes[0] as AnimationKeyFrameEdge | undefined;
|
||||
|
||||
if (firstFrame !== undefined && firstFrame.offset === 0) {
|
||||
if (firstFrame !== undefined && (firstFrame.offset === undefined || firstFrame.offset === 0)) {
|
||||
firstFrame[property] = value;
|
||||
} else {
|
||||
_keyframes = [
|
||||
{ offset: 0, [property]: value },
|
||||
..._keyframes
|
||||
];
|
||||
] as AnimationKeyFrame[];
|
||||
}
|
||||
|
||||
return ani;
|
||||
};
|
||||
|
||||
const to = (property: string, value: any) => {
|
||||
const lastFrame = _keyframes[_keyframes.length - 1] as AnimationKeyFrame | undefined;
|
||||
const lastFrame = _keyframes[_keyframes.length - 1] as AnimationKeyFrameEdge | undefined;
|
||||
|
||||
if (lastFrame !== undefined && lastFrame.offset === 1) {
|
||||
if (lastFrame !== undefined && (lastFrame.offset === undefined || lastFrame.offset === 1)) {
|
||||
lastFrame[property] = value;
|
||||
} else {
|
||||
_keyframes = [
|
||||
..._keyframes,
|
||||
{ offset: 1, [property]: value }
|
||||
];
|
||||
] as AnimationKeyFrame[];
|
||||
}
|
||||
return ani;
|
||||
};
|
||||
|
Reference in New Issue
Block a user