mirror of
https://github.com/angular/angular.git
synced 2026-09-14 13:54:52 +08:00
refactor(core): Replace usages of the Function type for animations
`Function` is usually not recommended as its not specific enough.
This commit is contained in:
committed by
Andrew Scott
parent
bfdb652f9e
commit
79b7ac722a
@@ -52,23 +52,8 @@ const MAX_ANIMATION_TIMEOUT_DEFAULT = 4000;
|
||||
*/
|
||||
export type AnimationFunction = (event: AnimationCallbackEvent) => void;
|
||||
|
||||
export type AnimationEventFunction = (
|
||||
el: Element,
|
||||
value: AnimationFunction,
|
||||
) => AnimationRemoveFunction;
|
||||
export type AnimationClassFunction = (
|
||||
el: Element,
|
||||
value: Set<string> | null,
|
||||
resolvers: Function[] | undefined,
|
||||
) => AnimationRemoveFunction;
|
||||
export type AnimationRemoveFunction = (removeFn: VoidFunction) => void;
|
||||
|
||||
export interface AnimationDetails {
|
||||
classes: Set<string> | null;
|
||||
classFns?: Function[];
|
||||
animateFn: AnimationRemoveFunction;
|
||||
isEventBinding: boolean;
|
||||
}
|
||||
export type RunEnterAnimationFn = () => void;
|
||||
export type RunLeaveAnimationFn = () => {promise: Promise<void>; resolve: VoidFunction};
|
||||
|
||||
export interface LongestAnimation {
|
||||
animationName: string | undefined;
|
||||
@@ -76,17 +61,21 @@ export interface LongestAnimation {
|
||||
duration: number;
|
||||
}
|
||||
|
||||
export interface NodeAnimations {
|
||||
animateFns: Function[];
|
||||
export interface EnterNodeAnimations {
|
||||
animateFns: RunEnterAnimationFn[];
|
||||
resolvers?: VoidFunction[];
|
||||
}
|
||||
export interface LeaveNodeAnimations {
|
||||
animateFns: RunLeaveAnimationFn[];
|
||||
resolvers?: VoidFunction[];
|
||||
}
|
||||
|
||||
export interface AnimationLViewData {
|
||||
// Enter animations that apply to nodes in this view
|
||||
enter?: Map<number, NodeAnimations>;
|
||||
enter?: Map<number, EnterNodeAnimations>;
|
||||
|
||||
// Leave animations that apply to nodes in this view
|
||||
leave?: Map<number, NodeAnimations>;
|
||||
leave?: Map<number, LeaveNodeAnimations>;
|
||||
|
||||
// Leave animations that apply to nodes in this view
|
||||
// We chose to use unknown instead of PromiseSettledResult<void> to avoid requiring the type
|
||||
@@ -100,3 +89,8 @@ export interface AnimationLViewData {
|
||||
// the animations in that case.
|
||||
skipLeaveAnimations?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Function that returns the class or class list binded to the animate instruction
|
||||
*/
|
||||
export type AnimationClassBindingFn = () => string | string[];
|
||||
|
||||
@@ -8,12 +8,12 @@
|
||||
|
||||
import {afterNextRender} from '../render3/after_render/hooks';
|
||||
import {InjectionToken, Injector} from '../di';
|
||||
import {NodeAnimations} from './interfaces';
|
||||
import {EnterNodeAnimations} from './interfaces';
|
||||
|
||||
export interface AnimationQueue {
|
||||
queue: Set<Function>;
|
||||
queue: Set<VoidFunction>;
|
||||
isScheduled: boolean;
|
||||
scheduler: Function | null;
|
||||
scheduler: typeof initializeAnimationQueueScheduler | null;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -33,7 +33,10 @@ export const ANIMATION_QUEUE = new InjectionToken<AnimationQueue>(
|
||||
},
|
||||
);
|
||||
|
||||
export function addToAnimationQueue(injector: Injector, animationFns: Function | Function[]) {
|
||||
export function addToAnimationQueue(
|
||||
injector: Injector,
|
||||
animationFns: VoidFunction | VoidFunction[],
|
||||
) {
|
||||
const animationQueue = injector.get(ANIMATION_QUEUE);
|
||||
if (Array.isArray(animationFns)) {
|
||||
for (const animateFn of animationFns) {
|
||||
@@ -71,7 +74,7 @@ export function initializeAnimationQueueScheduler(injector: Injector) {
|
||||
|
||||
export function queueEnterAnimations(
|
||||
injector: Injector,
|
||||
enterAnimations: Map<number, NodeAnimations>,
|
||||
enterAnimations: Map<number, EnterNodeAnimations>,
|
||||
) {
|
||||
for (const [_, nodeAnimations] of enterAnimations) {
|
||||
addToAnimationQueue(injector, nodeAnimations.animateFns);
|
||||
|
||||
@@ -7,7 +7,15 @@
|
||||
*/
|
||||
|
||||
import {stringify} from '../util/stringify'; // Adjust imports as per actual location
|
||||
import {ANIMATIONS_DISABLED, LongestAnimation, NodeAnimations} from './interfaces';
|
||||
import {
|
||||
ANIMATIONS_DISABLED,
|
||||
RunEnterAnimationFn,
|
||||
RunLeaveAnimationFn,
|
||||
LongestAnimation,
|
||||
EnterNodeAnimations,
|
||||
LeaveNodeAnimations,
|
||||
AnimationClassBindingFn,
|
||||
} from './interfaces';
|
||||
import {INJECTOR, LView, DECLARATION_LCONTAINER, ANIMATIONS} from '../render3/interfaces/view';
|
||||
import {RuntimeError, RuntimeErrorCode} from '../errors';
|
||||
import {Renderer} from '../render3/interfaces/renderer';
|
||||
@@ -61,7 +69,11 @@ export function assertElementNodes(nativeElement: Element, instruction: string)
|
||||
* host binding. When removing classes, we need the entire list of animation classes
|
||||
* added to properly remove them when the longest animation fires.
|
||||
*/
|
||||
export function trackEnterClasses(el: HTMLElement, classList: string[], cleanupFns: Function[]) {
|
||||
export function trackEnterClasses(
|
||||
el: HTMLElement,
|
||||
classList: string[],
|
||||
cleanupFns: VoidFunction[],
|
||||
) {
|
||||
const elementData = enterClassMap.get(el);
|
||||
if (elementData) {
|
||||
for (const klass of classList) {
|
||||
@@ -95,7 +107,7 @@ export const noOpAnimationComplete = () => {};
|
||||
// we remove all of the classes in the case of animation composition via host bindings.
|
||||
export const enterClassMap = new WeakMap<
|
||||
HTMLElement,
|
||||
{classList: string[]; cleanupFns: Function[]}
|
||||
{classList: string[]; cleanupFns: VoidFunction[]}
|
||||
>();
|
||||
export const longestAnimations = new WeakMap<HTMLElement, LongestAnimation>();
|
||||
|
||||
@@ -162,23 +174,23 @@ export function trackLeavingNodes(tNode: TNode, el: HTMLElement): void {
|
||||
/**
|
||||
* Retrieves the list of specified enter animations from the lView
|
||||
*/
|
||||
export function getLViewEnterAnimations(lView: LView): Map<number, NodeAnimations> {
|
||||
export function getLViewEnterAnimations(lView: LView): Map<number, EnterNodeAnimations> {
|
||||
const animationData = (lView[ANIMATIONS] ??= {});
|
||||
return (animationData.enter ??= new Map<number, NodeAnimations>());
|
||||
return (animationData.enter ??= new Map());
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the list of specified leave animations from the lView
|
||||
*/
|
||||
export function getLViewLeaveAnimations(lView: LView): Map<number, NodeAnimations> {
|
||||
export function getLViewLeaveAnimations(lView: LView): Map<number, LeaveNodeAnimations> {
|
||||
const animationData = (lView[ANIMATIONS] ??= {});
|
||||
return (animationData.leave ??= new Map<number, NodeAnimations>());
|
||||
return (animationData.leave ??= new Map());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the list of classes from a passed in value
|
||||
*/
|
||||
export function getClassListFromValue(value: string | Function | string[]): string[] | null {
|
||||
export function getClassListFromValue(value: string | AnimationClassBindingFn): string[] | null {
|
||||
const classes = typeof value === 'function' ? value() : value;
|
||||
let classList: string[] | null = Array.isArray(classes) ? classes : null;
|
||||
if (typeof classes === 'string') {
|
||||
@@ -253,9 +265,9 @@ export function isLongestAnimation(
|
||||
* @param fn The animation function to be called later
|
||||
*/
|
||||
export function addAnimationToLView(
|
||||
animations: Map<number, NodeAnimations>,
|
||||
animations: Map<number, EnterNodeAnimations | LeaveNodeAnimations>,
|
||||
tNode: TNode,
|
||||
fn: Function,
|
||||
fn: RunEnterAnimationFn | RunLeaveAnimationFn,
|
||||
) {
|
||||
const nodeAnimations = animations.get(tNode.index) ?? {animateFns: []};
|
||||
nodeAnimations.animateFns.push(fn);
|
||||
@@ -264,7 +276,7 @@ export function addAnimationToLView(
|
||||
|
||||
export function cleanupAfterLeaveAnimations(
|
||||
resolvers: VoidFunction[] | undefined,
|
||||
cleanupFns: Function[],
|
||||
cleanupFns: VoidFunction[],
|
||||
): void {
|
||||
if (resolvers) {
|
||||
for (const fn of resolvers) {
|
||||
@@ -286,7 +298,7 @@ export function leaveAnimationFunctionCleanup(
|
||||
tNode: TNode,
|
||||
nativeElement: HTMLElement,
|
||||
resolvers: VoidFunction[] | undefined,
|
||||
cleanupFns: Function[],
|
||||
cleanupFns: VoidFunction[],
|
||||
) {
|
||||
clearLeavingNodes(tNode, nativeElement as HTMLElement);
|
||||
cleanupAfterLeaveAnimations(resolvers, cleanupFns);
|
||||
|
||||
@@ -7,6 +7,7 @@
|
||||
*/
|
||||
|
||||
import {
|
||||
AnimationClassBindingFn,
|
||||
AnimationCallbackEvent,
|
||||
AnimationFunction,
|
||||
MAX_ANIMATION_TIMEOUT,
|
||||
@@ -54,7 +55,7 @@ import {initializeAnimationQueueScheduler, queueEnterAnimations} from '../../ani
|
||||
*
|
||||
* @codeGenApi
|
||||
*/
|
||||
export function ɵɵanimateEnter(value: string | Function): typeof ɵɵanimateEnter {
|
||||
export function ɵɵanimateEnter(value: string | AnimationClassBindingFn): typeof ɵɵanimateEnter {
|
||||
performanceMarkFeature('NgAnimateEnter');
|
||||
|
||||
if ((typeof ngServerMode !== 'undefined' && ngServerMode) || !areAnimationSupported) {
|
||||
@@ -86,7 +87,11 @@ export function ɵɵanimateEnter(value: string | Function): typeof ɵɵanimateEn
|
||||
return ɵɵanimateEnter; // For chaining
|
||||
}
|
||||
|
||||
export function runEnterAnimation(lView: LView, tNode: TNode, value: string | Function) {
|
||||
export function runEnterAnimation(
|
||||
lView: LView,
|
||||
tNode: TNode,
|
||||
value: string | AnimationClassBindingFn,
|
||||
): void {
|
||||
const nativeElement = getNativeByTNode(tNode, lView) as HTMLElement;
|
||||
|
||||
ngDevMode && assertElementNodes(nativeElement, 'animate.enter');
|
||||
@@ -97,7 +102,7 @@ export function runEnterAnimation(lView: LView, tNode: TNode, value: string | Fu
|
||||
// Retrieve the actual class list from the value. This will resolve any resolver functions from
|
||||
// bindings.
|
||||
const activeClasses = getClassListFromValue(value);
|
||||
const cleanupFns: Function[] = [];
|
||||
const cleanupFns: VoidFunction[] = [];
|
||||
|
||||
// In the case where multiple animations are happening on the element, we need
|
||||
// to get the longest animation to ensure we don't complete animations early.
|
||||
@@ -233,7 +238,7 @@ function runEnterAnimationFunction(lView: LView, tNode: TNode, value: AnimationF
|
||||
*
|
||||
* @codeGenApi
|
||||
*/
|
||||
export function ɵɵanimateLeave(value: string | Function): typeof ɵɵanimateLeave {
|
||||
export function ɵɵanimateLeave(value: string | AnimationClassBindingFn): typeof ɵɵanimateLeave {
|
||||
performanceMarkFeature('NgAnimateLeave');
|
||||
|
||||
if ((typeof ngServerMode !== 'undefined' && ngServerMode) || !areAnimationSupported) {
|
||||
@@ -263,7 +268,7 @@ export function ɵɵanimateLeave(value: string | Function): typeof ɵɵanimateLe
|
||||
function runLeaveAnimations(
|
||||
lView: LView,
|
||||
tNode: TNode,
|
||||
value: string | Function,
|
||||
value: string | AnimationClassBindingFn,
|
||||
): {promise: Promise<void>; resolve: VoidFunction} {
|
||||
const {promise, resolve} = promiseWithResolvers<void>();
|
||||
const nativeElement = getNativeByTNode(tNode, lView) as Element;
|
||||
@@ -305,7 +310,7 @@ function animateLeaveClassRunner(
|
||||
ngZone: NgZone,
|
||||
) {
|
||||
cancelAnimationsIfRunning(el, renderer);
|
||||
const cleanupFns: Function[] = [];
|
||||
const cleanupFns: VoidFunction[] = [];
|
||||
const resolvers = getLViewLeaveAnimations(lView).get(tNode.index)?.resolvers;
|
||||
|
||||
const handleOutAnimationEnd = (event: AnimationEvent | TransitionEvent | CustomEvent) => {
|
||||
@@ -408,7 +413,7 @@ function runLeaveAnimationFunction(
|
||||
|
||||
ngDevMode && assertElementNodes(nativeElement, 'animate.leave');
|
||||
|
||||
const cleanupFns: Function[] = [];
|
||||
const cleanupFns: VoidFunction[] = [];
|
||||
const renderer = lView[RENDERER];
|
||||
const animationsDisabled = areAnimationsDisabled(lView);
|
||||
const ngZone = lView[INJECTOR]!.get(NgZone);
|
||||
|
||||
Reference in New Issue
Block a user