UNPKG

kwikid-components-react

Version:

KwikID's Component Library in React

185 lines (174 loc) 8.1 kB
"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;