Skip to content

Commit

Permalink
feat(animations): Add a provider to lazy load the animations
Browse files Browse the repository at this point in the history
In order to support Lazy loading of Animations `@angular/animations/browser` must be lazy loaded.

Due to the dependencies of the exising providers a new entry point in `platform-browser` had to be created.

Usage: use `provideLazyLoadedAnimation()` in the list of providers in ``bootstrapApplication`.
  • Loading branch information
JeanMeche committed Jun 20, 2023
1 parent 9588b11 commit 7766964
Show file tree
Hide file tree
Showing 65 changed files with 4,966 additions and 808 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
15 changes: 15 additions & 0 deletions goldens/public-api/platform-browser/animations/index.md
Expand Up @@ -5,13 +5,28 @@
```ts

import { ANIMATION_MODULE_TYPE } from '@angular/core';
import { AnimationBuilder } from '@angular/animations';
import { AnimationFactory } from '@angular/animations';
import { AnimationMetadata } from '@angular/animations';
import * as i0 from '@angular/core';
import * as i1 from '@angular/platform-browser';
import { ModuleWithProviders } from '@angular/core';
import { Provider } from '@angular/core';
import { RendererFactory2 } from '@angular/core';

export { ANIMATION_MODULE_TYPE }

// @public (undocumented)
export class BrowserAnimationBuilder extends AnimationBuilder {
constructor(rootRenderer: RendererFactory2, doc: Document);
// (undocumented)
build(animation: AnimationMetadata | AnimationMetadata[]): AnimationFactory;
// (undocumented)
static ɵfac: i0.ɵɵFactoryDeclaration<BrowserAnimationBuilder, never>;
// (undocumented)
static ɵprov: i0.ɵɵInjectableDeclaration<BrowserAnimationBuilder>;
}

// @public
export class BrowserAnimationsModule {
static withConfig(config: BrowserAnimationsModuleConfig): ModuleWithProviders<BrowserAnimationsModule>;
Expand Down
15 changes: 15 additions & 0 deletions goldens/public-api/platform-browser/lazy-animations/errors.md
@@ -0,0 +1,15 @@
## API Report File for "angular-srcs"

> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts

// @public
export const enum RuntimeErrorCode {
// (undocumented)
MODULE_LOADING_FAILED = 5950
}

// (No @packageDocumentation comment for this package)

```
14 changes: 14 additions & 0 deletions goldens/public-api/platform-browser/lazy-animations/index.md
@@ -0,0 +1,14 @@
## API Report File for "@angular/platform-browser_lazy-animations"

> Do not edit this file. It is a report generated by [API Extractor](https://api-extractor.com/).
```ts

import { Provider } from '@angular/core';

// @public
export function provideLazyLoadedAnimations(type?: 'animations' | 'noop'): Provider[];

// (No @packageDocumentation comment for this package)

```
1 change: 1 addition & 0 deletions packages.bzl
Expand Up @@ -93,6 +93,7 @@ DOCS_ENTRYPOINTS = [
"platform-browser-dynamic",
"platform-browser-dynamic/testing",
"platform-browser/animations",
"platform-browser/lazy-animations",
"platform-browser/testing",
"platform-server",
"platform-server/init",
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
24 changes: 24 additions & 0 deletions packages/animations/browser/src/createEngine.ts
@@ -0,0 +1,24 @@
/**
* @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.io/license
*/

import {ApplicationRef} from '@angular/core';

import {NoopAnimationStyleNormalizer, WebAnimationsStyleNormalizer} from './dsl/animation_style_normalizer';
import {NoopAnimationDriver, WebAnimationsDriver} from './render/animation_driver';
import {AnimationEngine} from './render/animation_engine_next';

export function createEngine(
type: 'animations'|'noop', applicationRef: ApplicationRef, doc: Document): AnimationEngine {
if (type === 'noop') {
return new AnimationEngine(
doc, new NoopAnimationDriver(), new NoopAnimationStyleNormalizer(), applicationRef);
}

return new AnimationEngine(
doc, new WebAnimationsDriver(), new WebAnimationsStyleNormalizer(), applicationRef);
}
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,6 +71,7 @@ const DIMENSIONAL_PROP_SET = new Set([
'perspective'
]);

@Injectable()
export class WebAnimationsStyleNormalizer extends AnimationStyleNormalizer {
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.

7 changes: 3 additions & 4 deletions packages/animations/browser/src/private_export.ts
Expand Up @@ -5,12 +5,11 @@
* 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
*/
export {createEngine as ɵcreateEngine} from './createEngine';
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

0 comments on commit 7766964

Please sign in to comment.