@codeworker.br/govbr-tw-react
Version:
Biblioteca de componentes React usando Tailwind CSS que implementa o Padrão Digital de Governo.
84 lines (83 loc) • 7.05 kB
JavaScript
var __rest = (this && this.__rest) || function (s, e) {
var t = {};
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p) && e.indexOf(p) < 0)
t[p] = s[p];
if (s != null && typeof Object.getOwnPropertySymbols === "function")
for (var i = 0, p = Object.getOwnPropertySymbols(s); i < p.length; i++) {
if (e.indexOf(p[i]) < 0 && Object.prototype.propertyIsEnumerable.call(s, p[i]))
t[p[i]] = s[p[i]];
}
return t;
};
import { jsxs as _jsxs, jsx as _jsx } from "react/jsx-runtime";
import { Children, useEffect, useMemo, useState, } from "react";
import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
import { faChevronLeft, faChevronRight } from "@fortawesome/free-solid-svg-icons";
import BASE_CLASSNAMES from "../../config/baseClassNames";
import { cn } from "../../libs/utils";
import { Button } from "../Button";
import { carouselSliderVariants, navigationButtonVariants } from "./variants";
const chunkChildren = (children, size) => {
const chunkSize = Math.max(1, Math.floor(size));
if (chunkSize === 1) {
return children.map((child) => [child]);
}
const chunks = [];
for (let index = 0; index < children.length; index += chunkSize) {
chunks.push(children.slice(index, index + chunkSize));
}
return chunks;
};
export const CarouselSlider = (_a) => {
var { className, children, itemsPerView = 1, loop = false, showIndicators = true, floatingControls = true, variant = "light", density = "comfortable", border = true } = _a, props = __rest(_a, ["className", "children", "itemsPerView", "loop", "showIndicators", "floatingControls", "variant", "density", "border"]);
const childrenArray = useMemo(() => Children.toArray(children), [children]);
const safeItemsPerView = useMemo(() => {
const totalItems = Math.max(childrenArray.length, 1);
const desired = Math.floor(itemsPerView !== null && itemsPerView !== void 0 ? itemsPerView : 1);
if (!Number.isFinite(desired) || desired <= 0)
return 1;
return Math.min(desired, totalItems);
}, [childrenArray.length, itemsPerView]);
const slides = useMemo(() => chunkChildren(childrenArray, safeItemsPerView), [childrenArray, safeItemsPerView]);
const [currentSlide, setCurrentSlide] = useState(0);
const totalSlides = slides.length || 1;
const canGoPrev = loop || currentSlide > 0;
const canGoNext = loop || currentSlide < totalSlides - 1;
useEffect(() => {
setCurrentSlide((previous) => Math.min(previous, totalSlides - 1));
}, [totalSlides]);
const goPrev = () => {
if (!totalSlides)
return;
if (currentSlide === 0) {
if (loop) {
setCurrentSlide(totalSlides - 1);
}
return;
}
setCurrentSlide((value) => Math.max(0, value - 1));
};
const goNext = () => {
if (!totalSlides)
return;
if (currentSlide === totalSlides - 1) {
if (loop) {
setCurrentSlide(0);
}
return;
}
setCurrentSlide((value) => Math.min(totalSlides - 1, value + 1));
};
return (_jsxs("div", Object.assign({ className: cn(carouselSliderVariants({ variant, density }), BASE_CLASSNAMES.carouselSlider.root, border ? "" : "!border-none !rounded-none", className) }, props, { children: [_jsxs("div", { className: "flex items-center justify-between", children: [_jsxs("span", { className: "text-xs font-normal uppercase tracking-wide ml-3", children: [currentSlide + 1, " / ", totalSlides] }), _jsxs("div", { className: "flex items-center gap-2", children: [_jsx(Button, { size: "icon", density: density === "compact" ? "high" : "default", variant: variant === "dark" ? "ghost-dark" : "ghost", onClick: goPrev, disabled: !canGoPrev, "aria-label": "Slide anterior", children: _jsx(FontAwesomeIcon, { icon: faChevronLeft }) }), _jsx(Button, { size: "icon", density: density === "compact" ? "high" : "default", variant: variant === "dark" ? "ghost-dark" : "ghost", onClick: goNext, disabled: !canGoNext, "aria-label": "Proximo slide", children: _jsx(FontAwesomeIcon, { icon: faChevronRight }) })] })] }), _jsxs("div", { className: "relative", children: [_jsx("div", { className: cn("group/viewport overflow-hidden rounded-xl", BASE_CLASSNAMES.carouselSlider.viewport), children: _jsx("div", { className: cn("flex w-full transition-transform duration-500 ease-in-out"), style: { transform: `translateX(-${currentSlide * 100}%)` }, role: "list", "aria-live": "polite", children: slides.map((group, slideIndex) => (_jsx("div", { className: cn("w-full flex-shrink-0 px-1", BASE_CLASSNAMES.carouselSlider.slide), role: "group", "aria-roledescription": "slide", "aria-label": `Slide ${slideIndex + 1} de ${totalSlides}`, children: _jsx("div", { className: "grid gap-4", style: {
gridTemplateColumns: `repeat(${Math.min(safeItemsPerView, group.length)}, minmax(0, 1fr))`,
}, children: group.map((item, itemIndex) => {
return (_jsx("div", { className: cn("h-full transition"), children: item }, `carousel-slider-item-${slideIndex}-${itemIndex}`));
}) }) }, `carousel-slider-${slideIndex}`))) }) }), _jsx(Button, { size: "icon", density: density === "compact" ? "high" : "default", variant: variant === "dark" ? "ghost-dark" : "ghost", onClick: goPrev, disabled: !canGoPrev, "aria-label": "Slide anterior", className: cn("-left-3 hidden opacity-0 transition group-hover/viewport:flex group-hover/viewport:opacity-100", navigationButtonVariants({ floating: floatingControls })), children: _jsx(FontAwesomeIcon, { icon: faChevronLeft }) }), _jsx(Button, { size: "icon", density: density === "compact" ? "high" : "default", variant: variant === "dark" ? "ghost-dark" : "ghost", onClick: goNext, disabled: !canGoNext, "aria-label": "Proximo slide", className: cn("-right-3 hidden opacity-0 transition group-hover/viewport:flex group-hover/viewport:opacity-100", navigationButtonVariants({ floating: floatingControls })), children: _jsx(FontAwesomeIcon, { icon: faChevronRight }) })] }), showIndicators && totalSlides > 1 && (_jsx("div", { className: cn("flex items-center justify-center gap-2", BASE_CLASSNAMES.carouselSlider.dots), children: slides.map((_, slideIndex) => (_jsx("button", { type: "button", className: cn("h-2 w-2 rounded-full transition", slideIndex === currentSlide
? variant === "dark"
? "bg-govbr-pure-0"
: "bg-govbr-blue-warm-vivid-70"
: variant === "dark"
? "bg-govbr-blue-warm-20/40"
: "bg-govbr-blue-warm-vivid-70/40"), onClick: () => setCurrentSlide(slideIndex), "aria-label": `Ir para o slide ${slideIndex + 1}` }, `indicator-${slideIndex}`))) }))] })));
};
export default CarouselSlider;