kwikid-components-react
Version:
KwikID's Component Library in React
185 lines (174 loc) • 8.1 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.default = void 0;
var _kwikidToolkit = require("kwikid-toolkit");
var _react = _interopRequireWildcard(require("react"));
var _fa = require("react-icons/fa6");
var _Carousel = _interopRequireDefault(require("./Carousel.defaults"));
var _Carousel2 = require("./Carousel.style");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
function _interopRequireWildcard(e, t) { if ("function" == typeof WeakMap) var r = new WeakMap(), n = new WeakMap(); return (_interopRequireWildcard = function (e, t) { if (!t && e && e.__esModule) return e; var o, i, f = { __proto__: null, default: e }; if (null === e || "object" != typeof e && "function" != typeof e) return f; if (o = t ? n : r) { if (o.has(e)) return o.get(e); o.set(e, f); } for (const t in e) "default" !== t && {}.hasOwnProperty.call(e, t) && ((i = (o = Object.defineProperty) && Object.getOwnPropertyDescriptor(e, t)) && (i.get || i.set) ? o(f, t, i) : f[t] = e[t]); return f; })(e, t); }
// Constants to replace magic numbers
const HALF_DIVISOR = 2;
const FULL_PERCENTAGE = 100;
const MIN_SWIPE_DISTANCE = 50;
const KwikUICarousel = _ref => {
let {
children = [],
customStyles = _Carousel.default.customStyles,
indicators = {
isActive: _Carousel.default.indicators.isActive,
showAllIndicators: _Carousel.default.indicators.showAllIndicators,
maxVisibleIndicators: _Carousel.default.indicators.maxVisibleIndicators
}
} = _ref;
const [currentIndex, setCurrentIndex] = (0, _react.useState)(0);
const [length, setLength] = (0, _react.useState)(children.length);
const [touchStart, setTouchStart] = (0, _react.useState)(null);
const [touchEnd, setTouchEnd] = (0, _react.useState)(null);
const childRefs = (0, _react.useRef)([]);
// Pre-create refs for all children to avoid using useRef in callback
const childRefMap = _react.default.useMemo(() => {
const refs = [];
for (let i = 0; i < children.length; i += 1) {
refs.push(/*#__PURE__*/_react.default.createRef());
}
return refs;
}, [children.length]);
// Initialize child refs
const clonedChildren = _react.default.Children.map(children, (child, index) => {
childRefs.current[index] = childRefMap[index];
return /*#__PURE__*/_react.default.cloneElement(child, {
ref: childRefMap[index]
});
});
// Visible indicators logic
const slicedChildren = indicators !== null && indicators !== void 0 && indicators.showAllIndicators ? clonedChildren : clonedChildren.slice(Math.max(currentIndex - Math.floor(indicators.maxVisibleIndicators / HALF_DIVISOR), 0), Math.min(currentIndex + Math.ceil(indicators.maxVisibleIndicators / HALF_DIVISOR), length));
// Update length when children change
(0, _react.useEffect)(() => {
setLength(children.length);
}, [children]);
// Pause currently playing media when changing slides
const pauseCurrentMedia = (0, _react.useCallback)(() => {
var _childRefs$current$cu;
if (!((_childRefs$current$cu = childRefs.current[currentIndex]) !== null && _childRefs$current$cu !== void 0 && _childRefs$current$cu.current)) return;
if (childRefs.current[currentIndex].current.localName === "video") {
childRefs.current[currentIndex].current.pause();
}
if ((0, _kwikidToolkit.isNotEmptyValue)(childRefs.current[currentIndex].current.video)) {
childRefs.current[currentIndex].current.video.pause();
}
}, [currentIndex]);
// Navigation functions
const next = (0, _react.useCallback)(() => {
setCurrentIndex(prevIndex => {
pauseCurrentMedia();
return prevIndex < length - 1 ? prevIndex + 1 : prevIndex;
});
}, [length, pauseCurrentMedia]);
const prev = (0, _react.useCallback)(() => {
setCurrentIndex(prevIndex => {
pauseCurrentMedia();
return prevIndex > 0 ? prevIndex - 1 : prevIndex;
});
}, [pauseCurrentMedia]);
const goToSlide = (0, _react.useCallback)(index => {
if (index === currentIndex) return;
pauseCurrentMedia();
setCurrentIndex(index);
}, [currentIndex, pauseCurrentMedia]);
// Handle touch events for swipe navigation
const handleTouchStart = e => {
setTouchStart(e.targetTouches[0].clientX);
};
const handleTouchMove = e => {
setTouchEnd(e.targetTouches[0].clientX);
};
const handleTouchEnd = () => {
if (!touchStart || !touchEnd) return;
const distance = touchStart - touchEnd;
const isSwipe = Math.abs(distance) > MIN_SWIPE_DISTANCE; // Minimum distance for a swipe
if (isSwipe) {
if (distance > 0) {
next();
} else {
prev();
}
}
// Reset touch values
setTouchStart(null);
setTouchEnd(null);
};
// Keyboard navigation
(0, _react.useEffect)(() => {
const handleKeyDown = e => {
if (e.key === "ArrowLeft") {
prev();
} else if (e.key === "ArrowRight") {
next();
}
};
window.addEventListener("keydown", handleKeyDown);
return () => {
window.removeEventListener("keydown", handleKeyDown);
};
}, [next, prev]);
return /*#__PURE__*/_react.default.createElement(_Carousel2.KwikUIStyleCarouselContainer, {
customStyles: customStyles.container,
role: "region",
"aria-label": "Image carousel"
}, /*#__PURE__*/_react.default.createElement(_Carousel2.KwikUIStyleCarouselWrapper, null, /*#__PURE__*/_react.default.createElement(_Carousel2.KwikUIStyleArrowLeft, {
currentIndex: currentIndex,
onClick: prev,
"aria-label": "Previous slide",
role: "button",
tabIndex: 0
}, /*#__PURE__*/_react.default.createElement(_fa.FaAngleLeft, {
size: "1rem"
})), /*#__PURE__*/_react.default.createElement(_Carousel2.KwikUIStyleCarouselContentWrapper, null, /*#__PURE__*/_react.default.createElement(_Carousel2.KwikUIStyleCarouselContent, {
customStyles: customStyles.content,
style: {
transform: "translateX(-".concat(currentIndex * FULL_PERCENTAGE, "%)"),
transition: touchStart ? "none" : "all 0.35s ease-in-out"
},
onTouchStart: handleTouchStart,
onTouchMove: handleTouchMove,
onTouchEnd: handleTouchEnd
}, clonedChildren)), /*#__PURE__*/_react.default.createElement(_Carousel2.KwikUIStyleArrowRight, {
currentIndex: currentIndex,
childrenLength: length,
onClick: next,
"aria-label": "Next slide",
role: "button",
tabIndex: 0
}, /*#__PURE__*/_react.default.createElement(_fa.FaAngleRight, {
size: "1rem"
}))), /*#__PURE__*/_react.default.createElement(_Carousel2.KwikUIStyleCarouselControlsContainer, null, (indicators === null || indicators === void 0 ? void 0 : indicators.isActive) && /*#__PURE__*/_react.default.createElement(_Carousel2.KwikUIStyleCarouselIndicatorsDiv, {
role: "group",
"aria-label": "Slide indicators"
}, indicators !== null && indicators !== void 0 && indicators.showAllIndicators ? slicedChildren.map((_, i) => /*#__PURE__*/_react.default.createElement(_Carousel2.KwikUIStyleCarouselIndicatorsIcons, {
key: "indicator-".concat(i),
isActive: i === currentIndex,
onClick: () => goToSlide(i),
role: "button",
tabIndex: 0,
"aria-label": "Go to slide ".concat(i + 1),
"aria-current": i === currentIndex ? "true" : "false"
})) : slicedChildren.map((_, i) => {
const indicatorIndex = Math.max(currentIndex - Math.floor(indicators.maxVisibleIndicators / HALF_DIVISOR), 0) + i;
return /*#__PURE__*/_react.default.createElement(_Carousel2.KwikUIStyleCarouselIndicatorsIcons, {
key: "indicator-".concat(indicatorIndex),
isActive: indicatorIndex === currentIndex,
onClick: () => goToSlide(indicatorIndex),
role: "button",
tabIndex: 0,
"aria-label": "Go to slide ".concat(indicatorIndex + 1),
"aria-current": indicatorIndex === currentIndex ? "true" : "false"
});
})), /*#__PURE__*/_react.default.createElement(_Carousel2.KwikUIStyleSlideCounter, {
"aria-live": "polite"
}, currentIndex + 1, " / ", length)));
};
var _default = exports.default = KwikUICarousel;