react-responsive-3d-carousel
Version:
React Responsive 3D Carousel
936 lines (914 loc) • 37.7 kB
JavaScript
import { jsxs, jsx } from 'react/jsx-runtime';
import { useEffect, useMemo, useRef, createContext, useState, useCallback } from 'react';
/******************************************************************************
Copyright (c) Microsoft Corporation.
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted.
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH
REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY
AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT,
INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM
LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR
OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR
PERFORMANCE OF THIS SOFTWARE.
***************************************************************************** */
/* global Reflect, Promise, SuppressedError, Symbol */
var __assign = function() {
__assign = Object.assign || function __assign(t) {
for (var s, i = 1, n = arguments.length; i < n; i++) {
s = arguments[i];
for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p)) t[p] = s[p];
}
return t;
};
return __assign.apply(this, arguments);
};
typeof SuppressedError === "function" ? SuppressedError : function (error, suppressed, message) {
var e = new Error(message);
return e.name = "SuppressedError", e.error = error, e.suppressed = suppressed, e;
};
var CSS_VARIABLE = {
CONTAINER_WIDTH: '--container-width',
CONTAINER_HEIGHT: '--container-height',
ITEM_WIDTH: '--item-width',
};
var useAutoPlay = function (autoplay, interval, slideNext, pauseRef) {
/**
* Auto play the carousel
*/
useEffect(function () {
if (!autoplay)
return;
var timer = window.setInterval(function () {
if (pauseRef.current)
return;
slideNext();
}, interval);
return function () {
clearInterval(timer);
};
}, [autoplay, interval, slideNext]);
};
var useFocus = function (containerRef, autoFocus, slideWithKeyboard, slideNext, slidePrev) {
/**
* Auto-focus the container element when autoFocus is true.
*/
useEffect(function () {
var container = containerRef.current;
if (!container)
return;
if (autoFocus)
container.focus();
}, [autoFocus]);
/**
* Set up keydown event listener for keyboard navigation.
*/
useEffect(function () {
if (slideWithKeyboard === 'none')
return;
var container = containerRef.current;
if (!container)
return;
var handleKeyDown = function (e) {
if (container !== document.activeElement)
return;
switch (e.key) {
case 'ArrowLeft':
if (slideWithKeyboard === 'horizontal' ||
slideWithKeyboard === 'both') {
slidePrev();
}
break;
case 'ArrowRight':
if (slideWithKeyboard === 'horizontal' ||
slideWithKeyboard === 'both') {
slideNext();
}
break;
case 'ArrowUp':
if (slideWithKeyboard === 'vertical' ||
slideWithKeyboard === 'both') {
slidePrev();
}
break;
case 'ArrowDown':
if (slideWithKeyboard === 'vertical' ||
slideWithKeyboard === 'both') {
slideNext();
}
break;
}
};
window.addEventListener('keydown', handleKeyDown);
return function () {
window.removeEventListener('keydown', handleKeyDown);
};
}, [slideWithKeyboard, slideNext, slidePrev]);
};
var DEFAULT_TWO_CAROUSEL_INDEX_TRANSFORM = {
default: {
translate: {
x: 0,
y: 0,
z: -1,
},
rotate: {
x: 0,
y: 0,
z: 0,
},
offset: {
x: 0,
y: 0,
z: 0,
},
},
0: {
translate: {
x: 0,
y: 0,
z: 0,
},
rotate: {
x: 0,
y: 0,
z: 0,
},
offset: {
x: 0,
y: 0,
z: 0,
},
},
};
var DEFAULT_THREE_CAROUSEL_INDEX_TRANSFORM = {
default: {
translate: {
x: 0,
y: 0,
z: -1,
},
rotate: {
x: 0,
y: 0,
z: 0,
},
offset: {
x: 0,
y: 0,
z: 0,
},
},
'-1': {
translate: {
x: -0.5,
y: 0,
z: 0,
},
rotate: {
x: 0,
y: 40,
z: 0,
},
offset: {
x: 0.5 * Math.cos(40 * (Math.PI / 180)),
y: 0,
z: -1 * Math.sin(30 * (Math.PI / 180)),
},
},
0: {
translate: {
x: 0,
y: 0,
z: 0,
},
rotate: {
x: 0,
y: 0,
z: 0,
},
offset: {
x: 0,
y: 0,
z: 0,
},
},
1: {
translate: {
x: 0.5,
y: 0,
z: 0,
},
rotate: {
x: 0,
y: -40,
z: 0,
},
offset: {
x: -0.5 * Math.cos(40 * (Math.PI / 180)),
y: 0,
z: -1 * Math.sin(30 * (Math.PI / 180)),
},
},
};
var DEFAULT_FIVE_CAROUSEL_INDEX_TRANSFORM = {
default: {
translate: {
x: 0,
y: 0,
z: -1,
},
rotate: {
x: 0,
y: 0,
z: 0,
},
offset: {
x: 0,
y: 0,
z: 0,
},
},
'-2': {
translate: {
x: -0.5,
y: 0,
z: 0,
},
rotate: {
x: 0,
y: 40,
z: 0,
},
offset: {
x: 0.5 * Math.cos(40 * (Math.PI / 180)),
y: 0,
z: -1 * Math.sin(40 * (Math.PI / 180)),
},
},
'-1': {
translate: {
x: -0.25,
y: 0,
z: 0,
},
rotate: {
x: 0,
y: 20,
z: 0,
},
offset: {
x: 0.25 * Math.cos(40 * (Math.PI / 180)),
y: 0,
z: -0.5 * Math.sin(40 * (Math.PI / 180)),
},
},
0: {
translate: {
x: 0,
y: 0,
z: 0,
},
rotate: {
x: 0,
y: 0,
z: 0,
},
offset: {
x: 0,
y: 0,
z: 0,
},
},
1: {
translate: {
x: 0.25,
y: 0,
z: 0,
},
rotate: {
x: 0,
y: -20,
z: 0,
},
offset: {
x: -0.25 * Math.cos(40 * (Math.PI / 180)),
y: 0,
z: -0.5 * Math.sin(40 * (Math.PI / 180)),
},
},
2: {
translate: {
x: 0.5,
y: 0,
z: 0,
},
rotate: {
x: 0,
y: -40,
z: 0,
},
offset: {
x: -0.5 * Math.cos(40 * (Math.PI / 180)),
y: 0,
z: -1 * Math.sin(40 * (Math.PI / 180)),
},
},
};
var round = function (num, decimal) {
return Math.round(num * Math.pow(10, decimal)) / Math.pow(10, decimal);
};
/**
* Adjust default carousel layout info based on the default option values
*/
var adjustDefaultCarouselLayoutInfo = function (info, defaultOption) {
var _a, _b, _c;
var adjustedInfo = {};
var widthFactor = (_a = defaultOption === null || defaultOption === void 0 ? void 0 : defaultOption.widthFactor) !== null && _a !== void 0 ? _a : 1;
var depthFactor = (_b = defaultOption === null || defaultOption === void 0 ? void 0 : defaultOption.depthFactor) !== null && _b !== void 0 ? _b : 1;
var angleFactor = (_c = defaultOption === null || defaultOption === void 0 ? void 0 : defaultOption.angleFactor) !== null && _c !== void 0 ? _c : 1;
Object.entries(info).forEach(function (_a) {
var key = _a[0], itemInfo = _a[1];
var adjustedTranslate = {
x: round(itemInfo.translate.x * widthFactor, 3), // it's always number : constant/layout.ts
y: itemInfo.translate.y,
z: round(itemInfo.translate.z * widthFactor, 3), // it's always number : constant/layout.ts
};
var adjustedRotate = {
x: round(itemInfo.rotate.x * angleFactor, 3),
y: round(itemInfo.rotate.y * angleFactor, 3),
z: round(itemInfo.rotate.z * angleFactor, 3),
};
var adjustedOffset = {
x: round(itemInfo.offset.x * widthFactor, 3), // it's always number : constant/layout.ts
y: itemInfo.offset.y,
z: round(itemInfo.offset.z * depthFactor, 3), // it's always number : constant/layout.ts
};
adjustedInfo[key] = {
translate: adjustedTranslate,
rotate: adjustedRotate,
offset: adjustedOffset,
};
});
return adjustedInfo;
};
/**
* Get default carousel layout info based on the length of items
*/
var getDefaultCarouselLayoutInfo = function (length, defaultOption) {
// Get default layout info based on 'defaultOption.numOfSlides'
if (defaultOption && 'numOfSlides' in defaultOption) {
if (defaultOption.numOfSlides === 2) {
return adjustDefaultCarouselLayoutInfo(DEFAULT_TWO_CAROUSEL_INDEX_TRANSFORM, defaultOption);
}
else if (defaultOption.numOfSlides === 3) {
return adjustDefaultCarouselLayoutInfo(DEFAULT_THREE_CAROUSEL_INDEX_TRANSFORM, defaultOption);
}
else if (defaultOption.numOfSlides === 5) {
return adjustDefaultCarouselLayoutInfo(DEFAULT_FIVE_CAROUSEL_INDEX_TRANSFORM, defaultOption);
}
}
// Get default layout info based on the length of items
if (length < 3) {
return adjustDefaultCarouselLayoutInfo(DEFAULT_TWO_CAROUSEL_INDEX_TRANSFORM, defaultOption);
}
else if (length < 5) {
return adjustDefaultCarouselLayoutInfo(DEFAULT_THREE_CAROUSEL_INDEX_TRANSFORM, defaultOption);
}
else {
return adjustDefaultCarouselLayoutInfo(DEFAULT_FIVE_CAROUSEL_INDEX_TRANSFORM, defaultOption);
}
};
/**
* Transform layout info to CSS style
*/
var transformLayoutInfoToStyle = function (info, align) {
var width = info.width, height = info.height, translate = info.translate, rotate = info.rotate, offset = info.offset;
// Transform width
var newWidth = typeof width === 'number'
? "calc(".concat(width, " * var(").concat(CSS_VARIABLE.CONTAINER_WIDTH, "))")
: (width !== null && width !== void 0 ? width : 'auto');
// Transform height
var newHeight = typeof height === 'number'
? "calc(".concat(height, " * var(").concat(CSS_VARIABLE.CONTAINER_HEIGHT, "))")
: (height !== null && height !== void 0 ? height : 'auto');
// Set init initTranslateY depend on the align
var initTranslateY;
switch (align) {
case 'top':
initTranslateY = 0;
break;
case 'bottom':
initTranslateY = -100;
break;
case 'center':
initTranslateY = -50;
break;
}
// Transform rotate
var magnitude = Math.sqrt(Math.pow(rotate.x, 2) + Math.pow(rotate.y, 2) + Math.pow(rotate.z, 2));
var nx = magnitude ? rotate.x / magnitude : 0;
var ny = magnitude ? rotate.y / magnitude : 0;
var nz = magnitude ? rotate.z / magnitude : 0;
// Transform translate
var translateX = typeof translate.x === 'number'
? "".concat(translate.x, " * var(").concat(CSS_VARIABLE.CONTAINER_WIDTH, ")")
: translate.x;
var translateY = typeof translate.y === 'number'
? "".concat(translate.y, " * var(").concat(CSS_VARIABLE.CONTAINER_HEIGHT, ")")
: translate.y;
var translateZ = typeof translate.z === 'number'
? "".concat(translate.z, " * var(").concat(CSS_VARIABLE.CONTAINER_WIDTH, ")")
: translate.z;
// Transform offset
var offsetX = typeof offset.x === 'number' ? "".concat(offset.x, " * 100%") : offset.x;
var offsetY = typeof offset.y === 'number' ? "".concat(offset.y, " * 100%") : offset.y;
var offsetZ = typeof offset.z === 'number'
? "".concat(offset.z, " * var(").concat(CSS_VARIABLE.ITEM_WIDTH, ")")
: offset.z;
return {
width: newWidth,
height: newHeight,
transform: "translate(-50%, ".concat(initTranslateY, "%) \n translate3d(calc(").concat(translateX, " + ").concat(offsetX, "), calc(").concat(translateY, " + ").concat(offsetY, "), calc(").concat(translateZ, " + ").concat(offsetZ, ")) \n rotate3d(").concat(nx, ", ").concat(ny, ", ").concat(nz, ", calc(").concat(magnitude, "deg)"),
};
};
/**
* Transform carousel layout info to CSS style
*/
var transformCarouselLayoutInfoToStyle = function (info, align) {
var style = {};
for (var key in info) {
style[key] = transformLayoutInfoToStyle(info[key], align);
}
return style;
};
var useLayout = function (items, htmlItemsRef, align, width, height, aspectRatio, layout, curIndex, defaultOption) {
/**
* Memoize the layout styles from layout info
*/
var layoutStyle = useMemo(function () {
var layoutInfo = layout === 'default'
? getDefaultCarouselLayoutInfo(items.length, defaultOption)
: layout;
return transformCarouselLayoutInfoToStyle(layoutInfo, align);
}, [items, align, layout, defaultOption]);
/**
* Apply the calculated layout styles to each item on every render.
*/
useEffect(function () {
var htmlItems = htmlItemsRef.current;
var applyStyle = function (item, style) {
item.style.width = style.width === 'auto' ? width : style.width;
item.style.height = style.height === 'auto' ? height : style.height;
item.style.transform = style.transform;
// Toggle item width class
if (item.style.width !== 'auto' || (item.style.height !== 'auto' && aspectRatio !== 'auto')) {
item.classList.add('fixed-width');
}
else {
item.classList.remove('fixed-width');
}
// Toggle item height class
if (item.style.height !== 'auto' || (item.style.width !== 'auto' && aspectRatio !== 'auto')) {
item.classList.add('fixed-height');
}
else {
item.classList.remove('fixed-height');
}
};
htmlItems.forEach(function (item, i) {
// Check the simple-calculated index first
var primaryIdx = i - curIndex;
if (layoutStyle[primaryIdx]) {
applyStyle(item, layoutStyle[primaryIdx]);
return;
}
// Check the other side of the carousel
var secondaryIdx = primaryIdx + (primaryIdx > 0 ? -items.length : items.length);
if (layoutStyle[secondaryIdx]) {
applyStyle(item, layoutStyle[secondaryIdx]);
return;
}
// If there's no layout info for the index, apply the default layout
applyStyle(item, layoutStyle.default);
});
}, [items, width, height, aspectRatio, layoutStyle, curIndex]);
};
var useSize = function (items, htmlItemsRef, listRef, width, curIndex) {
/**
* Set the width of each item as a CSS variable on every render.
*/
useEffect(function () {
var htmlItems = htmlItemsRef.current;
htmlItems.forEach(function (item) {
item.style.setProperty(CSS_VARIABLE.ITEM_WIDTH, "".concat(item.offsetWidth, "px"));
});
}, [items, width, curIndex]);
/**
* Set the width and height of the Carousel list as a CSS variable
* Use ResizeObserver if available; otherwise, falls back to window resize event.
*/
useEffect(function () {
var list = listRef.current;
if (!list)
return;
var handleResize = function () {
list.style.setProperty(CSS_VARIABLE.CONTAINER_WIDTH, "".concat(list.offsetWidth, "px"));
list.style.setProperty(CSS_VARIABLE.CONTAINER_HEIGHT, "".concat(list.offsetHeight, "px"));
};
handleResize(); // Initial call
var resizeObserver = 'ResizeObserver' in window ? new ResizeObserver(handleResize) : null;
if (resizeObserver) {
resizeObserver.observe(list);
}
else {
window.addEventListener('resize', handleResize);
}
return function () {
if (resizeObserver) {
resizeObserver.disconnect();
}
else {
window.removeEventListener('resize', handleResize);
}
};
}, []);
};
var MIN_SWIPE_DISTANCE = 30; // Minimum distance in pixels to consider a swipe
var useSwipe = function (_a) {
var containerRef = _a.containerRef, swipeable = _a.swipeable, swipeDirection = _a.swipeDirection, slideNext = _a.slideNext, slidePrev = _a.slidePrev, onSwipeStart = _a.onSwipeStart, onSwipeEnd = _a.onSwipeEnd, onSwipeMove = _a.onSwipeMove;
// Ref to track if a swipe is currently in progress
var isSwiping = useRef(false);
/**
* Handle swipe gestures on a container element
*/
useEffect(function () {
if (!swipeable)
return;
var container = containerRef.current;
if (!container)
return;
var startX = 0;
var startY = 0;
var handleSwipeStart = function (event) {
isSwiping.current = true;
startX = event.touches[0].clientX;
startY = event.touches[0].clientY;
onSwipeStart && onSwipeStart(event);
};
var handleSwipeMove = function (event) {
if (!isSwiping.current)
return;
onSwipeMove && onSwipeMove(event);
};
var handleSwipeEnd = function (event) {
if (!isSwiping.current)
return;
isSwiping.current = false;
onSwipeEnd && onSwipeEnd(event);
var endX = event.changedTouches[0].clientX;
var endY = event.changedTouches[0].clientY;
var deltaX = endX - startX;
var deltaY = endY - startY;
var absDeltaX = Math.abs(deltaX);
var absDeltaY = Math.abs(deltaY);
var absDelta = Math.sqrt(Math.pow(absDeltaX, 2) + Math.pow(absDeltaY, 2));
if (absDelta < MIN_SWIPE_DISTANCE)
return;
if (swipeDirection === 'horizontal' && absDeltaX > absDeltaY) {
event.preventDefault();
if (deltaX > 0) {
slidePrev();
}
else {
slideNext();
}
}
else if (swipeDirection === 'vertical' && absDeltaY > absDeltaX) {
event.preventDefault();
if (deltaY > 0) {
slidePrev();
}
else {
slideNext();
}
}
};
container.addEventListener('touchstart', handleSwipeStart, {
passive: true,
});
container.addEventListener('touchmove', handleSwipeMove, {
passive: true,
});
container.addEventListener('touchend', handleSwipeEnd);
return function () {
container.removeEventListener('touchstart', handleSwipeStart);
container.removeEventListener('touchmove', handleSwipeMove);
container.removeEventListener('touchend', handleSwipeEnd);
};
}, [
swipeable,
swipeDirection,
slideNext,
slidePrev,
onSwipeStart,
onSwipeEnd,
onSwipeMove,
]);
return { isSwiping: isSwiping };
};
var Arrows = function (_a) {
var _b = _a.width, width = _b === void 0 ? '3rem' : _b, _c = _a.height, height = _c === void 0 ? '5rem' : _c, _d = _a.color, color = _d === void 0 ? '#ffffff' : _d, _e = _a.hoverColor, hoverColor = _e === void 0 ? '#888888' : _e, _f = _a.shadow, shadow = _f === void 0 ? '0 0.05rem 0.1rem rgba(0, 0, 0, 0.3)' : _f, _g = _a.nextArrowTranslate, nextArrowTranslate = _g === void 0 ? ['0px', '0px'] : _g, _h = _a.prevArrowTranslate, prevArrowTranslate = _h === void 0 ? ['0px', '0px'] : _h, onClickNext = _a.onClickNext, onClickPrev = _a.onClickPrev, nextIcon = _a.nextIcon, prevIcon = _a.prevIcon;
var handleClickPrev = function (e) {
e.stopPropagation();
onClickPrev && onClickPrev(e);
};
var handleClickNext = function (e) {
e.stopPropagation();
onClickNext && onClickNext(e);
};
var arrowsStyle = {
'--arrow-width': width,
'--arrow-height': height,
'--arrow-drop-shadow': shadow,
'--arrow-color': color,
'--arrow-hover-color': hoverColor,
};
return (jsxs("div", { className: "react-responsive-3d-carousel__arrows", style: arrowsStyle, children: [jsx("button", { type: "button", onClick: handleClickPrev, "aria-label": "previous slide", style: {
transform: "translateY(-50%) translate(".concat(prevArrowTranslate[0], ", ").concat(prevArrowTranslate[1], ")"),
}, children: prevIcon || jsx(LeftCaretIcon, {}) }), jsx("button", { type: "button", onClick: handleClickNext, "aria-label": "next slide", style: {
transform: "translateY(-50%) translate(".concat(nextArrowTranslate[0], ", ").concat(nextArrowTranslate[1], ")"),
}, children: nextIcon || jsx(RightCaretIcon, {}) })] }));
};
var LeftCaretIcon = function () {
return (jsx("svg", { width: "24", height: "24", viewBox: "0 0 24 24", preserveAspectRatio: "none", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsx("polyline", { points: "15 18 9 12 15 6" }) }));
};
var RightCaretIcon = function () {
return (jsx("svg", { width: "24", height: "24", viewBox: "0 0 24 24", preserveAspectRatio: "none", fill: "none", stroke: "currentColor", strokeWidth: "2", strokeLinecap: "round", strokeLinejoin: "round", children: jsx("polyline", { points: "9 18 15 12 9 6" }) }));
};
Arrows.displayName = 'Arrows';
var Indicators = function (_a) {
var length = _a.length, curIndex = _a.curIndex, _b = _a.color, color = _b === void 0 ? '#ffffff' : _b, _c = _a.width, width = _c === void 0 ? '0.7rem' : _c, _d = _a.height, height = _d === void 0 ? '0.7rem' : _d, _e = _a.gap, gap = _e === void 0 ? '1.5rem' : _e, _f = _a.activeColor, activeColor = _f === void 0 ? '#888888' : _f, _g = _a.shadow, shadow = _g === void 0 ? '0 0.05rem 0.1rem rgba(0, 0, 0, 0.5)' : _g, _h = _a.translate, translate = _h === void 0 ? ['0px', '0px'] : _h, indicatorIcon = _a.indicatorIcon, onClick = _a.onClick;
var handleClick = function (e, index) {
e.stopPropagation();
onClick && onClick(e, index);
};
var indicatorsStyle = {
gap: gap,
transform: "translate(".concat(translate[0], ", ").concat(translate[1], ")"),
'--indicator-width': width,
'--indicator-height': height,
'--indicator-color': color,
'--indicator-active-color': activeColor,
'--indicator-shadow': shadow,
};
return (jsx("ul", { className: "react-responsive-3d-carousel__indicators", style: indicatorsStyle, children: Array.from({ length: length }, function (_, i) { return (jsx("li", { onClick: function (e) { return handleClick(e, i); }, "aria-label": "slide item ".concat(i + 1), className: i === curIndex ? 'active' : '', children: indicatorIcon ? indicatorIcon : jsx(CircleIcon, {}) }, i)); }) }));
};
var CircleIcon = function () {
return (jsx("svg", { preserveAspectRatio: "none", width: "24", height: "24", viewBox: "0 0 24 24", fill: "currentColor", children: jsx("circle", { cx: "12", cy: "12", r: "10" }) }));
};
Indicators.displayName = 'Indicators';
var Status = function (_a) {
var length = _a.length, curIndex = _a.curIndex, _b = _a.color, color = _b === void 0 ? '#ffffff' : _b, _c = _a.fontSize, fontSize = _c === void 0 ? '1rem' : _c, _d = _a.fontWeight, fontWeight = _d === void 0 ? '600' : _d, _e = _a.shadow, shadow = _e === void 0 ? '0 0.05rem 0.1rem rgba(0, 0, 0, 0.5)' : _e, _f = _a.translate, translate = _f === void 0 ? ['0px', '0px'] : _f;
var statusStyle = {
color: color,
fontSize: fontSize,
fontWeight: fontWeight,
textShadow: shadow,
transform: "translate(".concat(translate[0], ", ").concat(translate[1], ")"),
};
return (jsx("p", { className: "react-responsive-3d-carousel__status", "aria-label": "".concat(curIndex + 1, " of ").concat(length), style: statusStyle, children: "".concat(curIndex + 1, " / ").concat(length) }));
};
Status.displayName = 'Status';
var CarouselContext = createContext({
curIndex: 0,
setCurIndex: function (_) { },
slideNext: function () { },
slidePrev: function () { },
});
var Carousel = function (_a) {
var children = _a.children, _b = _a.ariaLabel, ariaLabel = _b === void 0 ? '3d carousel' : _b, items = _a.items, _c = _a.startIndex, startIndex = _c === void 0 ? 0 : _c,
/** Container */
_d = _a.containerHeight,
/** Container */
containerHeight = _d === void 0 ? 'auto' : _d, _e = _a.containerWidth, containerWidth = _e === void 0 ? '100%' : _e, _f = _a.containerPadding, containerPadding = _f === void 0 ? '1rem' : _f,
/** Carousel 2D */
_g = _a.width,
/** Carousel 2D */
strNumWidth = _g === void 0 ? '400px' : _g, _h = _a.height, strNumHeight = _h === void 0 ? '300px' : _h, _j = _a.aspectRatio, aspectRatio = _j === void 0 ? 'auto' : _j, _k = _a.align, align = _k === void 0 ? 'center' : _k, _l = _a.boxShadow, boxShadow = _l === void 0 ? '0 0.1rem 0.5rem rgba(0, 0, 0, 0.5)' : _l,
/** Carousel 3D */
_m = _a.perspective,
/** Carousel 3D */
perspective = _m === void 0 ? 1 : _m, _o = _a.perspectiveOrigin, perspectiveOrigin = _o === void 0 ? 'center' : _o, _p = _a.layout, layout = _p === void 0 ? 'default' : _p, defaultOption = _a.defaultOption,
/** Carousel Transition */
_q = _a.sizeDuration,
/** Carousel Transition */
sizeDuration = _q === void 0 ? 1000 : _q, _r = _a.sizeTimingFn, sizeTimingFn = _r === void 0 ? 'ease-in-out' : _r, _s = _a.transformDuration, transformDuration = _s === void 0 ? 1000 : _s, _t = _a.transformTimingFn, transformTimingFn = _t === void 0 ? 'ease-in-out' : _t,
/** Carousel Interaction */
_u = _a.focusOnSelect,
/** Carousel Interaction */
focusOnSelect = _u === void 0 ? true : _u, _v = _a.pauseOnHover, pauseOnHover = _v === void 0 ? true : _v, _w = _a.pauseOnTransition, pauseOnTransition = _w === void 0 ? 'both' : _w,
/** Carousel Callback */
onClickItem = _a.onClickItem, onChange = _a.onChange,
/** Carousel Play */
_x = _a.autoPlay,
/** Carousel Play */
autoPlay = _x === void 0 ? true : _x, _y = _a.interval, interval = _y === void 0 ? 3000 : _y, _z = _a.infiniteLoop, infiniteLoop = _z === void 0 ? true : _z,
/** Carousel Focus */
_0 = _a.autoFocus,
/** Carousel Focus */
autoFocus = _0 === void 0 ? false : _0, _1 = _a.slideWithKeyboard, slideWithKeyboard = _1 === void 0 ? 'both' : _1,
/** Carousel Swipe */
_2 = _a.swipeable,
/** Carousel Swipe */
swipeable = _2 === void 0 ? true : _2, _3 = _a.swipeDirection, swipeDirection = _3 === void 0 ? 'horizontal' : _3, onSwipeStart = _a.onSwipeStart, onSwipeEnd = _a.onSwipeEnd, onSwipeMove = _a.onSwipeMove,
/* Status */
_4 = _a.showStatus,
/* Status */
showStatus = _4 === void 0 ? true : _4, status = _a.status,
/* Arrows */
_5 = _a.showArrows,
/* Arrows */
showArrows = _5 === void 0 ? true : _5, arrows = _a.arrows,
/* Indicators */
_6 = _a.showIndicators,
/* Indicators */
showIndicators = _6 === void 0 ? true : _6, indicators = _a.indicators;
var containerRef = useRef(null); // The carousel container element
var listRef = useRef(null); // The carousel list element
var pauseRef = useRef(false); // Flag to pause carousel auto play
var transitionRef = useRef({ size: false, transform: false }); // Flag to prevent multiple transitions
var _7 = useState(startIndex), curIndex = _7[0], setCurIndex = _7[1]; // Current center carousel's index
// Transform number or string type width and height to string type
var width = useMemo(function () {
return typeof strNumWidth === 'number'
? "calc(".concat(strNumWidth, " * var(").concat(CSS_VARIABLE.CONTAINER_WIDTH, "))")
: strNumWidth;
}, [strNumWidth]);
var height = useMemo(function () {
return typeof strNumHeight === 'number'
? "calc(".concat(strNumHeight, " * var(").concat(CSS_VARIABLE.CONTAINER_HEIGHT, "))")
: strNumHeight;
}, [strNumHeight]);
var htmlItemsRef = useRef([]);
/**
* Memoize renderedItems
*/
useEffect(function () {
var container = containerRef.current;
if (!container)
return;
htmlItemsRef.current = Array.from(container.getElementsByClassName('react-responsive-3d-carousel__item'));
}, [items]);
/**
* Transition flags
*/
useEffect(function () {
var sizeDurationOffset = sizeDuration - 100;
var transformDurationOffset = transformDuration - 100;
if (sizeDurationOffset > 0)
transitionRef.current.size = true;
if (transformDurationOffset > 0)
transitionRef.current.transform = true;
var sizeTimeoutId = setTimeout(function () {
transitionRef.current.size = false;
}, sizeDurationOffset);
var transformTimeoutId = setTimeout(function () {
transitionRef.current.transform = false;
}, transformDurationOffset);
return function () {
clearTimeout(sizeTimeoutId);
clearTimeout(transformTimeoutId);
};
}, [curIndex, sizeDuration, transformDuration]);
/**
* Slide to the previous carousel item
*/
var slidePrev = useCallback(function () {
if ((pauseOnTransition === 'size' || pauseOnTransition === 'both') && transitionRef.current.size) {
return;
}
if ((pauseOnTransition === 'transform' || pauseOnTransition === 'both') && transitionRef.current.transform) {
return;
}
setCurIndex(function (curIndex) {
if (!infiniteLoop && curIndex === 0)
return curIndex;
return (curIndex - 1 + items.length) % items.length;
});
}, [items, infiniteLoop, setCurIndex, pauseOnTransition]);
/**
* Slide to the next carousel item
*/
var slideNext = useCallback(function () {
if ((pauseOnTransition === 'size' || pauseOnTransition === 'both') && transitionRef.current.size) {
return;
}
if ((pauseOnTransition === 'transform' || pauseOnTransition === 'both') && transitionRef.current.transform) {
return;
}
setCurIndex(function (curIndex) {
if (!infiniteLoop && curIndex === items.length - 1)
return curIndex;
return (curIndex + 1) % items.length;
});
}, [items, infiniteLoop, setCurIndex, pauseOnTransition]);
/**
* Sync curIndex with startIndex, if startIndex is changed
*/
useEffect(function () {
setCurIndex(startIndex);
}, [startIndex]);
/**
* Adjust curIndex if it's out of range
*/
useEffect(function () {
if (curIndex < 0)
setCurIndex(0);
else if (items.length - 1 < curIndex)
setCurIndex(items.length - 1);
}, [items, curIndex]);
/**
* Callback function for onChange
*/
var isFlag = useRef(false); // Flag to prevent calling onChange on the first render
useEffect(function () {
if (!isFlag.current) {
isFlag.current = true;
return;
}
onChange && onChange(curIndex, items[curIndex]);
}, [curIndex, onChange]);
// Auto play
useAutoPlay(autoPlay, interval, slideNext, pauseRef);
// Set width of the list and items as CSS variables
useSize(items, htmlItemsRef, listRef, width, curIndex);
// Carousel layout style
useLayout(items, htmlItemsRef, align, width, height, aspectRatio, layout, curIndex, defaultOption);
// Swipe feature
useSwipe({
containerRef: containerRef,
swipeable: swipeable,
swipeDirection: swipeDirection,
slideNext: slideNext,
slidePrev: slidePrev,
onSwipeStart: onSwipeStart,
onSwipeEnd: onSwipeEnd,
onSwipeMove: onSwipeMove,
});
// Focus and keyboard navigation
useFocus(containerRef, autoFocus, slideWithKeyboard, slideNext, slidePrev);
/**
* Handler functions
*/
var handleClickItem = function (e, index) {
focusOnSelect && setCurIndex(index);
onClickItem && onClickItem(e, index, items[curIndex], curIndex === index);
};
var handleMouseEnterItem = function () {
pauseOnHover && (pauseRef.current = true);
};
var handleMouseLeaveItem = function () {
pauseOnHover && (pauseRef.current = false);
};
var handleClickNextArrow = function (e) {
slideNext();
(arrows === null || arrows === void 0 ? void 0 : arrows.onClickNext) && arrows.onClickNext(e);
};
var handleClickPrevArrow = function (e) {
slidePrev();
(arrows === null || arrows === void 0 ? void 0 : arrows.onClickPrev) && arrows.onClickPrev(e);
};
var handleClickIndicator = function (e, index) {
setCurIndex(index);
(indicators === null || indicators === void 0 ? void 0 : indicators.onClick) && indicators.onClick(e, index);
};
/**
* Styles
*/
var containerStyle = {
width: containerWidth,
height: containerHeight,
padding: containerPadding,
};
var listStyle = {
perspective: typeof perspective === 'number'
? "calc(".concat(perspective, " * var(").concat(CSS_VARIABLE.CONTAINER_WIDTH, "))")
: perspective,
perspectiveOrigin: perspectiveOrigin,
height: containerHeight === 'auto' ? 'auto' : '100%',
};
var itemStyle = {
width: width,
height: height,
aspectRatio: aspectRatio,
transition: "transform ".concat(transformDuration, "ms ").concat(transformTimingFn, ", width ").concat(sizeDuration, "ms ").concat(sizeTimingFn, ", height ").concat(sizeDuration, "ms ").concat(sizeTimingFn),
cursor: focusOnSelect ? 'pointer' : 'initial',
top: align === 'top' ? '0%' : align === 'bottom' ? '100%' : '50%',
boxShadow: boxShadow,
};
return (jsx(CarouselContext.Provider, { value: { curIndex: curIndex, setCurIndex: setCurIndex, slideNext: slideNext, slidePrev: slidePrev }, children: jsxs("div", { className: "react-responsive-3d-carousel", "aria-label": ariaLabel, tabIndex: slideWithKeyboard !== 'none' ? 0 : undefined, style: containerStyle, ref: containerRef, children: [jsxs("ul", { className: "react-responsive-3d-carousel__list", style: listStyle, ref: listRef, children: [jsx("div", { className: "react-responsive-3d-carousel__dummy", style: __assign(__assign({}, itemStyle), { visibility: 'hidden' }) }), items.map(function (item, index) {
return (jsx("li", { className: "react-responsive-3d-carousel__item \n ".concat((width !== 'auto' || (height !== 'auto' && aspectRatio !== 'auto')) ? 'fixed-width' : '', " \n ").concat((height !== 'auto' || (width !== 'auto' && aspectRatio !== 'auto')) ? 'fixed-height' : ''), onClick: function (e) { return handleClickItem(e, index); }, style: itemStyle, onMouseEnter: handleMouseEnterItem, onMouseLeave: handleMouseLeaveItem, children: item }, index));
}), children] }), showStatus && (jsx("div", { className: "react-responsive-3d-carousel__status-container", children: jsx(Status, __assign({ length: items.length, curIndex: curIndex }, status)) })), showArrows && (jsx("div", { className: "react-responsive-3d-carousel__arrows-container", children: jsx(Arrows, __assign({ onClickNext: handleClickNextArrow, onClickPrev: handleClickPrevArrow }, arrows)) })), showIndicators && (jsx("div", { className: "react-responsive-3d-carousel__indicators-container", children: jsx(Indicators, __assign({ length: items.length, curIndex: curIndex, onClick: handleClickIndicator }, indicators)) }))] }) }));
};
export { Arrows, Carousel, CarouselContext, Indicators, Status };