fix(animations): do not delay style() values before a stagger() runs

Closes #17412
This commit is contained in:
Matias Niemelä 2017-06-14 20:44:51 -07:00
parent f1626574dd
commit 34f3832af9
2 changed files with 81 additions and 5 deletions

View File

@ -409,11 +409,12 @@ export class AnimationTimelineBuilderVisitor implements AstVisitor {
break;
}
const timeline = context.currentTimeline;
if (delay) {
context.currentTimeline.delayNextStep(delay);
timeline.delayNextStep(delay);
}
const startingTime = context.currentTimeline.currentTime;
const startingTime = timeline.currentTime;
ast.animation.visit(this, context);
context.previousNode = ast;
@ -612,10 +613,19 @@ export class TimelineBuilder {
get currentTime() { return this.startTime + this.duration; }
delayNextStep(delay: number) {
if (this.duration == 0) {
this.startTime += delay;
} else {
// in the event that a style() step is placed right before a stagger()
// and that style() step is the very first style() value in the animation
// then we need to make a copy of the keyframe [0, copy, 1] so that the delay
// properly applies the style() values to work with the stagger...
const hasPreStyleStep = this._keyframes.size == 1 && Object.keys(this._pendingStyles).length;
if (this.duration || hasPreStyleStep) {
this.forwardTime(this.currentTime + delay);
if (hasPreStyleStep) {
this.snapshotCurrentStyles();
}
} else {
this.startTime += delay;
}
}

View File

@ -529,6 +529,72 @@ export function main() {
expect(p3.duration).toEqual(4000);
});
it('should properly apply pre styling before a stagger is issued', () => {
@Component({
selector: 'ani-cmp',
template: `
<div [@myAnimation]="exp">
<div *ngFor="let item of items" class="item">
{{ item }}
</div>
</div>
`,
animations: [
trigger(
'myAnimation',
[
transition(
'* => go',
[
query(
':enter',
[
style({opacity: 0}),
stagger(
100,
[
animate(1000, style({opacity: 1})),
]),
]),
]),
]),
]
})
class Cmp {
public exp: any;
public items: any[] = [0, 1, 2, 3, 4];
}
TestBed.configureTestingModule({declarations: [Cmp]});
const engine = TestBed.get(ɵAnimationEngine);
const fixture = TestBed.createComponent(Cmp);
const cmp = fixture.componentInstance;
cmp.exp = 'go';
fixture.detectChanges();
engine.flush();
const players = getLog();
expect(players.length).toEqual(5);
for (let i = 0; i < players.length; i++) {
const player = players[i];
const kf = player.keyframes;
const limit = kf.length - 1;
const staggerDelay = 100 * i;
const duration = 1000 + staggerDelay;
expect(kf[0]).toEqual({opacity: '0', offset: 0});
if (limit > 1) {
const offsetAtStaggerDelay = staggerDelay / duration;
expect(kf[1]).toEqual({opacity: '0', offset: offsetAtStaggerDelay});
}
expect(kf[limit]).toEqual({opacity: '1', offset: 1});
expect(player.duration).toEqual(duration);
}
});
it('should apply a full stagger step delay if the timing data is left undefined', () => {
@Component({
selector: 'ani-cmp',