@gem-sdk/swiper 0.0.15-dev.1 → 0.0.15

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.
package/swiper.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Swiper 0.0.15-dev.1
2
+ * Swiper 0.0.15
3
3
  * Gem SDK - Swiper, Customized of swiper
4
4
  * https://swiperjs.com
5
5
  *
@@ -829,6 +829,9 @@ var Swiper = (function () {
829
829
 
830
830
  function updateSlides() {
831
831
  const swiper = this;
832
+ function getDirectionPropertyValue(node, label) {
833
+ return parseFloat(node.getPropertyValue(swiper.getDirectionLabel(label)) || 0);
834
+ }
832
835
  const params = swiper.params;
833
836
  const {
834
837
  wrapperEl,
@@ -837,8 +840,10 @@ var Swiper = (function () {
837
840
  rtlTranslate: rtl,
838
841
  wrongRTL
839
842
  } = swiper;
843
+ const isVirtual = swiper.virtual && params.virtual.enabled;
844
+ const previousSlidesLength = isVirtual ? swiper.virtual.slides.length : swiper.slides.length;
840
845
  const slides = elementChildren(slidesEl, `.${swiper.params.slideClass}, swiper-slide`);
841
- const slidesLength = slides.length;
846
+ const slidesLength = isVirtual ? swiper.virtual.slides.length : slides.length;
842
847
  let snapGrid = [];
843
848
  const slidesGrid = [];
844
849
  const slidesSizesGrid = [];
@@ -856,15 +861,15 @@ var Swiper = (function () {
856
861
  let slidePosition = -offsetBefore;
857
862
  let prevSlideSize = 0;
858
863
  let index = 0;
859
- if (typeof swiperSize === 'undefined') return;
864
+ if (typeof swiperSize === 'undefined') {
865
+ return;
866
+ }
860
867
  if (typeof spaceBetween === 'string' && spaceBetween.indexOf('%') >= 0) {
861
868
  spaceBetween = parseFloat(spaceBetween.replace('%', '')) / 100 * swiperSize;
862
869
  } else if (typeof spaceBetween === 'string') {
863
870
  spaceBetween = parseFloat(spaceBetween);
864
871
  }
865
-
866
- // core-lite: compute total slides size without optional modules
867
- swiper.slidesTotalSize = -spaceBetween;
872
+ swiper.virtualSize = -spaceBetween;
868
873
 
869
874
  // reset margins
870
875
  slides.forEach(slideEl => {
@@ -882,34 +887,49 @@ var Swiper = (function () {
882
887
  setCSSProperty(wrapperEl, '--swiper-centered-offset-before', '');
883
888
  setCSSProperty(wrapperEl, '--swiper-centered-offset-after', '');
884
889
  }
890
+ const gridEnabled = params.grid && params.grid.rows > 1 && swiper.grid;
891
+ if (gridEnabled) {
892
+ swiper.grid.initSlides(slides);
893
+ } else if (swiper.grid) {
894
+ swiper.grid.unsetSlides();
895
+ }
885
896
 
886
897
  // Calc slides
887
898
  let slideSize;
888
- const shouldResetSlideSize = params.slidesPerView === 'auto' && params.breakpoints && Object.keys(params.breakpoints).filter(key => typeof params.breakpoints[key].slidesPerView !== 'undefined').length > 0;
899
+ const shouldResetSlideSize = params.slidesPerView === 'auto' && params.breakpoints && Object.keys(params.breakpoints).filter(key => {
900
+ return typeof params.breakpoints[key].slidesPerView !== 'undefined';
901
+ }).length > 0;
889
902
  for (let i = 0; i < slidesLength; i += 1) {
890
903
  slideSize = 0;
891
904
  let slide;
892
905
  if (slides[i]) slide = slides[i];
906
+ if (gridEnabled) {
907
+ swiper.grid.updateSlide(i, slide, slides);
908
+ }
893
909
  if (slides[i] && elementStyle(slide, 'display') === 'none') continue; // eslint-disable-line
894
910
 
895
911
  if (params.slidesPerView === 'auto') {
896
- if (shouldResetSlideSize && slides[i]) {
912
+ if (shouldResetSlideSize) {
897
913
  slides[i].style[swiper.getDirectionLabel('width')] = ``;
898
914
  }
899
915
  const slideStyles = getComputedStyle(slide);
900
916
  const currentTransform = slide.style.transform;
901
917
  const currentWebKitTransform = slide.style.webkitTransform;
902
- if (currentTransform) slide.style.transform = 'none';
903
- if (currentWebKitTransform) slide.style.webkitTransform = 'none';
918
+ if (currentTransform) {
919
+ slide.style.transform = 'none';
920
+ }
921
+ if (currentWebKitTransform) {
922
+ slide.style.webkitTransform = 'none';
923
+ }
904
924
  if (params.roundLengths) {
905
925
  slideSize = swiper.isHorizontal() ? elementOuterSize(slide, 'width', true) : elementOuterSize(slide, 'height', true);
906
926
  } else {
907
927
  // eslint-disable-next-line
908
- const width = parseFloat(slideStyles.getPropertyValue('width')) || slide.offsetWidth;
909
- const paddingLeft = parseFloat(slideStyles.getPropertyValue('padding-left')) || 0;
910
- const paddingRight = parseFloat(slideStyles.getPropertyValue('padding-right')) || 0;
911
- const marginLeft = parseFloat(slideStyles.getPropertyValue('margin-left')) || 0;
912
- const marginRight = parseFloat(slideStyles.getPropertyValue('margin-right')) || 0;
928
+ const width = getDirectionPropertyValue(slideStyles, 'width');
929
+ const paddingLeft = getDirectionPropertyValue(slideStyles, 'padding-left');
930
+ const paddingRight = getDirectionPropertyValue(slideStyles, 'padding-right');
931
+ const marginLeft = getDirectionPropertyValue(slideStyles, 'margin-left');
932
+ const marginRight = getDirectionPropertyValue(slideStyles, 'margin-right');
913
933
  const boxSizing = slideStyles.getPropertyValue('box-sizing');
914
934
  if (boxSizing && boxSizing === 'border-box') {
915
935
  slideSize = width + marginLeft + marginRight;
@@ -921,8 +941,12 @@ var Swiper = (function () {
921
941
  slideSize = width + paddingLeft + paddingRight + marginLeft + marginRight + (offsetWidth - clientWidth);
922
942
  }
923
943
  }
924
- if (currentTransform) slide.style.transform = currentTransform;
925
- if (currentWebKitTransform) slide.style.webkitTransform = currentWebKitTransform;
944
+ if (currentTransform) {
945
+ slide.style.transform = currentTransform;
946
+ }
947
+ if (currentWebKitTransform) {
948
+ slide.style.webkitTransform = currentWebKitTransform;
949
+ }
926
950
  if (params.roundLengths) slideSize = Math.floor(slideSize);
927
951
  } else {
928
952
  slideSize = (swiperSize - (params.slidesPerView - 1) * spaceBetween) / params.slidesPerView;
@@ -931,13 +955,13 @@ var Swiper = (function () {
931
955
  slides[i].style[swiper.getDirectionLabel('width')] = `${slideSize}px`;
932
956
  }
933
957
  }
934
- if (slides[i]) slides[i].swiperSlideSize = slideSize;
958
+ if (slides[i]) {
959
+ slides[i].swiperSlideSize = slideSize;
960
+ }
935
961
  slidesSizesGrid.push(slideSize);
936
962
  if (params.centeredSlides) {
937
963
  slidePosition = slidePosition + slideSize / 2 + prevSlideSize / 2 + spaceBetween;
938
- if (prevSlideSize === 0 && i !== 0) {
939
- slidePosition = slidePosition - swiperSize / 2 - spaceBetween;
940
- }
964
+ if (prevSlideSize === 0 && i !== 0) slidePosition = slidePosition - swiperSize / 2 - spaceBetween;
941
965
  if (i === 0) slidePosition = slidePosition - swiperSize / 2 - spaceBetween;
942
966
  if (Math.abs(slidePosition) < 1 / 1000) slidePosition = 0;
943
967
  if (params.roundLengths) slidePosition = Math.floor(slidePosition);
@@ -945,37 +969,55 @@ var Swiper = (function () {
945
969
  slidesGrid.push(slidePosition);
946
970
  } else {
947
971
  if (params.roundLengths) slidePosition = Math.floor(slidePosition);
948
- if ((index - Math.min(swiper.params.slidesPerGroupSkip, index)) % swiper.params.slidesPerGroup === 0) {
949
- snapGrid.push(slidePosition);
950
- }
972
+ if ((index - Math.min(swiper.params.slidesPerGroupSkip, index)) % swiper.params.slidesPerGroup === 0) snapGrid.push(slidePosition);
951
973
  slidesGrid.push(slidePosition);
952
974
  slidePosition = slidePosition + slideSize + spaceBetween;
953
975
  }
954
- swiper.slidesTotalSize += slideSize + spaceBetween;
976
+ swiper.virtualSize += slideSize + spaceBetween;
955
977
  prevSlideSize = slideSize;
956
978
  index += 1;
957
979
  }
958
- swiper.slidesTotalSize = Math.max(swiper.slidesTotalSize, swiperSize) + offsetAfter;
959
- if (rtl && wrongRTL && params.effect === 'slide') {
960
- wrapperEl.style.width = `${swiper.slidesTotalSize + spaceBetween}px`;
980
+ swiper.virtualSize = Math.max(swiper.virtualSize, swiperSize) + offsetAfter;
981
+ if (rtl && wrongRTL && (params.effect === 'slide' || params.effect === 'coverflow')) {
982
+ wrapperEl.style.width = `${swiper.virtualSize + spaceBetween}px`;
961
983
  }
962
984
  if (params.setWrapperSize) {
963
- wrapperEl.style[swiper.getDirectionLabel('width')] = `${swiper.slidesTotalSize + spaceBetween}px`;
985
+ wrapperEl.style[swiper.getDirectionLabel('width')] = `${swiper.virtualSize + spaceBetween}px`;
986
+ }
987
+ if (gridEnabled) {
988
+ swiper.grid.updateWrapperSize(slideSize, snapGrid);
964
989
  }
965
990
 
966
- // Remove last snap points depending on width (non-centered)
991
+ // Remove last grid elements depending on width
967
992
  if (!params.centeredSlides) {
968
993
  const newSlidesGrid = [];
969
994
  for (let i = 0; i < snapGrid.length; i += 1) {
970
995
  let slidesGridItem = snapGrid[i];
971
996
  if (params.roundLengths) slidesGridItem = Math.floor(slidesGridItem);
972
- if (snapGrid[i] <= swiper.slidesTotalSize - swiperSize) {
997
+ if (snapGrid[i] <= swiper.virtualSize - swiperSize) {
973
998
  newSlidesGrid.push(slidesGridItem);
974
999
  }
975
1000
  }
976
1001
  snapGrid = newSlidesGrid;
977
- if (Math.floor(swiper.slidesTotalSize - swiperSize) - Math.floor(snapGrid[snapGrid.length - 1]) > 1) {
978
- snapGrid.push(swiper.slidesTotalSize - swiperSize);
1002
+ if (Math.floor(swiper.virtualSize - swiperSize) - Math.floor(snapGrid[snapGrid.length - 1]) > 1) {
1003
+ snapGrid.push(swiper.virtualSize - swiperSize);
1004
+ }
1005
+ }
1006
+ if (isVirtual && params.loop) {
1007
+ const size = slidesSizesGrid[0] + spaceBetween;
1008
+ if (params.slidesPerGroup > 1) {
1009
+ const groups = Math.ceil((swiper.virtual.slidesBefore + swiper.virtual.slidesAfter) / params.slidesPerGroup);
1010
+ const groupSize = size * params.slidesPerGroup;
1011
+ for (let i = 0; i < groups; i += 1) {
1012
+ snapGrid.push(snapGrid[snapGrid.length - 1] + groupSize);
1013
+ }
1014
+ }
1015
+ for (let i = 0; i < swiper.virtual.slidesBefore + swiper.virtual.slidesAfter; i += 1) {
1016
+ if (params.slidesPerGroup === 1) {
1017
+ snapGrid.push(snapGrid[snapGrid.length - 1] + size);
1018
+ }
1019
+ slidesGrid.push(slidesGrid[slidesGrid.length - 1] + size);
1020
+ swiper.virtualSize += size;
979
1021
  }
980
1022
  }
981
1023
  if (snapGrid.length === 0) snapGrid = [0];
@@ -983,7 +1025,9 @@ var Swiper = (function () {
983
1025
  const key = swiper.isHorizontal() && rtl ? 'marginLeft' : swiper.getDirectionLabel('marginRight');
984
1026
  slides.filter((_, slideIndex) => {
985
1027
  if (!params.cssMode || params.loop) return true;
986
- if (slideIndex === slides.length - 1) return false;
1028
+ if (slideIndex === slides.length - 1) {
1029
+ return false;
1030
+ }
987
1031
  return true;
988
1032
  }).forEach(slideEl => {
989
1033
  slideEl.style[key] = `${spaceBetween}px`;
@@ -1033,9 +1077,7 @@ var Swiper = (function () {
1033
1077
  swiper.snapGrid = swiper.snapGrid.map(v => v + addToSnapGrid);
1034
1078
  swiper.slidesGrid = swiper.slidesGrid.map(v => v + addToSlidesGrid);
1035
1079
  }
1036
-
1037
- // Emit changes
1038
- if (slidesLength !== (previousSlidesGridLength ? slides.length : slides.length)) {
1080
+ if (slidesLength !== previousSlidesLength) {
1039
1081
  swiper.emit('slidesLengthChange');
1040
1082
  }
1041
1083
  if (snapGrid.length !== previousSnapGridLength) {
@@ -1049,7 +1091,7 @@ var Swiper = (function () {
1049
1091
  swiper.updateSlidesOffset();
1050
1092
  }
1051
1093
  swiper.emit('slidesUpdated');
1052
- if (!params.cssMode && params.effect === 'slide') {
1094
+ if (!isVirtual && !params.cssMode && (params.effect === 'slide' || params.effect === 'fade')) {
1053
1095
  const backFaceHiddenClass = `${params.containerModifierClass}backface-hidden`;
1054
1096
  const hasClassBackfaceClassAdded = swiper.el.classList.contains(backFaceHiddenClass);
1055
1097
  if (slidesLength <= params.maxBackfaceHiddenSlides) {
@@ -1063,13 +1105,20 @@ var Swiper = (function () {
1063
1105
  function updateAutoHeight(speed) {
1064
1106
  const swiper = this;
1065
1107
  const activeSlides = [];
1108
+ const isVirtual = swiper.virtual && swiper.params.virtual.enabled;
1109
+ let newHeight = 0;
1110
+ let i;
1066
1111
  if (typeof speed === 'number') {
1067
1112
  swiper.setTransition(speed);
1068
1113
  } else if (speed === true) {
1069
1114
  swiper.setTransition(swiper.params.speed);
1070
1115
  }
1071
- const getSlideByIndex = index => swiper.slides[index];
1072
-
1116
+ const getSlideByIndex = index => {
1117
+ if (isVirtual) {
1118
+ return swiper.slides[swiper.getSlideIndexByData(index)];
1119
+ }
1120
+ return swiper.slides[index];
1121
+ };
1073
1122
  // Find slides currently in view
1074
1123
  if (swiper.params.slidesPerView !== 'auto' && swiper.params.slidesPerView > 1) {
1075
1124
  if (swiper.params.centeredSlides) {
@@ -1077,9 +1126,9 @@ var Swiper = (function () {
1077
1126
  activeSlides.push(slide);
1078
1127
  });
1079
1128
  } else {
1080
- for (let i = 0; i < Math.ceil(swiper.params.slidesPerView); i += 1) {
1129
+ for (i = 0; i < Math.ceil(swiper.params.slidesPerView); i += 1) {
1081
1130
  const index = swiper.activeIndex + i;
1082
- if (index > swiper.slides.length) break;
1131
+ if (index > swiper.slides.length && !isVirtual) break;
1083
1132
  activeSlides.push(getSlideByIndex(index));
1084
1133
  }
1085
1134
  }
@@ -1088,13 +1137,14 @@ var Swiper = (function () {
1088
1137
  }
1089
1138
 
1090
1139
  // Find new height from highest slide in view
1091
- let newHeight = 0;
1092
- for (let i = 0; i < activeSlides.length; i += 1) {
1140
+ for (i = 0; i < activeSlides.length; i += 1) {
1093
1141
  if (typeof activeSlides[i] !== 'undefined') {
1094
1142
  const height = activeSlides[i].offsetHeight;
1095
1143
  newHeight = height > newHeight ? height : newHeight;
1096
1144
  }
1097
1145
  }
1146
+
1147
+ // Update Height
1098
1148
  if (newHeight || newHeight === 0) swiper.wrapperEl.style.height = `${newHeight}px`;
1099
1149
  }
1100
1150
 
@@ -1239,16 +1289,46 @@ var Swiper = (function () {
1239
1289
  slidesEl,
1240
1290
  activeIndex
1241
1291
  } = swiper;
1242
- const getNextSlide = slideEl => elementNextAll(slideEl, `.${params.slideClass}, swiper-slide`)[0];
1243
- const getPrevSlide = slideEl => elementPrevAll(slideEl, `.${params.slideClass}, swiper-slide`)[0];
1244
- const activeSlide = slides[activeIndex];
1245
- let nextSlide;
1292
+ const isVirtual = swiper.virtual && params.virtual.enabled;
1293
+ const gridEnabled = swiper.grid && params.grid && params.grid.rows > 1;
1294
+ const getFilteredSlide = selector => {
1295
+ return elementChildren(slidesEl, `.${params.slideClass}${selector}, swiper-slide${selector}`)[0];
1296
+ };
1297
+ let activeSlide;
1246
1298
  let prevSlide;
1299
+ let nextSlide;
1300
+ if (isVirtual) {
1301
+ if (params.loop) {
1302
+ let slideIndex = activeIndex - swiper.virtual.slidesBefore;
1303
+ if (slideIndex < 0) slideIndex = swiper.virtual.slides.length + slideIndex;
1304
+ if (slideIndex >= swiper.virtual.slides.length) slideIndex -= swiper.virtual.slides.length;
1305
+ activeSlide = getFilteredSlide(`[data-swiper-slide-index="${slideIndex}"]`);
1306
+ } else {
1307
+ activeSlide = getFilteredSlide(`[data-swiper-slide-index="${activeIndex}"]`);
1308
+ }
1309
+ } else {
1310
+ if (gridEnabled) {
1311
+ activeSlide = slides.find(slideEl => slideEl.column === activeIndex);
1312
+ nextSlide = slides.find(slideEl => slideEl.column === activeIndex + 1);
1313
+ prevSlide = slides.find(slideEl => slideEl.column === activeIndex - 1);
1314
+ } else {
1315
+ activeSlide = slides[activeIndex];
1316
+ }
1317
+ }
1247
1318
  if (activeSlide) {
1248
- nextSlide = getNextSlide(activeSlide);
1249
- prevSlide = getPrevSlide(activeSlide);
1250
- if (params.loop && !nextSlide) nextSlide = slides[0];
1251
- if (params.loop && !prevSlide) prevSlide = slides[slides.length - 1];
1319
+ if (!gridEnabled) {
1320
+ // Next Slide
1321
+ nextSlide = elementNextAll(activeSlide, `.${params.slideClass}, swiper-slide`)[0];
1322
+ if (params.loop && !nextSlide) {
1323
+ nextSlide = slides[0];
1324
+ }
1325
+
1326
+ // Prev Slide
1327
+ prevSlide = elementPrevAll(activeSlide, `.${params.slideClass}, swiper-slide`)[0];
1328
+ if (params.loop && !prevSlide === 0) {
1329
+ prevSlide = slides[slides.length - 1];
1330
+ }
1331
+ }
1252
1332
  }
1253
1333
  slides.forEach(slideEl => {
1254
1334
  toggleSlideClasses(slideEl, slideEl === activeSlide, params.slideActiveClass);
@@ -1339,6 +1419,7 @@ var Swiper = (function () {
1339
1419
  activeIndex = i;
1340
1420
  }
1341
1421
  }
1422
+ // Normalize slideIndex
1342
1423
  if (params.normalizeSlideIndex) {
1343
1424
  if (activeIndex < 0 || typeof activeIndex === 'undefined') activeIndex = 0;
1344
1425
  }
@@ -1356,6 +1437,16 @@ var Swiper = (function () {
1356
1437
  } = swiper;
1357
1438
  let activeIndex = newActiveIndex;
1358
1439
  let snapIndex;
1440
+ const getVirtualRealIndex = aIndex => {
1441
+ let realIndex = aIndex - swiper.virtual.slidesBefore;
1442
+ if (realIndex < 0) {
1443
+ realIndex = swiper.virtual.slides.length + realIndex;
1444
+ }
1445
+ if (realIndex >= swiper.virtual.slides.length) {
1446
+ realIndex -= swiper.virtual.slides.length;
1447
+ }
1448
+ return realIndex;
1449
+ };
1359
1450
  if (typeof activeIndex === 'undefined') {
1360
1451
  activeIndex = getActiveIndexByTranslate(swiper);
1361
1452
  }
@@ -1373,12 +1464,32 @@ var Swiper = (function () {
1373
1464
  }
1374
1465
  return;
1375
1466
  }
1376
- let realIndex = activeIndex;
1377
- if (swiper.slides[activeIndex]) {
1467
+ if (activeIndex === previousIndex && swiper.params.loop && swiper.virtual && swiper.params.virtual.enabled) {
1468
+ swiper.realIndex = getVirtualRealIndex(activeIndex);
1469
+ return;
1470
+ }
1471
+ const gridEnabled = swiper.grid && params.grid && params.grid.rows > 1;
1472
+
1473
+ // Get real index
1474
+ let realIndex;
1475
+ if (swiper.virtual && params.virtual.enabled && params.loop) {
1476
+ realIndex = getVirtualRealIndex(activeIndex);
1477
+ } else if (gridEnabled) {
1478
+ const firstSlideInColumn = swiper.slides.find(slideEl => slideEl.column === activeIndex);
1479
+ let activeSlideIndex = parseInt(firstSlideInColumn.getAttribute('data-swiper-slide-index'), 10);
1480
+ if (Number.isNaN(activeSlideIndex)) {
1481
+ activeSlideIndex = Math.max(swiper.slides.indexOf(firstSlideInColumn), 0);
1482
+ }
1483
+ realIndex = Math.floor(activeSlideIndex / params.grid.rows);
1484
+ } else if (swiper.slides[activeIndex]) {
1378
1485
  const slideIndex = swiper.slides[activeIndex].getAttribute('data-swiper-slide-index');
1379
1486
  if (slideIndex) {
1380
1487
  realIndex = parseInt(slideIndex, 10);
1488
+ } else {
1489
+ realIndex = activeIndex;
1381
1490
  }
1491
+ } else {
1492
+ realIndex = activeIndex;
1382
1493
  }
1383
1494
  Object.assign(swiper, {
1384
1495
  previousSnapIndex,
@@ -1425,7 +1536,11 @@ var Swiper = (function () {
1425
1536
  }
1426
1537
  if (slide && slideFound) {
1427
1538
  swiper.clickedSlide = slide;
1428
- swiper.clickedIndex = slideIndex;
1539
+ if (swiper.virtual && swiper.params.virtual.enabled) {
1540
+ swiper.clickedIndex = parseInt(slide.getAttribute('data-swiper-slide-index'), 10);
1541
+ } else {
1542
+ swiper.clickedIndex = slideIndex;
1543
+ }
1429
1544
  } else {
1430
1545
  swiper.clickedSlide = undefined;
1431
1546
  swiper.clickedIndex = undefined;
@@ -1459,6 +1574,9 @@ var Swiper = (function () {
1459
1574
  translate,
1460
1575
  wrapperEl
1461
1576
  } = swiper;
1577
+ if (params.virtualTranslate) {
1578
+ return rtl ? -translate : translate;
1579
+ }
1462
1580
  if (params.cssMode) {
1463
1581
  return translate;
1464
1582
  }
@@ -1492,7 +1610,7 @@ var Swiper = (function () {
1492
1610
  swiper.translate = swiper.isHorizontal() ? x : y;
1493
1611
  if (params.cssMode) {
1494
1612
  wrapperEl[swiper.isHorizontal() ? 'scrollLeft' : 'scrollTop'] = swiper.isHorizontal() ? -x : -y;
1495
- } else {
1613
+ } else if (!params.virtualTranslate) {
1496
1614
  if (swiper.isHorizontal()) {
1497
1615
  x -= swiper.cssOverflowAdjustment();
1498
1616
  } else {
@@ -1729,6 +1847,7 @@ var Swiper = (function () {
1729
1847
  let snapIndex = skip + Math.floor((slideIndex - skip) / swiper.params.slidesPerGroup);
1730
1848
  if (snapIndex >= snapGrid.length) snapIndex = snapGrid.length - 1;
1731
1849
  const translate = -snapGrid[snapIndex];
1850
+ // Normalize slideIndex
1732
1851
  if (params.normalizeSlideIndex) {
1733
1852
  for (let i = 0; i < slidesGrid.length; i += 1) {
1734
1853
  const normalizedTranslate = -Math.floor(translate * 100);
@@ -1745,24 +1864,33 @@ var Swiper = (function () {
1745
1864
  }
1746
1865
  }
1747
1866
  }
1748
-
1749
1867
  // Directions locks
1750
1868
  if (swiper.initialized && slideIndex !== activeIndex) {
1751
1869
  if (!swiper.allowSlideNext && (rtl ? translate > swiper.translate && translate > swiper.minTranslate() : translate < swiper.translate && translate < swiper.minTranslate())) {
1752
1870
  return false;
1753
1871
  }
1754
1872
  if (!swiper.allowSlidePrev && translate > swiper.translate && translate > swiper.maxTranslate()) {
1755
- if ((activeIndex || 0) !== slideIndex) return false;
1873
+ if ((activeIndex || 0) !== slideIndex) {
1874
+ return false;
1875
+ }
1756
1876
  }
1757
1877
  }
1758
1878
  if (slideIndex !== (previousIndex || 0) && runCallbacks) {
1759
1879
  swiper.emit('beforeSlideChangeStart');
1760
1880
  }
1881
+
1882
+ // Update progress
1761
1883
  swiper.updateProgress(translate);
1762
1884
  let direction;
1763
1885
  if (slideIndex > activeIndex) direction = 'next';else if (slideIndex < activeIndex) direction = 'prev';else direction = 'reset';
1764
- if (rtl && -translate === swiper.translate || !rtl && translate === swiper.translate) {
1886
+
1887
+ // initial virtual
1888
+ const isVirtual = swiper.virtual && swiper.params.virtual.enabled;
1889
+ const isInitialVirtual = isVirtual && initial;
1890
+ // Update Index
1891
+ if (!isInitialVirtual && (rtl && -translate === swiper.translate || !rtl && translate === swiper.translate)) {
1765
1892
  swiper.updateActiveIndex(slideIndex);
1893
+ // Update Height
1766
1894
  if (params.autoHeight) {
1767
1895
  swiper.updateAutoHeight();
1768
1896
  }
@@ -1780,7 +1908,24 @@ var Swiper = (function () {
1780
1908
  const isH = swiper.isHorizontal();
1781
1909
  const t = rtl ? translate : -translate;
1782
1910
  if (speed === 0) {
1783
- wrapperEl[isH ? 'scrollLeft' : 'scrollTop'] = t;
1911
+ if (isVirtual) {
1912
+ swiper.wrapperEl.style.scrollSnapType = 'none';
1913
+ swiper._immediateVirtual = true;
1914
+ }
1915
+ if (isVirtual && !swiper._cssModeVirtualInitialSet && swiper.params.initialSlide > 0) {
1916
+ swiper._cssModeVirtualInitialSet = true;
1917
+ requestAnimationFrame(() => {
1918
+ wrapperEl[isH ? 'scrollLeft' : 'scrollTop'] = t;
1919
+ });
1920
+ } else {
1921
+ wrapperEl[isH ? 'scrollLeft' : 'scrollTop'] = t;
1922
+ }
1923
+ if (isVirtual) {
1924
+ requestAnimationFrame(() => {
1925
+ swiper.wrapperEl.style.scrollSnapType = '';
1926
+ swiper._immediateVirtual = false;
1927
+ });
1928
+ }
1784
1929
  } else {
1785
1930
  if (!swiper.support.smoothScroll) {
1786
1931
  animateCSSModeScroll({
@@ -1798,7 +1943,10 @@ var Swiper = (function () {
1798
1943
  return true;
1799
1944
  }
1800
1945
  const browser = getBrowser();
1801
- browser.isSafari;
1946
+ const isSafari = browser.isSafari;
1947
+ if (isVirtual && !initial && isSafari && swiper.isElement) {
1948
+ swiper.virtual.update(false, false, slideIndex);
1949
+ }
1802
1950
  swiper.setTransition(speed);
1803
1951
  swiper.setTranslate(translate);
1804
1952
  swiper.updateActiveIndex(slideIndex);
@@ -1969,6 +2117,8 @@ var Swiper = (function () {
1969
2117
  if (swiper.params?.isSneakPeekCenter && slides.length > 1 && swiper.activeIndex === 0) {
1970
2118
  const gap = Math.abs(swiper.snapGrid[1] - swiper.snapGrid[0]);
1971
2119
  const swiperTranslate = JSON.parse(JSON.stringify(swiper.snapGrid[1]));
2120
+
2121
+ // Move last item to first position only if active slide is the first slide
1972
2122
  const lastSlide = slides[slides.length - 1];
1973
2123
  lastSlide.swiperLoopMoveDOM = true;
1974
2124
  swiper.slidesEl.prepend(lastSlide);
@@ -2003,8 +2153,11 @@ var Swiper = (function () {
2003
2153
  perGroup = Math.max(swiper.slidesPerViewDynamic('current', true), 1);
2004
2154
  }
2005
2155
  const increment = swiper.activeIndex < params.slidesPerGroupSkip ? 1 : perGroup;
2156
+ const isVirtual = swiper.virtual && params.virtual.enabled;
2006
2157
  if (params.loop) {
2007
- if (animating && params.loopPreventsSliding) return false;
2158
+ if (animating && !isVirtual && params.loopPreventsSliding) return false;
2159
+
2160
+ // Kiểm tra xem loop có bị disable không
2008
2161
  const currentSlidesPerView = params.slidesPerView === 'auto' ? swiper.slidesPerViewDynamic() : Math.ceil(parseFloat(params.slidesPerView, 10));
2009
2162
  if (swiper.slides.length >= currentSlidesPerView) {
2010
2163
  swiper.loopFix({
@@ -2031,6 +2184,7 @@ var Swiper = (function () {
2031
2184
  const gap = Math.abs(swiper.snapGrid[lastSnapGridIndex] - swiper.snapGrid[lastSnapGridIndex - 1]);
2032
2185
  const swiperTranslate = structuredClone(swiper.snapGrid[lastSnapGridIndex - 1]);
2033
2186
  if (!swiper.params.loop) return;
2187
+ // Move first item to last position only if active slide is the last slide
2034
2188
  const firstSlide = slides[0];
2035
2189
  firstSlide.swiperLoopMoveDOM = true;
2036
2190
  swiper.slidesEl.append(firstSlide);
@@ -2055,14 +2209,17 @@ var Swiper = (function () {
2055
2209
  params,
2056
2210
  snapGrid,
2057
2211
  slidesGrid,
2058
- rtlTranslate: rtlTranslate,
2059
- enabled
2212
+ rtlTranslate,
2213
+ enabled,
2214
+ animating
2060
2215
  } = swiper;
2061
2216
  if (!enabled || swiper.destroyed) return swiper;
2062
2217
  if (typeof speed === 'undefined') {
2063
2218
  speed = swiper.params.speed;
2064
2219
  }
2220
+ swiper.virtual && params.virtual.enabled;
2065
2221
  if (params.loop) {
2222
+ // Kiểm tra xem loop có bị disable không
2066
2223
  const currentSlidesPerView = params.slidesPerView === 'auto' ? swiper.slidesPerViewDynamic() : Math.ceil(parseFloat(params.slidesPerView, 10));
2067
2224
  if (swiper.slides.length >= currentSlidesPerView) {
2068
2225
  swiper.loopFix({
@@ -2079,16 +2236,18 @@ var Swiper = (function () {
2079
2236
  }
2080
2237
  const normalizedTranslate = normalize(translate);
2081
2238
  const normalizedSnapGrid = snapGrid.map(val => normalize(val));
2239
+ const isFreeMode = params.freeMode && params.freeMode.enabled;
2082
2240
  let prevSnap = snapGrid[normalizedSnapGrid.indexOf(normalizedTranslate) - 1];
2083
- if (typeof prevSnap === 'undefined' && params.cssMode) {
2241
+ if (typeof prevSnap === 'undefined' && (params.cssMode || isFreeMode)) {
2084
2242
  let prevSnapIndex;
2085
2243
  snapGrid.forEach((snap, snapIndex) => {
2086
2244
  if (normalizedTranslate >= snap) {
2245
+ // prevSnap = snap;
2087
2246
  prevSnapIndex = snapIndex;
2088
2247
  }
2089
2248
  });
2090
2249
  if (typeof prevSnapIndex !== 'undefined') {
2091
- prevSnap = snapGrid[prevSnapIndex > 0 ? prevSnapIndex - 1 : prevSnapIndex];
2250
+ prevSnap = isFreeMode ? snapGrid[prevSnapIndex] : snapGrid[prevSnapIndex > 0 ? prevSnapIndex - 1 : prevSnapIndex];
2092
2251
  }
2093
2252
  }
2094
2253
  let prevIndex = 0;
@@ -2101,7 +2260,7 @@ var Swiper = (function () {
2101
2260
  }
2102
2261
  }
2103
2262
  if (params.rewind && swiper.isBeginning) {
2104
- const lastIndex = swiper.slides.length - 1;
2263
+ const lastIndex = swiper.params.virtual && swiper.params.virtual.enabled && swiper.virtual ? swiper.virtual.slides.length - 1 : swiper.slides.length - 1;
2105
2264
  return swiper.slideTo(lastIndex, speed, runCallbacks, internal);
2106
2265
  } else if (params.loop && swiper.activeIndex === 0 && params.cssMode) {
2107
2266
  requestAnimationFrame(() => {
@@ -2115,6 +2274,8 @@ var Swiper = (function () {
2115
2274
  if (swiper.params?.isSneakPeekCenter && slides.length > 1 && swiper.activeIndex === 0) {
2116
2275
  const gap = Math.abs(swiper.snapGrid[1] - swiper.snapGrid[0]);
2117
2276
  const swiperTranslate = JSON.parse(JSON.stringify(swiper.snapGrid[1]));
2277
+
2278
+ // Move last item to first position only if active slide is the first slide
2118
2279
  if (!swiper.params.loop) return;
2119
2280
  const lastSlide = slides[slides.length - 1];
2120
2281
  lastSlide.swiperLoopMoveDOM = true;
@@ -2191,19 +2352,20 @@ var Swiper = (function () {
2191
2352
  slidesEl
2192
2353
  } = swiper;
2193
2354
  const slidesPerView = params.slidesPerView === 'auto' ? swiper.slidesPerViewDynamic() : params.slidesPerView;
2194
- const slideToIndex = swiper.clickedIndex;
2355
+ let slideToIndex = swiper.getSlideIndexWhenGrid(swiper.clickedIndex);
2195
2356
  let realIndex;
2196
2357
  const slideSelector = swiper.isElement ? `swiper-slide` : `.${params.slideClass}`;
2358
+ const isGrid = swiper.grid && swiper.params.grid && swiper.params.grid.rows > 1;
2197
2359
  if (params.loop) {
2198
2360
  if (swiper.animating) return;
2199
2361
  realIndex = parseInt(swiper.clickedSlide.getAttribute('data-swiper-slide-index'), 10);
2200
2362
  if (params.centeredSlides) {
2201
2363
  swiper.slideToLoop(realIndex);
2202
- } else if (slideToIndex > swiper.slides.length - slidesPerView) {
2364
+ } else if (slideToIndex > (isGrid ? (swiper.slides.length - slidesPerView) / 2 - (swiper.params.grid.rows - 1) : swiper.slides.length - slidesPerView)) {
2203
2365
  swiper.loopFix();
2204
- const clickedEl = elementChildren(slidesEl, `${slideSelector}[data-swiper-slide-index="${realIndex}"]`)[0];
2366
+ slideToIndex = swiper.getSlideIndex(elementChildren(slidesEl, `${slideSelector}[data-swiper-slide-index="${realIndex}"]`)[0]);
2205
2367
  nextTick(() => {
2206
- if (clickedEl) swiper.slideTo(swiper.getSlideIndex(clickedEl));
2368
+ swiper.slideTo(slideToIndex);
2207
2369
  });
2208
2370
  } else {
2209
2371
  swiper.slideTo(slideToIndex);
@@ -2230,7 +2392,7 @@ var Swiper = (function () {
2230
2392
  params,
2231
2393
  slidesEl
2232
2394
  } = swiper;
2233
- if (!params.loop) return;
2395
+ if (!params.loop || swiper.virtual && swiper.params.virtual.enabled) return;
2234
2396
  const initSlides = () => {
2235
2397
  const slides = elementChildren(slidesEl, `.${params.slideClass}, swiper-slide`);
2236
2398
  slides.forEach((el, index) => {
@@ -2239,17 +2401,21 @@ var Swiper = (function () {
2239
2401
  };
2240
2402
  const clearBlankSlides = () => {
2241
2403
  const slides = elementChildren(slidesEl, `.${params.slideBlankClass}`);
2242
- slides.forEach(el => el.remove());
2404
+ slides.forEach(el => {
2405
+ el.remove();
2406
+ });
2243
2407
  if (slides.length > 0) {
2244
2408
  swiper.recalcSlides();
2245
2409
  swiper.updateSlides();
2246
2410
  }
2247
2411
  };
2248
- if (params.loopAddBlankSlides && params.slidesPerGroup > 1) {
2412
+ const gridEnabled = swiper.grid && params.grid && params.grid.rows > 1;
2413
+ if (params.loopAddBlankSlides && (params.slidesPerGroup > 1 || gridEnabled)) {
2249
2414
  clearBlankSlides();
2250
2415
  }
2251
- const slidesPerGroup = params.slidesPerGroup;
2416
+ const slidesPerGroup = params.slidesPerGroup * (gridEnabled ? params.grid.rows : 1);
2252
2417
  const shouldFillGroup = swiper.slides.length % slidesPerGroup !== 0;
2418
+ const shouldFillGrid = gridEnabled && swiper.slides.length % params.grid.rows !== 0;
2253
2419
  const addBlankSlides = amountOfSlides => {
2254
2420
  for (let i = 0; i < amountOfSlides; i += 1) {
2255
2421
  const slideEl = swiper.isElement ? createElement('swiper-slide', [params.slideBlankClass]) : createElement('div', [params.slideClass, params.slideBlankClass]);
@@ -2266,6 +2432,16 @@ var Swiper = (function () {
2266
2432
  showWarning('Swiper Loop Warning: The number of slides is not even to slidesPerGroup, loop mode may not function properly. You need to add more slides (or make duplicates, or empty slides)');
2267
2433
  }
2268
2434
  initSlides();
2435
+ } else if (shouldFillGrid) {
2436
+ if (params.loopAddBlankSlides) {
2437
+ const slidesToAdd = params.grid.rows - swiper.slides.length % params.grid.rows;
2438
+ addBlankSlides(slidesToAdd);
2439
+ swiper.recalcSlides();
2440
+ swiper.updateSlides();
2441
+ } else {
2442
+ showWarning('Swiper Loop Warning: The number of slides is not even to grid.rows, loop mode may not function properly. You need to add more slides (or make duplicates, or empty slides)');
2443
+ }
2444
+ initSlides();
2269
2445
  } else {
2270
2446
  initSlides();
2271
2447
  }
@@ -2284,12 +2460,13 @@ var Swiper = (function () {
2284
2460
  setTranslate,
2285
2461
  activeSlideIndex,
2286
2462
  initial,
2463
+ byController,
2287
2464
  byMousewheel
2288
2465
  } = _temp === void 0 ? {} : _temp;
2289
2466
  const swiper = this;
2290
2467
  if (!swiper.params.loop) return;
2291
2468
 
2292
- // Disable loop mode if number of slides is smaller than slidesPerView
2469
+ // Disable loop mode nếu số slides ít hơn slidesPerView
2293
2470
  const currentSlidesPerView = swiper.params.slidesPerView === 'auto' ? swiper.slidesPerViewDynamic() : Math.ceil(parseFloat(swiper.params.slidesPerView, 10));
2294
2471
  if (swiper.slides.length < currentSlidesPerView) {
2295
2472
  console.warn('Swiper: Loop mode disabled - slides.length < slidesPerView');
@@ -2309,6 +2486,21 @@ var Swiper = (function () {
2309
2486
  } = params;
2310
2487
  swiper.allowSlidePrev = true;
2311
2488
  swiper.allowSlideNext = true;
2489
+ if (swiper.virtual && params.virtual.enabled) {
2490
+ if (slideTo) {
2491
+ if (!params.centeredSlides && swiper.snapIndex === 0) {
2492
+ swiper.slideTo(swiper.virtual.slides.length, 0, false, true);
2493
+ } else if (params.centeredSlides && swiper.snapIndex < params.slidesPerView) {
2494
+ swiper.slideTo(swiper.virtual.slides.length + swiper.snapIndex, 0, false, true);
2495
+ } else if (swiper.snapIndex === swiper.snapGrid.length - 1) {
2496
+ swiper.slideTo(swiper.virtual.slidesBefore, 0, false, true);
2497
+ }
2498
+ }
2499
+ swiper.allowSlidePrev = allowSlidePrev;
2500
+ swiper.allowSlideNext = allowSlideNext;
2501
+ swiper.emit('loopFix');
2502
+ return;
2503
+ }
2312
2504
  let slidesPerView = params.slidesPerView;
2313
2505
  if (slidesPerView === 'auto') {
2314
2506
  slidesPerView = swiper.slidesPerViewDynamic();
@@ -2318,19 +2510,22 @@ var Swiper = (function () {
2318
2510
  slidesPerView = slidesPerView + 1;
2319
2511
  }
2320
2512
  }
2321
- const slidesPerGroup = params.slidesPerGroup;
2513
+ const slidesPerGroup = params.slidesPerGroupAuto ? slidesPerView : params.slidesPerGroup;
2322
2514
  let loopedSlides = centeredSlides ? Math.max(slidesPerGroup, Math.ceil(slidesPerView / 2)) : slidesPerGroup;
2323
2515
  if (loopedSlides % slidesPerGroup !== 0) {
2324
2516
  loopedSlides += slidesPerGroup - loopedSlides % slidesPerGroup;
2325
2517
  }
2326
2518
  loopedSlides += params.loopAdditionalSlides;
2327
2519
  swiper.loopedSlides = loopedSlides;
2328
- if (slides.length < slidesPerView + loopedSlides) {
2520
+ const gridEnabled = swiper.grid && params.grid && params.grid.rows > 1;
2521
+ if (slides.length < slidesPerView + loopedSlides || swiper.params.effect === 'cards' && slides.length < slidesPerView + loopedSlides * 2) {
2329
2522
  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');
2523
+ } else if (gridEnabled && params.grid.fill === 'row') {
2524
+ showWarning('Swiper Loop Warning: Loop mode is not compatible with grid.fill = `row`');
2330
2525
  }
2331
2526
  const prependSlidesIndexes = [];
2332
2527
  const appendSlidesIndexes = [];
2333
- const cols = slides.length;
2528
+ const cols = gridEnabled ? Math.ceil(slides.length / params.grid.rows) : slides.length;
2334
2529
  const isInitialOverflow = initial && cols - initialSlide < slidesPerView && !centeredSlides;
2335
2530
  let activeIndex = isInitialOverflow ? initialSlide : swiper.activeIndex;
2336
2531
  if (typeof activeSlideIndex === 'undefined') {
@@ -2342,15 +2537,24 @@ var Swiper = (function () {
2342
2537
  const isPrev = direction === 'prev' || !direction;
2343
2538
  let slidesPrepended = 0;
2344
2539
  let slidesAppended = 0;
2345
- const activeColIndex = activeSlideIndex;
2540
+ const activeColIndex = gridEnabled ? slides[activeSlideIndex].column : activeSlideIndex;
2346
2541
  const activeColIndexWithShift = activeColIndex + (centeredSlides && typeof setTranslate === 'undefined' ? -slidesPerView / 2 + 0.5 : 0);
2347
-
2348
2542
  // prepend last slides before start
2349
2543
  if (activeColIndexWithShift < loopedSlides) {
2350
2544
  slidesPrepended = Math.max(loopedSlides - activeColIndexWithShift, slidesPerGroup);
2351
2545
  for (let i = 0; i < loopedSlides - activeColIndexWithShift; i += 1) {
2352
2546
  const index = i - Math.floor(i / cols) * cols;
2353
- prependSlidesIndexes.push(cols - index - 1);
2547
+ if (gridEnabled) {
2548
+ const colIndexToPrepend = cols - index - 1;
2549
+ for (let i = slides.length - 1; i >= 0; i -= 1) {
2550
+ if (slides[i].column === colIndexToPrepend) prependSlidesIndexes.push(i);
2551
+ }
2552
+ // slides.forEach((slide, slideIndex) => {
2553
+ // if (slide.column === colIndexToPrepend) prependSlidesIndexes.push(slideIndex);
2554
+ // });
2555
+ } else {
2556
+ prependSlidesIndexes.push(cols - index - 1);
2557
+ }
2354
2558
  }
2355
2559
  } else if (activeColIndexWithShift + slidesPerView > cols - loopedSlides) {
2356
2560
  slidesAppended = Math.max(activeColIndexWithShift - (cols - loopedSlides * 2), slidesPerGroup);
@@ -2359,13 +2563,27 @@ var Swiper = (function () {
2359
2563
  }
2360
2564
  for (let i = 0; i < slidesAppended; i += 1) {
2361
2565
  const index = i - Math.floor(i / cols) * cols;
2362
- appendSlidesIndexes.push(index);
2566
+ if (gridEnabled) {
2567
+ slides.forEach((slide, slideIndex) => {
2568
+ if (slide.column === index) appendSlidesIndexes.push(slideIndex);
2569
+ });
2570
+ } else {
2571
+ appendSlidesIndexes.push(index);
2572
+ }
2363
2573
  }
2364
2574
  }
2365
2575
  swiper.__preventObserver__ = true;
2366
2576
  requestAnimationFrame(() => {
2367
2577
  swiper.__preventObserver__ = false;
2368
2578
  });
2579
+ if (swiper.params.effect === 'cards' && slides.length < slidesPerView + loopedSlides * 2) {
2580
+ if (appendSlidesIndexes.includes(activeSlideIndex)) {
2581
+ appendSlidesIndexes.splice(appendSlidesIndexes.indexOf(activeSlideIndex), 1);
2582
+ }
2583
+ if (prependSlidesIndexes.includes(activeSlideIndex)) {
2584
+ prependSlidesIndexes.splice(prependSlidesIndexes.indexOf(activeSlideIndex), 1);
2585
+ }
2586
+ }
2369
2587
  if (isPrev) {
2370
2588
  prependSlidesIndexes.forEach(index => {
2371
2589
  slides[index].swiperLoopMoveDOM = true;
@@ -2383,6 +2601,10 @@ var Swiper = (function () {
2383
2601
  swiper.recalcSlides();
2384
2602
  if (params.slidesPerView === 'auto') {
2385
2603
  swiper.updateSlides();
2604
+ } else if (gridEnabled && (prependSlidesIndexes.length > 0 && isPrev || appendSlidesIndexes.length > 0 && isNext)) {
2605
+ swiper.slides.forEach((slide, slideIndex) => {
2606
+ swiper.grid.updateSlide(slideIndex, slide, swiper.slides);
2607
+ });
2386
2608
  }
2387
2609
  if (params.watchSlidesProgress) {
2388
2610
  swiper.updateSlidesOffset();
@@ -2402,10 +2624,12 @@ var Swiper = (function () {
2402
2624
  swiper.touchEventsData.currentTranslate = swiper.touchEventsData.currentTranslate - diff;
2403
2625
  }
2404
2626
  }
2405
- } else if (setTranslate) {
2406
- const shift = prependSlidesIndexes.length;
2407
- swiper.slideTo(swiper.activeIndex + shift, 0, false, true);
2408
- swiper.touchEventsData.currentTranslate = swiper.translate;
2627
+ } else {
2628
+ if (setTranslate) {
2629
+ const shift = gridEnabled ? prependSlidesIndexes.length / params.grid.rows : prependSlidesIndexes.length;
2630
+ swiper.slideTo(swiper.activeIndex + shift, 0, false, true);
2631
+ swiper.touchEventsData.currentTranslate = swiper.translate;
2632
+ }
2409
2633
  }
2410
2634
  } else if (appendSlidesIndexes.length > 0 && isNext) {
2411
2635
  if (typeof slideRealIndex === 'undefined') {
@@ -2421,14 +2645,36 @@ var Swiper = (function () {
2421
2645
  swiper.touchEventsData.currentTranslate = swiper.touchEventsData.currentTranslate - diff;
2422
2646
  }
2423
2647
  }
2424
- } else if (setTranslate) {
2425
- const shift = appendSlidesIndexes.length;
2648
+ } else {
2649
+ const shift = gridEnabled ? appendSlidesIndexes.length / params.grid.rows : appendSlidesIndexes.length;
2426
2650
  swiper.slideTo(swiper.activeIndex - shift, 0, false, true);
2427
2651
  }
2428
2652
  }
2429
2653
  }
2430
2654
  swiper.allowSlidePrev = allowSlidePrev;
2431
2655
  swiper.allowSlideNext = allowSlideNext;
2656
+ if (swiper.controller && swiper.controller.control && !byController) {
2657
+ const loopParams = {
2658
+ slideRealIndex,
2659
+ direction,
2660
+ setTranslate,
2661
+ activeSlideIndex,
2662
+ byController: true
2663
+ };
2664
+ if (Array.isArray(swiper.controller.control)) {
2665
+ swiper.controller.control.forEach(c => {
2666
+ if (!c.destroyed && c.params.loop) c.loopFix({
2667
+ ...loopParams,
2668
+ slideTo: c.params.slidesPerView === params.slidesPerView ? slideTo : false
2669
+ });
2670
+ });
2671
+ } else if (swiper.controller.control instanceof swiper.constructor && swiper.controller.control.params.loop) {
2672
+ swiper.controller.control.loopFix({
2673
+ ...loopParams,
2674
+ slideTo: swiper.controller.control.params.slidesPerView === params.slidesPerView ? slideTo : false
2675
+ });
2676
+ }
2677
+ }
2432
2678
  swiper.emit('loopFix');
2433
2679
  }
2434
2680
 
@@ -2445,7 +2691,7 @@ var Swiper = (function () {
2445
2691
  const swiper = this;
2446
2692
  if (!swiper.params.loop) return;
2447
2693
 
2448
- // Disable loop mode if number of slides is smaller than slidesPerView
2694
+ // Disable loop mode nếu số slides ít hơn slidesPerView
2449
2695
  const currentSlidesPerView = swiper.params.slidesPerView === 'auto' ? swiper.slidesPerViewDynamic() : Math.ceil(parseFloat(swiper.params.slidesPerView, 10));
2450
2696
  if (swiper.slides.length < currentSlidesPerView) {
2451
2697
  console.warn('Swiper: Loop mode disabled - slides.length < slidesPerView');
@@ -2484,7 +2730,7 @@ var Swiper = (function () {
2484
2730
  }
2485
2731
  loopedSlides += params.loopAdditionalSlides;
2486
2732
  swiper.loopedSlides = loopedSlides;
2487
- if (slides.length < slidesPerView + loopedSlides) {
2733
+ if (slides.length < slidesPerView + loopedSlides || swiper.params.effect === 'cards' && slides.length < slidesPerView + loopedSlides * 2) {
2488
2734
  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');
2489
2735
  }
2490
2736
  const isNext = direction === 'next' || !direction;
@@ -2510,16 +2756,20 @@ var Swiper = (function () {
2510
2756
  activeSlideIndex = swiper.getSlideIndex(slides.find(el => el.classList.contains(params.slideActiveClass)));
2511
2757
  }
2512
2758
 
2513
- // DocumentFragment to hold slide clones
2759
+ // Tạo DocumentFragment để chứa các slide clone
2514
2760
  const cloneFragment = document.createDocumentFragment();
2515
2761
 
2516
- // Clone slides according to numberOfSlidesNeedClone and append to fragment
2762
+ // Clone các slide theo numberOfSlidesNeedClone (đã đảo ngược) và thêm vào fragment
2517
2763
  (isNext ? numberOfSlidesNeedClone : numberOfSlidesNeedClone.reverse()).forEach(index => {
2518
2764
  if (slides[index]) {
2519
2765
  const originalSlide = slides[index];
2520
2766
  const clonedSlide = originalSlide.cloneNode(true);
2767
+
2768
+ // Đánh dấu slide clone
2521
2769
  clonedSlide.setAttribute('data-swiper-clone', 'true');
2522
2770
  clonedSlide.classList.add('swiper-slide-clone');
2771
+
2772
+ // Thêm clone vào fragment
2523
2773
  cloneFragment.appendChild(clonedSlide);
2524
2774
  }
2525
2775
  });
@@ -2540,28 +2790,32 @@ var Swiper = (function () {
2540
2790
  });
2541
2791
  }
2542
2792
 
2543
- // Sort cloned slides by data-swiper-slide-index
2793
+ // Sắp xếp cloneFragment theo data-swiper-slide-index tăng dần
2544
2794
  const clonedSlides = Array.from(cloneFragment.children);
2545
2795
  clonedSlides.sort((a, b) => {
2546
2796
  const indexA = parseInt(a.getAttribute('data-swiper-slide-index')) || 0;
2547
2797
  const indexB = parseInt(b.getAttribute('data-swiper-slide-index')) || 0;
2548
2798
  return indexA - indexB;
2549
2799
  });
2800
+
2801
+ // Xóa tất cả children cũ và thêm lại theo thứ tự đã sắp xếp
2550
2802
  cloneFragment.innerHTML = '';
2551
2803
  clonedSlides.forEach(slide => {
2552
2804
  cloneFragment.appendChild(slide);
2553
2805
  });
2554
2806
 
2555
- // Place fragment into the right position
2807
+ // Thêm fragment vào vị trí phù hợp
2556
2808
  if (isPrev) {
2809
+ // Nếu là prev, thêm fragment vào cuối slidesEl
2557
2810
  slidesEl.appendChild(cloneFragment);
2558
2811
  } else if (isNext) {
2812
+ // Nếu là next, thêm fragment vào đầu slidesEl
2559
2813
  slidesEl.insertBefore(cloneFragment, slidesEl.firstChild);
2560
2814
  }
2561
2815
  swiper.recalcSlides();
2562
2816
  swiper.updateSlides();
2563
2817
 
2564
- // Find old active slide index after recalculation
2818
+ // Tìm slide data-swiper-slide-index tương ứng
2565
2819
  let oldActiveIndex = null;
2566
2820
  for (let i = 0; i < slidesEl.children.length; i++) {
2567
2821
  const child = slidesEl.children[i];
@@ -2574,7 +2828,7 @@ var Swiper = (function () {
2574
2828
  swiper.slideTo(oldActiveIndex, 0);
2575
2829
  }
2576
2830
 
2577
- // Update translate after removing clones for animation
2831
+ // Tìm vị trí slide cũ sau khi remove clone để set lại translate tạo hiệu ứng animate
2578
2832
  const skip = Math.min(swiper.params.slidesPerGroupSkip, newIndex);
2579
2833
  let snapIndex = skip + Math.floor((newIndex - skip) / swiper.params.slidesPerGroup);
2580
2834
  if (snapIndex >= swiper.snapGrid.length) snapIndex = swiper.snapGrid.length - 1;
@@ -2600,8 +2854,7 @@ var Swiper = (function () {
2600
2854
  }
2601
2855
  swiper.setTranslate(updateTranslate);
2602
2856
  }
2603
-
2604
- // Remove clones
2857
+ // Remove slide clone ra khỏi slidesEl sau khi slideTo hoàn thành
2605
2858
  const cloneSlides = slidesEl.querySelectorAll('[data-swiper-clone="true"]');
2606
2859
  cloneSlides.forEach(cloneSlide => {
2607
2860
  if (cloneSlide.parentNode) {
@@ -2631,7 +2884,7 @@ var Swiper = (function () {
2631
2884
  params,
2632
2885
  slidesEl
2633
2886
  } = swiper;
2634
- if (!params.loop || !slidesEl) return;
2887
+ if (!params.loop || !slidesEl || swiper.virtual && swiper.params.virtual.enabled) return;
2635
2888
  swiper.recalcSlides();
2636
2889
  const newSlidesOrder = [];
2637
2890
  swiper.slides.forEach(slideEl => {
@@ -2692,6 +2945,7 @@ var Swiper = (function () {
2692
2945
  unsetGrabCursor
2693
2946
  };
2694
2947
 
2948
+ // Modified from https://stackoverflow.com/questions/54520554/custom-element-getrootnode-closest-function-crossing-multiple-parent-shadowd
2695
2949
  function closestElement(selector, base) {
2696
2950
  if (base === void 0) {
2697
2951
  base = this;
@@ -2700,7 +2954,9 @@ var Swiper = (function () {
2700
2954
  if (!el || el === getDocument() || el === getWindow()) return null;
2701
2955
  if (el.assignedSlot) el = el.assignedSlot;
2702
2956
  const found = el.closest(selector);
2703
- if (!found && !el.getRootNode) return null;
2957
+ if (!found && !el.getRootNode) {
2958
+ return null;
2959
+ }
2704
2960
  return found || __closestFrom(el.getRootNode().host);
2705
2961
  }
2706
2962
  return __closestFrom(base);
@@ -2728,7 +2984,9 @@ var Swiper = (function () {
2728
2984
  if (e.originalEvent) e = e.originalEvent;
2729
2985
  const data = swiper.touchEventsData;
2730
2986
  if (e.type === 'pointerdown') {
2731
- if (data.pointerId !== null && data.pointerId !== e.pointerId) return;
2987
+ if (data.pointerId !== null && data.pointerId !== e.pointerId) {
2988
+ return;
2989
+ }
2732
2990
  data.pointerId = e.pointerId;
2733
2991
  } else if (e.type === 'touchstart' && e.targetTouches.length === 1) {
2734
2992
  data.touchId = e.targetTouches[0].identifier;
@@ -2745,7 +3003,9 @@ var Swiper = (function () {
2745
3003
  } = swiper;
2746
3004
  if (!enabled) return;
2747
3005
  if (!params.simulateTouch && e.pointerType === 'mouse') return;
2748
- if (swiper.animating && params.preventInteractionOnTransition) return;
3006
+ if (swiper.animating && params.preventInteractionOnTransition) {
3007
+ return;
3008
+ }
2749
3009
  if (!swiper.animating && params.cssMode && params.loop) {
2750
3010
  swiper.loopFix();
2751
3011
  }
@@ -2756,6 +3016,8 @@ var Swiper = (function () {
2756
3016
  if ('which' in e && e.which === 3) return;
2757
3017
  if ('button' in e && e.button > 0) return;
2758
3018
  if (data.isTouched && data.isMoved) return;
3019
+
3020
+ // change target el for shadow root component
2759
3021
  const swipingClassHasValue = !!params.noSwipingClass && params.noSwipingClass !== '';
2760
3022
  // eslint-disable-next-line
2761
3023
  const eventPath = e.composedPath ? e.composedPath() : e.path;
@@ -2764,6 +3026,8 @@ var Swiper = (function () {
2764
3026
  }
2765
3027
  const noSwipingSelector = params.noSwipingSelector ? params.noSwipingSelector : `.${params.noSwipingClass}`;
2766
3028
  const isTargetShadow = !!(e.target && e.target.shadowRoot);
3029
+
3030
+ // use closestElement for shadow root element to get the actual closest for nested shadow root element
2767
3031
  if (params.noSwiping && (isTargetShadow ? closestElement(noSwipingSelector, targetEl) : targetEl.closest(noSwipingSelector))) {
2768
3032
  swiper.allowClick = true;
2769
3033
  return;
@@ -2775,7 +3039,12 @@ var Swiper = (function () {
2775
3039
  touches.currentY = e.pageY;
2776
3040
  const startX = touches.currentX;
2777
3041
  const startY = touches.currentY;
2778
- if (!preventEdgeSwipe(swiper, e, startX)) return;
3042
+
3043
+ // Do NOT start if iOS edge swipe is detected. Otherwise iOS app cannot swipe-to-go-back anymore
3044
+
3045
+ if (!preventEdgeSwipe(swiper, e, startX)) {
3046
+ return;
3047
+ }
2779
3048
  Object.assign(data, {
2780
3049
  isTouched: true,
2781
3050
  isMoved: false,
@@ -2804,6 +3073,9 @@ var Swiper = (function () {
2804
3073
  if ((params.touchStartForcePreventDefault || shouldPreventDefault) && !targetEl.isContentEditable) {
2805
3074
  e.preventDefault();
2806
3075
  }
3076
+ if (params.freeMode && params.freeMode.enabled && swiper.freeMode && swiper.animating && !params.cssMode) {
3077
+ swiper.freeMode.onTouchStart();
3078
+ }
2807
3079
  swiper.emit('touchStart', e);
2808
3080
  }
2809
3081
 
@@ -2822,7 +3094,7 @@ var Swiper = (function () {
2822
3094
  let e = event;
2823
3095
  if (e.originalEvent) e = e.originalEvent;
2824
3096
  if (e.type === 'pointermove') {
2825
- if (data.touchId !== null) return;
3097
+ if (data.touchId !== null) return; // return from pointer if we use touch
2826
3098
  const id = e.pointerId;
2827
3099
  if (id !== data.pointerId) return;
2828
3100
  }
@@ -2863,6 +3135,7 @@ var Swiper = (function () {
2863
3135
  }
2864
3136
  if (params.touchReleaseOnEdges && !params.loop) {
2865
3137
  if (swiper.isVertical()) {
3138
+ // Vertical
2866
3139
  if (pageY < touches.startY && swiper.translate <= swiper.maxTranslate() || pageY > touches.startY && swiper.translate >= swiper.minTranslate()) {
2867
3140
  data.isTouched = false;
2868
3141
  data.isMoved = false;
@@ -2964,6 +3237,7 @@ var Swiper = (function () {
2964
3237
  swiper.wrapperEl.dispatchEvent(evt);
2965
3238
  }
2966
3239
  data.allowMomentumBounce = false;
3240
+ // Grab Cursor
2967
3241
  if (params.grabCursor && (swiper.allowSlideNext === true || swiper.allowSlidePrev === true)) {
2968
3242
  swiper.setGrabCursor(true);
2969
3243
  }
@@ -3034,6 +3308,8 @@ var Swiper = (function () {
3034
3308
  if (!swiper.allowSlidePrev && !swiper.allowSlideNext) {
3035
3309
  data.currentTranslate = data.startTranslate;
3036
3310
  }
3311
+
3312
+ // Threshold
3037
3313
  if (params.threshold > 0) {
3038
3314
  if (Math.abs(diff) > params.threshold || data.allowThresholdMove) {
3039
3315
  if (!data.allowThresholdMove) {
@@ -3051,12 +3327,17 @@ var Swiper = (function () {
3051
3327
  }
3052
3328
  if (!params.followFinger || params.cssMode) return;
3053
3329
 
3054
- // core-lite: no optional feature updates; only watchSlidesProgress
3055
- if (params.watchSlidesProgress) {
3330
+ // Update active index in free mode
3331
+ if (params.freeMode && params.freeMode.enabled && swiper.freeMode || params.watchSlidesProgress) {
3056
3332
  swiper.updateActiveIndex();
3057
3333
  swiper.updateSlidesClasses();
3058
3334
  }
3335
+ if (params.freeMode && params.freeMode.enabled && swiper.freeMode) {
3336
+ swiper.freeMode.onTouchMove();
3337
+ }
3338
+ // Update progress
3059
3339
  swiper.updateProgress(data.currentTranslate);
3340
+ // Update translate
3060
3341
  swiper.setTranslate(data.currentTranslate);
3061
3342
  }
3062
3343
 
@@ -3068,7 +3349,7 @@ var Swiper = (function () {
3068
3349
  let targetTouch;
3069
3350
  const isTouchEvent = e.type === 'touchend' || e.type === 'touchcancel';
3070
3351
  if (!isTouchEvent) {
3071
- if (data.touchId !== null) return;
3352
+ if (data.touchId !== null) return; // return from pointer if we use touch
3072
3353
  if (e.pointerId !== data.pointerId) return;
3073
3354
  targetTouch = e;
3074
3355
  } else {
@@ -3077,7 +3358,9 @@ var Swiper = (function () {
3077
3358
  }
3078
3359
  if (['pointercancel', 'pointerout', 'pointerleave', 'contextmenu'].includes(e.type)) {
3079
3360
  const proceed = ['pointercancel', 'contextmenu'].includes(e.type) && (swiper.browser.isSafari || swiper.browser.isWebView);
3080
- if (!proceed) return;
3361
+ if (!proceed) {
3362
+ return;
3363
+ }
3081
3364
  }
3082
3365
  data.pointerId = null;
3083
3366
  data.touchId = null;
@@ -3095,7 +3378,9 @@ var Swiper = (function () {
3095
3378
  }
3096
3379
  data.allowTouchCallbacks = false;
3097
3380
  if (!data.isTouched) {
3098
- if (data.isMoved && params.grabCursor) swiper.setGrabCursor(false);
3381
+ if (data.isMoved && params.grabCursor) {
3382
+ swiper.setGrabCursor(false);
3383
+ }
3099
3384
  data.isMoved = false;
3100
3385
  data.startMoving = false;
3101
3386
  return;
@@ -3105,6 +3390,8 @@ var Swiper = (function () {
3105
3390
  if (params.grabCursor && data.isMoved && data.isTouched && (swiper.allowSlideNext === true || swiper.allowSlidePrev === true)) {
3106
3391
  swiper.setGrabCursor(false);
3107
3392
  }
3393
+
3394
+ // Time diff
3108
3395
  const touchEndTime = now();
3109
3396
  const timeDiff = touchEndTime - data.touchStartTime;
3110
3397
 
@@ -3131,8 +3418,20 @@ var Swiper = (function () {
3131
3418
  data.isMoved = false;
3132
3419
  data.startMoving = false;
3133
3420
  let currentPos;
3134
- if (params.followFinger) currentPos = rtl ? swiper.translate : -swiper.translate;else currentPos = -data.currentTranslate;
3135
- if (params.cssMode) return;
3421
+ if (params.followFinger) {
3422
+ currentPos = rtl ? swiper.translate : -swiper.translate;
3423
+ } else {
3424
+ currentPos = -data.currentTranslate;
3425
+ }
3426
+ if (params.cssMode) {
3427
+ return;
3428
+ }
3429
+ if (params.freeMode && params.freeMode.enabled) {
3430
+ swiper.freeMode.onTouchEnd({
3431
+ currentPos
3432
+ });
3433
+ return;
3434
+ }
3136
3435
 
3137
3436
  // Find current slide
3138
3437
  const swipeToLast = currentPos >= -swiper.maxTranslate() && !swiper.params.loop;
@@ -3154,22 +3453,22 @@ var Swiper = (function () {
3154
3453
  let rewindLastIndex = null;
3155
3454
  if (params.rewind) {
3156
3455
  if (swiper.isBeginning) {
3157
- rewindLastIndex = swiper.slides.length - 1;
3456
+ rewindLastIndex = params.virtual && params.virtual.enabled && swiper.virtual ? swiper.virtual.slides.length - 1 : swiper.slides.length - 1;
3158
3457
  } else if (swiper.isEnd) {
3159
3458
  rewindFirstIndex = 0;
3160
3459
  }
3161
3460
  }
3461
+ // Find current slide size
3162
3462
  const ratio = (currentPos - slidesGrid[stopIndex]) / groupSize;
3163
3463
  const increment = stopIndex < params.slidesPerGroupSkip - 1 ? 1 : params.slidesPerGroup;
3164
3464
  if (timeDiff > params.longSwipesMs) {
3465
+ // Long touches
3165
3466
  if (!params.longSwipes) {
3166
3467
  swiper.slideTo(swiper.activeIndex);
3167
3468
  return;
3168
3469
  }
3169
3470
  if (swiper.swipeDirection === 'next') {
3170
- if (ratio >= params.longSwipesRatio) {
3171
- swiper.slideTo(params.rewind && swiper.isEnd ? rewindFirstIndex : stopIndex + increment);
3172
- } else swiper.slideTo(stopIndex);
3471
+ if (ratio >= params.longSwipesRatio) swiper.slideTo(params.rewind && swiper.isEnd ? rewindFirstIndex : stopIndex + increment);else swiper.slideTo(stopIndex);
3173
3472
  }
3174
3473
  if (swiper.swipeDirection === 'prev') {
3175
3474
  if (ratio > 1 - params.longSwipesRatio) {
@@ -3221,6 +3520,7 @@ var Swiper = (function () {
3221
3520
  allowSlidePrev,
3222
3521
  snapGrid
3223
3522
  } = swiper;
3523
+ const isVirtual = swiper.virtual && swiper.params.virtual.enabled;
3224
3524
 
3225
3525
  // Disable locks on resize
3226
3526
  swiper.allowSlideNext = true;
@@ -3228,12 +3528,15 @@ var Swiper = (function () {
3228
3528
  swiper.updateSize();
3229
3529
  swiper.updateSlides();
3230
3530
  swiper.updateSlidesClasses();
3231
- if ((params.slidesPerView === 'auto' || params.slidesPerView > 1) && swiper.isEnd && !swiper.isBeginning && !swiper.params.centeredSlides) {
3531
+ const isVirtualLoop = isVirtual && params.loop;
3532
+ if ((params.slidesPerView === 'auto' || params.slidesPerView > 1) && swiper.isEnd && !swiper.isBeginning && !swiper.params.centeredSlides && !isVirtualLoop) {
3232
3533
  swiper.slideTo(swiper.slides.length - 1, 0, false, true);
3233
- } else if (swiper.params.loop) {
3234
- swiper.slideToLoop(swiper.realIndex, 0, false, true);
3235
3534
  } else {
3236
- swiper.slideTo(swiper.activeIndex, 0, false, true);
3535
+ if (swiper.params.loop && !isVirtual) {
3536
+ swiper.slideToLoop(swiper.realIndex, 0, false, true);
3537
+ } else {
3538
+ swiper.slideTo(swiper.activeIndex, 0, false, true);
3539
+ }
3237
3540
  }
3238
3541
  if (swiper.autoplay && swiper.autoplay.running && swiper.autoplay.paused) {
3239
3542
  clearTimeout(swiper.autoplay.resizeTimeout);
@@ -3243,11 +3546,10 @@ var Swiper = (function () {
3243
3546
  }
3244
3547
  }, 500);
3245
3548
  }
3246
-
3247
3549
  // Return locks after resize
3248
3550
  swiper.allowSlidePrev = allowSlidePrev;
3249
3551
  swiper.allowSlideNext = allowSlideNext;
3250
- if (params.watchOverflow && snapGrid !== swiper.snapGrid) {
3552
+ if (swiper.params.watchOverflow && snapGrid !== swiper.snapGrid) {
3251
3553
  swiper.checkOverflow();
3252
3554
  }
3253
3555
  }
@@ -3301,10 +3603,6 @@ var Swiper = (function () {
3301
3603
  if (swiper.params.cssMode || swiper.params.slidesPerView !== 'auto' && !swiper.params.autoHeight) {
3302
3604
  return;
3303
3605
  }
3304
- const el = e?.target;
3305
- // IMG, IFRAME, EMBED with width/height attributes don't change slide size — no need to call swiper.update()
3306
- if (!el || !['IMG', 'IFRAME', 'EMBED'].includes(el.tagName)) return;
3307
- if (el.hasAttribute('width') && el.hasAttribute('height')) return;
3308
3606
  swiper.update();
3309
3607
  }
3310
3608
 
@@ -3416,15 +3714,8 @@ var Swiper = (function () {
3416
3714
  detachEvents
3417
3715
  };
3418
3716
 
3419
- const toggleModule = (swiper, params, breakpointParams, prop) => {
3420
- const wasModuleEnabled = params[prop] && params[prop].enabled;
3421
- const isModuleEnabled = breakpointParams[prop] && breakpointParams[prop].enabled;
3422
- if (wasModuleEnabled && !isModuleEnabled) {
3423
- swiper[prop].disable();
3424
- }
3425
- if (!wasModuleEnabled && isModuleEnabled) {
3426
- swiper[prop].enable();
3427
- }
3717
+ const isGridEnabled = (swiper, params) => {
3718
+ return swiper.grid && params.grid && params.grid.rows > 1;
3428
3719
  };
3429
3720
  function setBreakpoint() {
3430
3721
  const swiper = this;
@@ -3445,20 +3736,38 @@ var Swiper = (function () {
3445
3736
  if (!breakpoint || swiper.currentBreakpoint === breakpoint) return;
3446
3737
  const breakpointOnlyParams = breakpoint in breakpoints ? breakpoints[breakpoint] : undefined;
3447
3738
  const breakpointParams = breakpointOnlyParams || swiper.originalParams;
3739
+ const wasMultiRow = isGridEnabled(swiper, params);
3740
+ const isMultiRow = isGridEnabled(swiper, breakpointParams);
3448
3741
  const wasGrabCursor = swiper.params.grabCursor;
3449
3742
  const isGrabCursor = breakpointParams.grabCursor;
3450
3743
  const wasEnabled = params.enabled;
3744
+ if (wasMultiRow && !isMultiRow) {
3745
+ el.classList.remove(`${params.containerModifierClass}grid`, `${params.containerModifierClass}grid-column`);
3746
+ swiper.emitContainerClasses();
3747
+ } else if (!wasMultiRow && isMultiRow) {
3748
+ el.classList.add(`${params.containerModifierClass}grid`);
3749
+ if (breakpointParams.grid.fill && breakpointParams.grid.fill === 'column' || !breakpointParams.grid.fill && params.grid.fill === 'column') {
3750
+ el.classList.add(`${params.containerModifierClass}grid-column`);
3751
+ }
3752
+ swiper.emitContainerClasses();
3753
+ }
3451
3754
  if (wasGrabCursor && !isGrabCursor) {
3452
3755
  swiper.unsetGrabCursor();
3453
3756
  } else if (!wasGrabCursor && isGrabCursor) {
3454
3757
  swiper.setGrabCursor();
3455
3758
  }
3456
3759
 
3457
- // Core-lite: toggle navigation & pagination only.
3458
- const modules = ['navigation', 'pagination'];
3459
- modules.forEach(prop => {
3760
+ // Toggle navigation, pagination, scrollbar
3761
+ ['navigation', 'pagination', 'scrollbar'].forEach(prop => {
3460
3762
  if (typeof breakpointParams[prop] === 'undefined') return;
3461
- toggleModule(swiper, params, breakpointParams, prop);
3763
+ const wasModuleEnabled = params[prop] && params[prop].enabled;
3764
+ const isModuleEnabled = breakpointParams[prop] && breakpointParams[prop].enabled;
3765
+ if (wasModuleEnabled && !isModuleEnabled) {
3766
+ swiper[prop].disable();
3767
+ }
3768
+ if (!wasModuleEnabled && isModuleEnabled) {
3769
+ swiper[prop].enable();
3770
+ }
3462
3771
  });
3463
3772
  const directionChanged = breakpointParams.direction && breakpointParams.direction !== params.direction;
3464
3773
  const needsReLoop = params.loop && (breakpointParams.slidesPerView !== params.slidesPerView || directionChanged);
@@ -3540,7 +3849,7 @@ var Swiper = (function () {
3540
3849
  getBreakpoint
3541
3850
  };
3542
3851
 
3543
- const prepareClasses = (entries, prefix) => {
3852
+ function prepareClasses(entries, prefix) {
3544
3853
  const resultClasses = [];
3545
3854
  entries.forEach(item => {
3546
3855
  if (typeof item === 'object') {
@@ -3554,7 +3863,7 @@ var Swiper = (function () {
3554
3863
  }
3555
3864
  });
3556
3865
  return resultClasses;
3557
- };
3866
+ }
3558
3867
  function addClasses() {
3559
3868
  const swiper = this;
3560
3869
  const {
@@ -3564,12 +3873,17 @@ var Swiper = (function () {
3564
3873
  el,
3565
3874
  device
3566
3875
  } = swiper;
3567
- // core-lite: removed module-specific classes
3568
3876
  // prettier-ignore
3569
3877
  const suffixes = prepareClasses(['initialized', params.direction, {
3878
+ 'free-mode': swiper.params.freeMode && params.freeMode.enabled
3879
+ }, {
3570
3880
  'autoheight': params.autoHeight
3571
3881
  }, {
3572
3882
  'rtl': rtl
3883
+ }, {
3884
+ 'grid': params.grid && params.grid.rows > 1
3885
+ }, {
3886
+ 'grid-column': params.grid && params.grid.rows > 1 && params.grid.fill === 'column'
3573
3887
  }, {
3574
3888
  'android': device.android
3575
3889
  }, {
@@ -3666,12 +3980,16 @@ var Swiper = (function () {
3666
3980
  autoHeight: false,
3667
3981
  // Set wrapper width
3668
3982
  setWrapperSize: false,
3669
- // Effects (core-lite only supports `slide`)
3983
+ // Virtual Translate
3984
+ virtualTranslate: false,
3985
+ // Effects
3670
3986
  effect: 'slide',
3987
+ // 'slide' or 'fade' or 'cube' or 'coverflow' or 'flip'
3988
+
3671
3989
  // Breakpoints
3672
3990
  breakpoints: undefined,
3673
3991
  breakpointsBase: 'window',
3674
- // Slides
3992
+ // Slides grid
3675
3993
  spaceBetween: 0,
3676
3994
  slidesPerView: 1,
3677
3995
  slidesPerGroup: 1,
@@ -3774,9 +4092,7 @@ var Swiper = (function () {
3774
4092
  if (moduleParamName === 'navigation' && params[moduleParamName] && params[moduleParamName].enabled && !params[moduleParamName].prevEl && !params[moduleParamName].nextEl) {
3775
4093
  params[moduleParamName].auto = true;
3776
4094
  }
3777
-
3778
- // Core-lite: keep only pagination auto-init.
3779
- if (moduleParamName === 'pagination' && params[moduleParamName] && params[moduleParamName].enabled && !params[moduleParamName].el) {
4095
+ if (['pagination', 'scrollbar'].indexOf(moduleParamName) >= 0 && params[moduleParamName] && params[moduleParamName].enabled && !params[moduleParamName].el) {
3780
4096
  params[moduleParamName].auto = true;
3781
4097
  }
3782
4098
  if (!(moduleParamName in params && 'enabled' in moduleParams)) {
@@ -3902,6 +4218,7 @@ var Swiper = (function () {
3902
4218
  // Indexes
3903
4219
  activeIndex: 0,
3904
4220
  realIndex: 0,
4221
+ //
3905
4222
  isBeginning: true,
3906
4223
  isEnd: false,
3907
4224
  // Props
@@ -3928,9 +4245,12 @@ var Swiper = (function () {
3928
4245
  currentTranslate: undefined,
3929
4246
  startTranslate: undefined,
3930
4247
  allowThresholdMove: undefined,
4248
+ // Form elements to match
3931
4249
  focusableElements: swiper.params.focusableElements,
4250
+ // Last click time
3932
4251
  lastClickTime: 0,
3933
4252
  clickTimeout: undefined,
4253
+ // Velocities
3934
4254
  velocities: [],
3935
4255
  allowMomentumBounce: undefined,
3936
4256
  startMoving: undefined,
@@ -3959,6 +4279,7 @@ var Swiper = (function () {
3959
4279
  swiper.init();
3960
4280
  }
3961
4281
 
4282
+ // Return app instance
3962
4283
  // eslint-disable-next-line no-constructor-return
3963
4284
  return swiper;
3964
4285
  }
@@ -3990,6 +4311,16 @@ var Swiper = (function () {
3990
4311
  getSlideIndexByData(index) {
3991
4312
  return this.getSlideIndex(this.slides.find(slideEl => slideEl.getAttribute('data-swiper-slide-index') * 1 === index));
3992
4313
  }
4314
+ getSlideIndexWhenGrid(index) {
4315
+ if (this.grid && this.params.grid && this.params.grid.rows > 1) {
4316
+ if (this.params.grid.fill === 'column') {
4317
+ index = Math.floor(index / this.params.grid.rows);
4318
+ } else if (this.params.grid.fill === 'row') {
4319
+ index = index % Math.ceil(this.slides.length / this.params.grid.rows);
4320
+ }
4321
+ }
4322
+ return index;
4323
+ }
3993
4324
  recalcSlides() {
3994
4325
  const swiper = this;
3995
4326
  const {
@@ -4091,15 +4422,21 @@ var Swiper = (function () {
4091
4422
  }
4092
4423
  }
4093
4424
  } else {
4425
+ // eslint-disable-next-line
4094
4426
  if (view === 'current') {
4095
4427
  for (let i = activeIndex + 1; i < slides.length; i += 1) {
4096
4428
  const slideInView = exact ? slidesGrid[i] + slidesSizesGrid[i] - slidesGrid[activeIndex] < swiperSize : slidesGrid[i] - slidesGrid[activeIndex] < swiperSize;
4097
- if (slideInView) spv += 1;
4429
+ if (slideInView) {
4430
+ spv += 1;
4431
+ }
4098
4432
  }
4099
4433
  } else {
4434
+ // previous
4100
4435
  for (let i = activeIndex - 1; i >= 0; i -= 1) {
4101
4436
  const slideInView = slidesGrid[activeIndex] - slidesGrid[i] < swiperSize;
4102
- if (slideInView) spv += 1;
4437
+ if (slideInView) {
4438
+ spv += 1;
4439
+ }
4103
4440
  }
4104
4441
  }
4105
4442
  }
@@ -4112,11 +4449,14 @@ var Swiper = (function () {
4112
4449
  snapGrid,
4113
4450
  params
4114
4451
  } = swiper;
4452
+ // Breakpoints
4115
4453
  if (params.breakpoints) {
4116
4454
  swiper.setBreakpoint();
4117
4455
  }
4118
4456
  [...swiper.el.querySelectorAll('[loading="lazy"]')].forEach(imageEl => {
4119
- if (imageEl.complete) processLazyPreloader(swiper, imageEl);
4457
+ if (imageEl.complete) {
4458
+ processLazyPreloader(swiper, imageEl);
4459
+ }
4120
4460
  });
4121
4461
  swiper.updateSize();
4122
4462
  swiper.updateSlides();
@@ -4130,12 +4470,22 @@ var Swiper = (function () {
4130
4470
  swiper.updateSlidesClasses();
4131
4471
  }
4132
4472
  let translated;
4133
- if ((params.slidesPerView === 'auto' || params.slidesPerView > 1) && swiper.isEnd && !params.centeredSlides) {
4134
- translated = swiper.slideTo(swiper.slides.length - 1, 0, false, true);
4473
+ if (params.freeMode && params.freeMode.enabled && !params.cssMode) {
4474
+ setTranslate();
4475
+ if (params.autoHeight) {
4476
+ swiper.updateAutoHeight();
4477
+ }
4135
4478
  } else {
4136
- translated = swiper.slideTo(swiper.activeIndex, 0, false, true);
4479
+ if ((params.slidesPerView === 'auto' || params.slidesPerView > 1) && swiper.isEnd && !params.centeredSlides) {
4480
+ const slides = swiper.virtual && params.virtual.enabled ? swiper.virtual.slides : swiper.slides;
4481
+ translated = swiper.slideTo(slides.length - 1, 0, false, true);
4482
+ } else {
4483
+ translated = swiper.slideTo(swiper.activeIndex, 0, false, true);
4484
+ }
4485
+ if (!translated) {
4486
+ setTranslate();
4487
+ }
4137
4488
  }
4138
- if (!translated) setTranslate();
4139
4489
  if (params.watchOverflow && snapGrid !== swiper.snapGrid) {
4140
4490
  swiper.checkOverflow();
4141
4491
  }
@@ -4148,6 +4498,7 @@ var Swiper = (function () {
4148
4498
  const swiper = this;
4149
4499
  const currentDirection = swiper.params.direction;
4150
4500
  if (!newDirection) {
4501
+ // eslint-disable-next-line
4151
4502
  newDirection = currentDirection === 'horizontal' ? 'vertical' : 'horizontal';
4152
4503
  }
4153
4504
  if (newDirection === currentDirection || newDirection !== 'horizontal' && newDirection !== 'vertical') {
@@ -4185,11 +4536,15 @@ var Swiper = (function () {
4185
4536
  mount(element) {
4186
4537
  const swiper = this;
4187
4538
  if (swiper.mounted) return true;
4539
+
4540
+ // Find el
4188
4541
  let el = element || swiper.params.el;
4189
4542
  if (typeof el === 'string') {
4190
4543
  el = document.querySelector(el);
4191
4544
  }
4192
- if (!el) return false;
4545
+ if (!el) {
4546
+ return false;
4547
+ }
4193
4548
  el.swiper = swiper;
4194
4549
  if (el.parentNode && el.parentNode.host && el.parentNode.host.nodeName === swiper.params.swiperElementNodeName.toUpperCase()) {
4195
4550
  swiper.isElement = true;
@@ -4200,10 +4555,12 @@ var Swiper = (function () {
4200
4555
  const getWrapper = () => {
4201
4556
  if (el && el.shadowRoot && el.shadowRoot.querySelector) {
4202
4557
  const res = el.shadowRoot.querySelector(getWrapperSelector());
4558
+ // Children needs to return slot items
4203
4559
  return res;
4204
4560
  }
4205
4561
  return elementChildren(el, getWrapperSelector())[0];
4206
4562
  };
4563
+ // Find Wrapper
4207
4564
  let wrapperEl = getWrapper();
4208
4565
  if (!wrapperEl && swiper.params.createElements) {
4209
4566
  wrapperEl = createElement('div', swiper.params.wrapperClass);
@@ -4218,6 +4575,7 @@ var Swiper = (function () {
4218
4575
  slidesEl: swiper.isElement && !el.parentNode.host.slideSlots ? el.parentNode.host : wrapperEl,
4219
4576
  hostEl: swiper.isElement ? el.parentNode.host : el,
4220
4577
  mounted: true,
4578
+ // RTL
4221
4579
  rtl: el.dir.toLowerCase() === 'rtl' || elementStyle(el, 'direction') === 'rtl',
4222
4580
  rtlTranslate: swiper.params.direction === 'horizontal' && (el.dir.toLowerCase() === 'rtl' || elementStyle(el, 'direction') === 'rtl'),
4223
4581
  wrongRTL: elementStyle(wrapperEl, 'display') === '-webkit-box'
@@ -4237,6 +4595,7 @@ var Swiper = (function () {
4237
4595
  const gap = Math.abs(swiper.snapGrid[1] - swiper.snapGrid[0]);
4238
4596
  const swiperTranslate = structuredClone(swiper.snapGrid[1]);
4239
4597
  if (isFirstSlide) {
4598
+ // Move last item to first position when at first slide
4240
4599
  const lastSlide = slides.at(-1);
4241
4600
  lastSlide.swiperLoopMoveDOM = true;
4242
4601
  swiper.slidesEl.prepend(lastSlide);
@@ -4248,6 +4607,7 @@ var Swiper = (function () {
4248
4607
  swiper.setTransition(speed);
4249
4608
  swiper.setTranslate(-swiperTranslate);
4250
4609
  } else if (isLastSlide) {
4610
+ // Move first item to last position when at last slide
4251
4611
  const firstSlide = slides[0];
4252
4612
  firstSlide.swiperLoopMoveDOM = true;
4253
4613
  swiper.slidesEl.append(firstSlide);
@@ -4268,24 +4628,42 @@ var Swiper = (function () {
4268
4628
  const mounted = swiper.mount(el);
4269
4629
  if (mounted === false) return swiper;
4270
4630
  swiper.emit('beforeInit');
4631
+
4632
+ // Set breakpoint
4271
4633
  if (swiper.params.breakpoints) {
4272
4634
  swiper.setBreakpoint();
4273
4635
  }
4636
+
4637
+ // Add Classes
4274
4638
  swiper.addClasses();
4639
+
4640
+ // Update size
4275
4641
  swiper.updateSize();
4642
+
4643
+ // Update slides
4276
4644
  swiper.updateSlides();
4277
4645
  if (swiper.params.watchOverflow) {
4278
4646
  swiper.checkOverflow();
4279
4647
  }
4648
+
4649
+ // Set Grab Cursor
4280
4650
  if (swiper.params.grabCursor && swiper.enabled) {
4281
4651
  swiper.setGrabCursor();
4282
4652
  }
4283
4653
 
4284
- // Slide to initial slide (core-lite: no optional feature initial offsets)
4285
- swiper.slideTo(swiper.params.initialSlide, 0, swiper.params.runCallbacksOnInit, false, true);
4654
+ // Slide To Initial Slide
4655
+ if (swiper.params.loop && swiper.virtual && swiper.params.virtual.enabled) {
4656
+ swiper.slideTo(swiper.params.initialSlide + swiper.virtual.slidesBefore, 0, swiper.params.runCallbacksOnInit, false, true);
4657
+ } else {
4658
+ swiper.slideTo(swiper.params.initialSlide, 0, swiper.params.runCallbacksOnInit, false, true);
4659
+ }
4660
+
4661
+ // Create loop
4286
4662
  if (swiper.params.loop) {
4287
4663
  swiper.loopCreate(undefined, true);
4288
4664
  }
4665
+
4666
+ // Attach events
4289
4667
  swiper.attachEvents();
4290
4668
  const lazyElements = [...swiper.el.querySelectorAll('[loading="lazy"]')];
4291
4669
  if (swiper.isElement) {
@@ -4295,12 +4673,18 @@ var Swiper = (function () {
4295
4673
  if (imageEl.complete) {
4296
4674
  processLazyPreloader(swiper, imageEl);
4297
4675
  } else {
4298
- imageEl.addEventListener('load', e => processLazyPreloader(swiper, e.target));
4676
+ imageEl.addEventListener('load', e => {
4677
+ processLazyPreloader(swiper, e.target);
4678
+ });
4299
4679
  }
4300
4680
  });
4301
4681
  preload(swiper);
4682
+
4683
+ // Init Flag
4302
4684
  swiper.initialized = true;
4303
4685
  preload(swiper);
4686
+
4687
+ // Emit
4304
4688
  swiper.emit('init');
4305
4689
  swiper.emit('afterInit');
4306
4690
  return swiper;
@@ -4323,15 +4707,27 @@ var Swiper = (function () {
4323
4707
  return null;
4324
4708
  }
4325
4709
  swiper.emit('beforeDestroy');
4710
+
4711
+ // Init Flag
4326
4712
  swiper.initialized = false;
4713
+
4714
+ // Detach events
4327
4715
  swiper.detachEvents();
4716
+
4717
+ // Destroy loop
4328
4718
  if (params.loop) {
4329
4719
  swiper.loopDestroy();
4330
4720
  }
4721
+
4722
+ // Cleanup styles
4331
4723
  if (cleanStyles) {
4332
4724
  swiper.removeClasses();
4333
- if (el && typeof el !== 'string') el.removeAttribute('style');
4334
- if (wrapperEl) wrapperEl.removeAttribute('style');
4725
+ if (el && typeof el !== 'string') {
4726
+ el.removeAttribute('style');
4727
+ }
4728
+ if (wrapperEl) {
4729
+ wrapperEl.removeAttribute('style');
4730
+ }
4335
4731
  if (slides && slides.length) {
4336
4732
  slides.forEach(slideEl => {
4337
4733
  slideEl.classList.remove(params.slideVisibleClass, params.slideFullyVisibleClass, params.slideActiveClass, params.slideNextClass, params.slidePrevClass);
@@ -4341,6 +4737,8 @@ var Swiper = (function () {
4341
4737
  }
4342
4738
  }
4343
4739
  swiper.emit('destroy');
4740
+
4741
+ // Detach emitter events
4344
4742
  Object.keys(swiper.eventsListeners).forEach(eventName => {
4345
4743
  swiper.off(eventName);
4346
4744
  });