swiper-react.mjs 12 KB

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