Skip to content

Commit

Permalink
feat(animations): Provide a way to lazy load the animations
Browse files Browse the repository at this point in the history
WIP
  • Loading branch information
JeanMeche committed Jun 15, 2023
1 parent 4550fe4 commit 1e600bb
Show file tree
Hide file tree
Showing 45 changed files with 3,612 additions and 903 deletions.
10 changes: 5 additions & 5 deletions WORKSPACE
Expand Up @@ -139,11 +139,11 @@ yarn_install(
# with bin symlinks in the external repository. This is needed to link the shared
# set of deps for example e2es.
exports_directories_only = False,
manual_build_file_contents = """\
filegroup(
name = "node_modules_files",
srcs = ["node_modules"],
)
manual_build_file_contents = """\\\r
filegroup(\r
name = "node_modules_files",\r
srcs = ["node_modules"],\r
)\r
""",
package_json = "//aio/tools/examples/shared:package.json",
yarn = YARN_LABEL,
Expand Down
6 changes: 6 additions & 0 deletions goldens/public-api/animations/browser/index.md
Expand Up @@ -4,6 +4,8 @@
```ts

import * as i0 from '@angular/core';

// @public (undocumented)
export abstract class AnimationDriver {
// (undocumented)
Expand All @@ -23,6 +25,10 @@ export abstract class AnimationDriver {
abstract validateAnimatableStyleProperty?: (prop: string) => boolean;
// (undocumented)
abstract validateStyleProperty(prop: string): boolean;
// (undocumented)
static ɵfac: i0.ɵɵFactoryDeclaration<AnimationDriver, never>;
// (undocumented)
static ɵprov: i0.ɵɵInjectableDeclaration<AnimationDriver>;
}

// (No @packageDocumentation comment for this package)
Expand Down
3 changes: 3 additions & 0 deletions goldens/public-api/platform-browser/animations/index.md
Expand Up @@ -41,6 +41,9 @@ export class NoopAnimationsModule {
// @public
export function provideAnimations(): Provider[];

// @public (undocumented)
export function provideLazyLoadedAnimations(): Provider[];

// @public
export function provideNoopAnimations(): Provider[];

Expand Down
1 change: 1 addition & 0 deletions packages/animations/browser/BUILD.bazel
Expand Up @@ -14,6 +14,7 @@ ng_module(
),
deps = [
"//packages/animations",
"//packages/common",
"//packages/core",
],
)
Expand Down
Expand Up @@ -7,7 +7,7 @@
*/
import {AnimateTimings, AnimationAnimateChildMetadata, AnimationAnimateMetadata, AnimationAnimateRefMetadata, AnimationGroupMetadata, AnimationKeyframesSequenceMetadata, AnimationMetadata, AnimationMetadataType, AnimationOptions, AnimationQueryMetadata, AnimationQueryOptions, AnimationReferenceMetadata, AnimationSequenceMetadata, AnimationStaggerMetadata, AnimationStateMetadata, AnimationStyleMetadata, AnimationTransitionMetadata, AnimationTriggerMetadata, AUTO_STYLE, style, ɵStyleDataMap} from '@angular/animations';

import {invalidDefinition, invalidKeyframes, invalidOffset, invalidParallelAnimation, invalidProperty, invalidStagger, invalidState, invalidStyleValue, invalidTrigger, keyframeOffsetsOutOfOrder, keyframesMissingOffsets} from '../error_helpers';
import {invalidDefinition, invalidKeyframes, invalidOffset, invalidParallelAnimation, invalidStagger, invalidState, invalidStyleValue, invalidTrigger, keyframeOffsetsOutOfOrder, keyframesMissingOffsets} from '../error_helpers';
import {AnimationDriver} from '../render/animation_driver';
import {getOrSetDefaultValue} from '../render/shared';
import {convertToMap, copyObj, extractStyleParams, iteratorToArray, NG_ANIMATING_SELECTOR, NG_TRIGGER_SELECTOR, normalizeAnimationEntry, resolveTiming, SUBSTITUTION_EXPR_START, validateStyleParams, visitDslNode} from '../util';
Expand Down
Expand Up @@ -5,10 +5,39 @@
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {invalidCssUnitValue} from '../../error_helpers';
import {dashCaseToCamelCase} from '../../util';

import {AnimationStyleNormalizer} from './animation_style_normalizer';
import {forwardRef, Injectable} from '@angular/core';

import {invalidCssUnitValue} from '../error_helpers';
import {dashCaseToCamelCase} from '../util';


/**
* @publicApi
*/
// Keep in mind that all browser test environments are init with the NoopAnimationsModule
// Effectively overwriting this providedIn:'root'. See /tools/browser_tests.init.ts
// So everytime the WebAnimationsStyleNormalizer is expected, it must me provided explicitly.
@Injectable({providedIn: 'root', useClass: forwardRef(() => NoopAnimationStyleNormalizer)})
export abstract class AnimationStyleNormalizer {
abstract normalizePropertyName(propertyName: string, errors: Error[]): string;
abstract normalizeStyleValue(
userProvidedProperty: string, normalizedProperty: string, value: string|number,
errors: Error[]): string;
}

@Injectable()
export class NoopAnimationStyleNormalizer implements AnimationStyleNormalizer {
normalizePropertyName(propertyName: string, errors: Error[]): string {
return propertyName;
}

normalizeStyleValue(
userProvidedProperty: string, normalizedProperty: string, value: string|number,
errors: Error[]): string {
return <any>value;
}
}

const DIMENSIONAL_PROP_SET = new Set([
'width',
Expand Down Expand Up @@ -42,7 +71,12 @@ const DIMENSIONAL_PROP_SET = new Set([
'perspective'
]);

@Injectable()
export class WebAnimationsStyleNormalizer extends AnimationStyleNormalizer {
constructor() {
super();
}

override normalizePropertyName(propertyName: string, errors: Error[]): string {
return dashCaseToCamelCase(propertyName);
}
Expand Down
Expand Up @@ -12,12 +12,12 @@ import {getOrSetDefaultValue} from '../render/shared';
import {copyObj, interpolateParams, iteratorToArray} from '../util';

import {StyleAst, TransitionAst} from './animation_ast';
import {AnimationStyleNormalizer} from './animation_style_normalizer';
import {buildAnimationTimelines} from './animation_timeline_builder';
import {AnimationTimelineInstruction} from './animation_timeline_instruction';
import {TransitionMatcherFn} from './animation_transition_expr';
import {AnimationTransitionInstruction, createTransitionInstruction} from './animation_transition_instruction';
import {ElementInstructionMap} from './element_instruction_map';
import {AnimationStyleNormalizer} from './style_normalization/animation_style_normalizer';

const EMPTY_OBJECT = {};

Expand Down
2 changes: 1 addition & 1 deletion packages/animations/browser/src/dsl/animation_trigger.ts
Expand Up @@ -8,8 +8,8 @@
import {AnimationMetadataType, ɵStyleDataMap} from '@angular/animations';

import {SequenceAst, TransitionAst, TriggerAst} from './animation_ast';
import {AnimationStyleNormalizer} from './animation_style_normalizer';
import {AnimationStateStyles, AnimationTransitionFactory} from './animation_transition_factory';
import {AnimationStyleNormalizer} from './style_normalization/animation_style_normalizer';



Expand Down

This file was deleted.

6 changes: 2 additions & 4 deletions packages/animations/browser/src/private_export.ts
Expand Up @@ -6,11 +6,9 @@
* found in the LICENSE file at https://angular.io/license
*/
export {Animation as ɵAnimation} from './dsl/animation';
export {AnimationStyleNormalizer as ɵAnimationStyleNormalizer, NoopAnimationStyleNormalizer as ɵNoopAnimationStyleNormalizer} from './dsl/style_normalization/animation_style_normalizer';
export {WebAnimationsStyleNormalizer as ɵWebAnimationsStyleNormalizer} from './dsl/style_normalization/web_animations_style_normalizer';
export {NoopAnimationDriver as ɵNoopAnimationDriver} from './render/animation_driver';
export {AnimationStyleNormalizer as ɵAnimationStyleNormalizer, NoopAnimationStyleNormalizer as ɵNoopAnimationStyleNormalizer, WebAnimationsStyleNormalizer as ɵWebAnimationsStyleNormalizer} from './dsl/animation_style_normalizer';
export {NoopAnimationDriver as ɵNoopAnimationDriver, WebAnimationsDriver as ɵWebAnimationsDriver} from './render/animation_driver';
export {AnimationEngine as ɵAnimationEngine} from './render/animation_engine_next';
export {containsElement as ɵcontainsElement, getParentElement as ɵgetParentElement, invokeQuery as ɵinvokeQuery, validateStyleProperty as ɵvalidateStyleProperty} from './render/shared';
export {WebAnimationsDriver as ɵWebAnimationsDriver} from './render/web_animations/web_animations_driver';
export {WebAnimationsPlayer as ɵWebAnimationsPlayer} from './render/web_animations/web_animations_player';
export {allowPreviousPlayerStylesMerge as ɵallowPreviousPlayerStylesMerge, normalizeKeyframes as ɵnormalizeKeyframes} from './util';
79 changes: 73 additions & 6 deletions packages/animations/browser/src/render/animation_driver.ts
Expand Up @@ -5,15 +5,15 @@
* Use of this source code is governed by an MIT-style license that can be
* found in the LICENSE file at https://angular.io/license
*/
import {AnimationPlayer, NoopAnimationPlayer} from '@angular/animations';
import {AnimationPlayer, NoopAnimationPlayer, ɵStyleDataMap} from '@angular/animations';
import {Injectable} from '@angular/core';

import {containsElement, getParentElement, invokeQuery, validateStyleProperty} from './shared';
import {allowPreviousPlayerStylesMerge, balancePreviousStylesIntoKeyframes, camelCaseToDashCase, copyStyles, normalizeKeyframes} from '../util';

import {containsElement, getParentElement, invokeQuery, validateStyleProperty, validateWebAnimatableStyleProperty} from './shared';
import {packageNonAnimatableStyles} from './special_cased_styles';
import {WebAnimationsPlayer} from './web_animations/web_animations_player';

/**
* @publicApi
*/
@Injectable()
export class NoopAnimationDriver implements AnimationDriver {
validateStyleProperty(prop: string): boolean {
return validateStyleProperty(prop);
Expand Down Expand Up @@ -48,9 +48,76 @@ export class NoopAnimationDriver implements AnimationDriver {
}
}

export class WebAnimationsDriver implements AnimationDriver {
validateStyleProperty(prop: string): boolean {
// Perform actual validation in dev mode only, in prod mode this check is a noop.
if (typeof ngDevMode === 'undefined' || ngDevMode) {
return validateStyleProperty(prop);
}
return true;
}

validateAnimatableStyleProperty(prop: string): boolean {
// Perform actual validation in dev mode only, in prod mode this check is a noop.
if (typeof ngDevMode === 'undefined' || ngDevMode) {
const cssProp = camelCaseToDashCase(prop);
return validateWebAnimatableStyleProperty(cssProp);
}
return true;
}

matchesElement(_element: any, _selector: string): boolean {
// This method is deprecated and no longer in use so we return false.
return false;
}

containsElement(elm1: any, elm2: any): boolean {
return containsElement(elm1, elm2);
}

getParentElement(element: unknown): unknown {
return getParentElement(element);
}

query(element: any, selector: string, multi: boolean): any[] {
return invokeQuery(element, selector, multi);
}

computeStyle(element: any, prop: string, defaultValue?: string): string {
return (window.getComputedStyle(element) as any)[prop] as string;
}

animate(
element: any, keyframes: Array<Map<string, string|number>>, duration: number, delay: number,
easing: string, previousPlayers: AnimationPlayer[] = []): AnimationPlayer {
const fill = delay == 0 ? 'both' : 'forwards';
const playerOptions: {[key: string]: string|number} = {duration, delay, fill};
// we check for this to avoid having a null|undefined value be present
// for the easing (which results in an error for certain browsers #9752)
if (easing) {
playerOptions['easing'] = easing;
}

const previousStyles: ɵStyleDataMap = new Map();
const previousWebAnimationPlayers = <WebAnimationsPlayer[]>previousPlayers.filter(
player => player instanceof WebAnimationsPlayer);
if (allowPreviousPlayerStylesMerge(duration, delay)) {
previousWebAnimationPlayers.forEach(player => {
player.currentSnapshot.forEach((val, prop) => previousStyles.set(prop, val));
});
}

let _keyframes = normalizeKeyframes(keyframes).map(styles => copyStyles(styles));
_keyframes = balancePreviousStylesIntoKeyframes(element, _keyframes, previousStyles);
const specialStyles = packageNonAnimatableStyles(element, _keyframes);
return new WebAnimationsPlayer(element, _keyframes, playerOptions, specialStyles);
}
}

/**
* @publicApi
*/
@Injectable({providedIn: 'root', useFactory: () => new NoopAnimationDriver()})
export abstract class AnimationDriver {
static NOOP: AnimationDriver = (/* @__PURE__ */ new NoopAnimationDriver());

Expand Down
23 changes: 17 additions & 6 deletions packages/animations/browser/src/render/animation_engine_next.ts
Expand Up @@ -6,11 +6,13 @@
* found in the LICENSE file at https://angular.io/license
*/
import {AnimationMetadata, AnimationPlayer, AnimationTriggerMetadata} from '@angular/animations';
import {DOCUMENT} from '@angular/common';
import {ApplicationRef, Inject, Injectable, OnDestroy} from '@angular/core';

import {TriggerAst} from '../dsl/animation_ast';
import {buildAnimationAst} from '../dsl/animation_ast_builder';
import {AnimationStyleNormalizer} from '../dsl/animation_style_normalizer';
import {AnimationTrigger, buildTrigger} from '../dsl/animation_trigger';
import {AnimationStyleNormalizer} from '../dsl/style_normalization/animation_style_normalizer';
import {triggerBuildFailed} from '../error_helpers';
import {warnTriggerBuild} from '../warning_helpers';

Expand All @@ -19,7 +21,9 @@ import {parseTimelineCommand} from './shared';
import {TimelineAnimationEngine} from './timeline_animation_engine';
import {TransitionAnimationEngine} from './transition_animation_engine';

export class AnimationEngine {

@Injectable({providedIn: 'root'})
export class AnimationEngine implements OnDestroy {
private _transitionEngine: TransitionAnimationEngine;
private _timelineEngine: TimelineAnimationEngine;

Expand All @@ -28,16 +32,23 @@ export class AnimationEngine {
// this method is designed to be overridden by the code that uses this engine
public onRemovalComplete = (element: any, context: any) => {};

// The `ApplicationRef` is injected here explicitly to force the dependency ordering.
// Since the `ApplicationRef` should be created earlier before the `AnimationEngine`, they
// both have `ngOnDestroy` hooks and `flush()` must be called after all views are destroyed.
constructor(
private bodyNode: any, private _driver: AnimationDriver,
private _normalizer: AnimationStyleNormalizer) {
this._transitionEngine = new TransitionAnimationEngine(bodyNode, _driver, _normalizer);
this._timelineEngine = new TimelineAnimationEngine(bodyNode, _driver, _normalizer);
@Inject(DOCUMENT) doc: Document, private _driver: AnimationDriver,
private _normalizer: AnimationStyleNormalizer, appRef: ApplicationRef) {
this._transitionEngine = new TransitionAnimationEngine(doc.body, _driver, _normalizer);
this._timelineEngine = new TimelineAnimationEngine(doc.body, _driver, _normalizer);

this._transitionEngine.onRemovalComplete = (element: any, context: any) =>
this.onRemovalComplete(element, context);
}

ngOnDestroy(): void {
this.flush();
}

registerTrigger(
componentId: string, namespaceId: string, hostElement: any, name: string,
metadata: AnimationTriggerMetadata): void {
Expand Down
2 changes: 1 addition & 1 deletion packages/animations/browser/src/render/shared.ts
Expand Up @@ -7,7 +7,7 @@
*/
import {AnimationEvent, AnimationPlayer, AUTO_STYLE, NoopAnimationPlayer, ɵAnimationGroupPlayer, ɵPRE_STYLE as PRE_STYLE, ɵStyleDataMap} from '@angular/animations';

import {AnimationStyleNormalizer} from '../../src/dsl/style_normalization/animation_style_normalizer';
import {AnimationStyleNormalizer} from '../../src/dsl/animation_style_normalizer';
import {animationFailed} from '../error_helpers';

import {ANIMATABLE_PROP_SET} from './web_animations/animatable_props_set';
Expand Down
Expand Up @@ -9,10 +9,10 @@ import {AnimationMetadata, AnimationMetadataType, AnimationOptions, AnimationPla

import {Ast} from '../dsl/animation_ast';
import {buildAnimationAst} from '../dsl/animation_ast_builder';
import {AnimationStyleNormalizer} from '../dsl/animation_style_normalizer';
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';
Expand Down
Expand Up @@ -7,12 +7,12 @@
*/
import {AnimationOptions, AnimationPlayer, AUTO_STYLE, NoopAnimationPlayer, ɵAnimationGroupPlayer as AnimationGroupPlayer, ɵPRE_STYLE as PRE_STYLE, ɵStyleDataMap} from '@angular/animations';

import {AnimationStyleNormalizer} from '../dsl/animation_style_normalizer';
import {AnimationTimelineInstruction} from '../dsl/animation_timeline_instruction';
import {AnimationTransitionFactory} from '../dsl/animation_transition_factory';
import {AnimationTransitionInstruction} from '../dsl/animation_transition_instruction';
import {AnimationTrigger} from '../dsl/animation_trigger';
import {ElementInstructionMap} from '../dsl/element_instruction_map';
import {AnimationStyleNormalizer} from '../dsl/style_normalization/animation_style_normalizer';
import {missingEvent, missingTrigger, transitionFailed, triggerTransitionsFailed, unregisteredTrigger, unsupportedTriggerEvent} from '../error_helpers';
import {copyObj, ENTER_CLASSNAME, eraseStyles, LEAVE_CLASSNAME, NG_ANIMATING_CLASSNAME, NG_ANIMATING_SELECTOR, NG_TRIGGER_CLASSNAME, NG_TRIGGER_SELECTOR, setStyles} from '../util';

Expand Down

0 comments on commit 1e600bb

Please sign in to comment.