rynex
Version:
A minimalist TypeScript framework for building reactive web applications with no virtual DOM
205 lines • 6.22 kB
JavaScript
/**
* Rynex Animation & Transition Helpers
* Simple, performant animations without external dependencies
*/
import { debugLog, debugWarn } from '../debug.js';
/**
* Transition wrapper - applies CSS transitions to elements
* Usage: transition(element, { duration: 300, easing: 'ease-in-out' })
*/
export function transition(element, config = {}) {
if (!element || !(element instanceof HTMLElement)) {
debugWarn('Animation', 'Invalid element provided to transition');
return element;
}
const { duration = 300, easing = 'ease', delay = 0, onStart, onEnd } = config;
try {
element.style.transition = `all ${duration}ms ${easing} ${delay}ms`;
debugLog('Animation', `Transition applied: ${duration}ms ${easing}`);
if (onStart) {
onStart();
}
if (onEnd) {
element.addEventListener('transitionend', () => onEnd(), { once: true });
}
}
catch (error) {
debugWarn('Animation', 'Error applying transition:', error);
}
return element;
}
/**
* Animate - Web Animations API wrapper
* Usage: animate(element, { keyframes: [{ opacity: 0 }, { opacity: 1 }], duration: 300 })
*/
export function animate(element, config) {
if (!element || !(element instanceof HTMLElement)) {
debugWarn('Animation', 'Invalid element provided to animate');
return null;
}
const { keyframes, duration = 300, easing = 'ease', delay = 0, iterations = 1, direction = 'normal', fill = 'both', onStart, onEnd } = config;
try {
if (onStart) {
onStart();
}
const animation = element.animate(keyframes, {
duration,
easing,
delay,
iterations,
direction,
fill
});
debugLog('Animation', `Animation started: ${duration}ms`);
if (onEnd) {
animation.onfinish = () => onEnd();
}
return animation;
}
catch (error) {
debugWarn('Animation', 'Error creating animation:', error);
return null;
}
}
/**
* Fade transition - fade in/out
* Usage: fade(element, 'in', { duration: 300 })
*/
export function fade(element, direction = 'in', config = {}) {
if (!element || !(element instanceof HTMLElement)) {
debugWarn('Animation', 'Invalid element provided to fade');
return null;
}
const { duration = 300, easing = 'ease', delay = 0, onStart, onEnd } = config;
const currentOpacity = window.getComputedStyle(element).opacity;
let keyframes;
if (direction === 'toggle') {
direction = parseFloat(currentOpacity) > 0.5 ? 'out' : 'in';
}
if (direction === 'in') {
keyframes = [
{ opacity: 0 },
{ opacity: 1 }
];
}
else {
keyframes = [
{ opacity: 1 },
{ opacity: 0 }
];
}
return animate(element, {
keyframes,
duration,
easing,
delay,
onStart,
onEnd
});
}
/**
* Slide transition - slide in/out
* Usage: slide(element, 'down', { duration: 300 })
*/
export function slide(element, direction = 'down', config = {}) {
if (!element || !(element instanceof HTMLElement)) {
debugWarn('Animation', 'Invalid element provided to slide');
return null;
}
const { duration = 300, easing = 'ease', delay = 0, onStart, onEnd } = config;
let keyframes;
switch (direction) {
case 'up':
keyframes = [
{ transform: 'translateY(100%)', opacity: 0 },
{ transform: 'translateY(0)', opacity: 1 }
];
break;
case 'down':
keyframes = [
{ transform: 'translateY(-100%)', opacity: 0 },
{ transform: 'translateY(0)', opacity: 1 }
];
break;
case 'left':
keyframes = [
{ transform: 'translateX(100%)', opacity: 0 },
{ transform: 'translateX(0)', opacity: 1 }
];
break;
case 'right':
keyframes = [
{ transform: 'translateX(-100%)', opacity: 0 },
{ transform: 'translateX(0)', opacity: 1 }
];
break;
}
return animate(element, {
keyframes,
duration,
easing,
delay,
onStart,
onEnd
});
}
/**
* Scale transition - scale in/out
* Usage: scale(element, 'in', { duration: 300 })
*/
export function scale(element, direction = 'in', config = {}) {
if (!element || !(element instanceof HTMLElement)) {
debugWarn('Animation', 'Invalid element provided to scale');
return null;
}
const { duration = 300, easing = 'ease', delay = 0, onStart, onEnd } = config;
const currentTransform = window.getComputedStyle(element).transform;
let keyframes;
if (direction === 'toggle') {
direction = currentTransform !== 'none' && currentTransform.includes('scale') ? 'out' : 'in';
}
if (direction === 'in') {
keyframes = [
{ transform: 'scale(0)', opacity: 0 },
{ transform: 'scale(1)', opacity: 1 }
];
}
else {
keyframes = [
{ transform: 'scale(1)', opacity: 1 },
{ transform: 'scale(0)', opacity: 0 }
];
}
return animate(element, {
keyframes,
duration,
easing,
delay,
onStart,
onEnd
});
}
/**
* Rotate transition - rotate element
* Usage: rotate(element, 360, { duration: 300 })
*/
export function rotate(element, degrees = 360, config = {}) {
if (!element || !(element instanceof HTMLElement)) {
debugWarn('Animation', 'Invalid element provided to rotate');
return null;
}
const { duration = 300, easing = 'ease', delay = 0, onStart, onEnd } = config;
const keyframes = [
{ transform: 'rotate(0deg)' },
{ transform: `rotate(${degrees}deg)` }
];
return animate(element, {
keyframes,
duration,
easing,
delay,
onStart,
onEnd
});
}
//# sourceMappingURL=animations.js.map