fix(animations): evaluate substitutions on option param values
This commit is contained in:
parent
022835bab2
commit
e9886d701d
|
@ -199,34 +199,35 @@ export class AnimationTimelineBuilderVisitor implements AstVisitor {
|
||||||
|
|
||||||
visitSequence(ast: SequenceAst, context: AnimationTimelineContext) {
|
visitSequence(ast: SequenceAst, context: AnimationTimelineContext) {
|
||||||
const subContextCount = context.subContextCount;
|
const subContextCount = context.subContextCount;
|
||||||
|
let ctx = context;
|
||||||
const options = ast.options;
|
const options = ast.options;
|
||||||
|
|
||||||
if (options && (options.params || options.delay)) {
|
if (options && (options.params || options.delay)) {
|
||||||
context.createSubContext(options);
|
ctx = context.createSubContext(options);
|
||||||
context.transformIntoNewTimeline();
|
ctx.transformIntoNewTimeline();
|
||||||
|
|
||||||
if (options.delay != null) {
|
if (options.delay != null) {
|
||||||
if (context.previousNode instanceof StyleAst) {
|
if (ctx.previousNode instanceof StyleAst) {
|
||||||
context.currentTimeline.snapshotCurrentStyles();
|
ctx.currentTimeline.snapshotCurrentStyles();
|
||||||
context.previousNode = DEFAULT_NOOP_PREVIOUS_NODE;
|
ctx.previousNode = DEFAULT_NOOP_PREVIOUS_NODE;
|
||||||
}
|
}
|
||||||
|
|
||||||
const delay = resolveTimingValue(options.delay);
|
const delay = resolveTimingValue(options.delay);
|
||||||
context.delayNextStep(delay);
|
ctx.delayNextStep(delay);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ast.steps.length) {
|
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
|
// 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
|
// this means that some animation function within the sequence
|
||||||
// ended up creating a sub timeline (which means the current
|
// ended up creating a sub timeline (which means the current
|
||||||
// timeline cannot overlap with the contents of the sequence)
|
// timeline cannot overlap with the contents of the sequence)
|
||||||
if (context.subContextCount > subContextCount) {
|
if (ctx.subContextCount > subContextCount) {
|
||||||
context.transformIntoNewTimeline();
|
ctx.transformIntoNewTimeline();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -475,7 +476,7 @@ export class AnimationTimelineContext {
|
||||||
|
|
||||||
Object.keys(newParams).forEach(name => {
|
Object.keys(newParams).forEach(name => {
|
||||||
if (!skipIfExists || !paramsToUpdate.hasOwnProperty(name)) {
|
if (!skipIfExists || !paramsToUpdate.hasOwnProperty(name)) {
|
||||||
paramsToUpdate[name] = newParams[name];
|
paramsToUpdate[name] = interpolateParams(newParams[name], paramsToUpdate, this.errors);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -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',
|
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 }}'})])})
|
expect(() => {invokeAnimationSequence(rootElement, [style({color: '{{ color }}'})])})
|
||||||
|
|
Loading…
Reference in New Issue