@gem-sdk/swiper 0.0.7 → 0.0.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. package/modules/a11y.min.mjs +1 -1
  2. package/modules/a11y.mjs +1 -1
  3. package/modules/pagination.min.mjs +1 -1
  4. package/modules/pagination.min.mjs.map +1 -1
  5. package/modules/pagination.mjs +20 -16
  6. package/package.json +3 -3
  7. package/shared/swiper-core.min.mjs +1 -1
  8. package/shared/swiper-core.min.mjs.map +1 -1
  9. package/shared/swiper-core.mjs +425 -52
  10. package/shared/update-swiper.min.mjs +1 -1
  11. package/shared/update-swiper.min.mjs.map +1 -1
  12. package/shared/update-swiper.mjs +1 -1
  13. package/shared/utils.min.mjs +1 -1
  14. package/shared/utils.min.mjs.map +1 -1
  15. package/shared/utils.mjs +1 -1
  16. package/swiper-bundle.css +2 -2
  17. package/swiper-bundle.js +448 -71
  18. package/swiper-bundle.min.css +2 -2
  19. package/swiper-bundle.min.js +3 -3
  20. package/swiper-bundle.min.js.map +1 -1
  21. package/swiper-bundle.min.mjs +2 -2
  22. package/swiper-bundle.mjs +2 -2
  23. package/swiper-effect-utils.min.mjs +2 -2
  24. package/swiper-effect-utils.mjs +2 -2
  25. package/swiper-element-bundle.js +451 -74
  26. package/swiper-element-bundle.min.js +3 -3
  27. package/swiper-element-bundle.min.js.map +1 -1
  28. package/swiper-element-bundle.min.mjs +2 -2
  29. package/swiper-element-bundle.mjs +2 -2
  30. package/swiper-element.d.ts +5 -0
  31. package/swiper-element.js +429 -56
  32. package/swiper-element.min.js +3 -3
  33. package/swiper-element.min.js.map +1 -1
  34. package/swiper-element.min.mjs +2 -2
  35. package/swiper-element.mjs +2 -2
  36. package/swiper-react.d.ts +5 -0
  37. package/swiper-react.mjs +2 -2
  38. package/swiper-vue.d.ts +9 -0
  39. package/swiper-vue.mjs +7 -3
  40. package/swiper.css +2 -2
  41. package/swiper.js +426 -53
  42. package/swiper.less +2 -2
  43. package/swiper.min.css +2 -2
  44. package/swiper.min.js +3 -3
  45. package/swiper.min.js.map +1 -1
  46. package/swiper.min.mjs +2 -2
  47. package/swiper.mjs +2 -2
  48. package/swiper.scss +2 -2
  49. package/types/swiper-class.d.ts +10 -0
  50. package/types/swiper-events.d.ts +5 -0
  51. package/types/swiper-options.d.ts +7 -0
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Swiper Custom Element 0.0.7
2
+ * Swiper Custom Element 0.0.9
3
3
  * Gem SDK - Swiper, Customized of swiper
4
4
  * https://swiperjs.com
5
5
  *
@@ -7,7 +7,7 @@
7
7
  *
8
8
  * Released under the MIT License
9
9
  *
10
- * Released on: October 9, 2025
10
+ * Released on: December 8, 2025
11
11
  */
12
12
 
13
13
  (function () {
@@ -2038,56 +2038,63 @@
2038
2038
  if (typeof speed === 'undefined') {
2039
2039
  speed = swiper.params.speed;
2040
2040
  }
2041
- const gridEnabled = swiper.grid && swiper.params.grid && swiper.params.grid.rows > 1;
2042
2041
  let newIndex = index;
2043
2042
  if (swiper.params.loop) {
2044
- if (swiper.virtual && swiper.params.virtual.enabled) {
2045
- // eslint-disable-next-line
2046
- newIndex = newIndex + swiper.virtual.slidesBefore;
2043
+ swiper.slides;
2044
+ const totalSlides = swiper.slides.length;
2045
+ let targetSlideIndex;
2046
+ targetSlideIndex = swiper.getSlideIndexByData(newIndex);
2047
+ const cols = swiper.slides.length;
2048
+ const {
2049
+ centeredSlides
2050
+ } = swiper.params;
2051
+ let slidesPerView = swiper.params.slidesPerView;
2052
+ if (slidesPerView === 'auto') {
2053
+ slidesPerView = swiper.slidesPerViewDynamic();
2047
2054
  } else {
2048
- let targetSlideIndex;
2049
- if (gridEnabled) {
2050
- const slideIndex = newIndex * swiper.params.grid.rows;
2051
- targetSlideIndex = swiper.slides.find(slideEl => slideEl.getAttribute('data-swiper-slide-index') * 1 === slideIndex).column;
2052
- } else {
2053
- targetSlideIndex = swiper.getSlideIndexByData(newIndex);
2054
- }
2055
- const cols = gridEnabled ? Math.ceil(swiper.slides.length / swiper.params.grid.rows) : swiper.slides.length;
2056
- const {
2057
- centeredSlides
2058
- } = swiper.params;
2059
- let slidesPerView = swiper.params.slidesPerView;
2060
- if (slidesPerView === 'auto') {
2061
- slidesPerView = swiper.slidesPerViewDynamic();
2062
- } else {
2063
- slidesPerView = Math.ceil(parseFloat(swiper.params.slidesPerView, 10));
2064
- if (centeredSlides && slidesPerView % 2 === 0) {
2065
- slidesPerView = slidesPerView + 1;
2066
- }
2067
- }
2068
- let needLoopFix = cols - targetSlideIndex < slidesPerView;
2069
- if (centeredSlides) {
2070
- needLoopFix = needLoopFix || targetSlideIndex < Math.ceil(slidesPerView / 2);
2071
- }
2072
- if (internal && centeredSlides && swiper.params.slidesPerView !== 'auto' && !gridEnabled) {
2073
- needLoopFix = false;
2074
- }
2075
- if (needLoopFix) {
2076
- const direction = centeredSlides ? targetSlideIndex < swiper.activeIndex ? 'prev' : 'next' : targetSlideIndex - swiper.activeIndex - 1 < swiper.params.slidesPerView ? 'next' : 'prev';
2077
- swiper.loopFix({
2078
- direction,
2079
- slideTo: true,
2080
- activeSlideIndex: direction === 'next' ? targetSlideIndex + 1 : targetSlideIndex - cols + 1,
2081
- slideRealIndex: direction === 'next' ? swiper.realIndex : undefined
2082
- });
2055
+ slidesPerView = Math.ceil(parseFloat(swiper.params.slidesPerView, 10));
2056
+ if (centeredSlides && slidesPerView % 2 === 0) {
2057
+ slidesPerView = slidesPerView + 1;
2083
2058
  }
2084
- if (gridEnabled) {
2085
- const slideIndex = newIndex * swiper.params.grid.rows;
2086
- newIndex = swiper.slides.find(slideEl => slideEl.getAttribute('data-swiper-slide-index') * 1 === slideIndex).column;
2059
+ }
2060
+ let needLoopFix = cols - targetSlideIndex < slidesPerView;
2061
+ if (centeredSlides) {
2062
+ needLoopFix = needLoopFix || targetSlideIndex < Math.ceil(slidesPerView / 2);
2063
+ }
2064
+ if (internal && centeredSlides && swiper.params.slidesPerView !== 'auto') {
2065
+ needLoopFix = false;
2066
+ }
2067
+ if (centeredSlides && needLoopFix) {
2068
+ const direction = centeredSlides ? targetSlideIndex < swiper.activeIndex ? 'prev' : 'next' : targetSlideIndex - swiper.activeIndex - 1 < swiper.params.slidesPerView ? 'next' : 'prev';
2069
+ swiper.loopFix({
2070
+ direction,
2071
+ slideTo: true,
2072
+ activeSlideIndex: direction === 'next' ? targetSlideIndex + 1 : targetSlideIndex - cols + 1,
2073
+ slideRealIndex: direction === 'next' ? swiper.realIndex : undefined
2074
+ });
2075
+ }
2076
+ if (!centeredSlides && needLoopFix) {
2077
+ let direction;
2078
+ let nextSteps;
2079
+ let prevSteps;
2080
+ if (swiper.activeIndex < targetSlideIndex) {
2081
+ nextSteps = targetSlideIndex - swiper.activeIndex;
2082
+ prevSteps = swiper.activeIndex - (targetSlideIndex - totalSlides);
2087
2083
  } else {
2088
- newIndex = swiper.getSlideIndexByData(newIndex);
2089
- }
2084
+ prevSteps = swiper.activeIndex - targetSlideIndex;
2085
+ nextSteps = targetSlideIndex + totalSlides - swiper.activeIndex;
2086
+ }
2087
+ direction = nextSteps > prevSteps ? 'prev' : 'next';
2088
+ swiper.loopFixDot({
2089
+ direction,
2090
+ slideTo: true,
2091
+ activeSlideIndex: direction === 'next' ? targetSlideIndex + 1 : targetSlideIndex - cols + 1,
2092
+ slideRealIndex: direction === 'next' ? swiper.realIndex : undefined,
2093
+ targetSlideIndex,
2094
+ newIndex: swiper.getSlideIndexByData(newIndex)
2095
+ });
2090
2096
  }
2097
+ newIndex = swiper.getSlideIndexByData(newIndex);
2091
2098
  }
2092
2099
  requestAnimationFrame(() => {
2093
2100
  swiper.slideTo(newIndex, speed, runCallbacks, internal);
@@ -2095,6 +2102,87 @@
2095
2102
  return swiper;
2096
2103
  }
2097
2104
 
2105
+ function slideToLoopCenterSneakPeek(index, speed, runCallbacks, internal) {
2106
+ if (index === void 0) {
2107
+ index = 0;
2108
+ }
2109
+ if (runCallbacks === void 0) {
2110
+ runCallbacks = true;
2111
+ }
2112
+ if (typeof index === 'string') {
2113
+ const indexAsNumber = parseInt(index, 10);
2114
+ index = indexAsNumber;
2115
+ }
2116
+ const swiper = this;
2117
+ if (swiper.destroyed) return;
2118
+ if (typeof speed === 'undefined') {
2119
+ speed = swiper.params.speed;
2120
+ }
2121
+ let newIndex = index;
2122
+ if (swiper.params.loop) {
2123
+ swiper.slides;
2124
+ const totalSlides = swiper.slides.length;
2125
+ let targetSlideIndex;
2126
+ targetSlideIndex = swiper.getSlideIndexByData(newIndex);
2127
+ const cols = swiper.slides.length;
2128
+ const {
2129
+ centeredSlides
2130
+ } = swiper.params;
2131
+ let slidesPerView = swiper.params.slidesPerView;
2132
+ if (slidesPerView === 'auto') {
2133
+ slidesPerView = swiper.slidesPerViewDynamic();
2134
+ } else {
2135
+ slidesPerView = Math.ceil(parseFloat(swiper.params.slidesPerView, 10));
2136
+ if (centeredSlides && slidesPerView % 2 === 0) {
2137
+ slidesPerView = slidesPerView + 1;
2138
+ }
2139
+ }
2140
+ if (internal && centeredSlides && swiper.params.slidesPerView !== 'auto') ;
2141
+ const isSneakPeekCenter = swiper.params?.isSneakPeekCenter;
2142
+ if (isSneakPeekCenter) {
2143
+ let direction;
2144
+ let nextSteps;
2145
+ let prevSteps;
2146
+ if (swiper.activeIndex < targetSlideIndex) {
2147
+ nextSteps = targetSlideIndex - swiper.activeIndex;
2148
+ prevSteps = swiper.activeIndex - (targetSlideIndex - totalSlides);
2149
+ } else {
2150
+ prevSteps = swiper.activeIndex - targetSlideIndex;
2151
+ nextSteps = targetSlideIndex + totalSlides - swiper.activeIndex;
2152
+ }
2153
+ direction = nextSteps > prevSteps ? 'prev' : 'next';
2154
+ swiper.loopFixDot({
2155
+ direction,
2156
+ slideTo: true,
2157
+ activeSlideIndex: direction === 'next' ? targetSlideIndex + 1 : targetSlideIndex - cols + 1,
2158
+ slideRealIndex: direction === 'next' ? swiper.realIndex : undefined,
2159
+ targetSlideIndex,
2160
+ newIndex: swiper.getSlideIndexByData(newIndex)
2161
+ });
2162
+ }
2163
+ newIndex = swiper.getSlideIndexByData(newIndex);
2164
+ }
2165
+ swiper.slideTo(newIndex, speed, runCallbacks, internal);
2166
+ const slides = swiper.slides;
2167
+ if (swiper.params?.isSneakPeekCenter && slides.length > 1 && swiper.activeIndex === 0) {
2168
+ const gap = Math.abs(swiper.snapGrid[1] - swiper.snapGrid[0]);
2169
+ const swiperTranslate = JSON.parse(JSON.stringify(swiper.snapGrid[1]));
2170
+
2171
+ // Move last item to first position only if active slide is the first slide
2172
+ const lastSlide = slides[slides.length - 1];
2173
+ lastSlide.swiperLoopMoveDOM = true;
2174
+ swiper.slidesEl.prepend(lastSlide);
2175
+ lastSlide.swiperLoopMoveDOM = false;
2176
+ swiper.setTransition(0);
2177
+ swiper.setTranslate(-(swiperTranslate + gap));
2178
+ swiper.recalcSlides();
2179
+ swiper.updateSlides();
2180
+ swiper.setTransition(swiper.params.speed);
2181
+ swiper.setTranslate(-swiperTranslate);
2182
+ }
2183
+ return;
2184
+ }
2185
+
2098
2186
  /* eslint no-unused-vars: "off" */
2099
2187
  function slideNext(speed, runCallbacks, internal) {
2100
2188
  if (runCallbacks === void 0) {
@@ -2119,7 +2207,7 @@
2119
2207
  if (params.loop) {
2120
2208
  if (animating && !isVirtual && params.loopPreventsSliding) return false;
2121
2209
 
2122
- // Check if loop is disabled
2210
+ // Kiểm tra xem loop bị disable không
2123
2211
  const currentSlidesPerView = params.slidesPerView === 'auto' ? swiper.slidesPerViewDynamic() : Math.ceil(parseFloat(params.slidesPerView, 10));
2124
2212
  if (swiper.slides.length >= currentSlidesPerView) {
2125
2213
  swiper.loopFix({
@@ -2138,7 +2226,27 @@
2138
2226
  if (params.rewind && swiper.isEnd) {
2139
2227
  return swiper.slideTo(0, speed, runCallbacks, internal);
2140
2228
  }
2141
- return swiper.slideTo(swiper.activeIndex + increment, speed, runCallbacks, internal);
2229
+ requestAnimationFrame(() => {
2230
+ swiper.slideTo(swiper.activeIndex + increment, speed, runCallbacks, internal);
2231
+ const slides = swiper.slides;
2232
+ if (swiper.params?.isSneakPeekCenter && slides.length > 1 && (swiper.activeIndex === slides.length - 1 || swiper.isEnd)) {
2233
+ const lastSnapGridIndex = swiper.snapGrid.length - 1;
2234
+ const gap = Math.abs(swiper.snapGrid[lastSnapGridIndex] - swiper.snapGrid[lastSnapGridIndex - 1]);
2235
+ const swiperTranslate = structuredClone(swiper.snapGrid[lastSnapGridIndex - 1]);
2236
+
2237
+ // Move first item to last position only if active slide is the last slide
2238
+ const firstSlide = slides[0];
2239
+ firstSlide.swiperLoopMoveDOM = true;
2240
+ swiper.slidesEl.append(firstSlide);
2241
+ firstSlide.swiperLoopMoveDOM = false;
2242
+ swiper.setTransition(0);
2243
+ swiper.setTranslate(-(swiperTranslate - gap));
2244
+ swiper.recalcSlides();
2245
+ swiper.updateSlides();
2246
+ swiper.setTransition(swiper.params.speed);
2247
+ swiper.setTranslate(-swiperTranslate);
2248
+ }
2249
+ });
2142
2250
  }
2143
2251
 
2144
2252
  /* eslint no-unused-vars: "off" */
@@ -2159,11 +2267,9 @@
2159
2267
  if (typeof speed === 'undefined') {
2160
2268
  speed = swiper.params.speed;
2161
2269
  }
2162
- const isVirtual = swiper.virtual && params.virtual.enabled;
2270
+ swiper.virtual && params.virtual.enabled;
2163
2271
  if (params.loop) {
2164
- if (animating && !isVirtual && params.loopPreventsSliding) return false;
2165
-
2166
- // Check if loop is disabled
2272
+ // Kiểm tra xem loop bị disable không
2167
2273
  const currentSlidesPerView = params.slidesPerView === 'auto' ? swiper.slidesPerViewDynamic() : Math.ceil(parseFloat(params.slidesPerView, 10));
2168
2274
  if (swiper.slides.length >= currentSlidesPerView) {
2169
2275
  swiper.loopFix({
@@ -2212,7 +2318,27 @@
2212
2318
  });
2213
2319
  return true;
2214
2320
  }
2215
- return swiper.slideTo(prevIndex, speed, runCallbacks, internal);
2321
+ requestAnimationFrame(() => {
2322
+ swiper.slideTo(prevIndex, speed, runCallbacks, internal);
2323
+ const slides = swiper.slides;
2324
+ if (swiper.params?.isSneakPeekCenter && slides.length > 1 && swiper.activeIndex === 0) {
2325
+ const gap = Math.abs(swiper.snapGrid[1] - swiper.snapGrid[0]);
2326
+ const swiperTranslate = JSON.parse(JSON.stringify(swiper.snapGrid[1]));
2327
+
2328
+ // Move last item to first position only if active slide is the first slide
2329
+ const lastSlide = slides[slides.length - 1];
2330
+ lastSlide.swiperLoopMoveDOM = true;
2331
+ swiper.slidesEl.prepend(lastSlide);
2332
+ lastSlide.swiperLoopMoveDOM = false;
2333
+ swiper.setTransition(0);
2334
+ swiper.setTranslate(-(swiperTranslate + gap));
2335
+ swiper.recalcSlides();
2336
+ swiper.updateSlides();
2337
+ swiper.setTransition(swiper.params.speed);
2338
+ swiper.setTranslate(-swiperTranslate);
2339
+ }
2340
+ });
2341
+ return;
2216
2342
  }
2217
2343
 
2218
2344
  /* eslint no-unused-vars: "off" */
@@ -2301,6 +2427,7 @@
2301
2427
  var slide = {
2302
2428
  slideTo,
2303
2429
  slideToLoop,
2430
+ slideToLoopCenterSneakPeek,
2304
2431
  slideNext,
2305
2432
  slidePrev,
2306
2433
  slideReset,
@@ -2388,7 +2515,7 @@
2388
2515
  const swiper = this;
2389
2516
  if (!swiper.params.loop) return;
2390
2517
 
2391
- // Disable loop mode if the number of slides is less than slidesPerView
2518
+ // Disable loop mode nếu số slides ít hơn slidesPerView
2392
2519
  const currentSlidesPerView = swiper.params.slidesPerView === 'auto' ? swiper.slidesPerViewDynamic() : Math.ceil(parseFloat(swiper.params.slidesPerView, 10));
2393
2520
  if (swiper.slides.length < currentSlidesPerView) {
2394
2521
  console.warn('Swiper: Loop mode disabled - slides.length < slidesPerView');
@@ -2600,6 +2727,206 @@
2600
2727
  swiper.emit('loopFix');
2601
2728
  }
2602
2729
 
2730
+ function loopFixDot(_temp) {
2731
+ let {
2732
+ slideRealIndex,
2733
+ slideTo = true,
2734
+ direction,
2735
+ activeSlideIndex,
2736
+ initial,
2737
+ targetSlideIndex,
2738
+ newIndex
2739
+ } = _temp === void 0 ? {} : _temp;
2740
+ const swiper = this;
2741
+ if (!swiper.params.loop) return;
2742
+
2743
+ // Disable loop mode nếu số slides ít hơn slidesPerView
2744
+ const currentSlidesPerView = swiper.params.slidesPerView === 'auto' ? swiper.slidesPerViewDynamic() : Math.ceil(parseFloat(swiper.params.slidesPerView, 10));
2745
+ if (swiper.slides.length < currentSlidesPerView) {
2746
+ console.warn('Swiper: Loop mode disabled - slides.length < slidesPerView');
2747
+ return;
2748
+ }
2749
+ swiper.emit('beforeLoopFix');
2750
+ const {
2751
+ slides,
2752
+ allowSlidePrev,
2753
+ allowSlideNext,
2754
+ slidesEl,
2755
+ params
2756
+ } = swiper;
2757
+ const targetData = slidesEl.children[targetSlideIndex].getAttribute('data-swiper-slide-index');
2758
+ const oldActiveData = Array.from(slidesEl.children).find(el => el.classList.contains(params.slideActiveClass)).getAttribute('data-swiper-slide-index');
2759
+ const {
2760
+ centeredSlides,
2761
+ initialSlide
2762
+ } = params;
2763
+ const swiperDataOldActiveIndex = slidesEl.children[swiper.activeIndex].getAttribute('data-swiper-slide-index');
2764
+ swiper.allowSlidePrev = true;
2765
+ swiper.allowSlideNext = true;
2766
+ let slidesPerView = params.slidesPerView;
2767
+ if (slidesPerView === 'auto') {
2768
+ slidesPerView = swiper.slidesPerViewDynamic();
2769
+ } else {
2770
+ slidesPerView = Math.ceil(parseFloat(params.slidesPerView, 10));
2771
+ if (centeredSlides && slidesPerView % 2 === 0) {
2772
+ slidesPerView = slidesPerView + 1;
2773
+ }
2774
+ }
2775
+ const slidesPerGroup = params.slidesPerGroupAuto ? slidesPerView : params.slidesPerGroup;
2776
+ let loopedSlides = centeredSlides ? Math.max(slidesPerGroup, Math.ceil(slidesPerView / 2)) : slidesPerGroup;
2777
+ if (loopedSlides % slidesPerGroup !== 0) {
2778
+ loopedSlides += slidesPerGroup - loopedSlides % slidesPerGroup;
2779
+ }
2780
+ loopedSlides += params.loopAdditionalSlides;
2781
+ swiper.loopedSlides = loopedSlides;
2782
+ if (slides.length < slidesPerView + loopedSlides || swiper.params.effect === 'cards' && slides.length < slidesPerView + loopedSlides * 2) {
2783
+ showWarning('Swiper Loop Warning: The number of slides is not enough for loop mode, it will be disabled or not function properly. You need to add more slides (or make duplicates) or lower the values of slidesPerView and slidesPerGroup parameters');
2784
+ }
2785
+ const isNext = direction === 'next' || !direction;
2786
+ const isPrev = direction === 'prev' || !direction;
2787
+ let numberOfSlidesNeedClone = [];
2788
+ let slidesIndex = [];
2789
+ for (let i = 0; i < slidesEl.children.length; i++) {
2790
+ slidesIndex.push(slidesEl.children[i].getAttribute('data-swiper-slide-index'));
2791
+ }
2792
+ if (isPrev) {
2793
+ for (let i = targetSlideIndex; i < slidesEl.children.length; i++) {
2794
+ numberOfSlidesNeedClone.push(i);
2795
+ }
2796
+ } else if (isNext) {
2797
+ for (let i = 0; i < slidesPerView - (slidesEl.children.length - targetSlideIndex); i++) {
2798
+ numberOfSlidesNeedClone.push(i);
2799
+ }
2800
+ }
2801
+ const cols = slides.length;
2802
+ const isInitialOverflow = initial && cols - initialSlide < slidesPerView && !centeredSlides;
2803
+ isInitialOverflow ? initialSlide : swiper.activeIndex;
2804
+ if (typeof activeSlideIndex === 'undefined') {
2805
+ activeSlideIndex = swiper.getSlideIndex(slides.find(el => el.classList.contains(params.slideActiveClass)));
2806
+ }
2807
+
2808
+ // Tạo DocumentFragment để chứa các slide clone
2809
+ const cloneFragment = document.createDocumentFragment();
2810
+
2811
+ // Clone các slide theo numberOfSlidesNeedClone (đã đảo ngược) và thêm vào fragment
2812
+ (isNext ? numberOfSlidesNeedClone : numberOfSlidesNeedClone.reverse()).forEach(index => {
2813
+ if (slides[index]) {
2814
+ const originalSlide = slides[index];
2815
+ const clonedSlide = originalSlide.cloneNode(true);
2816
+
2817
+ // Đánh dấu slide clone
2818
+ clonedSlide.setAttribute('data-swiper-clone', 'true');
2819
+ clonedSlide.classList.add('swiper-slide-clone');
2820
+
2821
+ // Thêm clone vào fragment
2822
+ cloneFragment.appendChild(clonedSlide);
2823
+ }
2824
+ });
2825
+ if (isPrev) {
2826
+ numberOfSlidesNeedClone.forEach(index => {
2827
+ const originalSlide = slides[index];
2828
+ originalSlide.swiperLoopMoveDOM = true;
2829
+ slidesEl.prepend(originalSlide);
2830
+ originalSlide.swiperLoopMoveDOM = false;
2831
+ });
2832
+ }
2833
+ if (isNext) {
2834
+ numberOfSlidesNeedClone.forEach(index => {
2835
+ const originalSlide = slides[index];
2836
+ originalSlide.swiperLoopMoveDOM = true;
2837
+ slidesEl.append(originalSlide);
2838
+ originalSlide.swiperLoopMoveDOM = false;
2839
+ });
2840
+ }
2841
+
2842
+ // Sắp xếp cloneFragment theo data-swiper-slide-index tăng dần
2843
+ const clonedSlides = Array.from(cloneFragment.children);
2844
+ clonedSlides.sort((a, b) => {
2845
+ const indexA = parseInt(a.getAttribute('data-swiper-slide-index')) || 0;
2846
+ const indexB = parseInt(b.getAttribute('data-swiper-slide-index')) || 0;
2847
+ return indexA - indexB;
2848
+ });
2849
+
2850
+ // Xóa tất cả children cũ và thêm lại theo thứ tự đã sắp xếp
2851
+ cloneFragment.innerHTML = '';
2852
+ clonedSlides.forEach(slide => {
2853
+ cloneFragment.appendChild(slide);
2854
+ });
2855
+
2856
+ // Thêm fragment vào vị trí phù hợp
2857
+ if (isPrev) {
2858
+ // Nếu là prev, thêm fragment vào cuối slidesEl
2859
+ slidesEl.appendChild(cloneFragment);
2860
+ } else if (isNext) {
2861
+ // Nếu là next, thêm fragment vào đầu slidesEl
2862
+ slidesEl.insertBefore(cloneFragment, slidesEl.firstChild);
2863
+ }
2864
+ swiper.recalcSlides();
2865
+ swiper.updateSlides();
2866
+
2867
+ // Tìm slide có data-swiper-slide-index tương ứng
2868
+ let oldActiveIndex = null;
2869
+ for (let i = 0; i < slidesEl.children.length; i++) {
2870
+ const child = slidesEl.children[i];
2871
+ if (child.getAttribute('data-swiper-slide-index') === swiperDataOldActiveIndex) {
2872
+ oldActiveIndex = i;
2873
+ break;
2874
+ }
2875
+ }
2876
+ if (slideTo && oldActiveIndex !== swiper.activeIndex) {
2877
+ swiper.slideTo(oldActiveIndex, 0);
2878
+ }
2879
+
2880
+ // Tìm vị trí slide cũ sau khi remove clone để set lại translate tạo hiệu ứng animate
2881
+ const skip = Math.min(swiper.params.slidesPerGroupSkip, newIndex);
2882
+ let snapIndex = skip + Math.floor((newIndex - skip) / swiper.params.slidesPerGroup);
2883
+ if (snapIndex >= swiper.snapGrid.length) snapIndex = swiper.snapGrid.length - 1;
2884
+ const translate = -swiper.snapGrid[snapIndex];
2885
+ if (translate === swiper.translate) {
2886
+ let oldActiveIndexAfterRemoveClone;
2887
+ for (let i = 0; i < slidesEl.children.length; i++) {
2888
+ const child = slidesEl.children[i];
2889
+ if (child.getAttribute('data-swiper-slide-index') === swiperDataOldActiveIndex) {
2890
+ oldActiveIndexAfterRemoveClone = i;
2891
+ break;
2892
+ }
2893
+ }
2894
+ const skip = Math.min(swiper.params.slidesPerGroupSkip, oldActiveIndexAfterRemoveClone);
2895
+ let snapIndex = skip + Math.floor((oldActiveIndexAfterRemoveClone - skip) / swiper.params.slidesPerGroup);
2896
+ if (snapIndex >= swiper.snapGrid.length) snapIndex = swiper.snapGrid.length - 1;
2897
+ const oldTranslate = -swiper.snapGrid[snapIndex];
2898
+ let updateTranslate;
2899
+ if (oldTranslate === swiper.translate) {
2900
+ updateTranslate = swiper.snapGrid[snapIndex > 0 ? snapIndex - 1 : swiper.snapGrid.length - 1];
2901
+ } else {
2902
+ updateTranslate = oldTranslate;
2903
+ }
2904
+ swiper.setTranslate(updateTranslate);
2905
+ }
2906
+ // Remove slide clone ra khỏi slidesEl sau khi slideTo hoàn thành
2907
+ const cloneSlides = slidesEl.querySelectorAll('[data-swiper-clone="true"]');
2908
+ cloneSlides.forEach(cloneSlide => {
2909
+ if (cloneSlide.parentNode) {
2910
+ cloneSlide.parentNode.removeChild(cloneSlide);
2911
+ }
2912
+ });
2913
+ swiper.recalcSlides();
2914
+ swiper.updateSlides();
2915
+ const targetDataIndex = Array.from(slidesEl.children).findIndex(el => el.getAttribute('data-swiper-slide-index') * 1 === targetData * 1);
2916
+ const oldDataIndex = Array.from(slidesEl.children).findIndex(el => el.getAttribute('data-swiper-slide-index') * 1 === oldActiveData * 1);
2917
+ const snapIndexNew = skip + Math.floor((targetDataIndex - skip) / swiper.params.slidesPerGroup);
2918
+ const snapIndexOld = skip + Math.floor((oldDataIndex - skip) / swiper.params.slidesPerGroup);
2919
+ if (slideTo && snapIndexNew === targetDataIndex) {
2920
+ const translateOld = -swiper.snapGrid[snapIndexOld > swiper.snapGrid.length - 1 ? snapIndexNew - 1 > swiper.snapGrid.length - 1 ? 0 : snapIndexNew - 1 : snapIndexOld];
2921
+ swiper.setTranslate(translateOld);
2922
+ }
2923
+ swiper.recalcSlides();
2924
+ swiper.updateSlides();
2925
+ swiper.allowSlidePrev = allowSlidePrev;
2926
+ swiper.allowSlideNext = allowSlideNext;
2927
+ swiper.emit('loopFixDot');
2928
+ }
2929
+
2603
2930
  function loopDestroy() {
2604
2931
  const swiper = this;
2605
2932
  const {
@@ -2626,6 +2953,7 @@
2626
2953
  var loop = {
2627
2954
  loopCreate,
2628
2955
  loopFix,
2956
+ loopFixDot,
2629
2957
  loopDestroy
2630
2958
  };
2631
2959
 
@@ -3220,6 +3548,9 @@
3220
3548
  swiper.slideTo(stopIndex);
3221
3549
  }
3222
3550
  }
3551
+ swiper.syncSneakPeekCenter({
3552
+ speed: swiper.params.speed
3553
+ });
3223
3554
  }
3224
3555
 
3225
3556
  function onResize() {
@@ -3761,6 +4092,7 @@
3761
4092
  loopAddBlankSlides: true,
3762
4093
  loopAdditionalSlides: 0,
3763
4094
  loopPreventsSliding: true,
4095
+ isSneakPeekCenter: false,
3764
4096
  // rewind
3765
4097
  rewind: false,
3766
4098
  // Swiping/no swiping
@@ -4302,6 +4634,46 @@
4302
4634
  });
4303
4635
  return true;
4304
4636
  }
4637
+ syncSneakPeekCenter(_temp) {
4638
+ let {
4639
+ speed = 0
4640
+ } = _temp === void 0 ? {} : _temp;
4641
+ const swiper = this;
4642
+ requestAnimationFrame(() => {
4643
+ const slides = swiper.slides;
4644
+ if (swiper.params?.isSneakPeekCenter && slides.length > 1) {
4645
+ const isFirstSlide = swiper.activeIndex === 0;
4646
+ const isLastSlide = swiper.activeIndex === slides.length - 1 || swiper.isEnd;
4647
+ const gap = Math.abs(swiper.snapGrid[1] - swiper.snapGrid[0]);
4648
+ const swiperTranslate = structuredClone(swiper.snapGrid[1]);
4649
+ if (isFirstSlide) {
4650
+ // Move last item to first position when at first slide
4651
+ const lastSlide = slides.at(-1);
4652
+ lastSlide.swiperLoopMoveDOM = true;
4653
+ swiper.slidesEl.prepend(lastSlide);
4654
+ lastSlide.swiperLoopMoveDOM = false;
4655
+ swiper.setTransition(0);
4656
+ swiper.setTranslate(-(swiperTranslate + gap));
4657
+ swiper.recalcSlides();
4658
+ swiper.updateSlides();
4659
+ swiper.setTransition(speed);
4660
+ swiper.setTranslate(-swiperTranslate);
4661
+ } else if (isLastSlide) {
4662
+ // Move first item to last position when at last slide
4663
+ const firstSlide = slides[0];
4664
+ firstSlide.swiperLoopMoveDOM = true;
4665
+ swiper.slidesEl.append(firstSlide);
4666
+ firstSlide.swiperLoopMoveDOM = false;
4667
+ swiper.setTransition(0);
4668
+ swiper.setTranslate(-(swiperTranslate - gap));
4669
+ swiper.recalcSlides();
4670
+ swiper.updateSlides();
4671
+ swiper.setTransition(speed);
4672
+ swiper.setTranslate(-swiperTranslate);
4673
+ }
4674
+ }
4675
+ });
4676
+ }
4305
4677
  init(el) {
4306
4678
  const swiper = this;
4307
4679
  if (swiper.initialized) return swiper;
@@ -4363,6 +4735,7 @@
4363
4735
  // Init Flag
4364
4736
  swiper.initialized = true;
4365
4737
  preload(swiper);
4738
+ swiper.syncSneakPeekCenter();
4366
4739
 
4367
4740
  // Emit
4368
4741
  swiper.emit('init');
@@ -5597,16 +5970,6 @@
5597
5970
  }
5598
5971
  }
5599
5972
  }
5600
- function getMoveDirection(prevIndex, nextIndex, length) {
5601
- prevIndex = prevIndex % length;
5602
- nextIndex = nextIndex % length;
5603
- if (nextIndex === prevIndex + 1) {
5604
- return 'next';
5605
- } else if (nextIndex === prevIndex - 1) {
5606
- return 'previous';
5607
- }
5608
- return;
5609
- }
5610
5973
  function onBulletClick(e) {
5611
5974
  const bulletEl = e.target.closest(classesToSelector(swiper.params.pagination.bulletClass));
5612
5975
  if (!bulletEl) {
@@ -5615,26 +5978,40 @@
5615
5978
  e.preventDefault();
5616
5979
  const index = elementIndex(bulletEl) * swiper.params.slidesPerGroup;
5617
5980
  if (swiper.params.loop) {
5618
- // Check if loop is disabled
5981
+ // Kiểm tra xem loop bị disable không
5619
5982
  const currentSlidesPerView = swiper.params.slidesPerView === 'auto' ? swiper.slidesPerViewDynamic() : Math.ceil(parseFloat(swiper.params.slidesPerView, 10));
5620
5983
  if (swiper.slides.length < currentSlidesPerView) {
5621
- // Loop is disabled, use slideTo directly
5984
+ // Loop bị disable, sử dụng slideTo trực tiếp
5622
5985
  swiper.slideTo(index);
5623
5986
  return;
5624
5987
  }
5625
5988
  if (swiper.realIndex === index) return;
5626
- const moveDirection = getMoveDirection(swiper.realIndex, index, swiper.slides.length);
5627
- if (moveDirection === 'next') {
5989
+ if (index === swiper.realIndex + 1 || index === 0 && swiper.realIndex === swiper.slides.length - 1) {
5628
5990
  swiper.slideNext();
5629
- } else if (moveDirection === 'previous') {
5991
+ } else if (index === swiper.realIndex - 1 || index === swiper.slides.length - 1 && swiper.realIndex === 0) {
5630
5992
  swiper.slidePrev();
5993
+ }
5994
+ // const moveDirection = getMoveDirection(swiper.realIndex, index, swiper.slides.length);
5995
+ if (swiper.params.isSneakPeekCenter) {
5996
+ swiper.slideToLoopCenterSneakPeek(index);
5631
5997
  } else {
5632
5998
  swiper.slideToLoop(index);
5633
5999
  }
6000
+
6001
+ // if (moveDirection === 'next') {
6002
+ // swiper.slideNext();
6003
+ // } else if (moveDirection === 'previous') {
6004
+ // swiper.slidePrev();
6005
+ // } else {
6006
+ // swiper.slideToLoop(index);
6007
+ // }
5634
6008
  } else {
5635
6009
  swiper.slideTo(index);
5636
6010
  }
5637
6011
  }
6012
+
6013
+ // Export function để sử dụng ở ngoài
6014
+ swiper.pagination.onBulletClick = onBulletClick;
5638
6015
  function update() {
5639
6016
  // Render || Update Pagination bullets/items
5640
6017
  const rtl = swiper.rtl;
@@ -9849,7 +10226,7 @@
9849
10226
  }
9850
10227
 
9851
10228
  /**
9852
- * Swiper 0.0.7
10229
+ * Swiper 0.0.9
9853
10230
  * Gem SDK - Swiper, Customized of swiper
9854
10231
  * https://swiperjs.com
9855
10232
  *
@@ -9857,7 +10234,7 @@
9857
10234
  *
9858
10235
  * Released under the MIT License
9859
10236
  *
9860
- * Released on: October 9, 2025
10237
+ * Released on: December 8, 2025
9861
10238
  */
9862
10239
 
9863
10240
 
@@ -9866,7 +10243,7 @@
9866
10243
  Swiper.use(modules);
9867
10244
 
9868
10245
  /* underscore in name -> watch for changes */
9869
- const paramsList = ['eventsPrefix', 'injectStyles', 'injectStylesUrls', 'modules', 'init', '_direction', 'oneWayMovement', 'swiperElementNodeName', 'touchEventsTarget', 'initialSlide', '_speed', 'cssMode', 'updateOnWindowResize', 'resizeObserver', 'nested', 'focusableElements', '_enabled', '_width', '_height', 'preventInteractionOnTransition', 'userAgent', 'url', '_edgeSwipeDetection', '_edgeSwipeThreshold', '_freeMode', '_autoHeight', 'setWrapperSize', 'virtualTranslate', '_effect', 'breakpoints', 'breakpointsBase', '_spaceBetween', '_slidesPerView', 'maxBackfaceHiddenSlides', '_grid', '_slidesPerGroup', '_slidesPerGroupSkip', '_slidesPerGroupAuto', '_centeredSlides', '_centeredSlidesBounds', '_slidesOffsetBefore', '_slidesOffsetAfter', 'normalizeSlideIndex', '_centerInsufficientSlides', '_watchOverflow', 'roundLengths', 'touchRatio', 'touchAngle', 'simulateTouch', '_shortSwipes', '_longSwipes', 'longSwipesRatio', 'longSwipesMs', '_followFinger', 'allowTouchMove', '_threshold', 'touchMoveStopPropagation', 'touchStartPreventDefault', 'touchStartForcePreventDefault', 'touchReleaseOnEdges', 'uniqueNavElements', '_resistance', '_resistanceRatio', '_watchSlidesProgress', '_grabCursor', 'preventClicks', 'preventClicksPropagation', '_slideToClickedSlide', '_loop', 'loopAdditionalSlides', 'loopAddBlankSlides', 'loopPreventsSliding', '_rewind', '_allowSlidePrev', '_allowSlideNext', '_swipeHandler', '_noSwiping', 'noSwipingClass', 'noSwipingSelector', 'passiveListeners', 'containerModifierClass', 'slideClass', 'slideActiveClass', 'slideVisibleClass', 'slideFullyVisibleClass', 'slideNextClass', 'slidePrevClass', 'slideBlankClass', 'wrapperClass', 'lazyPreloaderClass', 'lazyPreloadPrevNext', 'runCallbacksOnInit', 'observer', 'observeParents', 'observeSlideChildren',
10246
+ const paramsList = ['eventsPrefix', 'injectStyles', 'injectStylesUrls', 'modules', 'init', '_direction', 'oneWayMovement', 'swiperElementNodeName', 'touchEventsTarget', 'initialSlide', '_speed', 'cssMode', 'updateOnWindowResize', 'resizeObserver', 'nested', 'focusableElements', '_enabled', '_width', '_height', 'preventInteractionOnTransition', 'userAgent', 'url', '_edgeSwipeDetection', '_edgeSwipeThreshold', '_freeMode', '_autoHeight', 'setWrapperSize', 'virtualTranslate', '_effect', 'breakpoints', 'breakpointsBase', '_spaceBetween', '_isSneakPeekCenter', '_slidesPerView', 'maxBackfaceHiddenSlides', '_grid', '_slidesPerGroup', '_slidesPerGroupSkip', '_slidesPerGroupAuto', '_centeredSlides', '_centeredSlidesBounds', '_slidesOffsetBefore', '_slidesOffsetAfter', 'normalizeSlideIndex', '_centerInsufficientSlides', '_watchOverflow', 'roundLengths', 'touchRatio', 'touchAngle', 'simulateTouch', '_shortSwipes', '_longSwipes', 'longSwipesRatio', 'longSwipesMs', '_followFinger', 'allowTouchMove', '_threshold', 'touchMoveStopPropagation', 'touchStartPreventDefault', 'touchStartForcePreventDefault', 'touchReleaseOnEdges', 'uniqueNavElements', '_resistance', '_resistanceRatio', '_watchSlidesProgress', '_grabCursor', 'preventClicks', 'preventClicksPropagation', '_slideToClickedSlide', '_loop', 'loopAdditionalSlides', 'loopAddBlankSlides', 'loopPreventsSliding', '_rewind', '_allowSlidePrev', '_allowSlideNext', '_swipeHandler', '_noSwiping', 'noSwipingClass', 'noSwipingSelector', 'passiveListeners', 'containerModifierClass', 'slideClass', 'slideActiveClass', 'slideVisibleClass', 'slideFullyVisibleClass', 'slideNextClass', 'slidePrevClass', 'slideBlankClass', 'wrapperClass', 'lazyPreloaderClass', 'lazyPreloadPrevNext', 'runCallbacksOnInit', 'observer', 'observeParents', 'observeSlideChildren',
9870
10247
  // modules
9871
10248
  'a11y', '_autoplay', '_controller', 'coverflowEffect', 'cubeEffect', 'fadeEffect', 'flipEffect', 'creativeEffect', 'cardsEffect', 'hashNavigation', 'history', 'keyboard', 'mousewheel', '_navigation', '_pagination', 'parallax', '_scrollbar', '_thumbs', 'virtual', 'zoom', 'control'];
9872
10249
 
@@ -10191,7 +10568,7 @@
10191
10568
  }
10192
10569
 
10193
10570
  /**
10194
- * Swiper Custom Element 0.0.7
10571
+ * Swiper Custom Element 0.0.9
10195
10572
  * Gem SDK - Swiper, Customized of swiper
10196
10573
  * https://swiperjs.com
10197
10574
  *
@@ -10199,7 +10576,7 @@
10199
10576
  *
10200
10577
  * Released under the MIT License
10201
10578
  *
10202
- * Released on: October 9, 2025
10579
+ * Released on: December 8, 2025
10203
10580
  */
10204
10581
 
10205
10582