Skip to content

Instantly share code, notes, and snippets.

@rpivo
Last active April 23, 2022 13:21
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save rpivo/33f937160eeff2a727b9e244ce967453 to your computer and use it in GitHub Desktop.
Save rpivo/33f937160eeff2a727b9e244ce967453 to your computer and use it in GitHub Desktop.
Giving a component multiple animations in solidjs

Giving a component multiple animations in solidjs

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>
  );
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment