Web Animations API #657
Description
This issue supersedes: #70
Enhancement
Summary
In order to provide functional web animations for our widgets should provide a way to specify animations on the vNode
level without needed to expose the underlying HTMLElements
to the user.
Animations should be able to be controlled via changes in widget properties / state and should be removable. Animation effects
should have capability to be provided as functions such that they can access widget properties and meta
to utilise dimensions
in the values provided.
A polyfill will be required for browsers that do not fully support the Web Animations API.
This functionality can be achieved via a mixin which uses meta
to access the underlying HTMLElements
and the afterRender
decorator to find VNodes
with animation
properties.
Animations Interface
interface AnimationProperties {
id: string;
effects: any[];
controls?: AnimationControls;
timing?: AnimationTimingProperties;
}
interface AnimationControls {
play?: boolean;
onFinish?: () => void;
reverse?: boolean;
cancel?: boolean;
finish?: boolean;
playbackRate?: number;
startTime?: number;
currentTime?: number;
}
interface AnimationTimingProperties {
duration?: number;
delay?: number;
direction?: string;
easing?: string;
endDelay?: number;
fill?: string;
iterations?: number;
iterationStart?: number;
}
Example usage
_animateOpen() {
const { size, scroll } = this.meta(Dimensions).get('content');
const dim = this.meta(Dimensions).get('content');
return [
{ height: `${size.height}px` },
{ height: `${scroll.height}px` }
];
}
render() {
const timing = {
duration: 300,
fill: 'forwards',
easing: 'ease-in-out'
};
return v('div', {
key: 'content',
classes: this.classes(css.content),
animate: [ {
id: 'down',
effects: this._animateOpen.bind(this),
timing,
controls: {
play: true
}
}]
}, [ 'Content' ]);
}
Issues
VNode typing
One of the problems presented by this approach in that we are currently unable to type
the properties
of a VNode
based on the mixins that have been applied to it's containing widget. The only way to do this currently is by adding to the underlying VirtualDomProperties
as we do for the Themeable properties, but this is far from ideal.
Possible approaches to this include using a higher order function to wrap around the call to v
, animate(v('div', {}), animationProperties)
or exporting a decorated v
on the widget instance that includes the animation properties in its typings.
Meta get node timing #662
Currently the requireNode
callback in meta fires as soon as the requested node is available. This can happen before parent elements / widgets have had their properties processed and as such any styles applied to them will not yet have impacted the required node. When working with animations and accessing Dimensions via meta this is highly problematic.
We should look into implementing an events system that can allow callers to ensure specific nodes have been processed before dimensions etc are requested.