From b10029c18b11dc40577e1dfd86d2edfbbee16bad Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Matias=20Niemel=C3=A4?= Date: Tue, 25 Apr 2017 15:06:31 -0700 Subject: [PATCH] docs(animations): add documentation for new animation features --- packages/animations/src/animation_builder.ts | 43 ++- packages/animations/src/animation_metadata.ts | 365 +++++++++++++++++- packages/animations/src/animations.ts | 2 +- .../src/players/animation_player.ts | 4 + .../animations/src/animation_builder.ts | 8 +- .../animations/src/private_export.ts | 2 +- .../animations/animations.d.ts | 12 +- 7 files changed, 407 insertions(+), 29 deletions(-) diff --git a/packages/animations/src/animation_builder.ts b/packages/animations/src/animation_builder.ts index 71224df0e4..0bc5f1404d 100644 --- a/packages/animations/src/animation_builder.ts +++ b/packages/animations/src/animation_builder.ts @@ -9,15 +9,54 @@ import {AnimationMetadata, AnimationOptions} from './animation_metadata'; import {AnimationPlayer} from './players/animation_player'; /** + * AnimationBuilder is an injectable service that is available when the {@link + * BrowserAnimationsModule BrowserAnimationsModule} or {@link NoopAnimationsModule + * NoopAnimationsModule} modules are used within an application. + * + * The purpose if this service is to produce an animation sequence programmatically within an + * angular component or directive. + * + * Programmatic animations are first built and then a player is created when the build animation is + * attached to an element. + * + * ```ts + * // remember to include the BrowserAnimationsModule module for this to work... + * import {AnimationBuilder} from '@angular/animations'; + * + * class MyCmp { + * constructor(private _builder: AnimationBuilder) {} + * + * makeAnimation(element: any) { + * // first build the animation + * const myAnimation = this._builder.build([ + * style({ width: 0 }), + * animate(1000, style({ width: '100px' })) + * ]); + * + * // then create a player from it + * const player = myAnimation.create(element); + * + * player.play(); + * } + * } + * ``` + * + * When an animation is built an instance of {@link AnimationFactory AnimationFactory} will be + * returned. Using that an {@link AnimationPlayer AnimationPlayer} can be created which can then be + * used to start the animation. + * * @experimental Animation support is experimental. */ export abstract class AnimationBuilder { - abstract build(animation: AnimationMetadata|AnimationMetadata[]): Animation; + abstract build(animation: AnimationMetadata|AnimationMetadata[]): AnimationFactory; } /** + * An instance of `AnimationFactory` is returned from {@link AnimationBuilder#build + * AnimationBuilder.build}. + * * @experimental Animation support is experimental. */ -export abstract class Animation { +export abstract class AnimationFactory { abstract create(element: any, options?: AnimationOptions): AnimationPlayer; } diff --git a/packages/animations/src/animation_metadata.ts b/packages/animations/src/animation_metadata.ts index 50d503afc7..8530faf100 100755 --- a/packages/animations/src/animation_metadata.ts +++ b/packages/animations/src/animation_metadata.ts @@ -8,6 +8,9 @@ export interface ɵStyleData { [key: string]: string|number; } /** + * Metadata representing the entry of animations. Instances of this interface are created internally + * within the Angular animation DSL. + * * @experimental Animation support is experimental. */ export declare type AnimateTimings = { @@ -17,6 +20,23 @@ export declare type AnimateTimings = { }; /** + * `AnimationOptions` represents options that can be passed into most animation DSL methods. + * When options are provided, the delay value of an animation can be changed and animation input + * parameters can be passed in to change styling and timing data when an animation is started. + * + * The following animation DSL functions are able to accept animation option data: + * + * - {@link transition transition()} + * - {@link sequence sequence()} + * - {@link group group()} + * - {@link query query()} + * - {@link animation animation()} + * - {@link useAnimation useAnimation()} + * - {@link animateChild animateChild()} + * + * Programmatic animations built using {@link AnimationBuilder the AnimationBuilder service} also + * make use of AnimationOptions. + * * @experimental Animation support is experimental. */ export declare interface AnimationOptions { @@ -25,11 +45,17 @@ export declare interface AnimationOptions { } /** + * Metadata representing the entry of animations. Instances of this interface are created internally + * within the Angular animation DSL when {@link animateChild animateChild()} is used. + * * @experimental Animation support is experimental. */ export declare interface AnimateChildOptions extends AnimationOptions { duration?: number|string; } /** + * Metadata representing the entry of animations. Usages of this enum are created + * each time an animation DSL function is used. + * * @experimental Animation support is experimental. */ export const enum AnimationMetadataType { @@ -59,6 +85,9 @@ export const AUTO_STYLE = '*'; export interface AnimationMetadata { type: AnimationMetadataType; } /** + * Metadata representing the entry of animations. Instances of this interface are provided via the + * animation DSL when the {@link trigger trigger animation function} is called. + * * @experimental Animation support is experimental. */ export interface AnimationTriggerMetadata extends AnimationMetadata { @@ -68,7 +97,7 @@ export interface AnimationTriggerMetadata extends AnimationMetadata { } /** - * Metadata representing the entry of animations. Instances of this class are provided via the + * Metadata representing the entry of animations. Instances of this interface are provided via the * animation DSL when the {@link state state animation function} is called. * * @experimental Animation support is experimental. @@ -79,7 +108,7 @@ export interface AnimationStateMetadata extends AnimationMetadata { } /** - * Metadata representing the entry of animations. Instances of this class are provided via the + * Metadata representing the entry of animations. Instances of this interface are provided via the * animation DSL when the {@link transition transition animation function} is called. * * @experimental Animation support is experimental. @@ -108,7 +137,7 @@ export interface AnimationQueryMetadata extends AnimationMetadata { } /** - * Metadata representing the entry of animations. Instances of this class are provided via the + * Metadata representing the entry of animations. Instances of this interface are provided via the * animation DSL when the {@link keyframes keyframes animation function} is called. * * @experimental Animation support is experimental. @@ -118,7 +147,7 @@ export interface AnimationKeyframesSequenceMetadata extends AnimationMetadata { } /** - * Metadata representing the entry of animations. Instances of this class are provided via the + * Metadata representing the entry of animations. Instances of this interface are provided via the * animation DSL when the {@link style style animation function} is called. * * @experimental Animation support is experimental. @@ -129,7 +158,7 @@ export interface AnimationStyleMetadata extends AnimationMetadata { } /** - * Metadata representing the entry of animations. Instances of this class are provided via the + * Metadata representing the entry of animations. Instances of this interface are provided via the * animation DSL when the {@link animate animate animation function} is called. * * @experimental Animation support is experimental. @@ -140,6 +169,9 @@ export interface AnimationAnimateMetadata extends AnimationMetadata { } /** + * Metadata representing the entry of animations. Instances of this interface are provided via the + * animation DSL when the {@link animateChild animateChild animation function} is called. + * * @experimental Animation support is experimental. */ export interface AnimationAnimateChildMetadata extends AnimationMetadata { @@ -147,6 +179,9 @@ export interface AnimationAnimateChildMetadata extends AnimationMetadata { } /** + * Metadata representing the entry of animations. Instances of this interface are provided via the + * animation DSL when the {@link useAnimation useAnimation animation function} is called. + * * @experimental Animation support is experimental. */ export interface AnimationAnimateRefMetadata extends AnimationMetadata { @@ -155,7 +190,7 @@ export interface AnimationAnimateRefMetadata extends AnimationMetadata { } /** - * Metadata representing the entry of animations. Instances of this class are provided via the + * Metadata representing the entry of animations. Instances of this interface are provided via the * animation DSL when the {@link sequence sequence animation function} is called. * * @experimental Animation support is experimental. @@ -166,7 +201,7 @@ export interface AnimationSequenceMetadata extends AnimationMetadata { } /** - * Metadata representing the entry of animations. Instances of this class are provided via the + * Metadata representing the entry of animations. Instances of this interface are provided via the * animation DSL when the {@link group group animation function} is called. * * @experimental Animation support is experimental. @@ -177,6 +212,20 @@ export interface AnimationGroupMetadata extends AnimationMetadata { } /** + * Metadata representing the entry of animations. Instances of this interface are provided via the + * animation DSL when the {@link query query animation function} is called. + * + * @experimental Animation support is experimental. + */ +export declare interface AnimationQueryOptions extends AnimationOptions { + optional?: boolean; + limit?: number; +} + +/** + * Metadata representing the entry of animations. Instances of this interface are provided via the + * animation DSL when the {@link stagger stagger animation function} is called. + * * @experimental Animation support is experimental. */ export interface AnimationStaggerMetadata extends AnimationMetadata { @@ -628,6 +677,38 @@ export function transition( } /** + * `animation` is an animation-specific function that is designed to be used inside of Angular's + * animation DSL language. + * + * `var myAnimation = animation(...)` is designed to produce a reusable animation that can be later + * invoked in another animation or sequence. Reusable animations are designed to make use of + * animation parameters and the produced animation can be used via the `useAnimation` method. + * + * ``` + * var fadeAnimation = animation([ + * style({ opacity: '{{ start }}' }), + * animate('{{ time }}', + * style({ opacity: '{{ end }}')) + * ], { params: { time: '1000ms', start: 0, end: 1 }}); + * ``` + * + * If parameters are attached to an animation then they act as **default parameter values**. When an + * animation is invoked via `useAnimation` then parameter values are allowed to be passed in + * directly. If any of the passed in parameter values are missing then the default values will be + * used. + * + * ``` + * useAnimation(fadeAnimation, { + * params: { + * time: '2s', + * start: 1, + * end: 0 + * } + * }) + * ``` + * + * If one or more parameter values are missing before animated then an error will be thrown. + * * @experimental Animation support is experimental. */ export function animation( @@ -637,6 +718,100 @@ export function animation( } /** + * `animateChild` is an animation-specific function that is designed to be used inside of Angular's + * animation DSL language. It works by allowing a queried element to execute its own + * animation within the animation sequence. + * + * Each time an animation is triggered in angular, the parent animation + * will always get priority and any child animations will be blocked. In order + * for a child animation to run, the parent animation must query each of the elements + * containing child animations and then allow the animations to run using `animateChild`. + * + * The example HTML code below shows both parent and child elements that have animation + * triggers that will execute at the same time. + * + * ```html + * + * + *
+ * + *
+ *
Hello
+ *
+ * one + *
+ *
+ * two + *
+ *
+ * three + *
+ *
+ * ``` + * + * Now when the `exp` value changes to true, only the `parentAnimation` animation will animate + * because it has priority. However, using `query` and `animateChild` each of the inner animations + * can also fire: + * + * ```ts + * // parent-child.component.ts + * import {trigger, transition, animate, style, query, animateChild} from '@angular/animations'; + * @Component({ + * selector: 'parent-child-component', + * animations: [ + * trigger('parentAnimation', [ + * transition('false => true', [ + * query('header', [ + * style({ opacity: 0 }), + * animate(500, style({ opacity: 1 })) + * ]), + * query('@childAnimation', [ + * animateChild() + * ]) + * ]) + * ]), + * trigger('childAnimation', [ + * transition('false => true', [ + * style({ opacity: 0 }), + * animate(500, style({ opacity: 1 })) + * ]) + * ]) + * ] + * }) + * class ParentChildCmp { + * exp: boolean = false; + * } + * ``` + * + * In the animation code above, when the `parentAnimation` transition kicks off it first queries to + * find the header element and fades it in. It then finds each of the sub elements that contain the + * `@childAnimation` trigger and then allows for their animations to fire. + * + * This example can be further extended by using stagger: + * + * ```ts + * query('@childAnimation', stagger(100, [ + * animateChild() + * ])) + * ``` + * + * Now each of the sub animations start off with respect to the `100ms` staggering step. + * + * ## The first frame of child animations + * When sub animations are executed using `animateChild` the animation engine will always apply the + * first frame of every sub animation immediately at the start of the animation sequence. This way + * the parent animation does not need to set any initial styling data on the sub elements before the + * sub animations kick off. + * + * In the example above the first frame of the `childAnimation`'s `false => true` transition + * consists of a style of `opacity: 0`. This is applied immediately when the `parentAnimation` + * animation transition sequence starts. Only then when the `@childAnimation` is queried and called + * with `animateChild` will it then animate to its destination of `opacity: 1`. + * + * Note that this feature designed to be used alongside {@link query query()} and it will only work + * with animations that are assigned using the Angular animation DSL (this means that CSS keyframes + * and transitions are not handled by this API). + * * @experimental Animation support is experimental. */ export function animateChild(options: AnimateChildOptions | null = null): @@ -645,6 +820,10 @@ export function animateChild(options: AnimateChildOptions | null = null): } /** + * `useAnimation` is an animation-specific function that is designed to be used inside of Angular's + * animation DSL language. It is used to kick off a reusable animation that is created using {@link + * animation animation()}. + * * @experimental Animation support is experimental. */ export function useAnimation( @@ -654,14 +833,95 @@ export function useAnimation( } /** - * @experimental Animation support is experimental. - */ -export declare interface AnimationQueryOptions extends AnimationOptions { - optional?: boolean; - limit?: number; -} - -/** + * `query` is an animation-specific function that is designed to be used inside of Angular's + * animation DSL language. + * + * query() is used to find one or more inner elements within the current element that is + * being animated within the sequence. The provided animation steps are applied + * to the queried element (by default, an array is provided, then this will be + * treated as an animation sequence). + * + * ### Usage + * + * query() is designed to collect mutiple elements and works internally by using + * `element.querySelectorAll`. An additional options object can be provided which + * can be used to limit the total amount of items to be collected. + * + * ```js + * query('div', [ + * animate(...), + * animate(...) + * ], { limit: 1 }) + * ``` + * + * query(), by default, will throw an error when zero items are found. If a query + * has the `optional` flag set to true then this error will be ignored. + * + * ```js + * query('.some-element-that-may-not-be-there', [ + * animate(...), + * animate(...) + * ], { optional: true }) + * ``` + * + * ### Special Selector Values + * + * The selector value within a query can collect elements that contain angular-specific + * characteristics + * using special pseudo-selectors tokens. + * + * These include: + * + * - Querying for newly inserted/removed elements using `query(":enter")`/`query(":leave")` + * - Querying all currently animating elements using `query(":animating")` + * - Querying elements that contain an animation trigger using `query("@triggerName")` + * - Querying all elements that contain an animation triggers using `query("@*")` + * - Including the current element into the animation sequence using `query(":self")` + * + * + * Each of these pseudo-selector tokens can be merged together into a combined query selector + * string: + * + * ``` + * query(':self, .record:enter, .record:leave, @subTrigger', [...]) + * ``` + * + * ### Demo + * + * ``` + * @Component({ + * selector: 'inner', + * template: ` + *
+ *

Title

+ *
+ * Blah blah blah + *
+ *
+ * `, + * animations: [ + * trigger('queryAnimation', [ + * transition('* => goAnimate', [ + * // hide the inner elements + * query('h1', style({ opacity: 0 })), + * query('.content', style({ opacity: 0 })), + * + * // animate the inner elements in, one by one + * query('h1', animate(1000, style({ opacity: 1 })), + * query('.content', animate(1000, style({ opacity: 1 })), + * ]) + * ]) + * ] + * }) + * class Cmp { + * exp = ''; + * + * goAnimate() { + * this.exp = 'goAnimate'; + * } + * } + * ``` + * * @experimental Animation support is experimental. */ export function query( @@ -671,6 +931,81 @@ export function query( } /** + * `stagger` is an animation-specific function that is designed to be used inside of Angular's + * animation DSL language. It is designed to be used inside of an animation {@link query query()} + * and works by issuing a timing gap between after each queried item is animated. + * + * ### Usage + * + * In the example below there is a container element that wraps a list of items stamped out + * by an ngFor. The container element contains an animation trigger that will later be set + * to query for each of the inner items. + * + * ```html + * + * + *
+ *
+ *
+ * {{ item }} + *
+ *
+ * ``` + * + * The component code for this looks as such: + * + * ```ts + * import {trigger, transition, style, animate, query, stagger} from '@angular/animations'; + * @Component({ + * templateUrl: 'list.component.html', + * animations: [ + * trigger('listAnimation', [ + * //... + * ]) + * ] + * }) + * class ListComponent { + * items = []; + * + * showItems() { + * this.items = [0,1,2,3,4]; + * } + * + * hideItems() { + * this.items = []; + * } + * + * toggle() { + * this.items.length ? this.hideItems() : this.showItems(); + * } + * } + * ``` + * + * And now for the animation trigger code: + * + * ```ts + * trigger('listAnimation', [ + * transition('* => *', [ // each time the binding value changes + * query(':leave', [ + * stagger(100, [ + * animate('0.5s', style({ opacity: 0 })) + * ]) + * ]), + * query(':enter', [ + * style({ opacity: 0 }), + * stagger(100, [ + * animate('0.5s', style({ opacity: 1 })) + * ]) + * ]) + * ]) + * ]) + * ``` + * + * Now each time the items are added/removed then either the opacity + * fade-in animation will run or each removed item will be faded out. + * When either of these animations occur then a stagger effect will be + * applied after each item's animation is started. + * * @experimental Animation support is experimental. */ export function stagger( diff --git a/packages/animations/src/animations.ts b/packages/animations/src/animations.ts index 66548c1847..7f8acfadc9 100644 --- a/packages/animations/src/animations.ts +++ b/packages/animations/src/animations.ts @@ -11,7 +11,7 @@ * @description * Entry point for all animation APIs of the animation package. */ -export {Animation, AnimationBuilder} from './animation_builder'; +export {AnimationBuilder, AnimationFactory} from './animation_builder'; export {AnimationEvent} from './animation_event'; export {AUTO_STYLE, AnimateChildOptions, AnimateTimings, AnimationAnimateChildMetadata, AnimationAnimateMetadata, AnimationAnimateRefMetadata, AnimationGroupMetadata, AnimationKeyframesSequenceMetadata, AnimationMetadata, AnimationMetadataType, AnimationOptions, AnimationQueryMetadata, AnimationQueryOptions, AnimationReferenceMetadata, AnimationSequenceMetadata, AnimationStaggerMetadata, AnimationStateMetadata, AnimationStyleMetadata, AnimationTransitionMetadata, AnimationTriggerMetadata, animate, animateChild, animation, group, keyframes, query, sequence, stagger, state, style, transition, trigger, useAnimation, ɵStyleData} from './animation_metadata'; export {AnimationPlayer, NoopAnimationPlayer} from './players/animation_player'; diff --git a/packages/animations/src/players/animation_player.ts b/packages/animations/src/players/animation_player.ts index 2bb971949e..14d14f35f6 100644 --- a/packages/animations/src/players/animation_player.ts +++ b/packages/animations/src/players/animation_player.ts @@ -8,6 +8,10 @@ import {scheduleMicroTask} from '../util'; /** + * AnimationPlayer controls an animation sequence that was produced from a programmatic animation. + * (see {@link AnimationBuilder AnimationBuilder} for more information on how to create programmatic + * animations.) + * * @experimental Animation support is experimental. */ export interface AnimationPlayer { diff --git a/packages/platform-browser/animations/src/animation_builder.ts b/packages/platform-browser/animations/src/animation_builder.ts index 96bda7eab0..d94f6c5e2d 100644 --- a/packages/platform-browser/animations/src/animation_builder.ts +++ b/packages/platform-browser/animations/src/animation_builder.ts @@ -5,7 +5,7 @@ * 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 {Animation, AnimationBuilder, AnimationMetadata, AnimationOptions, AnimationPlayer, NoopAnimationPlayer, sequence} from '@angular/animations'; +import {AnimationBuilder, AnimationFactory, AnimationMetadata, AnimationOptions, AnimationPlayer, NoopAnimationPlayer, sequence} from '@angular/animations'; import {Injectable, RendererFactory2, RendererType2, ViewEncapsulation} from '@angular/core'; import {AnimationRenderer} from './animation_renderer'; @@ -26,16 +26,16 @@ export class BrowserAnimationBuilder extends AnimationBuilder { this._renderer = rootRenderer.createRenderer(document.body, typeData) as AnimationRenderer; } - build(animation: AnimationMetadata|AnimationMetadata[]): Animation { + build(animation: AnimationMetadata|AnimationMetadata[]): AnimationFactory { const id = this._nextAnimationId.toString(); this._nextAnimationId++; const entry = Array.isArray(animation) ? sequence(animation) : animation; issueAnimationCommand(this._renderer, null, id, 'register', [entry]); - return new BrowserAnimation(id, this._renderer); + return new BrowserAnimationFactory(id, this._renderer); } } -export class BrowserAnimation extends Animation { +export class BrowserAnimationFactory extends AnimationFactory { constructor(private _id: string, private _renderer: AnimationRenderer) { super(); } create(element: any, options?: AnimationOptions): AnimationPlayer { diff --git a/packages/platform-browser/animations/src/private_export.ts b/packages/platform-browser/animations/src/private_export.ts index fd5b40e4ab..b37f0e7b95 100644 --- a/packages/platform-browser/animations/src/private_export.ts +++ b/packages/platform-browser/animations/src/private_export.ts @@ -5,5 +5,5 @@ * 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 {BrowserAnimation as ɵBrowserAnimation, BrowserAnimationBuilder as ɵBrowserAnimationBuilder} from './animation_builder'; +export {BrowserAnimationBuilder as ɵBrowserAnimationBuilder, BrowserAnimationFactory as ɵBrowserAnimationFactory} from './animation_builder'; export {AnimationRenderer as ɵAnimationRenderer, AnimationRendererFactory as ɵAnimationRendererFactory} from './animation_renderer'; diff --git a/tools/public_api_guard/animations/animations.d.ts b/tools/public_api_guard/animations/animations.d.ts index b0bae4d58a..d395e86ebf 100644 --- a/tools/public_api_guard/animations/animations.d.ts +++ b/tools/public_api_guard/animations/animations.d.ts @@ -19,11 +19,6 @@ export declare type AnimateTimings = { /** @experimental */ export declare function animation(steps: AnimationMetadata | AnimationMetadata[], options?: AnimationOptions | null): AnimationReferenceMetadata; -/** @experimental */ -export declare abstract class Animation { - abstract create(element: any, options?: AnimationOptions): AnimationPlayer; -} - /** @experimental */ export interface AnimationAnimateChildMetadata extends AnimationMetadata { options: AnimationOptions | null; @@ -43,7 +38,7 @@ export interface AnimationAnimateRefMetadata extends AnimationMetadata { /** @experimental */ export declare abstract class AnimationBuilder { - abstract build(animation: AnimationMetadata | AnimationMetadata[]): Animation; + abstract build(animation: AnimationMetadata | AnimationMetadata[]): AnimationFactory; } /** @experimental */ @@ -56,6 +51,11 @@ export interface AnimationEvent { triggerName: string; } +/** @experimental */ +export declare abstract class AnimationFactory { + abstract create(element: any, options?: AnimationOptions): AnimationPlayer; +} + /** @experimental */ export interface AnimationGroupMetadata extends AnimationMetadata { options: AnimationOptions | null;