Skip to content

Instantly share code, notes, and snippets.

@coagmano
Last active March 8, 2021 04:37
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save coagmano/f63546db3c6867e051d3501a972ba41c to your computer and use it in GitHub Desktop.
Save coagmano/f63546db3c6867e051d3501a972ba41c to your computer and use it in GitHub Desktop.
Blaze animate HOC
{{> UI.ContentBlock }}
import './animate.html';
import { Meteor } from 'meteor/meteor';
import { Template } from 'meteor/templating';
Template.animate.onRendered(function() {
if (this.firstNode.parentNode && this.firstNode.parentNode._uihooks) {
throw new Error(
'The parent of this animate component already has _uihooks set',
this
);
}
const animationElements = this.findAll('.animate');
// HACK: initial animation rendered, as insertElement, doesn't seem to fire
requestAnimationFrame(() => {
[...animationElements].forEach(node => {
node.classList.remove('animate');
});
});
// add the parentNode te the instance, so we can access it in the destroyed function
this.parentNode = this.firstNode.parentNode;
this.parentNode._uihooks = {
insertElement: (node, next) => {
this.parentNode.insertBefore(node, next);
if (node.classList.contains('animate')) {
animationElements.push(node);
// animate
requestAnimationFrame(() => {
node.classList.remove('animate');
});
}
},
removeElement: node => {
const indexOfElement = animationElements.indexOf(node);
if (
document.hasFocus() &&
indexOfElement !== -1 &&
!Meteor.isTest
) {
// remove from animation elements array
const onTransitionEnd = () => {
node.remove();
node.removeEventListener('transitionend', onTransitionEnd);
node = null;
};
animationElements.splice(indexOfElement, 1);
node.addEventListener('transitionend', onTransitionEnd);
node.classList.add('animate');
} else {
// otherwise remove immediately
node.remove();
node = null;
}
},
};
});
/**
The destroyed method, which remove the hooks to make sure, they work again next time.
*/
Template.animate.onDestroyed(function() {
Meteor.defer(() => {
if (this._parentNode) this._parentNode._uihooks = null;
});
});
.todo-list li {
opacity: 1;
transition: opacity 1s;
}
.todo-list li.animate {
opacity: 0
}
<template name="todoList">
<div class="todo-list-container">
<ul class="todo-list">
{{#animate}}
{{#each todo in todos}}
<li class="animate">{{todo.body}}</li>
{{/each}}
{{/animate}}
</ul>
</div>
</template>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment