/
githubmirror
/
angular
Обзор
Документация
Войти
/
githubmirror
/
angular
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
packages/animations/browser/src/render/timeline_animation_engine.ts
205 строк
6 KB
arturovt
refactor(animations): mark non-default `new` expressions as pure (#61452)
19 май 2025, 11:26
19 май 2025, 11:26
7aae854
Код
Авторство
О чём код?
/** * @license * Copyright Google LLC All Rights Reserved. * * Use of this source code is governed by an MIT-style license that can be * found in the LICENSE file at https://angular.dev/license */ import { AnimationMetadata, AnimationMetadataType, AnimationOptions, AnimationPlayer, AUTO_STYLE, ɵStyleDataMap, } from '../../../src/animations'; import {Ast} from '../dsl/animation_ast'; import {buildAnimationAst} from '../dsl/animation_ast_builder'; import {buildAnimationTimelines} from '../dsl/animation_timeline_builder'; import {AnimationTimelineInstruction} from '../dsl/animation_timeline_instruction'; import {ElementInstructionMap} from '../dsl/element_instruction_map'; import {AnimationStyleNormalizer} from '../dsl/style_normalization/animation_style_normalizer'; import { createAnimationFailed, missingOrDestroyedAnimation, missingPlayer, registerFailed, } from '../error_helpers'; import {ENTER_CLASSNAME, LEAVE_CLASSNAME} from '../util'; import {warnRegister} from '../warning_helpers'; import {AnimationDriver} from './animation_driver'; import { getOrSetDefaultValue, listenOnPlayer, makeAnimationEvent, normalizeKeyframes, optimizeGroupPlayer, } from './shared'; const EMPTY_INSTRUCTION_MAP = /* @__PURE__ */ new ElementInstructionMap(); export class TimelineAnimationEngine { private _animations = new Map<string, Ast<AnimationMetadataType>>(); private _playersById = new Map<string, AnimationPlayer>(); public players: AnimationPlayer[] = []; constructor( public bodyNode: any, private _driver: AnimationDriver, private _normalizer: AnimationStyleNormalizer, ) {} register(id: string, metadata: AnimationMetadata | AnimationMetadata[]) { const errors: Error[] = []; const warnings: string[] = []; const ast = buildAnimationAst(this._driver, metadata, errors, warnings); if (errors.length) { throw registerFailed(errors); } else { if (typeof ngDevMode === 'undefined' || ngDevMode) { if (warnings.length) { warnRegister(warnings); } } this._animations.set(id, ast); } } private _buildPlayer( i: AnimationTimelineInstruction, preStyles: ɵStyleDataMap, postStyles?: ɵStyleDataMap, ): AnimationPlayer { const element = i.element; const keyframes = normalizeKeyframes(this._normalizer, i.keyframes, preStyles, postStyles); return this._driver.animate(element, keyframes, i.duration, i.delay, i.easing, [], true); } create(id: string, element: any, options: AnimationOptions = {}): AnimationPlayer { const errors: Error[] = []; const ast = this._animations.get(id); let instructions: AnimationTimelineInstruction[]; const autoStylesMap = new Map<any, ɵStyleDataMap>(); if (ast) { instructions = buildAnimationTimelines( this._driver, element, ast, ENTER_CLASSNAME, LEAVE_CLASSNAME, new Map(), new Map(), options, EMPTY_INSTRUCTION_MAP, errors, ); instructions.forEach((inst) => { const styles = getOrSetDefaultValue( autoStylesMap, inst.element, new Map<string, string | number | null>(), ); inst.postStyleProps.forEach((prop) => styles.set(prop, null)); }); } else { errors.push(missingOrDestroyedAnimation()); instructions = []; } if (errors.length) { throw createAnimationFailed(errors); } autoStylesMap.forEach((styles, element) => { styles.forEach((_, prop) => { styles.set(prop, this._driver.computeStyle(element, prop, AUTO_STYLE)); }); }); const players = instructions.map((i) => { const styles = autoStylesMap.get(i.element); return this._buildPlayer(i, new Map(), styles); }); const player = optimizeGroupPlayer(players); this._playersById.set(id, player); player.onDestroy(() => this.destroy(id)); this.players.push(player); return player; } destroy(id: string) { const player = this._getPlayer(id); player.destroy(); this._playersById.delete(id); const index = this.players.indexOf(player); if (index >= 0) { this.players.splice(index, 1); } } private _getPlayer(id: string): AnimationPlayer { const player = this._playersById.get(id); if (!player) { throw missingPlayer(id); } return player; } listen( id: string, element: string, eventName: string, callback: (event: any) => any, ): () => void { // triggerName, fromState, toState are all ignored for timeline animations const baseEvent = makeAnimationEvent(element, '', '', ''); listenOnPlayer(this._getPlayer(id), eventName, baseEvent, callback); return () => {}; } command(id: string, element: any, command: string, args: any[]): void { if (command == 'register') { this.register(id, args[0] as AnimationMetadata | AnimationMetadata[]); return; } if (command == 'create') { const options = (args[0] || {}) as AnimationOptions; this.create(id, element, options); return; } const player = this._getPlayer(id); switch (command) { case 'play': player.play(); break; case 'pause': player.pause(); break; case 'reset': player.reset(); break; case 'restart': player.restart(); break; case 'finish': player.finish(); break; case 'init': player.init(); break; case 'setPosition': player.setPosition(parseFloat(args[0] as string)); break; case 'destroy': this.destroy(id); break; } } }