The following example gives a component multiple animations within its animation
style prop, resulting in an animation
prop that looks something like this:
animation: 3000ms ease 0s infinite normal none running fade-in, 3000ms ease 0s infinite normal none running slide-up, 3000ms ease 0s infinite normal none running fade-out;
The above is essentially three separate animations with all animation properties set, each running infinitely. The animation duration (3000ms
) is dynamic based on the interval
prop passed to the component. It would be easy to make other animation properties dynamic as well.
The createAnimationString()
function generates this string of multiple animations, which is then set on the style
property of the element being returned from the component.
The below example supports multiple start animations (startAnimation
) and end animations (endAnimation
).
Here's what the component would look like in use:
<Carousel
interval={3000}
items={carosuelItems}
startAnimation="fade-in slide-up"
endAnimation="fade-out"
/>
Declare keyframe animations in a global css scope:
@keyframes fade-in {
0% {
opacity: 0;
}
25% {
opacity: 1;
}
}
@keyframes fade-out {
75% {
opacity: 1;
}
100% {
opacity: 0;
}
}
@keyframes slide-up {
0% {
transform: translateY(100%);
}
25% {
transform: translateY(0);
}
}
The below Carousel
component accepts an items
prop that is an array of children. A setInterval()
cycles through these children at the same rate as the animations (using the same interval
).
import { createSignal } from 'solid-js';
interface CarouselProps {
endAnimation?: string;
interval?: number;
items: Array<Children>;
startAnimation?: string;
}
function createAnimationString(startAnimation: string, endAnimation: string, interval: number) {
const baseAnimationString = `${interval}ms ease 0s infinite normal none running `;
let animation = '';
if (startAnimation) {
const animations = startAnimation.split(' ');
for (const a of animations) {
animation += `, ${baseAnimationString}${a}`;
}
}
if (endAnimation) {
const animations = endAnimation.split(' ');
for (const a of animations) {
animation += `, ${baseAnimationString}${a}`;
}
}
return animation.substring(2); // ignore the ", " separator at the front of the string.
}
export default function ({
endAnimation = '',
interval = 5000,
items,
startAnimation = '',
}: CarouselProps) {
const [item, setItem] = createSignal(items[0]);
const arrLength = items.length;
let itemIndex = 0;
const animation = createAnimationString(startAnimation, endAnimation, interval);
setInterval(() => {
if (itemIndex === arrLength - 1) itemIndex = 0;
else itemIndex++;
setItem(items[itemIndex]);
}, interval);
return (
<span style={{ position: 'relative' }}>
<span style={{ animation, position: 'absolute' }}>{item}</span>
</span>
);
}