@mantine/carousel
Version:
Embla based carousel
287 lines (286 loc) • 10.3 kB
JavaScript
"use client";
const require_runtime = require("./_virtual/_rolldown/runtime.cjs");
const require_Carousel_context = require("./Carousel.context.cjs");
const require_Carousel_module = require("./Carousel.module.cjs");
const require_CarouselSlide = require("./CarouselSlide/CarouselSlide.cjs");
const require_CarouselVariables = require("./CarouselVariables/CarouselVariables.cjs");
const require_get_chevron_rotation = require("./get-chevron-rotation.cjs");
let react = require("react");
let embla_carousel_react = require("embla-carousel-react");
embla_carousel_react = require_runtime.__toESM(embla_carousel_react);
let _mantine_core = require("@mantine/core");
let _mantine_hooks = require("@mantine/hooks");
let react_jsx_runtime = require("react/jsx-runtime");
//#region packages/@mantine/carousel/src/Carousel.tsx
const defaultProps = {
controlSize: 26,
controlsOffset: "sm",
slideSize: "100%",
slideGap: 0,
orientation: "horizontal",
includeGapInSize: true,
initialSlide: 0,
withControls: true,
withIndicators: false,
withKeyboardEvents: true,
type: "media"
};
const defaultEmblaOptions = {
align: "center",
loop: false,
slidesToScroll: 1,
dragFree: false,
inViewThreshold: 0,
skipSnaps: false,
containScroll: "trimSnaps"
};
const varsResolver = (0, _mantine_core.createVarsResolver)((_, { height, controlSize, controlsOffset }) => ({ root: {
"--carousel-height": (0, _mantine_core.rem)(height),
"--carousel-control-size": (0, _mantine_core.rem)(controlSize),
"--carousel-controls-offset": (0, _mantine_core.getSpacing)(controlsOffset)
} }));
const Carousel = (0, _mantine_core.factory)((_props) => {
const props = (0, _mantine_core.useProps)("Carousel", defaultProps, _props);
const { classNames, className, style, styles, unstyled, vars, children, getEmblaApi, onNextSlide, onPreviousSlide, onSlideChange, nextControlProps, previousControlProps, controlSize, controlsOffset, slideSize, slideGap, orientation, height, includeGapInSize, draggable, initialSlide, withControls, withIndicators, plugins, nextControlIcon, previousControlIcon, withKeyboardEvents, mod, type, emblaOptions, attributes, getIndicatorProps, id, ...others } = props;
const getStyles = (0, _mantine_core.useStyles)({
name: "Carousel",
classes: require_Carousel_module.default,
props,
className,
style,
classNames,
styles,
unstyled,
attributes,
vars,
varsResolver
});
const _id = (0, _mantine_hooks.useId)(id);
const responsiveClassName = (0, _mantine_core.useRandomClassName)();
const { dir } = (0, _mantine_core.useDirection)();
const [emblaRefElement, embla] = (0, embla_carousel_react.default)({
axis: orientation === "horizontal" ? "x" : "y",
direction: orientation === "horizontal" ? dir : void 0,
startIndex: initialSlide,
...defaultEmblaOptions,
...emblaOptions
}, plugins);
const [selected, setSelected] = (0, react.useState)(0);
const [slidesCount, setSlidesCount] = (0, react.useState)(0);
const handleScroll = (0, react.useCallback)((index) => embla && embla.scrollTo(index), [embla]);
const handleSelect = (0, react.useCallback)(() => {
if (!embla) return;
const slide = embla.selectedScrollSnap();
setSelected(slide);
slide !== selected && onSlideChange?.(slide);
}, [
embla,
setSelected,
onSlideChange,
selected
]);
const handlePrevious = (0, react.useCallback)(() => {
embla?.scrollPrev();
onPreviousSlide?.();
}, [embla]);
const handleNext = (0, react.useCallback)(() => {
embla?.scrollNext();
onNextSlide?.();
}, [embla]);
const handleKeydown = (0, react.useCallback)((event) => {
if (withKeyboardEvents) {
if (event.key === "ArrowRight") {
event.preventDefault();
handleNext();
}
if (event.key === "ArrowLeft") {
event.preventDefault();
handlePrevious();
}
if (event.key === "Home") {
event.preventDefault();
embla?.scrollTo(0);
}
if (event.key === "End") {
event.preventDefault();
embla?.scrollTo(embla.scrollSnapList().length - 1);
}
}
}, [
embla,
handleNext,
handlePrevious
]);
(0, react.useEffect)(() => {
if (embla) {
getEmblaApi?.(embla);
handleSelect();
setSlidesCount(embla.scrollSnapList().length);
embla.on("select", handleSelect);
return () => {
embla.off("select", handleSelect);
};
}
}, [
embla,
emblaOptions?.slidesToScroll,
handleSelect
]);
(0, react.useEffect)(() => {
if (embla) {
embla.reInit();
setSlidesCount(embla.scrollSnapList().length);
setSelected((currentSelected) => (0, _mantine_hooks.clamp)(currentSelected, 0, react.Children.toArray(children).length - 1));
}
}, [react.Children.toArray(children).length, emblaOptions?.slidesToScroll]);
const canScrollPrev = embla?.canScrollPrev() || false;
const canScrollNext = embla?.canScrollNext() || false;
const handleIndicatorKeyDown = (0, react.useCallback)((event, index) => {
const isHorizontal = orientation === "horizontal";
const nextKey = isHorizontal ? "ArrowRight" : "ArrowDown";
const prevKey = isHorizontal ? "ArrowLeft" : "ArrowUp";
if (event.key === nextKey) {
event.preventDefault();
const nextIndex = index < slidesCount - 1 ? index + 1 : 0;
handleScroll(nextIndex);
(event.currentTarget.parentElement?.children[nextIndex])?.focus();
}
if (event.key === prevKey) {
event.preventDefault();
const prevIndex = index > 0 ? index - 1 : slidesCount - 1;
handleScroll(prevIndex);
(event.currentTarget.parentElement?.children[prevIndex])?.focus();
}
if (event.key === "Home") {
event.preventDefault();
handleScroll(0);
(event.currentTarget.parentElement?.children[0])?.focus();
}
if (event.key === "End") {
event.preventDefault();
handleScroll(slidesCount - 1);
(event.currentTarget.parentElement?.children[slidesCount - 1])?.focus();
}
}, [
orientation,
slidesCount,
handleScroll
]);
const indicators = Array(slidesCount).fill(0).map((_, index) => /* @__PURE__ */ (0, react.createElement)(_mantine_core.UnstyledButton, {
...getStyles("indicator"),
key: index,
role: "tab",
"aria-label": `Go to slide ${index + 1}`,
"aria-selected": index === selected,
tabIndex: index === selected ? 0 : -1,
"data-active": index === selected || void 0,
onClick: () => handleScroll(index),
onKeyDown: (event) => handleIndicatorKeyDown(event, index),
"data-orientation": orientation,
onMouseDown: (event) => event.preventDefault(),
...getIndicatorProps?.(index)
}));
return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(require_Carousel_context.CarouselProvider, {
value: {
getStyles,
orientation
},
children: [type === "container" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_CarouselVariables.CarouselContainerVariables, {
...props,
selector: `.${responsiveClassName}`
}) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(require_CarouselVariables.CarouselVariables, {
...props,
selector: `.${responsiveClassName}`
}), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)(_mantine_core.Box, {
role: "region",
"aria-roledescription": "carousel",
...getStyles("root", { className: responsiveClassName }),
...others,
id: _id,
mod: [{
orientation,
"include-gap-in-size": includeGapInSize
}, mod],
onKeyDownCapture: handleKeydown,
children: [
/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.VisuallyHidden, {
role: "status",
"aria-live": "polite",
"aria-atomic": "true",
children: slidesCount > 0 && `Slide ${selected + 1} of ${slidesCount}`
}),
withControls && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
...getStyles("controls"),
"data-orientation": orientation,
children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.UnstyledButton, {
"aria-controls": _id,
"aria-label": "Previous slide",
"aria-disabled": !canScrollPrev,
"data-inactive": !canScrollPrev || void 0,
"data-type": "previous",
tabIndex: canScrollPrev ? 0 : -1,
...previousControlProps,
...getStyles("control", {
className: previousControlProps?.className,
style: previousControlProps?.style
}),
onClick: (event) => {
handlePrevious();
previousControlProps?.onClick?.(event);
},
children: typeof previousControlIcon !== "undefined" ? previousControlIcon : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.AccordionChevron, { style: { transform: `rotate(${require_get_chevron_rotation.getChevronRotation({
dir,
orientation,
direction: "previous"
})}deg)` } })
}), /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.UnstyledButton, {
"aria-controls": _id,
"aria-label": "Next slide",
"aria-disabled": !canScrollNext,
"data-inactive": !canScrollNext || void 0,
"data-type": "next",
tabIndex: canScrollNext ? 0 : -1,
...getStyles("control", {
className: nextControlProps?.className,
style: nextControlProps?.style
}),
...nextControlProps,
onClick: (event) => {
handleNext();
nextControlProps?.onClick?.(event);
},
children: typeof nextControlIcon !== "undefined" ? nextControlIcon : /* @__PURE__ */ (0, react_jsx_runtime.jsx)(_mantine_core.AccordionChevron, { style: { transform: `rotate(${require_get_chevron_rotation.getChevronRotation({
dir,
orientation,
direction: "next"
})}deg)` } })
})]
}),
/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
...getStyles("viewport"),
ref: emblaRefElement,
"data-type": type,
children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
...getStyles("container", { className: responsiveClassName }),
"data-orientation": orientation,
children
})
}),
withIndicators && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
...getStyles("indicators"),
role: "tablist",
"aria-label": "Slides",
"data-orientation": orientation,
children: indicators
})
]
})]
});
});
Carousel.classes = require_Carousel_module.default;
Carousel.varsResolver = varsResolver;
Carousel.displayName = "@mantine/carousel/Carousel";
Carousel.Slide = require_CarouselSlide.CarouselSlide;
//#endregion
exports.Carousel = Carousel;
//# sourceMappingURL=Carousel.cjs.map