Skip to content

Potential improvements for the Carousel #4

@L1lith

Description

@L1lith

Just a few ideas for the carousel, I wrote my own custom carousel and I wouldn't mind if you co-opted some of the ideas or implementation details into your library. It's not perfect or anything but here are some ideas

  1. You don't need a dedicated CDBCarouselItem component if you just automatically parse the children as CarouselItems by default (unless say they are a CBDCarouselInner or something like that, you can do this automatically)
  2. Add support to customize the forward and back buttons (I've done a small implementation of this here)

I apologize if it's a little messy, it's a component from a project i had to implement myself because I couldn't find any carousel components I liked on NPM.

import React, { useState } from "react";
import "./carousel.scss";
import hasChildren from "../functions/hasChildren";

export function Carousel(props) {
  // Declare a new state variable, which we'll call "count"
  const [index, setIndex] = useState(0);
  let rotateInterval = null;
  const interval = props.hasOwnProperty("interval")
    ? props.interval
    : 30 * 1000;
  const children = (
    !Array.isArray(props.children) ? [props.children] : props.children
  ).filter(
    (child) =>
      child /* exclude null and undefined and other non-truthy values */
  );
  const goNext = (skipInterval = false) => {
    setIndex(getIndexWrapping(index + 1, children.length));
    if (!skipInterval) setChangeInterval();
  };
  const goBack = () => {
    setIndex(getIndexWrapping(index - 1, children.length));
    setChangeInterval();
  };
  const setChangeInterval = () => {
    if (rotateInterval !== null) {
      clearInterval(rotateInterval);
      //rotateInterval = null; // redundant as it already gets reassigned
    }
    rotateInterval = setInterval(() => {
      console.log("called");
      goNext(true);
    }, interval);
  };
  if (Number.isFinite(interval)) setChangeInterval(interval);
  if (children.length < 1) throw new Error("Expected at least 1 child");
  const buttons = [];
  for (let i = 0; i < children.length; i++) {
    const child = children[i];
    if (child.type === Next) {
      children.splice(i, 1);
      i--;
      buttons.push(
        React.cloneElement(child, {
          goNext,
          key: buttons.length + 1,
        })
      );
    } else if (child.type === Back) {
      children.splice(i, 1);
      i--;
      buttons.push(
        React.cloneElement(child, {
          goBack,
          key: buttons.length + 1,
        })
      );
    }
  }
  return (
    <div className="carousel">
      <span className="content">{children[index]}</span>
      <span className="controls">{buttons}</span>
    </div>
  );
}

function getIndexWrapping(newIndex, total) {
  if (!isFinite(total) || total < 1) throw new Error("Invalid Total");
  while (newIndex < 0) {
    newIndex += total;
  }
  newIndex = newIndex % total;
  return newIndex;
}

export function Next(props) {
  const componentProps = { ...props };
  delete componentProps.children;
  delete componentProps.goNext;
  if (componentProps.hasOwnProperty("className")) {
    componentProps.className =
      typeof componentProps.className == "string"
        ? "next " + componentProps.className
        : "next";
  } else {
    componentProps.className = "next";
  }
  return (
    <button onClick={props.goNext} {...componentProps}>
      {hasChildren(props.children) ? props.children : Next}
    </button>
  );
}

export function Back(props) {
  const componentProps = { ...props };
  delete componentProps.children;
  delete componentProps.goBack;
  if (componentProps.hasOwnProperty("className")) {
    componentProps.className =
      typeof componentProps.className == "string"
        ? "back " + componentProps.className
        : "back";
  } else {
    componentProps.className = "back";
  }
  return (
    <button onClick={props.goBack} {...componentProps}>
      {hasChildren(props.children) ? props.children : Back}
    </button>
  );
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions