diff --git a/packages/core/src/animation/interfaces.ts b/packages/core/src/animation/interfaces.ts index a8b4fbb0489..f17a9f0bf3e 100644 --- a/packages/core/src/animation/interfaces.ts +++ b/packages/core/src/animation/interfaces.ts @@ -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 | null, - resolvers: Function[] | undefined, -) => AnimationRemoveFunction; -export type AnimationRemoveFunction = (removeFn: VoidFunction) => void; - -export interface AnimationDetails { - classes: Set | null; - classFns?: Function[]; - animateFn: AnimationRemoveFunction; - isEventBinding: boolean; -} +export type RunEnterAnimationFn = () => void; +export type RunLeaveAnimationFn = () => {promise: Promise; 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; + enter?: Map; // Leave animations that apply to nodes in this view - leave?: Map; + leave?: Map; // Leave animations that apply to nodes in this view // We chose to use unknown instead of PromiseSettledResult 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[]; diff --git a/packages/core/src/animation/queue.ts b/packages/core/src/animation/queue.ts index 4bc53cf1206..c430269f28c 100644 --- a/packages/core/src/animation/queue.ts +++ b/packages/core/src/animation/queue.ts @@ -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; + queue: Set; isScheduled: boolean; - scheduler: Function | null; + scheduler: typeof initializeAnimationQueueScheduler | null; } /** @@ -33,7 +33,10 @@ export const ANIMATION_QUEUE = new InjectionToken( }, ); -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, + enterAnimations: Map, ) { for (const [_, nodeAnimations] of enterAnimations) { addToAnimationQueue(injector, nodeAnimations.animateFns); diff --git a/packages/core/src/animation/utils.ts b/packages/core/src/animation/utils.ts index 8daf9554a38..365dd1f4297 100644 --- a/packages/core/src/animation/utils.ts +++ b/packages/core/src/animation/utils.ts @@ -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(); @@ -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 { +export function getLViewEnterAnimations(lView: LView): Map { const animationData = (lView[ANIMATIONS] ??= {}); - return (animationData.enter ??= new Map()); + return (animationData.enter ??= new Map()); } /** * Retrieves the list of specified leave animations from the lView */ -export function getLViewLeaveAnimations(lView: LView): Map { +export function getLViewLeaveAnimations(lView: LView): Map { const animationData = (lView[ANIMATIONS] ??= {}); - return (animationData.leave ??= new Map()); + 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, + animations: Map, 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); diff --git a/packages/core/src/render3/instructions/animation.ts b/packages/core/src/render3/instructions/animation.ts index 5b34015fa84..ea8f70bcb6c 100644 --- a/packages/core/src/render3/instructions/animation.ts +++ b/packages/core/src/render3/instructions/animation.ts @@ -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; resolve: VoidFunction} { const {promise, resolve} = promiseWithResolvers(); 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);