JSFiddle - React, Tailwind, and code Playground

by mariomc

HTML

<body>
  <div class="outer-container">
    <div class="container">
    </div>
  </div>


  <p>
    <button class="prev-button">Prev</button>
    <button class="next-button">Next</button>
  </p>
</body>

CSS

.outer-container {
  width: 100vw;
  margin: 0 auto;
}

.container {
 /* Container is not 100% just for debug/visualization purposes */
  width: 50%;
  margin: 0 auto;
  height: 200px;
  position: relative;
}

.slide {
  height: 100%;
  font-size: 5rem;
  position: absolute;
  inset: 0;
  background-color: white;
  outline: 1px solid red;
  align-items: center;
  justify-content: center;
  display: flex;
}

.animating {
  background: green;
}

.active {
  z-index: 1;
  transform: translate3d(0, 0, 0);
}

.prev {
  z-index: 2;
  transform: translate3d(-100%, 0, 0);
}

.next {
  z-index: 2;
  transform: translate3d(100%, 0, 0);
}

JavaScript

const NEXT = 'next';
const PREV = 'prev';
const ACTIVE = 'active';
const ANIMATION_DURATION = 5000;
const container = document.querySelector('.container');

const removeAllStateClasses = ({
  active,
  next
}) => {
  active.classList.remove(ACTIVE);
  next.classList.remove(NEXT, PREV);
}

const addAllStateClasses = ({
  active,
}) => {
  active.classList.add(ACTIVE);
}

const buildSlides = (number) => {
  const slides = Array(number).fill(0);
  const slidesHTML = slides.map((slide, index) => `<div class="slide">${index +1}</div>`).join("");
  container.innerHTML = slidesHTML;
  const all = Array.from(container.querySelectorAll('.slide'));
  const [active] = all;
  addAllStateClasses(active);
  return { active, first: all.at(0), last: all.at(-1) };
}

const { first, last, all, ...rest } = buildSlides(4);

let state = {
	active,
  direction: NEXT,
  animation: null,
};

addAllStateClasses({
  active
});

const setState = (newState) => {
  state = {
    ...state,
    ...newState
  };
}

const animationStart = (oldState, newState, animation) => {
  const direction = newState.direction;
  setState({
    animation
  });
  oldState.next.classList.remove('prev', 'next');
  newState.next.classList.add(direction);
  newState.active.classList.add('animating');
}

const animationEnd = (oldState, newState) => {
  newState.active.classList.remove('animating');
  removeAllStateClasses(oldState);
  addAllStateClasses(newState);

  setState({
    ...newState,
    animation: null
  });
};


const selectActive = (state, direction) => {
  if (direction === NEXT) return state.active.nextElementSibling || first;
  return state.active.previousElementSibling || last;
}

const move = (previousState, direction = NEXT) => {
  // Represents the next slide in the current direction
  const active = selectActive(previousState, direction);
  const newState = {
    active, 
    next,
    direction,
  };
  return newState;
}

const transitionState = async (oldState, newState) => {
  const...