diff --git a/packages/animations/browser/src/dsl/animation_timeline_builder.ts b/packages/animations/browser/src/dsl/animation_timeline_builder.ts index 2c29d9e071..dbcc078895 100644 --- a/packages/animations/browser/src/dsl/animation_timeline_builder.ts +++ b/packages/animations/browser/src/dsl/animation_timeline_builder.ts @@ -199,34 +199,35 @@ export class AnimationTimelineBuilderVisitor implements AstVisitor { visitSequence(ast: SequenceAst, context: AnimationTimelineContext) { const subContextCount = context.subContextCount; + let ctx = context; const options = ast.options; if (options && (options.params || options.delay)) { - context.createSubContext(options); - context.transformIntoNewTimeline(); + ctx = context.createSubContext(options); + ctx.transformIntoNewTimeline(); if (options.delay != null) { - if (context.previousNode instanceof StyleAst) { - context.currentTimeline.snapshotCurrentStyles(); - context.previousNode = DEFAULT_NOOP_PREVIOUS_NODE; + if (ctx.previousNode instanceof StyleAst) { + ctx.currentTimeline.snapshotCurrentStyles(); + ctx.previousNode = DEFAULT_NOOP_PREVIOUS_NODE; } const delay = resolveTimingValue(options.delay); - context.delayNextStep(delay); + ctx.delayNextStep(delay); } } if (ast.steps.length) { - ast.steps.forEach(s => s.visit(this, context)); + ast.steps.forEach(s => s.visit(this, ctx)); // this is here just incase the inner steps only contain or end with a style() call - context.currentTimeline.applyStylesToKeyframe(); + ctx.currentTimeline.applyStylesToKeyframe(); // this means that some animation function within the sequence // ended up creating a sub timeline (which means the current // timeline cannot overlap with the contents of the sequence) - if (context.subContextCount > subContextCount) { - context.transformIntoNewTimeline(); + if (ctx.subContextCount > subContextCount) { + ctx.transformIntoNewTimeline(); } } @@ -475,7 +476,7 @@ export class AnimationTimelineContext { Object.keys(newParams).forEach(name => { if (!skipIfExists || !paramsToUpdate.hasOwnProperty(name)) { - paramsToUpdate[name] = newParams[name]; + paramsToUpdate[name] = interpolateParams(newParams[name], paramsToUpdate, this.errors); } }); } diff --git a/packages/animations/browser/test/dsl/animation_spec.ts b/packages/animations/browser/test/dsl/animation_spec.ts index 4387bb3e89..dc40da85a8 100644 --- a/packages/animations/browser/test/dsl/animation_spec.ts +++ b/packages/animations/browser/test/dsl/animation_spec.ts @@ -358,6 +358,56 @@ export function main() { ]); }); + it('should substitute in values that are defined as parameters for inner areas of a sequence', + () => { + const steps = sequence( + [ + sequence( + [ + sequence( + [ + style({height: '{{ x0 }}px'}), + animate(1000, style({height: '{{ x2 }}px'})), + ], + buildParams({x2: '{{ x1 }}3'})), + ], + buildParams({x1: '{{ x0 }}2'})), + ], + buildParams({x0: '1'})); + + const players = invokeAnimationSequence(rootElement, steps); + expect(players.length).toEqual(1); + const [player] = players; + expect(player.keyframes).toEqual([ + {offset: 0, height: '1px'}, {offset: 1, height: '123px'} + ]); + }); + + it('should substitute in values that are defined as parameters for reusable animations', + () => { + const anim = animation([ + style({height: '{{ start }}'}), + animate(1000, style({height: '{{ end }}'})), + ]); + + const steps = sequence( + [ + sequence( + [ + useAnimation(anim, buildParams({start: '{{ a }}', end: '{{ b }}'})), + ], + buildParams({a: '100px', b: '200px'})), + ], + buildParams({a: '0px'})); + + const players = invokeAnimationSequence(rootElement, steps); + expect(players.length).toEqual(1); + const [player] = players; + expect(player.keyframes).toEqual([ + {offset: 0, height: '100px'}, {offset: 1, height: '200px'} + ]); + }); + it('should throw an error when an input variable is not provided when invoked and is not a default value', () => { expect(() => {invokeAnimationSequence(rootElement, [style({color: '{{ color }}'})])})