UNPKG

12.6 kBJavaScriptView Raw
1/**
2 * Swiper React 11.1.1
3 * Most modern mobile touch slider and framework with hardware accelerated transitions
4 * https://swiperjs.com
5 *
6 * Copyright 2014-2024 Vladimir Kharlampidi
7 *
8 * Released under the MIT License
9 *
10 * Released on: April 9, 2024
11 */
12
13import React, { useEffect, useLayoutEffect, useContext, createContext, forwardRef, useState, useRef } from 'react';
14import { S as Swiper$1 } from './shared/swiper-core.mjs';
15import { g as getParams, m as mountSwiper, a as getChangedParams, u as updateOnVirtualData } from './shared/update-on-virtual-data.mjs';
16import { d as uniqueClasses, w as wrapperClass, n as needsNavigation, b as needsScrollbar, a as needsPagination, e as extend, u as updateSwiper } from './shared/update-swiper.mjs';
17
18function _extends() {
19 _extends = Object.assign ? Object.assign.bind() : function (target) {
20 for (var i = 1; i < arguments.length; i++) {
21 var source = arguments[i];
22 for (var key in source) {
23 if (Object.prototype.hasOwnProperty.call(source, key)) {
24 target[key] = source[key];
25 }
26 }
27 }
28 return target;
29 };
30 return _extends.apply(this, arguments);
31}
32
33function isChildSwiperSlide(child) {
34 return child.type && child.type.displayName && child.type.displayName.includes('SwiperSlide');
35}
36function processChildren(c) {
37 const slides = [];
38 React.Children.toArray(c).forEach(child => {
39 if (isChildSwiperSlide(child)) {
40 slides.push(child);
41 } else if (child.props && child.props.children) {
42 processChildren(child.props.children).forEach(slide => slides.push(slide));
43 }
44 });
45 return slides;
46}
47function getChildren(c) {
48 const slides = [];
49 const slots = {
50 'container-start': [],
51 'container-end': [],
52 'wrapper-start': [],
53 'wrapper-end': []
54 };
55 React.Children.toArray(c).forEach(child => {
56 if (isChildSwiperSlide(child)) {
57 slides.push(child);
58 } else if (child.props && child.props.slot && slots[child.props.slot]) {
59 slots[child.props.slot].push(child);
60 } else if (child.props && child.props.children) {
61 const foundSlides = processChildren(child.props.children);
62 if (foundSlides.length > 0) {
63 foundSlides.forEach(slide => slides.push(slide));
64 } else {
65 slots['container-end'].push(child);
66 }
67 } else {
68 slots['container-end'].push(child);
69 }
70 });
71 return {
72 slides,
73 slots
74 };
75}
76
77function renderVirtual(swiper, slides, virtualData) {
78 if (!virtualData) return null;
79 const getSlideIndex = index => {
80 let slideIndex = index;
81 if (index < 0) {
82 slideIndex = slides.length + index;
83 } else if (slideIndex >= slides.length) {
84 // eslint-disable-next-line
85 slideIndex = slideIndex - slides.length;
86 }
87 return slideIndex;
88 };
89 const style = swiper.isHorizontal() ? {
90 [swiper.rtlTranslate ? 'right' : 'left']: `${virtualData.offset}px`
91 } : {
92 top: `${virtualData.offset}px`
93 };
94 const {
95 from,
96 to
97 } = virtualData;
98 const loopFrom = swiper.params.loop ? -slides.length : 0;
99 const loopTo = swiper.params.loop ? slides.length * 2 : slides.length;
100 const slidesToRender = [];
101 for (let i = loopFrom; i < loopTo; i += 1) {
102 if (i >= from && i <= to) {
103 slidesToRender.push(slides[getSlideIndex(i)]);
104 }
105 }
106 return slidesToRender.map((child, index) => {
107 return /*#__PURE__*/React.cloneElement(child, {
108 swiper,
109 style,
110 key: child.props.virtualIndex || child.key || `slide-${index}`
111 });
112 });
113}
114
115function useIsomorphicLayoutEffect(callback, deps) {
116 // eslint-disable-next-line
117 if (typeof window === 'undefined') return useEffect(callback, deps);
118 return useLayoutEffect(callback, deps);
119}
120
121const SwiperSlideContext = /*#__PURE__*/createContext(null);
122const useSwiperSlide = () => {
123 return useContext(SwiperSlideContext);
124};
125const SwiperContext = /*#__PURE__*/createContext(null);
126const useSwiper = () => {
127 return useContext(SwiperContext);
128};
129
130const Swiper = /*#__PURE__*/forwardRef(function (_temp, externalElRef) {
131 let {
132 className,
133 tag: Tag = 'div',
134 wrapperTag: WrapperTag = 'div',
135 children,
136 onSwiper,
137 ...rest
138 } = _temp === void 0 ? {} : _temp;
139 let eventsAssigned = false;
140 const [containerClasses, setContainerClasses] = useState('swiper');
141 const [virtualData, setVirtualData] = useState(null);
142 const [breakpointChanged, setBreakpointChanged] = useState(false);
143 const initializedRef = useRef(false);
144 const swiperElRef = useRef(null);
145 const swiperRef = useRef(null);
146 const oldPassedParamsRef = useRef(null);
147 const oldSlides = useRef(null);
148 const nextElRef = useRef(null);
149 const prevElRef = useRef(null);
150 const paginationElRef = useRef(null);
151 const scrollbarElRef = useRef(null);
152 const {
153 params: swiperParams,
154 passedParams,
155 rest: restProps,
156 events
157 } = getParams(rest);
158 const {
159 slides,
160 slots
161 } = getChildren(children);
162 const onBeforeBreakpoint = () => {
163 setBreakpointChanged(!breakpointChanged);
164 };
165 Object.assign(swiperParams.on, {
166 _containerClasses(swiper, classes) {
167 setContainerClasses(classes);
168 }
169 });
170 const initSwiper = () => {
171 // init swiper
172 Object.assign(swiperParams.on, events);
173 eventsAssigned = true;
174 const passParams = {
175 ...swiperParams
176 };
177 delete passParams.wrapperClass;
178 swiperRef.current = new Swiper$1(passParams);
179 if (swiperRef.current.virtual && swiperRef.current.params.virtual.enabled) {
180 swiperRef.current.virtual.slides = slides;
181 const extendWith = {
182 cache: false,
183 slides,
184 renderExternal: setVirtualData,
185 renderExternalUpdate: false
186 };
187 extend(swiperRef.current.params.virtual, extendWith);
188 extend(swiperRef.current.originalParams.virtual, extendWith);
189 }
190 };
191 if (!swiperElRef.current) {
192 initSwiper();
193 }
194
195 // Listen for breakpoints change
196 if (swiperRef.current) {
197 swiperRef.current.on('_beforeBreakpoint', onBeforeBreakpoint);
198 }
199 const attachEvents = () => {
200 if (eventsAssigned || !events || !swiperRef.current) return;
201 Object.keys(events).forEach(eventName => {
202 swiperRef.current.on(eventName, events[eventName]);
203 });
204 };
205 const detachEvents = () => {
206 if (!events || !swiperRef.current) return;
207 Object.keys(events).forEach(eventName => {
208 swiperRef.current.off(eventName, events[eventName]);
209 });
210 };
211 useEffect(() => {
212 return () => {
213 if (swiperRef.current) swiperRef.current.off('_beforeBreakpoint', onBeforeBreakpoint);
214 };
215 });
216
217 // set initialized flag
218 useEffect(() => {
219 if (!initializedRef.current && swiperRef.current) {
220 swiperRef.current.emitSlidesClasses();
221 initializedRef.current = true;
222 }
223 });
224
225 // mount swiper
226 useIsomorphicLayoutEffect(() => {
227 if (externalElRef) {
228 externalElRef.current = swiperElRef.current;
229 }
230 if (!swiperElRef.current) return;
231 if (swiperRef.current.destroyed) {
232 initSwiper();
233 }
234 mountSwiper({
235 el: swiperElRef.current,
236 nextEl: nextElRef.current,
237 prevEl: prevElRef.current,
238 paginationEl: paginationElRef.current,
239 scrollbarEl: scrollbarElRef.current,
240 swiper: swiperRef.current
241 }, swiperParams);
242 if (onSwiper && !swiperRef.current.destroyed) onSwiper(swiperRef.current);
243 // eslint-disable-next-line
244 return () => {
245 if (swiperRef.current && !swiperRef.current.destroyed) {
246 swiperRef.current.destroy(true, false);
247 }
248 };
249 }, []);
250
251 // watch for params change
252 useIsomorphicLayoutEffect(() => {
253 attachEvents();
254 const changedParams = getChangedParams(passedParams, oldPassedParamsRef.current, slides, oldSlides.current, c => c.key);
255 oldPassedParamsRef.current = passedParams;
256 oldSlides.current = slides;
257 if (changedParams.length && swiperRef.current && !swiperRef.current.destroyed) {
258 updateSwiper({
259 swiper: swiperRef.current,
260 slides,
261 passedParams,
262 changedParams,
263 nextEl: nextElRef.current,
264 prevEl: prevElRef.current,
265 scrollbarEl: scrollbarElRef.current,
266 paginationEl: paginationElRef.current
267 });
268 }
269 return () => {
270 detachEvents();
271 };
272 });
273
274 // update on virtual update
275 useIsomorphicLayoutEffect(() => {
276 updateOnVirtualData(swiperRef.current);
277 }, [virtualData]);
278
279 // bypass swiper instance to slides
280 function renderSlides() {
281 if (swiperParams.virtual) {
282 return renderVirtual(swiperRef.current, slides, virtualData);
283 }
284 return slides.map((child, index) => {
285 return /*#__PURE__*/React.cloneElement(child, {
286 swiper: swiperRef.current,
287 swiperSlideIndex: index
288 });
289 });
290 }
291 return /*#__PURE__*/React.createElement(Tag, _extends({
292 ref: swiperElRef,
293 className: uniqueClasses(`${containerClasses}${className ? ` ${className}` : ''}`)
294 }, restProps), /*#__PURE__*/React.createElement(SwiperContext.Provider, {
295 value: swiperRef.current
296 }, slots['container-start'], /*#__PURE__*/React.createElement(WrapperTag, {
297 className: wrapperClass(swiperParams.wrapperClass)
298 }, slots['wrapper-start'], renderSlides(), slots['wrapper-end']), needsNavigation(swiperParams) && /*#__PURE__*/React.createElement(React.Fragment, null, /*#__PURE__*/React.createElement("div", {
299 ref: prevElRef,
300 className: "swiper-button-prev"
301 }), /*#__PURE__*/React.createElement("div", {
302 ref: nextElRef,
303 className: "swiper-button-next"
304 })), needsScrollbar(swiperParams) && /*#__PURE__*/React.createElement("div", {
305 ref: scrollbarElRef,
306 className: "swiper-scrollbar"
307 }), needsPagination(swiperParams) && /*#__PURE__*/React.createElement("div", {
308 ref: paginationElRef,
309 className: "swiper-pagination"
310 }), slots['container-end']));
311});
312Swiper.displayName = 'Swiper';
313
314const SwiperSlide = /*#__PURE__*/forwardRef(function (_temp, externalRef) {
315 let {
316 tag: Tag = 'div',
317 children,
318 className = '',
319 swiper,
320 zoom,
321 lazy,
322 virtualIndex,
323 swiperSlideIndex,
324 ...rest
325 } = _temp === void 0 ? {} : _temp;
326 const slideElRef = useRef(null);
327 const [slideClasses, setSlideClasses] = useState('swiper-slide');
328 const [lazyLoaded, setLazyLoaded] = useState(false);
329 function updateClasses(_s, el, classNames) {
330 if (el === slideElRef.current) {
331 setSlideClasses(classNames);
332 }
333 }
334 useIsomorphicLayoutEffect(() => {
335 if (typeof swiperSlideIndex !== 'undefined') {
336 slideElRef.current.swiperSlideIndex = swiperSlideIndex;
337 }
338 if (externalRef) {
339 externalRef.current = slideElRef.current;
340 }
341 if (!slideElRef.current || !swiper) {
342 return;
343 }
344 if (swiper.destroyed) {
345 if (slideClasses !== 'swiper-slide') {
346 setSlideClasses('swiper-slide');
347 }
348 return;
349 }
350 swiper.on('_slideClass', updateClasses);
351 // eslint-disable-next-line
352 return () => {
353 if (!swiper) return;
354 swiper.off('_slideClass', updateClasses);
355 };
356 });
357 useIsomorphicLayoutEffect(() => {
358 if (swiper && slideElRef.current && !swiper.destroyed) {
359 setSlideClasses(swiper.getSlideClasses(slideElRef.current));
360 }
361 }, [swiper]);
362 const slideData = {
363 isActive: slideClasses.indexOf('swiper-slide-active') >= 0,
364 isVisible: slideClasses.indexOf('swiper-slide-visible') >= 0,
365 isPrev: slideClasses.indexOf('swiper-slide-prev') >= 0,
366 isNext: slideClasses.indexOf('swiper-slide-next') >= 0
367 };
368 const renderChildren = () => {
369 return typeof children === 'function' ? children(slideData) : children;
370 };
371 const onLoad = () => {
372 setLazyLoaded(true);
373 };
374 return /*#__PURE__*/React.createElement(Tag, _extends({
375 ref: slideElRef,
376 className: uniqueClasses(`${slideClasses}${className ? ` ${className}` : ''}`),
377 "data-swiper-slide-index": virtualIndex,
378 onLoad: onLoad
379 }, rest), zoom && /*#__PURE__*/React.createElement(SwiperSlideContext.Provider, {
380 value: slideData
381 }, /*#__PURE__*/React.createElement("div", {
382 className: "swiper-zoom-container",
383 "data-swiper-zoom": typeof zoom === 'number' ? zoom : undefined
384 }, renderChildren(), lazy && !lazyLoaded && /*#__PURE__*/React.createElement("div", {
385 className: "swiper-lazy-preloader"
386 }))), !zoom && /*#__PURE__*/React.createElement(SwiperSlideContext.Provider, {
387 value: slideData
388 }, renderChildren(), lazy && !lazyLoaded && /*#__PURE__*/React.createElement("div", {
389 className: "swiper-lazy-preloader"
390 })));
391});
392SwiperSlide.displayName = 'SwiperSlide';
393
394export { Swiper, SwiperSlide, useSwiper, useSwiperSlide };