inital commit for real
parent
769a79adc0
commit
dc161603af
|
@ -0,0 +1,187 @@
|
|||
import React, { useEffect, useRef, useState } from "react";
|
||||
import { FaChevronLeft, FaChevronRight } from "react-icons/fa";
|
||||
|
||||
/**
|
||||
* A responsive carousel component that displays a list of children in a sliding manner.
|
||||
* It supports various features such as auto-play, pause on hover, navigation buttons, and responsive design.
|
||||
*
|
||||
* @param {ReactNode[]} children - The list of children to be displayed in the carousel.
|
||||
* @param {number} limit - The maximum number of children to be displayed in a single slide.
|
||||
* @param {number} [mdLimit] - The maximum number of children to be displayed in a single slide on medium-sized screens.
|
||||
* @param {number} [smLimit] - The maximum number of children to be displayed in a single slide on small-sized screens.
|
||||
* @param {number} [lgLimit] - The maximum number of children to be displayed in a single slide on large-sized screens.
|
||||
* @param {string} [title] - The title of the carousel.
|
||||
* @param {string} [bgImg] - The background image of the carousel.
|
||||
* @param {number} [autoAdvanceInterval] - The interval at which the carousel auto-advances.
|
||||
* @param {boolean} [pauseOnHover] - Whether the carousel should pause on hover.
|
||||
* @param {boolean} [autoPlay] - Whether the carousel should auto-play.
|
||||
* @param {string} [arrowPosition] - The position of the navigation arrows.
|
||||
* @param {boolean} [showArrows] - Whether to show the navigation arrows.
|
||||
* @param {string} [border] - The border style of the carousel.
|
||||
* @param {boolean} [showNavigation] - Whether to show the navigation buttons.
|
||||
* @param {string} [gap] - The gap between the children.
|
||||
* @param {string} [bg] - The background color of the carousel.
|
||||
* @param {string} [px] - The padding x of the carousel.
|
||||
* @param {string} [py] - The padding y of the carousel.
|
||||
* @return {JSX.Element} The carousel component.
|
||||
*/
|
||||
|
||||
const useInterval = (callback, delay) => {
|
||||
const savedCallback = useRef();
|
||||
|
||||
useEffect(() => {
|
||||
savedCallback.current = callback;
|
||||
}, [callback]);
|
||||
|
||||
useEffect(() => {
|
||||
const tick = () => {
|
||||
savedCallback.current();
|
||||
};
|
||||
|
||||
if (delay !== null) {
|
||||
const id = setInterval(tick, delay);
|
||||
return () => clearInterval(id);
|
||||
}
|
||||
}, [delay]);
|
||||
};
|
||||
|
||||
const ResponsiveCarousel = ({
|
||||
children,
|
||||
limit,
|
||||
mdLimit,
|
||||
smLimit,
|
||||
lgLimit,
|
||||
title,
|
||||
bgImg,
|
||||
autoAdvanceInterval,
|
||||
pauseOnHover,
|
||||
autoPlay,
|
||||
arrowPosition,
|
||||
showArrows,
|
||||
border,
|
||||
showNavigation,
|
||||
gap,
|
||||
bg,
|
||||
px,
|
||||
py,
|
||||
}) => {
|
||||
const [currentSlide, setCurrentSlide] = useState(0);
|
||||
const slideCount = Math.ceil(children.length / limit);
|
||||
const [isPlaying, setIsPlaying] = useState(autoPlay);
|
||||
const [updatedLimit, setUpdatedLimit] = useState(limit);
|
||||
|
||||
useEffect(() => {
|
||||
const updateLimit = () => {
|
||||
if (window.innerWidth >= 1280) {
|
||||
setUpdatedLimit(lgLimit || limit);
|
||||
} else if (window.innerWidth >= 768) {
|
||||
setUpdatedLimit(mdLimit || limit);
|
||||
} else {
|
||||
setUpdatedLimit(smLimit || limit);
|
||||
}
|
||||
};
|
||||
updateLimit();
|
||||
window.addEventListener("resize", updateLimit);
|
||||
return () => window.removeEventListener("resize", updateLimit);
|
||||
}, [limit, mdLimit, smLimit, lgLimit]);
|
||||
|
||||
const chunkedChildren = Array.from({ length: slideCount }, (_, i) =>
|
||||
children.slice(i * updatedLimit, (i + 1) * updatedLimit)
|
||||
);
|
||||
|
||||
// console.log("border: ", border != "none" ? border + "px" : border);
|
||||
const prevSlide = () => {
|
||||
setCurrentSlide((prevSlide) =>
|
||||
prevSlide === 0 ? slideCount - 1 : prevSlide - 1
|
||||
);
|
||||
};
|
||||
|
||||
const nextSlide = () => {
|
||||
setCurrentSlide((prevSlide) =>
|
||||
prevSlide === slideCount - 1 ? 0 : prevSlide + 1
|
||||
);
|
||||
};
|
||||
|
||||
useEffect(() => {
|
||||
if (autoPlay) {
|
||||
const id = setInterval(() => {
|
||||
if (isPlaying) {
|
||||
nextSlide();
|
||||
}
|
||||
}, autoAdvanceInterval);
|
||||
|
||||
return () => clearInterval(id);
|
||||
}
|
||||
}, [autoPlay, autoAdvanceInterval, isPlaying]);
|
||||
|
||||
const handleMouseEnter = () => {
|
||||
if (pauseOnHover) {
|
||||
setIsPlaying(false);
|
||||
}
|
||||
};
|
||||
const RenderButtons = () => {
|
||||
return (
|
||||
<div className="flex justify-center">
|
||||
<button
|
||||
onClick={prevSlide}
|
||||
className="bg-white/40 hover:bg-gray-100 text-gray-dark font-bold py-2 px-2 "
|
||||
>
|
||||
<FaChevronLeft />
|
||||
</button>
|
||||
<button
|
||||
onClick={nextSlide}
|
||||
className="bg-white/40 hover:bg-gray-100 text-gray-dark font-bold py-2 px-2 "
|
||||
>
|
||||
<FaChevronRight />
|
||||
</button>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
const handleMouseLeave = () => {
|
||||
if (pauseOnHover) {
|
||||
setIsPlaying(autoPlay);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<>
|
||||
{title && (
|
||||
<div className={"w-full text-base flex justify-between "}>
|
||||
<div id="title" className="bg-white text-sm uppercase">
|
||||
{title}
|
||||
</div>
|
||||
|
||||
{showArrows && <RenderButtons position="topRight" />}
|
||||
</div>
|
||||
)}
|
||||
<div
|
||||
className={`bg-${bg} px-${px} py-${py} flex border border-${
|
||||
border != "none" ? border + "px" : border
|
||||
} border-gray-200 justify-evenly items-center overflow-hidden w-full relative mx-auto`}
|
||||
onMouseEnter={handleMouseEnter}
|
||||
onMouseLeave={handleMouseLeave}
|
||||
>
|
||||
<div className={`w-full flex justify-evenly gap-${gap}`}>
|
||||
{chunkedChildren.map((chunk, index) => (
|
||||
<div
|
||||
key={index}
|
||||
className={`flex w-full justify-evenly gap-${gap} transition-transform duration-500 ${
|
||||
index !== currentSlide ? "absolute" : ""
|
||||
} ${
|
||||
index === currentSlide
|
||||
? "translate-x-0"
|
||||
: index < currentSlide
|
||||
? "-translate-x-full"
|
||||
: "translate-x-full"
|
||||
}`}
|
||||
>
|
||||
{chunk}
|
||||
</div>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
};
|
||||
export default ResponsiveCarousel;
|
|
@ -0,0 +1,92 @@
|
|||
# ResponsiveCarousel.jsx
|
||||
=========================
|
||||
|
||||
## Overview
|
||||
------------
|
||||
|
||||
ResponsiveCarousel is a flexible and customizable carousel component built with React. It is designed to work seamlessly across various devices and screen sizes, providing a responsive and engaging user experience.
|
||||
|
||||
## Features
|
||||
------------
|
||||
|
||||
* **Responsive Design**: The carousel adapts to different screen sizes and devices, ensuring a consistent and optimal viewing experience.
|
||||
* **Customizable**: Easily customize the carousel's appearance, behavior, and layout to fit your specific needs.
|
||||
* **Touch and Swipe Support**: Supports touch and swipe gestures for navigating through the carousel on mobile devices.
|
||||
* **Keyboard Navigation**: Allows users to navigate through the carousel using their keyboard.
|
||||
* **Auto-Play and Pause**: Automatically plays the carousel and pauses on hover or when the user interacts with it.
|
||||
|
||||
## Props
|
||||
------------
|
||||
|
||||
The following props are available for customizing the ResponsiveCarousel component:
|
||||
|
||||
### Required Props
|
||||
|
||||
* **children**: The content to be displayed within the carousel. This can be a single element or an array of elements.
|
||||
|
||||
### Optional Props
|
||||
|
||||
* **limit**: The maximum number of items to display within the carousel at a given time. Defaults to 3.
|
||||
* **mdLimit**: The maximum number of items to display within the carousel on medium-sized screens. Defaults to 4.
|
||||
* **smLimit**: The maximum number of items to display within the carousel on small-sized screens. Defaults to 2.
|
||||
* **lgLimit**: The maximum number of items to display within the carousel on large-sized screens. Defaults to 5.
|
||||
* **title**: The title of the carousel. Defaults to an empty string.
|
||||
* **bgImg**: The background image of the carousel. Defaults to an empty string.
|
||||
* **autoAdvanceInterval**: The interval at which the carousel automatically advances. Defaults to 3000 milliseconds.
|
||||
* **pauseOnHover**: Whether the carousel should pause when the user hovers over it. Defaults to true.
|
||||
* **autoPlay**: Whether the carousel should automatically play. Defaults to true.
|
||||
* **arrowPosition**: The position of the navigation arrows. Defaults to "center".
|
||||
* **showArrows**: Whether to display the navigation arrows. Defaults to true.
|
||||
* **border**: The border style of the carousel. Defaults to "solid 1px #ccc".
|
||||
* **showNavigation**: Whether to display the navigation buttons. Defaults to true.
|
||||
* **gap**: The gap between items within the carousel. Defaults to "10px".
|
||||
* **bg**: The background color of the carousel. Defaults to "#fff".
|
||||
* **px**: The padding x of the carousel. Defaults to "20px".
|
||||
* **py**: The padding y of the carousel. Defaults to "10px".
|
||||
|
||||
## Usage
|
||||
-----
|
||||
|
||||
To use the ResponsiveCarousel component, simply import it into your React application and pass in the required props.
|
||||
|
||||
```jsx
|
||||
import React from 'react';
|
||||
import ResponsiveCarousel from './ResponsiveCarousel';
|
||||
|
||||
const MyComponent = () => {
|
||||
const carouselChildren = [
|
||||
<div key={1}>Child 1</div>,
|
||||
<div key={2}>Child 2</div>,
|
||||
<div key={3}>Child 3</div>,
|
||||
<div key={4}>Child 4</div>,
|
||||
<div key={5}>Child 5</div>,
|
||||
<div key={6}>Child 6</div>,
|
||||
];
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ResponsiveCarousel
|
||||
children={carouselChildren}
|
||||
limit={3}
|
||||
mdLimit={4}
|
||||
smLimit={2}
|
||||
lgLimit={5}
|
||||
title="My Carousel"
|
||||
bgImg="https://example.com/background.jpg"
|
||||
autoAdvanceInterval={3000}
|
||||
pauseOnHover={true}
|
||||
autoPlay={true}
|
||||
arrowPosition="center"
|
||||
showArrows={true}
|
||||
border="solid 1px #ccc"
|
||||
showNavigation={true}
|
||||
gap="10px"
|
||||
bg="#fff"
|
||||
px="20px"
|
||||
py="10px"
|
||||
/>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default MyComponent;
|
|
@ -0,0 +1,54 @@
|
|||
{
|
||||
"name": "re-comp-lib",
|
||||
"version": "1.0.0",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "re-comp-lib",
|
||||
"version": "1.0.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"react-icons": "^5.3.0"
|
||||
}
|
||||
},
|
||||
"node_modules/js-tokens": {
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
|
||||
"integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==",
|
||||
"peer": true
|
||||
},
|
||||
"node_modules/loose-envify": {
|
||||
"version": "1.4.0",
|
||||
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
|
||||
"integrity": "sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"js-tokens": "^3.0.0 || ^4.0.0"
|
||||
},
|
||||
"bin": {
|
||||
"loose-envify": "cli.js"
|
||||
}
|
||||
},
|
||||
"node_modules/react": {
|
||||
"version": "18.3.1",
|
||||
"resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz",
|
||||
"integrity": "sha512-wS+hAgJShR0KhEvPJArfuPVN1+Hz1t0Y6n5jLrGQbkb4urgPE/0Rve+1kMB1v/oWgHgm4WIcV+i7F2pTVj+2iQ==",
|
||||
"peer": true,
|
||||
"dependencies": {
|
||||
"loose-envify": "^1.1.0"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=0.10.0"
|
||||
}
|
||||
},
|
||||
"node_modules/react-icons": {
|
||||
"version": "5.3.0",
|
||||
"resolved": "https://registry.npmjs.org/react-icons/-/react-icons-5.3.0.tgz",
|
||||
"integrity": "sha512-DnUk8aFbTyQPSkCfF8dbX6kQjXA9DktMeJqfjrg6cK9vwQVMxmcA3BfP4QoiztVmEHtwlTgLFsPuH2NskKT6eg==",
|
||||
"peerDependencies": {
|
||||
"react": "*"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,18 @@
|
|||
{
|
||||
"name": "re-comp-lib",
|
||||
"version": "1.0.0",
|
||||
"description": "A lib of react components",
|
||||
"main": "null",
|
||||
"scripts": {
|
||||
"test": "vitest"
|
||||
},
|
||||
"keywords": [
|
||||
"components",
|
||||
"lib"
|
||||
],
|
||||
"author": "Jeremy Hayes",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"react-icons": "^5.3.0"
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue