wotsui-vue-directives
Version:
Vue Directives for WotsUI
153 lines (152 loc) • 5.31 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
const intersection_1 = require("../hooks/intersection");
const baseAnimation = {
delay: 100,
direction: 'normal',
duration: 250,
fillMode: 'both',
iterationCount: 1,
name: 'fade',
timingFunction: 'ease',
};
const baseSettings = {
...intersection_1.intersectionSettings,
target: 'self',
queue: false,
interval: 100,
animations: [{ ...baseAnimation }],
};
function animateOnScroll(el, binding) {
const settings = initSettings(binding);
const observer = new IntersectionObserver(handleIntersection, {
threshold: settings.treshold,
});
intersection_1.setIntersectionClasses(el, settings, false);
bindsMap.set(el, settings);
observer.observe(el);
}
exports.default = animateOnScroll;
function initSettings(binding) {
const settings = { ...baseSettings };
if (binding.modifiers.children)
settings.target = 'children';
if (binding.modifiers.queue)
settings.queue = true;
if (typeof binding.value === 'object' && binding.value.animations) {
Object.assign(settings, binding.value);
settings.animations = getAnimationsObjects(binding.value.animations);
}
else {
settings.animations = getAnimationsObjects(binding.value);
}
return settings;
}
function getAnimationsObjects(value) {
const animationsObjects = [];
if (Array.isArray(value)) {
value.forEach((val) => {
animationsObjects.push(createAnimationObject(val));
});
}
else {
animationsObjects.push(createAnimationObject(value));
}
return animationsObjects;
}
function createAnimationObject(value) {
const animationObject = { ...baseAnimation };
if (typeof value === 'number')
animationObject.duration = value;
if (typeof value === 'object')
Object.assign(animationObject, value);
if (typeof value === 'string')
animationObject.name = value;
return animationObject;
}
function handleIntersection(entries, observer) {
entries.forEach((entry) => {
if (entry.isIntersecting) {
const el = entry.target;
const settings = bindsMap.get(el);
if (!settings) {
observer.unobserve(el);
return;
}
intersection_1.setIntersectionClasses(el, settings, true);
el.dispatchEvent(new CustomEvent('animation-start'));
setAnimations(el, settings);
const estimatedTime = getEstimatedTime(el, settings);
setTimeout(() => {
if (el) {
el.dispatchEvent(new CustomEvent('animation-end'));
}
}, estimatedTime);
bindsMap.delete(el);
observer.unobserve(el);
}
});
}
function setAnimations(el, settings) {
if (settings.target === 'self') {
const animationString = getAnimationString(settings.animations, 0);
el.style.animation = animationString;
}
if (settings.target === 'children') {
const { children } = el;
for (let i = 0; i < children.length; i++) {
const child = children[i];
const delay = settings.queue ? i * +parseTime(settings.interval) : 0;
const animationString = getAnimationString(settings.animations, delay);
child.style.animation = animationString;
}
}
}
function getAnimationString(animationObjects, extraDelay = 0) {
const animations = [];
animationObjects.forEach((aniObj) => {
const aniProps = [];
const delay = +parseTime(aniObj.delay) + +parseTime(extraDelay);
aniProps.push(aniObj.name);
aniProps.push(parseTime(aniObj.duration, true));
aniProps.push(`${delay / 1000}s`);
aniProps.push(aniObj.direction);
aniProps.push(aniObj.fillMode);
aniProps.push(aniObj.iterationCount.toString());
aniProps.push(aniObj.timingFunction);
animations.push(aniProps.join(' '));
});
return animations.join(', ');
}
function getEstimatedTime(el, settings) {
let delay = +parseTime(settings.animations[0].delay);
let duration = +parseTime(settings.animations[0].duration);
for (const animation of settings.animations) {
const _delay = +parseTime(animation.delay);
const _duration = +parseTime(animation.duration);
if (_delay > delay)
delay = _delay;
if (_duration > duration)
duration = _duration;
}
let time = delay + duration;
if (settings.target === 'children' && settings.queue) {
const { length: n } = el.children;
time += +parseTime(settings.interval) * (n - 1);
}
return time;
}
function parseTime(value, toString = false) {
let parsedTime = 0;
if (typeof value === 'number') {
parsedTime = value;
}
if (typeof value === 'string') {
parsedTime = parseFloat(value.replace(/\D/g, '')) * 1000;
}
if (toString) {
return `${parsedTime / 1000}s`;
}
return parsedTime;
}
const bindsMap = new Map();