@mantine/carousel
Version:
Embla based carousel
273 lines (267 loc) • 8.9 kB
JavaScript
'use client';
;
var jsxRuntime = require('react/jsx-runtime');
var react = require('react');
var useEmblaCarousel = require('embla-carousel-react');
var core = require('@mantine/core');
var hooks = require('@mantine/hooks');
var Carousel_context = require('./Carousel.context.cjs');
var Carousel_module = require('./Carousel.module.css.cjs');
var CarouselSlide = require('./CarouselSlide/CarouselSlide.cjs');
var CarouselVariables = require('./CarouselVariables/CarouselVariables.cjs');
var getChevronRotation = require('./get-chevron-rotation.cjs');
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
var useEmblaCarousel__default = /*#__PURE__*/_interopDefault(useEmblaCarousel);
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 = core.createVarsResolver(
(_, { height, controlSize, controlsOffset }) => ({
root: {
"--carousel-height": core.rem(height),
"--carousel-control-size": core.rem(controlSize),
"--carousel-controls-offset": core.getSpacing(controlsOffset)
}
})
);
const Carousel = core.factory((_props, ref) => {
const props = 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,
...others
} = props;
const getStyles = core.useStyles({
name: "Carousel",
classes: Carousel_module,
props,
className,
style,
classNames,
styles,
unstyled,
attributes,
vars,
varsResolver
});
const responsiveClassName = core.useRandomClassName();
const { dir } = core.useDirection();
const [emblaRefElement, embla] = useEmblaCarousel__default.default(
{
axis: orientation === "horizontal" ? "x" : "y",
direction: orientation === "horizontal" ? dir : void 0,
startIndex: initialSlide,
...defaultEmblaOptions,
...emblaOptions
},
plugins
);
const [selected, setSelected] = react.useState(0);
const [slidesCount, setSlidesCount] = react.useState(0);
const handleScroll = react.useCallback((index) => embla && embla.scrollTo(index), [embla]);
const handleSelect = react.useCallback(() => {
if (!embla) {
return;
}
const slide = embla.selectedScrollSnap();
setSelected(slide);
slide !== selected && onSlideChange?.(slide);
}, [embla, setSelected, onSlideChange, selected]);
const handlePrevious = react.useCallback(() => {
embla?.scrollPrev();
onPreviousSlide?.();
}, [embla]);
const handleNext = react.useCallback(() => {
embla?.scrollNext();
onNextSlide?.();
}, [embla]);
const handleKeydown = react.useCallback(
(event) => {
if (withKeyboardEvents) {
if (event.key === "ArrowRight") {
event.preventDefault();
handleNext();
}
if (event.key === "ArrowLeft") {
event.preventDefault();
handlePrevious();
}
}
},
[embla]
);
react.useEffect(() => {
if (embla) {
getEmblaApi?.(embla);
handleSelect();
setSlidesCount(embla.scrollSnapList().length);
embla.on("select", handleSelect);
return () => {
embla.off("select", handleSelect);
};
}
return void 0;
}, [embla, emblaOptions?.slidesToScroll, handleSelect]);
react.useEffect(() => {
if (embla) {
embla.reInit();
setSlidesCount(embla.scrollSnapList().length);
setSelected(
(currentSelected) => 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 indicators = Array(slidesCount).fill(0).map((_, index) => /* @__PURE__ */ react.createElement(
core.UnstyledButton,
{
...getStyles("indicator"),
key: index,
"data-active": index === selected || void 0,
"aria-hidden": true,
tabIndex: -1,
onClick: () => handleScroll(index),
"data-orientation": orientation,
onMouseDown: (event) => event.preventDefault()
}
));
return /* @__PURE__ */ jsxRuntime.jsxs(Carousel_context.CarouselProvider, { value: { getStyles, orientation }, children: [
type === "container" ? /* @__PURE__ */ jsxRuntime.jsx(CarouselVariables.CarouselContainerVariables, { ...props, selector: `.${responsiveClassName}` }) : /* @__PURE__ */ jsxRuntime.jsx(CarouselVariables.CarouselVariables, { ...props, selector: `.${responsiveClassName}` }),
/* @__PURE__ */ jsxRuntime.jsxs(
core.Box,
{
ref,
...getStyles("root", { className: "responsiveClassName" }),
...others,
mod: [{ orientation, "include-gap-in-size": includeGapInSize }, mod],
onKeyDownCapture: handleKeydown,
children: [
withControls && /* @__PURE__ */ jsxRuntime.jsxs("div", { ...getStyles("controls"), "data-orientation": orientation, children: [
/* @__PURE__ */ jsxRuntime.jsx(
core.UnstyledButton,
{
...previousControlProps,
...getStyles("control", {
className: previousControlProps?.className,
style: previousControlProps?.style
}),
onClick: (event) => {
handlePrevious();
previousControlProps?.onClick?.(event);
},
"data-inactive": !canScrollPrev || void 0,
"data-type": "previous",
tabIndex: canScrollPrev ? 0 : -1,
children: typeof previousControlIcon !== "undefined" ? previousControlIcon : /* @__PURE__ */ jsxRuntime.jsx(
core.AccordionChevron,
{
style: {
transform: `rotate(${getChevronRotation.getChevronRotation({
dir,
orientation,
direction: "previous"
})}deg)`
}
}
)
}
),
/* @__PURE__ */ jsxRuntime.jsx(
core.UnstyledButton,
{
...getStyles("control", {
className: nextControlProps?.className,
style: nextControlProps?.style
}),
...nextControlProps,
onClick: (event) => {
handleNext();
nextControlProps?.onClick?.(event);
},
"data-inactive": !canScrollNext || void 0,
"data-type": "next",
tabIndex: canScrollNext ? 0 : -1,
children: typeof nextControlIcon !== "undefined" ? nextControlIcon : /* @__PURE__ */ jsxRuntime.jsx(
core.AccordionChevron,
{
style: {
transform: `rotate(${getChevronRotation.getChevronRotation({
dir,
orientation,
direction: "next"
})}deg)`
}
}
)
}
)
] }),
/* @__PURE__ */ jsxRuntime.jsx("div", { ...getStyles("viewport"), ref: emblaRefElement, "data-type": type, children: /* @__PURE__ */ jsxRuntime.jsx(
"div",
{
...getStyles("container", { className: responsiveClassName }),
"data-orientation": orientation,
children
}
) }),
withIndicators && /* @__PURE__ */ jsxRuntime.jsx("div", { ...getStyles("indicators"), "data-orientation": orientation, children: indicators })
]
}
)
] });
});
Carousel.classes = Carousel_module;
Carousel.displayName = "@mantine/carousel/Carousel";
Carousel.Slide = CarouselSlide.CarouselSlide;
exports.Carousel = Carousel;
//# sourceMappingURL=Carousel.cjs.map