diff --git a/public/docs/_examples/animations/e2e-spec.ts b/public/docs/_examples/animations/e2e-spec.ts new file mode 100644 index 0000000000..bb64840bf9 --- /dev/null +++ b/public/docs/_examples/animations/e2e-spec.ts @@ -0,0 +1,285 @@ +/// +/** + * The tests here basically just checking that the end styles + * of each animation are in effect. + * + * Relies on the Angular 2 testability only becoming stable once + * animation(s) have finished. + * + * Ideally we'd use https://developer.mozilla.org/en-US/docs/Web/API/Document/getAnimations + * but they're not supported in Chrome at the moment. The upcoming nganimate polyfill + * may also add some introspection support. + */ +describe('Animation Tests', () => { + + const INACTIVE_COLOR = 'rgba(238, 238, 238, 1)'; + const ACTIVE_COLOR = 'rgba(207, 216, 220, 1)'; + const NO_TRANSFORM_MATRIX_REGEX = /matrix\(1,\s*0,\s*0,\s*1,\s*0,\s*0\)/; + + beforeEach(() => { + browser.get(''); + }); + + describe('basic states', () => { + + let host: protractor.ElementFinder; + + beforeEach(() => { + host = element(by.css('hero-list-basic')); + }); + + it('animates between active and inactive', () => { + addHero(); + + let li = host.element(by.css('li')); + + expect(getScaleX(li)).toBe(1.0); + expect(li.getCssValue('backgroundColor')).toBe(INACTIVE_COLOR); + + li.click(); + expect(getScaleX(li)).toBe(1.1); + expect(li.getCssValue('backgroundColor')).toBe(ACTIVE_COLOR); + + li.click(); + expect(getScaleX(li)).toBe(1.0); + expect(li.getCssValue('backgroundColor')).toBe(INACTIVE_COLOR); + }); + + }); + + describe('styles inline in transitions', () => { + + var host: protractor.ElementFinder; + + beforeEach(function() { + host = element(by.css('hero-list-inline-styles')); + }); + + it('are not kept after animation', () => { + addHero(); + + var li = host.element(by.css('li')); + + li.click(); + expect(getScaleX(li)).toBe(1.0); + expect(li.getCssValue('backgroundColor')).toBe(INACTIVE_COLOR); + }); + + }); + + describe('combined transition syntax', () => { + + let host: protractor.ElementFinder; + + beforeEach(() => { + host = element(by.css('hero-list-combined-transitions')); + }); + + it('animates between active and inactive', () => { + addHero(); + + let li = host.element(by.css('li')); + + expect(getScaleX(li)).toBe(1.0); + expect(li.getCssValue('backgroundColor')).toBe(INACTIVE_COLOR); + + li.click(); + expect(getScaleX(li)).toBe(1.1); + expect(li.getCssValue('backgroundColor')).toBe(ACTIVE_COLOR); + + li.click(); + expect(getScaleX(li)).toBe(1.0); + expect(li.getCssValue('backgroundColor')).toBe(INACTIVE_COLOR); + }); + + }); + + describe('two-way transition syntax', () => { + + let host: protractor.ElementFinder; + + beforeEach(() => { + host = element(by.css('hero-list-twoway')); + }); + + it('animates between active and inactive', () => { + addHero(); + + let li = host.element(by.css('li')); + + expect(getScaleX(li)).toBe(1.0); + expect(li.getCssValue('backgroundColor')).toBe(INACTIVE_COLOR); + + li.click(); + expect(getScaleX(li)).toBe(1.1); + expect(li.getCssValue('backgroundColor')).toBe(ACTIVE_COLOR); + + li.click(); + expect(getScaleX(li)).toBe(1.0); + expect(li.getCssValue('backgroundColor')).toBe(INACTIVE_COLOR); + }); + + }); + + describe('enter & leave', () => { + + let host: protractor.ElementFinder; + + beforeEach(() => { + host = element(by.css('hero-list-enter-leave')); + }); + + it('adds and removes element', () => { + addHero(); + + let li = host.element(by.css('li')); + expect(li.getCssValue('transform')).toMatch(NO_TRANSFORM_MATRIX_REGEX); + + removeHero(); + expect(li.isPresent()).toBe(false); + }); + + }); + + describe('enter & leave & states', () => { + + let host: protractor.ElementFinder; + + beforeEach(function() { + host = element(by.css('hero-list-enter-leave-states')); + }); + + it('adds and removes and animates between active and inactive', () => { + addHero(); + + let li = host.element(by.css('li')); + + expect(li.getCssValue('transform')).toMatch(NO_TRANSFORM_MATRIX_REGEX); + + li.click(); + expect(getScaleX(li)).toBe(1.1); + + li.click(); + expect(li.getCssValue('transform')).toMatch(NO_TRANSFORM_MATRIX_REGEX); + + removeHero(); + expect(li.isPresent()).toBe(false); + }); + + }); + + describe('auto style calc', () => { + + let host: protractor.ElementFinder; + + beforeEach(function() { + host = element(by.css('hero-list-auto')); + }); + + it('adds and removes element', () => { + addHero(); + + let li = host.element(by.css('li')); + expect(li.getCssValue('height')).toBe('50px'); + + removeHero(); + expect(li.isPresent()).toBe(false); + }); + + }); + + describe('different timings', () => { + + let host: protractor.ElementFinder; + + beforeEach(() => { + host = element(by.css('hero-list-timings')); + }); + + it('adds and removes element', () => { + addHero(); + + let li = host.element(by.css('li')); + expect(li.getCssValue('transform')).toMatch(NO_TRANSFORM_MATRIX_REGEX); + expect(li.getCssValue('opacity')).toMatch('1'); + + removeHero(); + expect(li.isPresent()).toBe(false); + }); + + }); + + describe('multiple keyframes', () => { + + let host: protractor.ElementFinder; + + beforeEach(() => { + host = element(by.css('hero-list-multistep')); + }); + + it('adds and removes element', () => { + addHero(); + + let li = host.element(by.css('li')); + expect(li.getCssValue('transform')).toMatch(NO_TRANSFORM_MATRIX_REGEX); + expect(li.getCssValue('opacity')).toMatch('1'); + + removeHero(); + expect(li.isPresent()).toBe(false); + }); + + }); + + describe('parallel groups', () => { + + var host: protractor.ElementFinder; + + beforeEach(() => { + host = element(by.css('hero-list-groups')); + }); + + it('adds and removes element', () => { + addHero(); + + let li = host.element(by.css('li')); + expect(li.getCssValue('transform')).toMatch(NO_TRANSFORM_MATRIX_REGEX); + expect(li.getCssValue('opacity')).toMatch('1'); + + removeHero(); + expect(li.isPresent()).toBe(false); + }); + + }); + + function addHero() { + element(by.buttonText('Add hero')).click(); + } + + function removeHero() { + element(by.buttonText('Remove hero')).click(); + } + + function getScaleX(el: protractor.ElementFinder) { + return protractor.promise.all([ + getBoundingClientWidth(el), + getOffsetWidth(el) + ]).then(function([clientWidth, offsetWidth]) { + return clientWidth / offsetWidth; + }); + } + + function getBoundingClientWidth(el: protractor.ElementFinder): protractor.promise.Promise { + return browser.executeScript( + 'return arguments[0].getBoundingClientRect().width', + el.getWebElement() + ); + } + + function getOffsetWidth(el: protractor.ElementFinder): protractor.promise.Promise { + return browser.executeScript( + 'return arguments[0].offsetWidth', + el.getWebElement() + ); + } + +}); diff --git a/public/docs/_examples/animations/ts/.gitignore b/public/docs/_examples/animations/ts/.gitignore new file mode 100644 index 0000000000..2cb7d2a2e9 --- /dev/null +++ b/public/docs/_examples/animations/ts/.gitignore @@ -0,0 +1 @@ +**/*.js diff --git a/public/docs/_examples/animations/ts/README.md b/public/docs/_examples/animations/ts/README.md new file mode 100644 index 0000000000..d734dbc224 --- /dev/null +++ b/public/docs/_examples/animations/ts/README.md @@ -0,0 +1 @@ +This example folder is in a WIP state as Animations are not merged into Angular yet. diff --git a/public/docs/_examples/animations/ts/app/hero-list-auto.component.ts b/public/docs/_examples/animations/ts/app/hero-list-auto.component.ts new file mode 100644 index 0000000000..46358ef4da --- /dev/null +++ b/public/docs/_examples/animations/ts/app/hero-list-auto.component.ts @@ -0,0 +1,46 @@ +import { + Component, + Input, + trigger, + state, + style, + animate, + transition, + group +} from '@angular/core'; +import { Hero, Heroes } from './hero.service'; + +@Component({ + moduleId: module.id, + selector: 'hero-list-auto', + // #docregion template + template: ` +
    +
  • + {{hero.name}} +
  • +
+ `, + // #enddocregion template + styleUrls: ['hero-list.component.css'], + + /* When the element leaves (transition "in => void" occurs), + * get the element's current computed height and animate + * it down to 0. + */ + // #docregion animationdef + animations: [ + trigger('shrinkOut', [ + state('in', style({height: '*'})), + transition('* => void', [ + style({height: '*'}), + animate(250, style({height: 0})) + ]) + ]) + ] + // #enddocregion animationdef +}) +export class HeroListAutoComponent { + @Input() heroes:Heroes; +} diff --git a/public/docs/_examples/animations/ts/app/hero-list-basic.component.ts b/public/docs/_examples/animations/ts/app/hero-list-basic.component.ts new file mode 100644 index 0000000000..00be0bd2a5 --- /dev/null +++ b/public/docs/_examples/animations/ts/app/hero-list-basic.component.ts @@ -0,0 +1,68 @@ +// #docplaster +// #docregion +// #docregion imports +import { + Component, + Input, + trigger, + state, + style, + transition, + animate +} from '@angular/core'; +// #enddocregion imports +import { Hero, Heroes } from './hero.service'; + +@Component({ + moduleId: module.id, + selector: 'hero-list-basic', + // #enddocregion + /* The click event calls hero.toggleState(), which + * causes the state of that hero to switch from + * active to inactive or vice versa. + */ + // #docregion + // #docregion template + template: ` +
    +
  • + {{hero.name}} +
  • +
+ `, + // #enddocregion template + styleUrls: ['hero-list.component.css'], + // #enddocregion + /** + * Define two states, "inactive" and "active", and the end + * styles that apply whenever the element is in those states. + * Then define animations for transitioning between the states, + * one in each direction + */ + // #docregion + // #docregion animationdef + animations: [ + trigger('heroState', [ + // #docregion states + state('inactive', style({ + backgroundColor: '#eee', + transform: 'scale(1)' + })), + state('active', style({ + backgroundColor: '#cfd8dc', + transform: 'scale(1.1)' + })), + // #enddocregion states + // #docregion transitions + transition('inactive => active', animate('100ms ease-in')), + transition('active => inactive', animate('100ms ease-out')) + // #enddocregion transitions + ]) + ] + // #enddocregion animationdef +}) +export class HeroListBasicComponent { + @Input() heroes:Heroes; +} diff --git a/public/docs/_examples/animations/ts/app/hero-list-classes.component.ts b/public/docs/_examples/animations/ts/app/hero-list-classes.component.ts new file mode 100644 index 0000000000..07f35f10b8 --- /dev/null +++ b/public/docs/_examples/animations/ts/app/hero-list-classes.component.ts @@ -0,0 +1,46 @@ +import { + Component, + Input, + trigger, + state, + style, + animate, + transition, + group +} from '@angular/core'; +import { Hero, Heroes } from './hero.service'; + +@Component({ + moduleId: module.id, + selector: 'hero-list-classes', + template: ` +
    +
  • + {{hero.name}} +
  • +
+ `, + styleUrls: ['hero-list.component.css'], + /** + * Define two states, "inactive" and "active", and make it so + * that the styles for those states are pulled in from the + * component stylesheet using CSS classes inactive and active. + * Then define animations for transitioning between the states, + * one in each direction + */ + // #docregion animationdef + animations: [ + trigger('heroState', [ + state('inactive', style('.inactive')), + state('active', style('.active')), + transition('inactive => active', animate(100)), + transition('active => inactive', animate(100)) + ]) + ] + // #enddocregion animationdef +}) +export class HeroListClassesComponent { + @Input() heroes:Heroes; +} diff --git a/public/docs/_examples/animations/ts/app/hero-list-combined-transitions.component.ts b/public/docs/_examples/animations/ts/app/hero-list-combined-transitions.component.ts new file mode 100644 index 0000000000..b6306e4b08 --- /dev/null +++ b/public/docs/_examples/animations/ts/app/hero-list-combined-transitions.component.ts @@ -0,0 +1,57 @@ +// #docregion +// #docregion imports +import { + Component, + Input, + trigger, + state, + style, + transition, + animate +} from '@angular/core'; +// #enddocregion imports +import { Hero, Heroes } from './hero.service'; + +@Component({ + moduleId: module.id, + selector: 'hero-list-combined-transitions', + // #docregion template + template: ` +
    +
  • + {{hero.name}} +
  • +
+ `, + // #enddocregion template + styleUrls: ['hero-list.component.css'], + /* + * Define two states, "inactive" and "active", and the end + * styles that apply whenever the element is in those states. + * Then define an animated transition between these two + * states, in *both* directions. + */ + // #docregion animationdef + animations: [ + trigger('heroState', [ + state('inactive', style({ + backgroundColor: '#eee', + transform: 'scale(1)' + })), + state('active', style({ + backgroundColor: '#cfd8dc', + transform: 'scale(1.1)' + })), + // #docregion transitions + transition('inactive => active, active => inactive', + animate('100ms ease-out')) + // #enddocregion transitions + ]) + ] + // #enddocregion animationdef +}) +export class HeroListCombinedTransitionsComponent { + @Input() heroes:Heroes; +} diff --git a/public/docs/_examples/animations/ts/app/hero-list-enter-leave-states.component.ts b/public/docs/_examples/animations/ts/app/hero-list-enter-leave-states.component.ts new file mode 100644 index 0000000000..9c0b0d6bbb --- /dev/null +++ b/public/docs/_examples/animations/ts/app/hero-list-enter-leave-states.component.ts @@ -0,0 +1,62 @@ +import { + Component, + Input, + trigger, + state, + style, + animate, + transition, + group +} from '@angular/core'; +import { Hero, Heroes } from './hero.service'; + +@Component({ + moduleId: module.id, + selector: 'hero-list-enter-leave-states', + // #docregion template + template: ` +
    +
  • + {{hero.name}} +
  • +
+ `, + // #enddocregion template + styleUrls: ['hero-list.component.css'], + /* The elements here have two possible states based + * on the hero state, "active", or "inactive". We animate + * six transitions: Between the two states in both directions, + * and between each state and void. With this we can animate + * the enter and leave of elements differently based on which + * state they are in when they are added and removed. + */ + // #docregion animationdef + animations: [ + trigger('heroState', [ + state('inactive', style({transform: 'translateX(0) scale(1)'})), + state('active', style({transform: 'translateX(0) scale(1.1)'})), + transition('inactive => active', animate('100ms ease-in')), + transition('active => inactive', animate('100ms ease-out')), + transition('void => inactive', [ + style({transform: 'translateX(-100%) scale(1)'}), + animate(100) + ]), + transition('inactive => void', [ + animate(100, style({transform: 'translateX(100%) scale(1)'})) + ]), + transition('void => active', [ + style({transform: 'translateX(0) scale(0)'}), + animate(200) + ]), + transition('active => void', [ + animate(200, style({transform: 'translateX(0) scale(0)'})) + ]) + ]) + ] + // #enddocregion animationdef +}) +export class HeroListEnterLeaveStatesComponent { + @Input() heroes:Heroes; +} diff --git a/public/docs/_examples/animations/ts/app/hero-list-enter-leave.component.ts b/public/docs/_examples/animations/ts/app/hero-list-enter-leave.component.ts new file mode 100644 index 0000000000..b654764649 --- /dev/null +++ b/public/docs/_examples/animations/ts/app/hero-list-enter-leave.component.ts @@ -0,0 +1,50 @@ +import { + Component, + Input, + trigger, + state, + style, + animate, + transition, + group +} from '@angular/core'; +import { Hero, Heroes } from './hero.service'; + +@Component({ + moduleId: module.id, + selector: 'hero-list-enter-leave', + // #docregion template + template: ` +
    +
  • + {{hero.name}} +
  • +
+ `, + // #enddocregion template + styleUrls: ['hero-list.component.css'], + /* The element here always has the state "in" when it + * is present. We animate two transitions: From void + * to in and from in to void, to achieve an animated + * enter and leave transition. The element enters from + * the left and leaves to the right using translateX. + */ + // #docregion animationdef + animations: [ + trigger('flyInOut', [ + state('in', style({transform: 'translateX(0)'})), + transition('void => *', [ + style({transform: 'translateX(-100%)'}), + animate(100) + ]), + transition('* => void', [ + animate(100, style({transform: 'translateX(100%)'})) + ]) + ]) + ] + // #enddocregion animationdef +}) +export class HeroListEnterLeaveComponent { + @Input() heroes:Heroes; +} diff --git a/public/docs/_examples/animations/ts/app/hero-list-groups.component.ts b/public/docs/_examples/animations/ts/app/hero-list-groups.component.ts new file mode 100644 index 0000000000..e45f7f5d54 --- /dev/null +++ b/public/docs/_examples/animations/ts/app/hero-list-groups.component.ts @@ -0,0 +1,78 @@ +import { + Component, + Input, + trigger, + state, + style, + animate, + transition, + group +} from '@angular/core'; +import { Hero, Heroes } from './hero.service'; + +@Component({ + moduleId: module.id, + selector: 'hero-list-groups', + template: ` +
    +
  • + {{hero.name}} +
  • +
+ `, + styleUrls: ['hero-list.component.css'], + styles: [` + li { + padding: 0 !important; + text-align: center; + } + `], + /* The element here always has the state "in" when it + * is present. We animate two transitions: From void + * to in and from in to void, to achieve an animated + * enter and leave transition. + * + * The transitions have *parallel group* that allow + * animating several properties at the same time but + * with different timing configurations. On enter + * (void => *) we start the opacity animation 0.1s + * earlier than the translation/width animation. + * On leave (* => void) we do the opposite - + * the translation/width animation begins immediately + * and the opacity animation 0.1s later. + */ + // #docregion animationdef + animations: [ + trigger('flyInOut', [ + state('in', style({width: 120, transform: 'translateX(0)', opacity: 1})), + transition('void => *', [ + style({width: 10, transform: 'translateX(50px)', opacity: 0}), + group([ + animate('0.3s 0.1s ease', style({ + transform: 'translateX(0)', + width: 120 + })), + animate('0.3s ease', style({ + opacity: 1 + })) + ]) + ]), + transition('* => void', [ + group([ + animate('0.3s ease', style({ + transform: 'translateX(50px)', + width: 10 + })), + animate('0.3s 0.2s ease', style({ + opacity: 0 + })) + ]) + ]) + ]) + ] + // #enddocregion animationdef +}) +export class HeroListGroupsComponent { + @Input() heroes:Heroes; +} diff --git a/public/docs/_examples/animations/ts/app/hero-list-inline-styles.component.ts b/public/docs/_examples/animations/ts/app/hero-list-inline-styles.component.ts new file mode 100644 index 0000000000..9af374b9a1 --- /dev/null +++ b/public/docs/_examples/animations/ts/app/hero-list-inline-styles.component.ts @@ -0,0 +1,59 @@ +// #docregion +// #docregion imports +import { + Component, + Input, + trigger, + state, + style, + transition, + animate +} from '@angular/core'; +// #enddocregion imports +import { Hero, Heroes } from './hero.service'; + +@Component({ + moduleId: module.id, + selector: 'hero-list-inline-styles', + // #docregion template + template: ` +
    +
  • + {{hero.name}} +
  • +
+ `, + // #enddocregion template + styleUrls: ['hero-list.component.css'], + /** + * Define two states, "inactive" and "active", and the end + * styles that apply whenever the element is in those states. + * Then define an animation for the inactive => active transition. + * This animation has no end styles, but only styles that are + * defined inline inside the transition and thus are only kept + * as long as the animation is running. + */ + // #docregion animationdef + animations: [ + trigger('heroState', [ + // #docregion transitions + transition('inactive => active', [ + style({ + backgroundColor: '#cfd8dc', + transform: 'scale(1.3)' + }), + animate('80ms ease-in', style({ + backgroundColor: '#eee', + transform: 'scale(1)' + })) + ]), + // #enddocregion transitions + ]) + ] + // #enddocregion animationdef +}) +export class HeroListInlineStylesComponent { + @Input() heroes:Heroes; +} diff --git a/public/docs/_examples/animations/ts/app/hero-list-keyframes.component.ts b/public/docs/_examples/animations/ts/app/hero-list-keyframes.component.ts new file mode 100644 index 0000000000..e86b7f6853 --- /dev/null +++ b/public/docs/_examples/animations/ts/app/hero-list-keyframes.component.ts @@ -0,0 +1,63 @@ +import { + Component, + Input, + trigger, + state, + style, + keyframes, + animate, + transition, + group +} from '@angular/core'; +import { Hero, Heroes } from './hero.service'; + +@Component({ + moduleId: module.id, + selector: 'hero-list-keyframes', + template: ` +
    +
  • + {{hero.name}} +
  • +
+ `, + styleUrls: ['hero-list.component.css'], + /* The element here always has the state "in" when it + * is present. We animate two transitions: From void + * to in and from in to void, to achieve an animated + * enter and leave transition. The actual animations + * are defined as CSS keyframes in the component + * stylesheet. They are pulled into the transition + * configuration using the keyframes() function. + */ + // #docregion animationdef + styles: [` + @keyframes flyIn { + 0% { opacity: 0; transform: translateX(-100%); } + 30% { opacity: 1; transform: translateX(15px); } + 100% { opacity: 1; transform: translateX(0); } + } + @keyframes flyOut { + 0% { opacity: 1; transform: translateX(0); } + 70% { opacity: 1; transform: translateX(-15px); } + 100% { opacity: 1; transform: translateX(100%); } + } + `], + animations: [ + trigger('flyInOut', [ + transition('void => *', [ + // Enable when CSS parser integration has been added + // animate(300, keyframes('flyIn')) + ]), + transition('* => void', [ + // Enable when CSS parser integration has been added + // animate(300, keyframes('flyOut')) + ]) + ]) + ] + // #enddocregion animationdef +}) +export class HeroListKeyframesComponent { + @Input() heroes:Heroes; +} diff --git a/public/docs/_examples/animations/ts/app/hero-list-multistep.component.ts b/public/docs/_examples/animations/ts/app/hero-list-multistep.component.ts new file mode 100644 index 0000000000..ced411194e --- /dev/null +++ b/public/docs/_examples/animations/ts/app/hero-list-multistep.component.ts @@ -0,0 +1,57 @@ +import { + Component, + Input, + trigger, + state, + style, + animate, + transition, + group, + keyframes +} from '@angular/core'; +import { Hero, Heroes } from './hero.service'; + +@Component({ + moduleId: module.id, + selector: 'hero-list-multistep', + template: ` +
    +
  • + {{hero.name}} +
  • +
+ `, + styleUrls: ['hero-list.component.css'], + /* The element here always has the state "in" when it + * is present. We animate two transitions: From void + * to in and from in to void, to achieve an animated + * enter and leave transition. Each transition is + * defined in terms of multiple keyframes, to give it + * a bounce effect. + */ + // #docregion animationdef + animations: [ + trigger('flyInOut', [ + state('in', style({transform: 'translateX(0)'})), + transition('void => *', [ + animate(300, keyframes([ + style({opacity: 0, transform: 'translateX(-100%)', offset: 0}), + style({opacity: 1, transform: 'translateX(15px)', offset: 0.3}), + style({opacity: 1, transform: 'translateX(0)', offset: 1.0}) + ])) + ]), + transition('* => void', [ + animate(300, keyframes([ + style({opacity: 1, transform: 'translateX(0)', offset: 0}), + style({opacity: 1, transform: 'translateX(-15px)', offset: 0.7}), + style({opacity: 0, transform: 'translateX(100%)', offset: 1.0}) + ])) + ]) + ]) + ] + // #enddocregion animationdef +}) +export class HeroListMultistepComponent { + @Input() heroes:Heroes; +} diff --git a/public/docs/_examples/animations/ts/app/hero-list-timings.component.ts b/public/docs/_examples/animations/ts/app/hero-list-timings.component.ts new file mode 100644 index 0000000000..58458cc9e6 --- /dev/null +++ b/public/docs/_examples/animations/ts/app/hero-list-timings.component.ts @@ -0,0 +1,57 @@ +import { + Component, + Input, + trigger, + state, + style, + animate, + transition, + group +} from '@angular/core'; +import { Hero, Heroes } from './hero.service'; + +@Component({ + moduleId: module.id, + selector: 'hero-list-timings', + template: ` +
    +
  • + {{hero.name}} +
  • +
+ `, + styleUrls: ['hero-list.component.css'], + /* The element here always has the state "in" when it + * is present. We animate two transitions: From void + * to in and from in to void, to achieve an animated + * enter and leave transition. The element enters from + * the left and leaves to the right using translateX, + * and fades in/out using opacity. We use different easings + * for enter and leave. + */ + // #docregion animationdef + animations: [ + trigger('flyInOut', [ + state('in', style({opacity: 1, transform: 'translateX(0)'})), + transition('void => *', [ + style({ + opacity: 0, + transform: 'translateX(-100%)' + }), + animate('0.2s ease-in') + ]), + transition('* => void', [ + animate('0.2s 10 ease-out', style({ + opacity: 0, + transform: 'translateX(100%)' + })) + ]) + ]) + ] + // #enddocregion animationdef +}) +export class HeroListTimingsComponent { + @Input() heroes:Heroes; +} diff --git a/public/docs/_examples/animations/ts/app/hero-list-twoway.component.ts b/public/docs/_examples/animations/ts/app/hero-list-twoway.component.ts new file mode 100644 index 0000000000..720a20cf07 --- /dev/null +++ b/public/docs/_examples/animations/ts/app/hero-list-twoway.component.ts @@ -0,0 +1,56 @@ +// #docregion +// #docregion imports +import { + Component, + Input, + trigger, + state, + style, + transition, + animate +} from '@angular/core'; +// #enddocregion imports +import { Hero, Heroes } from './hero.service'; + +@Component({ + moduleId: module.id, + selector: 'hero-list-twoway', + // #docregion template + template: ` +
    +
  • + {{hero.name}} +
  • +
+ `, + // #enddocregion template + styleUrls: ['hero-list.component.css'], + /* + * Define two states, "inactive" and "active", and the end + * styles that apply whenever the element is in those states. + * Then define an animated transition between these two + * states, in *both* directions. + */ + // #docregion animationdef + animations: [ + trigger('heroState', [ + state('inactive', style({ + backgroundColor: '#eee', + transform: 'scale(1)' + })), + state('active', style({ + backgroundColor: '#cfd8dc', + transform: 'scale(1.1)' + })), + // #docregion transitions + transition('inactive <=> active', animate('100ms ease-out')) + // #enddocregion transitions + ]) + ] + // #enddocregion animationdef +}) +export class HeroListTwowayComponent { + @Input() heroes:Heroes; +} diff --git a/public/docs/_examples/animations/ts/app/hero-list.component.css b/public/docs/_examples/animations/ts/app/hero-list.component.css new file mode 100644 index 0000000000..b256521e49 --- /dev/null +++ b/public/docs/_examples/animations/ts/app/hero-list.component.css @@ -0,0 +1,27 @@ +ul { + list-style-type: none; + padding: 0; +} + +li { + display: block; + width: 120px; + line-height: 50px; + padding: 0 10px; + box-sizing: border-box; + background-color: #eee; + border-radius: 4px; + margin: 10px; + cursor: pointer; + overflow: hidden; + white-space: nowrap; +} + +.active { + background-color: #cfd8dc; + transform: scale(1.1); +} +.inactive { + background-color: #eee; + transform: scale(1); +} diff --git a/public/docs/_examples/animations/ts/app/hero-team-builder.component.ts b/public/docs/_examples/animations/ts/app/hero-team-builder.component.ts new file mode 100644 index 0000000000..865fa2e5e2 --- /dev/null +++ b/public/docs/_examples/animations/ts/app/hero-team-builder.component.ts @@ -0,0 +1,128 @@ +import { Component } from '@angular/core'; +import { Hero, Heroes } from './hero.service'; +import { HeroListBasicComponent } from './hero-list-basic.component'; +import { HeroListInlineStylesComponent } from './hero-list-inline-styles.component'; +import { HeroListEnterLeaveComponent } from './hero-list-enter-leave.component'; +import { HeroListEnterLeaveStatesComponent } from './hero-list-enter-leave-states.component'; +import { HeroListCombinedTransitionsComponent } from './hero-list-combined-transitions.component'; +import { HeroListTwowayComponent } from './hero-list-twoway.component'; +import { HeroListAutoComponent } from './hero-list-auto.component'; +// Enable when CSS parser integration has been added +// import {HeroListClassesComponent} from './hero-list-classes.component'; +import { HeroListGroupsComponent } from './hero-list-groups.component'; +// Enable when CSS parser integration has been added +// import {HeroListKeyframesComponent} from './hero-list-keyframes.component'; +import { HeroListMultistepComponent } from './hero-list-multistep.component'; +import { HeroListTimingsComponent } from './hero-list-timings.component'; + +@Component({ + selector: 'hero-team-builder', + template: ` +
+ + +
+
+
+

Basic State

+

Switch between active/inactive on click.

+ +
+
+

Styles inline in transitions

+

Animated effect on click, no persistend end styles.

+ +
+
+

Combined transition syntax

+

Switch between active/inactive on click. Define just one transition used in both directions.

+ +
+
+

Two-way transition syntax

+

Switch between active/inactive on click. Define just one transition used in both directions using the <=> syntax.

+ +
+
+

Enter & Leave

+

Enter and leave animations using the void state.

+ +
+
+
+
+

Enter & Leave & States

+

Enter and leave animations combined with active/inactive state animations. Different enter and leave transitions depending on state.

+ +
+
+

Auto Style Calc

+

Leave animation from the current computed height using the auto-style value *.

+ +
+
+

Different Timings

+

Enter and leave animations with different easings, ease-in for enter, ease-out for leave.

+ +
+
+

Multiple Keyframes

+

Enter and leave animations with three keyframes in each, to give the transition some bounce.

+ +
+
+

Parallel Groups

+

Enter and leave animations with multiple properties animated in parallel with different timings.

+ +
+ + +
+ `, + styles: [` + .buttons { + text-align: center; + } + button { + padding: 1.5em 3em; + } + .columns { + display: flex; + flex-direction: row; + } + .column { + flex: 1; + padding: 10px; + } + .column p { + min-height: 6em; + } + `], + directives: [ + HeroListBasicComponent, + HeroListInlineStylesComponent, + HeroListCombinedTransitionsComponent, + HeroListTwowayComponent, + HeroListEnterLeaveComponent, + HeroListEnterLeaveStatesComponent, + HeroListAutoComponent, + HeroListTimingsComponent, + // HeroListClassesComponent, + // HeroListKeyframesComponent, + HeroListMultistepComponent, + HeroListGroupsComponent + ], + providers: [Heroes] +}) +export class HeroTeamBuilderComponent { + constructor(private heroes:Heroes) { } +} diff --git a/public/docs/_examples/animations/ts/app/hero.service.ts b/public/docs/_examples/animations/ts/app/hero.service.ts new file mode 100644 index 0000000000..6712707848 --- /dev/null +++ b/public/docs/_examples/animations/ts/app/hero.service.ts @@ -0,0 +1,54 @@ +import { Injectable } from '@angular/core'; + +export class Hero { + constructor(public name:string, + public state = 'inactive') { + } + + toggleState() { + this.state = (this.state === 'active' ? 'inactive' : 'active'); + } +} + +@Injectable() +export class Heroes implements Iterable { + + currentHeroes: Hero[] = []; + + [Symbol.iterator]() { + return this.currentHeroes.values(); + } + + canAdd() { + return this.currentHeroes.length < ALL_HEROES.length; + } + + canRemove() { + return this.currentHeroes.length > 0; + } + + add() { + this.currentHeroes.push(ALL_HEROES[this.currentHeroes.length]); + } + + remove() { + this.currentHeroes.splice(this.currentHeroes.length - 1, 1); + } + +} + +var ALL_HEROES = [ + 'Wolverine', + 'Magneto', + 'Emma Frost', + 'Thing', + 'Kitty Pryde', + 'Nightcrawler', + 'Juggernaut', + 'Beast', + 'Captain America', + 'Spider-Man', + 'Puck', + 'Alex Wilder', + 'Doctor Strange' +].map(name => new Hero(name)); diff --git a/public/docs/_examples/animations/ts/app/main.ts b/public/docs/_examples/animations/ts/app/main.ts new file mode 100644 index 0000000000..2b1229fd9e --- /dev/null +++ b/public/docs/_examples/animations/ts/app/main.ts @@ -0,0 +1,4 @@ +import { bootstrap } from '@angular/platform-browser-dynamic'; +import { HeroTeamBuilderComponent } from './hero-team-builder.component'; + +bootstrap(HeroTeamBuilderComponent); diff --git a/public/docs/_examples/animations/ts/dist/index.html b/public/docs/_examples/animations/ts/dist/index.html new file mode 100644 index 0000000000..1dee2eb46f --- /dev/null +++ b/public/docs/_examples/animations/ts/dist/index.html @@ -0,0 +1,12 @@ + + + + + + + + + + + + diff --git a/public/docs/_examples/animations/ts/example-config.json b/public/docs/_examples/animations/ts/example-config.json new file mode 100644 index 0000000000..e69de29bb2 diff --git a/public/docs/_examples/animations/ts/index.html b/public/docs/_examples/animations/ts/index.html new file mode 100644 index 0000000000..96c1cf769e --- /dev/null +++ b/public/docs/_examples/animations/ts/index.html @@ -0,0 +1,35 @@ + + + + + Animations + + + + + + + + + + + + + + + + + + + +

External H1 Title for E2E test

+ + +
    +
  • External list for E2E test
  • +
+ + + diff --git a/public/docs/_examples/animations/ts/plnkr.json b/public/docs/_examples/animations/ts/plnkr.json new file mode 100644 index 0000000000..5a4139282b --- /dev/null +++ b/public/docs/_examples/animations/ts/plnkr.json @@ -0,0 +1,7 @@ +{ + "description": "Angular 2 Animations", + "files":[ + "!**/*.d.ts", + "!**/*.js" + ] +} diff --git a/public/docs/_examples/animations/ts/style.css b/public/docs/_examples/animations/ts/style.css new file mode 100644 index 0000000000..e69de29bb2 diff --git a/public/docs/ts/latest/guide/_data.json b/public/docs/ts/latest/guide/_data.json index 1da2728f72..920580882a 100644 --- a/public/docs/ts/latest/guide/_data.json +++ b/public/docs/ts/latest/guide/_data.json @@ -63,6 +63,11 @@ "basics": true }, + "animations": { + "title": "Animations", + "intro": "A guide to Angular's animation system." + }, + "attribute-directives": { "title": "Attribute Directives", "intro": "Attribute directives attach behavior to elements." diff --git a/public/docs/ts/latest/guide/animations.jade b/public/docs/ts/latest/guide/animations.jade new file mode 100644 index 0000000000..efef40378b --- /dev/null +++ b/public/docs/ts/latest/guide/animations.jade @@ -0,0 +1,369 @@ +include ../_util-fns + +:marked + Motion is an important aspect in the design of modern web applications. We want our + user interfaces to have smooth transitions between states, and engaging animations + that call attention where it's needed. Well-designed animations can make a UI not only + more fun but also easier to use. + + Angular's animation system gives us what we need to make the kinds of animations we want. + We can build animations that run with the same kind of native performance that we're used + to with pure CSS animations. But we can also have our animation logic tightly integrated + with the rest of our application code, where they can be easily triggered and controlled. + +.alert.is-helpful + :marked + Angular animations are built on top of the standard [Web Animations API](https://w3c.github.io/web-animations/) + and they run natively on [browsers that support it](http://caniuse.com/#feat=web-animation). + + For other browsers, a polyfill is required. Grab + [`web-animations.min.js` from here](https://github.com/web-animations/web-animations-js) and + add it to your page. + + A more lightweight polyfill maintained by the Angular team is coming soon. + +:marked + # Table of Contents + + * [Quickstart Example: Transitioning Between Two States](#example-transitioning-between-states) + * [States and Transitions](#states-and-transitions) + * [Example: Entering and Leaving](#example-entering-and-leaving) + * [Example: Entering and Leaving from Different States](#example-entering-and-leaving-from-different-states) + * [Animatable Properties and Units](#animatable-properties-and-units) + * [Automatic Property Calculation](#automatic-property-calculation) + * [Animation Timing](#animation-timing) + * [Multi-Step Animations with Keyframes](#multi-step-animations-with-keyframes) + * [Parallel Animation Groups](#parallel-animation-groups) + +.l-sub-section + :marked + The examples referenced in this chapter are available as a [live example](/resources/live-examples/animations/ts/plnkr.html). + +a(id="example-transitioning-between-states") +.l-main-section +:marked + ## Quickstart Example: Transitioning Between Two States +figure + img(src="/resources/images/devguide/animations/animation_basic_click.gif" alt="A simple transition animation" align="right" style="width:220px;margin-left:20px" ) +:marked + Let's build a simple animation that transitions an element between two states + driven by a model attribute. + + Animations are defined inside `@Component` metadata. Before we can add some, we need + to import a few animation-specific functions: + ++makeExample('animations/ts/app/hero-list-basic.component.ts', 'imports')(format=".") + +:marked + With these we can now define an *animation trigger* called `heroState` in the component + metadata. It has animated transitions between two states: `active` and `inactive`. When a + hero is active, we display a the element in slightly larger size and lighter color. + ++makeExample('animations/ts/app/hero-list-basic.component.ts', 'animationdef')(format=".") + +.alert.is-helpful + :marked + In this example we are defining animation styles (color and transform) inline in the + animation metadata. In an upcoming release of Angular, support will be added for pulling + the styles in from the component CSS stylesheet instead. + +:marked + We now have an animation defined but it is not yet used anywhere. We can change that by + attaching it to one or more elements in the component's template using the "`@triggerName`" + syntax: + ++makeExample('animations/ts/app/hero-list-basic.component.ts', 'template')(format=".") + +:marked + Here we've applied the animation trigger to every element repeated by an `ngFor`. Each of + the repeated elements will animate independently. We're binding the value of the + attribute to the expression `hero.state`. We expect it to always be either `inactive` + or `active`, since that's what we have defined animation states for. + + With this setup, an animated transition is shown whenever a hero object changes state! + Here's the full component implementation: + ++makeExample('animations/ts/app/hero-list-basic.component.ts') + +:marked + ## States and Transitions + + Angular animations are defined in terms of logical **states** and **transitions** + between states. + + An animation state is a string value that we define in our application code. In the example + above we used the states `'active'` and `'inactive'` based on the logical state of + hero objects. The source of the state can be a simple object attribute as it was in this case, + or it can be a value computed in a method. The important thing is that we can read it into the + component's template. + + We can define *styles* for each animation state: + ++makeExample('animations/ts/app/hero-list-basic.component.ts', 'states')(format=".") + +:marked + These `state` definitions specify the *end styles* of each state. + They are applied to the element once it has transitioned to that state, and will stay + *as long as it remains in that state*. In that sense, we are defining more than just + animations here. We're actually defining what styles the element has in different states. + + Once we have states, we can define *transitions* between the states. Each transition + controls the timing of switching between one set of styles and the next: + ++makeExample('animations/ts/app/hero-list-basic.component.ts', 'transitions')(format=".") + +figure.image-display + img(src="/resources/images/devguide/animations/ng_animate_transitions_inactive_active.png" alt="In Angular animations we defines states and transitions between states" width="400") + +:marked + If we have the same timing configuration for several transitions, we can combine + them into the same `transition` definition: + ++makeExample('animations/ts/app/hero-list-combined-transitions.component.ts', 'transitions')(format=".") + +:marked + When we have the same timing for both directions of a transition, as we do in the previous + example, we can use the `<=>` shorthand syntax: + ++makeExample('animations/ts/app/hero-list-twoway.component.ts', 'transitions')(format=".") + +:marked + Sometimes we have styles that we want to apply during an animation but not keep around + after it finishes. We can define such styles inline in the `transition`. In this example, + the element receives one set of styles immediately and is then animated to the next. + When the transition finishes, none of these styles will be kept because they're not + defined in a `state`. + ++makeExample('animations/ts/app/hero-list-inline-styles.component.ts', 'transitions')(format=".") + +:marked + ### The wildcard state `*` + + The `*` ("wildcard") state matches *any* animation state. This is useful for defining styles and + transitions that should apply regardless of which state the animation is in. For example: + + * The `active => *` transition applies when the element's state changes from `active` to anything else. + * The `* => *` transition applies when *any* change between two states takes place. + +figure.image-display + img(src="/resources/images/devguide/animations/ng_animate_transitions_inactive_active_wildcards.png" alt="The wildcard state can be used to match many different transitions at once" width="400") + + +:marked + ### The `void` state + + There's one special state called `void` that may apply to any animation. It applies + when the element is *not* attached to a view. This may be because it has not yet been + added or because it has been removed. The `void` state is useful for defining "enter" and + "leave" animations. + + For example the `* => void` transition applies when the element leaves the view, + regardless of what state it was in before it left. + +figure.image-display + img(src="/resources/images/devguide/animations/ng_animate_transitions_void_in.png" alt="The void state can be used for enter and leave transitions" width="400") + +:marked + The wildcard state `*` also matches `void`. + + ## Example: Entering and Leaving +figure + img(src="/resources/images/devguide/animations/animation_enter_leave.gif" alt="Enter and leave animations" align="right" style="width:250px;" ) +:marked + Using the `void` and `*` states we can define transitions that animate the + entering and leaving of elements: + + * Enter: `void => *` + * Leave: `* => void` + ++makeExample('animations/ts/app/hero-list-enter-leave.component.ts', 'animationdef')(format=".") + +:marked + Note that in this case we have the styles applied to the void state directly in the + transition definitions, and not in a separate `state(void)` definition. We do this because + we want the transforms to be different on enter and leave: The element enters from the left + and leaves to the right. + + ## Example: Entering and Leaving from Different States +figure + img(src="/resources/images/devguide/animations/animation_enter_leave_states.gif" alt="Enter and leave animations combined with state animations" align="right" style="width:200px" ) +:marked + We can also combine this animation with the earlier state transition animation by + using the hero state as the animation state. What this will let us do is configure + different transitions for entering and leaving based on what the state of the hero + is: + + * Inactive hero enter: `void => inactive` + * Active hero enter: `void => active` + * Inactive hero leave: `active => void` + * Active hero leave: `inactive => void` + + We now have fine-grained control over each transition: + +figure.image-display + img(src="/resources/images/devguide/animations/ng_animate_transitions_inactive_active_void.png" alt="This example transitions between active, inactive, and void states" width="400") + + ++makeExample('animations/ts/app/hero-list-enter-leave-states.component.ts', 'animationdef')(format=".") + +:marked + ## Animatable Properties and Units + + Since Angular's animation support builds on top of Web Animations, we can animate any property + that the browser considers *animatable*. This includes positions, sizes, transforms, colors, + borders and many others. The W3C maintains + [a list of animatable properties](https://www.w3.org/TR/css3-transitions/#animatable-properties). + + For positional properties that have a numeric value, we can define a unit by providing + the value as a string with the appropriate suffix: + + * `'50px'` + * `'3em'` + * `'100%'` + + For most dimensinal properties we can also just define a number which is then assumed to be + in pixels: + + * `50` is the same as saying `'50px'` + + ## Automatic Property Calculation +figure + img(src="/resources/images/devguide/animations/animation_auto.gif" alt="Animation with automated height calculation" align="right" style="width:220px;margin-left:20px" ) +:marked + Sometimes the value of a dimensional style property that we want to + animate is not known until at runtime. For example, it is quite common for elements + to have widths and heights that depend on their content and the screen size. These + properties are often tricky to animate with CSS. + + With Angular we can use a special `*` property value in these cases. What it means + is that the value of this property will be computed at runtime and then plugged into + the animation. + + The "leave" animation in this example takes whatever height the element has before it + leaves and animates from that height to zero: + ++makeExample('animations/ts/app/hero-list-auto.component.ts', 'animationdef')(format=".") + +// Uncomment when the support is added and example works + :marked + ## Accessing Styles from Component Stylesheets + + In our examples so far we have specified all animated styles right in the + animation metadata. This is usually not what we want to do in anything + but the simplest animations. What we prefer to do instead is define all styles + in [component stylesheets](component-styles.html) and then just pull them into + the animations. + + We can do this simply by referencing the classes from the `style()` metadata + in the animations using the `.class` selector notation: + + +makeExample('animations/ts/src/hero-list-classes.component.ts', 'animationdef')(format=".") + +:marked + ## Animation Timing + + There are three timing properties we can tune for every animated transition: + The duration, the delay, and the easing function. They are all combined into + a single transition *timing string*. + + ### Duration + + The duration controls how long the animation takes to run from start to finish. + We can define a duration in three ways: + + * As a plain number, in milliseconds: `100` + * In a string, as milliseconds: `'100ms'` + * In a string, as seconds: `'0.1s'` + + ### Delay + + The delay controls how long to wait after an animation triggers before the + transition actually begins. We can define one by adding it in the same string + following the duration. It also has the same format options as the duration: + + * Wait for 100ms and then run for 200ms: `'0.2s 100ms'` + + ### Easing + + The [easing function](http://easings.net/) controls how the animation accelerates + and decelerates during its runtime. For example, using an `ease-in` function means + the animation begins relatively slowly but then picks up speed as it progresses. We + can control the easing by adding it as a *third* value in the string after the duration + and the delay (or as the *second* value when there is no delay): + + * Wait for 100ms and then run for 200ms, with easing: `'0.2s 100ms ease-out'` + * Run for 200ms, with easing: `'0.2s ease-in-out'` + +figure + img(src="/resources/images/devguide/animations/animation_timings.gif" alt="Animations with specific timings" align="right" style="width:220px;margin-left:20px" ) +:marked + ### Example + + Here are a couple of custom timings in action. Both "enter" and "leave" last for + 200 milliseconds but they have different easings. The leave begins after a + slight delay: + ++makeExample('animations/ts/app/hero-list-timings.component.ts', 'animationdef')(format=".") + +:marked + ## Multi-Step Animations with Keyframes +figure + img(src="/resources/images/devguide/animations/animation_multistep.gif" alt="Animations with some bounce implemented with keyframes" align="right" style="width:220px;margin-left:20px" ) +:marked + With animation *keyframes* we can go beyond a simple transition between two + sets of styles to a more intricate animation that goes through one or more + intermediate styles in between. + + For each keyframe, we can specify an *offset* that defines at which point + in the animation that keyframe applies. The offset is a number between zero, + which marks the beginning of the animation, and one, which marks the end. + + In this example we add some "bounce" to our enter and leave animations with + keyframes: + ++makeExample('animations/ts/app/hero-list-multistep.component.ts', 'animationdef')(format=".") + +:marked + Note that the offsets are *not* defined in terms of absolute time. They are relative + measures from 0 to 1. The final timeline of the animation will based on the combination + of keyframe offsets, duration, delay, and easing. + + Defining offsets for keyframes is optional. If we omit them, offsets with even + spacing are automatically assigned. For example, three keyframes without predefined + offsets will receive offsets `0`, `0.5`, and `1`. + +// Uncomment when the support is added and example works + :marked + ## Using Stylesheet Keyframes + + Earlier we saw how we can put animation styles into component stylesheets and then + pull them into our animations. The same trick can be applied to keyframes: We can + define the relative timeline of the animation with CSS + [@keyframes](https://developer.mozilla.org/en-US/docs/Web/CSS/@keyframes) + and then reference it from the stylesheets. + + In this example we define the same animations as we had in the previous section, + but this time using CSS keyframes: + + +makeExample('animations/ts/src/hero-list-keyframes.component.ts', 'animationdef')(format=".") + +:marked + ## Parallel Animation Groups +figure + img(src="/resources/images/devguide/animations/animation_groups.gif" alt="Parallel animations with different timings, implemented with groups" align="right" style="width:220px;margin-left:20px" ) +:marked + We've already seen how we can animate multiple style properties at the same time: + Just put all of them into the same `style()` definition! + + But we may also want to configure different *timings* for animations that happen + in parallel. For example, we may want to animate two CSS properties but use a + different easing function for each one. + + For this we can use animation *groups*. In this example we use groups both on + enter and leave so that we can use two different timing configurations. Both + are applied to the same element in parallel, but run independent of each other: + ++makeExample('animations/ts/app/hero-list-groups.component.ts', 'animationdef')(format=".") + +:marked + One group animates the element transform and width. The other animates the opacity. diff --git a/public/resources/images/devguide/animations/animation_auto.gif b/public/resources/images/devguide/animations/animation_auto.gif new file mode 100644 index 0000000000..a1708d9a58 Binary files /dev/null and b/public/resources/images/devguide/animations/animation_auto.gif differ diff --git a/public/resources/images/devguide/animations/animation_basic_click.gif b/public/resources/images/devguide/animations/animation_basic_click.gif new file mode 100644 index 0000000000..6030aebee9 Binary files /dev/null and b/public/resources/images/devguide/animations/animation_basic_click.gif differ diff --git a/public/resources/images/devguide/animations/animation_enter_leave.gif b/public/resources/images/devguide/animations/animation_enter_leave.gif new file mode 100644 index 0000000000..51d539b4fa Binary files /dev/null and b/public/resources/images/devguide/animations/animation_enter_leave.gif differ diff --git a/public/resources/images/devguide/animations/animation_enter_leave_states.gif b/public/resources/images/devguide/animations/animation_enter_leave_states.gif new file mode 100644 index 0000000000..47f5a57958 Binary files /dev/null and b/public/resources/images/devguide/animations/animation_enter_leave_states.gif differ diff --git a/public/resources/images/devguide/animations/animation_groups.gif b/public/resources/images/devguide/animations/animation_groups.gif new file mode 100644 index 0000000000..a0122ca772 Binary files /dev/null and b/public/resources/images/devguide/animations/animation_groups.gif differ diff --git a/public/resources/images/devguide/animations/animation_multistep.gif b/public/resources/images/devguide/animations/animation_multistep.gif new file mode 100644 index 0000000000..0a5876c069 Binary files /dev/null and b/public/resources/images/devguide/animations/animation_multistep.gif differ diff --git a/public/resources/images/devguide/animations/animation_timings.gif b/public/resources/images/devguide/animations/animation_timings.gif new file mode 100644 index 0000000000..fa9fc4eebb Binary files /dev/null and b/public/resources/images/devguide/animations/animation_timings.gif differ diff --git a/public/resources/images/devguide/animations/ng_animate_transitions_inactive_active.png b/public/resources/images/devguide/animations/ng_animate_transitions_inactive_active.png new file mode 100644 index 0000000000..1ab9b14f9d Binary files /dev/null and b/public/resources/images/devguide/animations/ng_animate_transitions_inactive_active.png differ diff --git a/public/resources/images/devguide/animations/ng_animate_transitions_inactive_active_void.png b/public/resources/images/devguide/animations/ng_animate_transitions_inactive_active_void.png new file mode 100644 index 0000000000..6c621e4ab1 Binary files /dev/null and b/public/resources/images/devguide/animations/ng_animate_transitions_inactive_active_void.png differ diff --git a/public/resources/images/devguide/animations/ng_animate_transitions_inactive_active_wildcards.png b/public/resources/images/devguide/animations/ng_animate_transitions_inactive_active_wildcards.png new file mode 100644 index 0000000000..bd2644304b Binary files /dev/null and b/public/resources/images/devguide/animations/ng_animate_transitions_inactive_active_wildcards.png differ diff --git a/public/resources/images/devguide/animations/ng_animate_transitions_void_in.png b/public/resources/images/devguide/animations/ng_animate_transitions_void_in.png new file mode 100644 index 0000000000..723ccfbe49 Binary files /dev/null and b/public/resources/images/devguide/animations/ng_animate_transitions_void_in.png differ