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

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-element.js CHANGED
@@ -1,5 +1,5 @@
1
1
  /**
2
- * Swiper Custom Element 0.0.15
2
+ * Swiper Custom Element 0.0.16-dev.1
3
3
  * Gem SDK - Swiper, Customized of swiper
4
4
  * https://swiperjs.com
5
5
  *
@@ -189,7 +189,7 @@
189
189
  function now() {
190
190
  return Date.now();
191
191
  }
192
- function getComputedStyle$1(el) {
192
+ function getComputedStyle(el) {
193
193
  const window = getWindow();
194
194
  let style;
195
195
  if (window.getComputedStyle) {
@@ -211,7 +211,7 @@
211
211
  let matrix;
212
212
  let curTransform;
213
213
  let transformMatrix;
214
- const curStyle = getComputedStyle$1(el);
214
+ const curStyle = getComputedStyle(el);
215
215
  if (window.WebKitCSSMatrix) {
216
216
  curTransform = curStyle.transform || curStyle.webkitTransform;
217
217
  if (curTransform.split(',').length > 6) {
@@ -459,6 +459,23 @@
459
459
  el.innerHTML = html;
460
460
  }
461
461
  }
462
+ function computeAutoSlideSize(slideEl, getDirectionPropValue) {
463
+ const styles = getComputedStyle(slideEl);
464
+ const width = getDirectionPropValue(styles, 'width');
465
+ const paddingLeft = getDirectionPropValue(styles, 'padding-left');
466
+ const paddingRight = getDirectionPropValue(styles, 'padding-right');
467
+ const marginLeft = getDirectionPropValue(styles, 'margin-left');
468
+ const marginRight = getDirectionPropValue(styles, 'margin-right');
469
+ const boxSizing = styles.getPropertyValue('box-sizing');
470
+ if (boxSizing && boxSizing === 'border-box') {
471
+ return width + marginLeft + marginRight;
472
+ }
473
+ const {
474
+ clientWidth,
475
+ offsetWidth
476
+ } = slideEl;
477
+ return width + paddingLeft + paddingRight + marginLeft + marginRight + (offsetWidth - clientWidth);
478
+ }
462
479
 
463
480
  let support;
464
481
  function calcSupport() {
@@ -841,9 +858,6 @@
841
858
 
842
859
  function updateSlides() {
843
860
  const swiper = this;
844
- function getDirectionPropertyValue(node, label) {
845
- return parseFloat(node.getPropertyValue(swiper.getDirectionLabel(label)) || 0);
846
- }
847
861
  const params = swiper.params;
848
862
  const {
849
863
  wrapperEl,
@@ -852,10 +866,8 @@
852
866
  rtlTranslate: rtl,
853
867
  wrongRTL
854
868
  } = swiper;
855
- const isVirtual = swiper.virtual && params.virtual.enabled;
856
- const previousSlidesLength = isVirtual ? swiper.virtual.slides.length : swiper.slides.length;
857
869
  const slides = elementChildren(slidesEl, `.${swiper.params.slideClass}, swiper-slide`);
858
- const slidesLength = isVirtual ? swiper.virtual.slides.length : slides.length;
870
+ const slidesLength = slides.length;
859
871
  let snapGrid = [];
860
872
  const slidesGrid = [];
861
873
  const slidesSizesGrid = [];
@@ -873,15 +885,15 @@
873
885
  let slidePosition = -offsetBefore;
874
886
  let prevSlideSize = 0;
875
887
  let index = 0;
876
- if (typeof swiperSize === 'undefined') {
877
- return;
878
- }
888
+ if (typeof swiperSize === 'undefined') return;
879
889
  if (typeof spaceBetween === 'string' && spaceBetween.indexOf('%') >= 0) {
880
890
  spaceBetween = parseFloat(spaceBetween.replace('%', '')) / 100 * swiperSize;
881
891
  } else if (typeof spaceBetween === 'string') {
882
892
  spaceBetween = parseFloat(spaceBetween);
883
893
  }
884
- swiper.virtualSize = -spaceBetween;
894
+
895
+ // core-lite: compute total slides size without optional modules
896
+ swiper.slidesTotalSize = -spaceBetween;
885
897
 
886
898
  // reset margins
887
899
  slides.forEach(slideEl => {
@@ -899,67 +911,91 @@
899
911
  setCSSProperty(wrapperEl, '--swiper-centered-offset-before', '');
900
912
  setCSSProperty(wrapperEl, '--swiper-centered-offset-after', '');
901
913
  }
902
- const gridEnabled = params.grid && params.grid.rows > 1 && swiper.grid;
903
- if (gridEnabled) {
904
- swiper.grid.initSlides(slides);
905
- } else if (swiper.grid) {
906
- swiper.grid.unsetSlides();
907
- }
908
914
 
909
915
  // Calc slides
910
916
  let slideSize;
911
- const shouldResetSlideSize = params.slidesPerView === 'auto' && params.breakpoints && Object.keys(params.breakpoints).filter(key => {
912
- return typeof params.breakpoints[key].slidesPerView !== 'undefined';
913
- }).length > 0;
914
- for (let i = 0; i < slidesLength; i += 1) {
915
- slideSize = 0;
916
- let slide;
917
- if (slides[i]) slide = slides[i];
918
- if (gridEnabled) {
919
- swiper.grid.updateSlide(i, slide, slides);
920
- }
921
- if (slides[i] && elementStyle(slide, 'display') === 'none') continue; // eslint-disable-line
917
+ const shouldResetSlideSize = params.slidesPerView === 'auto' && params.breakpoints && Object.keys(params.breakpoints).filter(key => typeof params.breakpoints[key].slidesPerView !== 'undefined').length > 0;
918
+ const isAutoSlides = params.slidesPerView === 'auto';
922
919
 
923
- if (params.slidesPerView === 'auto') {
920
+ // --- Phase 1: Batch DOM writes (grid updates, width/transform resets) ---
921
+ // Moving all style writes before any reads prevents per-slide forced reflows
922
+ if (gridEnabled) {
923
+ for (let i = 0; i < slidesLength; i += 1) {
924
+ if (slides[i]) swiper.grid.updateSlide(i, slides[i], slides);
925
+ }
926
+ }
927
+ const savedTransforms = [];
928
+ if (isAutoSlides) {
929
+ for (let i = 0; i < slidesLength; i += 1) {
930
+ if (!slides[i]) continue;
924
931
  if (shouldResetSlideSize) {
925
932
  slides[i].style[swiper.getDirectionLabel('width')] = ``;
926
933
  }
927
- const slideStyles = getComputedStyle(slide);
928
- const currentTransform = slide.style.transform;
929
- const currentWebKitTransform = slide.style.webkitTransform;
934
+ const currentTransform = slides[i].style.transform;
935
+ const currentWebKitTransform = slides[i].style.webkitTransform;
936
+ savedTransforms[i] = {
937
+ transform: currentTransform,
938
+ webkitTransform: currentWebKitTransform
939
+ };
930
940
  if (currentTransform) {
931
- slide.style.transform = 'none';
941
+ slides[i].style.transform = 'none';
932
942
  }
933
943
  if (currentWebKitTransform) {
934
- slide.style.webkitTransform = 'none';
944
+ slides[i].style.webkitTransform = 'none';
935
945
  }
946
+ }
947
+ }
948
+
949
+ // --- Phase 2: Batch DOM reads (single forced reflow for all slides) ---
950
+ // Read wrapper offset here (before Phase 3 writes) so it's batched with slide reads, not after
951
+ const wrapperOffset = swiper.isElement ? swiper.wrapperEl[`offset${swiper.isHorizontal() ? 'Left' : 'Top'}`] : 0;
952
+ const slideVisible = [];
953
+ const slideSizes = [];
954
+ for (let i = 0; i < slidesLength; i += 1) {
955
+ if (!slides[i]) {
956
+ slideVisible[i] = false;
957
+ continue;
958
+ }
959
+ if (elementStyle(slides[i], 'display') === 'none') {
960
+ slideVisible[i] = false;
961
+ continue;
962
+ }
963
+ slideVisible[i] = true;
964
+
965
+ // Cache offsetHeight for autoHeight (batched here to avoid a separate forced reflow in updateAutoHeight)
966
+ if (params.autoHeight) {
967
+ slides[i].swiperSlideHeight = slides[i]['offsetHeight'];
968
+ }
969
+ if (isAutoSlides) {
936
970
  if (params.roundLengths) {
937
- slideSize = swiper.isHorizontal() ? elementOuterSize(slide, 'width', true) : elementOuterSize(slide, 'height', true);
971
+ slideSizes[i] = swiper.isHorizontal() ? elementOuterSize(slides[i], 'width', true) : elementOuterSize(slides[i], 'height', true);
938
972
  } else {
939
- // eslint-disable-next-line
940
- const width = getDirectionPropertyValue(slideStyles, 'width');
941
- const paddingLeft = getDirectionPropertyValue(slideStyles, 'padding-left');
942
- const paddingRight = getDirectionPropertyValue(slideStyles, 'padding-right');
943
- const marginLeft = getDirectionPropertyValue(slideStyles, 'margin-left');
944
- const marginRight = getDirectionPropertyValue(slideStyles, 'margin-right');
945
- const boxSizing = slideStyles.getPropertyValue('box-sizing');
946
- if (boxSizing && boxSizing === 'border-box') {
947
- slideSize = width + marginLeft + marginRight;
948
- } else {
949
- const {
950
- clientWidth,
951
- offsetWidth
952
- } = slide;
953
- slideSize = width + paddingLeft + paddingRight + marginLeft + marginRight + (offsetWidth - clientWidth);
954
- }
973
+ slideSizes[i] = computeAutoSlideSize(slides[i], getDirectionPropertyValue);
955
974
  }
956
- if (currentTransform) {
957
- slide.style.transform = currentTransform;
975
+ if (params.roundLengths) slideSizes[i] = Math.floor(slideSizes[i]);
976
+ }
977
+ }
978
+
979
+ // --- Phase 3: Restore transforms (batch write) ---
980
+ if (isAutoSlides) {
981
+ for (let i = 0; i < slidesLength; i += 1) {
982
+ if (!savedTransforms[i]) continue;
983
+ if (savedTransforms[i].transform) {
984
+ slides[i].style.transform = savedTransforms[i].transform;
958
985
  }
959
- if (currentWebKitTransform) {
960
- slide.style.webkitTransform = currentWebKitTransform;
986
+ if (savedTransforms[i].webkitTransform) {
987
+ slides[i].style.webkitTransform = savedTransforms[i].webkitTransform;
961
988
  }
962
- if (params.roundLengths) slideSize = Math.floor(slideSize);
989
+ }
990
+ }
991
+
992
+ // --- Phase 4: Calculate positions + set sizes (math + deferred writes) ---
993
+ const cssOverflowAdj = swiper.cssOverflowAdjustment();
994
+ for (let i = 0; i < slidesLength; i += 1) {
995
+ slideSize = 0;
996
+ if (!slideVisible[i]) continue;
997
+ if (isAutoSlides) {
998
+ slideSize = slideSizes[i] || 0;
963
999
  } else {
964
1000
  slideSize = (swiperSize - (params.slidesPerView - 1) * spaceBetween) / params.slidesPerView;
965
1001
  if (params.roundLengths) slideSize = Math.floor(slideSize);
@@ -967,13 +1003,13 @@
967
1003
  slides[i].style[swiper.getDirectionLabel('width')] = `${slideSize}px`;
968
1004
  }
969
1005
  }
970
- if (slides[i]) {
971
- slides[i].swiperSlideSize = slideSize;
972
- }
1006
+ if (slides[i]) slides[i].swiperSlideSize = slideSize;
973
1007
  slidesSizesGrid.push(slideSize);
974
1008
  if (params.centeredSlides) {
975
1009
  slidePosition = slidePosition + slideSize / 2 + prevSlideSize / 2 + spaceBetween;
976
- if (prevSlideSize === 0 && i !== 0) slidePosition = slidePosition - swiperSize / 2 - spaceBetween;
1010
+ if (prevSlideSize === 0 && i !== 0) {
1011
+ slidePosition = slidePosition - swiperSize / 2 - spaceBetween;
1012
+ }
977
1013
  if (i === 0) slidePosition = slidePosition - swiperSize / 2 - spaceBetween;
978
1014
  if (Math.abs(slidePosition) < 1 / 1000) slidePosition = 0;
979
1015
  if (params.roundLengths) slidePosition = Math.floor(slidePosition);
@@ -981,55 +1017,42 @@
981
1017
  slidesGrid.push(slidePosition);
982
1018
  } else {
983
1019
  if (params.roundLengths) slidePosition = Math.floor(slidePosition);
984
- if ((index - Math.min(swiper.params.slidesPerGroupSkip, index)) % swiper.params.slidesPerGroup === 0) snapGrid.push(slidePosition);
1020
+ if ((index - Math.min(swiper.params.slidesPerGroupSkip, index)) % swiper.params.slidesPerGroup === 0) {
1021
+ snapGrid.push(slidePosition);
1022
+ }
985
1023
  slidesGrid.push(slidePosition);
986
1024
  slidePosition = slidePosition + slideSize + spaceBetween;
987
1025
  }
1026
+
1027
+ // Set swiperSlideOffset from computed grid position (avoids DOM reads in updateSlidesOffset)
1028
+ if (slides[i]) {
1029
+ slides[i].swiperSlideOffset = slidesGrid[slidesGrid.length - 1] - cssOverflowAdj - wrapperOffset;
1030
+ }
988
1031
  swiper.virtualSize += slideSize + spaceBetween;
989
1032
  prevSlideSize = slideSize;
990
1033
  index += 1;
991
1034
  }
992
- swiper.virtualSize = Math.max(swiper.virtualSize, swiperSize) + offsetAfter;
993
- if (rtl && wrongRTL && (params.effect === 'slide' || params.effect === 'coverflow')) {
994
- wrapperEl.style.width = `${swiper.virtualSize + spaceBetween}px`;
1035
+ swiper.slidesTotalSize = Math.max(swiper.slidesTotalSize, swiperSize) + offsetAfter;
1036
+ if (rtl && wrongRTL && params.effect === 'slide') {
1037
+ wrapperEl.style.width = `${swiper.slidesTotalSize + spaceBetween}px`;
995
1038
  }
996
1039
  if (params.setWrapperSize) {
997
- wrapperEl.style[swiper.getDirectionLabel('width')] = `${swiper.virtualSize + spaceBetween}px`;
998
- }
999
- if (gridEnabled) {
1000
- swiper.grid.updateWrapperSize(slideSize, snapGrid);
1040
+ wrapperEl.style[swiper.getDirectionLabel('width')] = `${swiper.slidesTotalSize + spaceBetween}px`;
1001
1041
  }
1002
1042
 
1003
- // Remove last grid elements depending on width
1043
+ // Remove last snap points depending on width (non-centered)
1004
1044
  if (!params.centeredSlides) {
1005
1045
  const newSlidesGrid = [];
1006
1046
  for (let i = 0; i < snapGrid.length; i += 1) {
1007
1047
  let slidesGridItem = snapGrid[i];
1008
1048
  if (params.roundLengths) slidesGridItem = Math.floor(slidesGridItem);
1009
- if (snapGrid[i] <= swiper.virtualSize - swiperSize) {
1049
+ if (snapGrid[i] <= swiper.slidesTotalSize - swiperSize) {
1010
1050
  newSlidesGrid.push(slidesGridItem);
1011
1051
  }
1012
1052
  }
1013
1053
  snapGrid = newSlidesGrid;
1014
- if (Math.floor(swiper.virtualSize - swiperSize) - Math.floor(snapGrid[snapGrid.length - 1]) > 1) {
1015
- snapGrid.push(swiper.virtualSize - swiperSize);
1016
- }
1017
- }
1018
- if (isVirtual && params.loop) {
1019
- const size = slidesSizesGrid[0] + spaceBetween;
1020
- if (params.slidesPerGroup > 1) {
1021
- const groups = Math.ceil((swiper.virtual.slidesBefore + swiper.virtual.slidesAfter) / params.slidesPerGroup);
1022
- const groupSize = size * params.slidesPerGroup;
1023
- for (let i = 0; i < groups; i += 1) {
1024
- snapGrid.push(snapGrid[snapGrid.length - 1] + groupSize);
1025
- }
1026
- }
1027
- for (let i = 0; i < swiper.virtual.slidesBefore + swiper.virtual.slidesAfter; i += 1) {
1028
- if (params.slidesPerGroup === 1) {
1029
- snapGrid.push(snapGrid[snapGrid.length - 1] + size);
1030
- }
1031
- slidesGrid.push(slidesGrid[slidesGrid.length - 1] + size);
1032
- swiper.virtualSize += size;
1054
+ if (Math.floor(swiper.slidesTotalSize - swiperSize) - Math.floor(snapGrid[snapGrid.length - 1]) > 1) {
1055
+ snapGrid.push(swiper.slidesTotalSize - swiperSize);
1033
1056
  }
1034
1057
  }
1035
1058
  if (snapGrid.length === 0) snapGrid = [0];
@@ -1037,9 +1060,7 @@
1037
1060
  const key = swiper.isHorizontal() && rtl ? 'marginLeft' : swiper.getDirectionLabel('marginRight');
1038
1061
  slides.filter((_, slideIndex) => {
1039
1062
  if (!params.cssMode || params.loop) return true;
1040
- if (slideIndex === slides.length - 1) {
1041
- return false;
1042
- }
1063
+ if (slideIndex === slides.length - 1) return false;
1043
1064
  return true;
1044
1065
  }).forEach(slideEl => {
1045
1066
  slideEl.style[key] = `${spaceBetween}px`;
@@ -1089,7 +1110,9 @@
1089
1110
  swiper.snapGrid = swiper.snapGrid.map(v => v + addToSnapGrid);
1090
1111
  swiper.slidesGrid = swiper.slidesGrid.map(v => v + addToSlidesGrid);
1091
1112
  }
1092
- if (slidesLength !== previousSlidesLength) {
1113
+
1114
+ // Emit changes
1115
+ if (slidesLength !== (previousSlidesGridLength ? slides.length : slides.length)) {
1093
1116
  swiper.emit('slidesLengthChange');
1094
1117
  }
1095
1118
  if (snapGrid.length !== previousSnapGridLength) {
@@ -1100,10 +1123,12 @@
1100
1123
  swiper.emit('slidesGridLengthChange');
1101
1124
  }
1102
1125
  if (params.watchSlidesProgress) {
1103
- swiper.updateSlidesOffset();
1126
+ swiper.updateSlidesOffset({
1127
+ isCalculatedFromUpdateSlides: false
1128
+ });
1104
1129
  }
1105
1130
  swiper.emit('slidesUpdated');
1106
- if (!isVirtual && !params.cssMode && (params.effect === 'slide' || params.effect === 'fade')) {
1131
+ if (!params.cssMode && params.effect === 'slide') {
1107
1132
  const backFaceHiddenClass = `${params.containerModifierClass}backface-hidden`;
1108
1133
  const hasClassBackfaceClassAdded = swiper.el.classList.contains(backFaceHiddenClass);
1109
1134
  if (slidesLength <= params.maxBackfaceHiddenSlides) {
@@ -1117,20 +1142,13 @@
1117
1142
  function updateAutoHeight(speed) {
1118
1143
  const swiper = this;
1119
1144
  const activeSlides = [];
1120
- const isVirtual = swiper.virtual && swiper.params.virtual.enabled;
1121
- let newHeight = 0;
1122
- let i;
1123
1145
  if (typeof speed === 'number') {
1124
1146
  swiper.setTransition(speed);
1125
1147
  } else if (speed === true) {
1126
1148
  swiper.setTransition(swiper.params.speed);
1127
1149
  }
1128
- const getSlideByIndex = index => {
1129
- if (isVirtual) {
1130
- return swiper.slides[swiper.getSlideIndexByData(index)];
1131
- }
1132
- return swiper.slides[index];
1133
- };
1150
+ const getSlideByIndex = index => swiper.slides[index];
1151
+
1134
1152
  // Find slides currently in view
1135
1153
  if (swiper.params.slidesPerView !== 'auto' && swiper.params.slidesPerView > 1) {
1136
1154
  if (swiper.params.centeredSlides) {
@@ -1138,9 +1156,9 @@
1138
1156
  activeSlides.push(slide);
1139
1157
  });
1140
1158
  } else {
1141
- for (i = 0; i < Math.ceil(swiper.params.slidesPerView); i += 1) {
1159
+ for (let i = 0; i < Math.ceil(swiper.params.slidesPerView); i += 1) {
1142
1160
  const index = swiper.activeIndex + i;
1143
- if (index > swiper.slides.length && !isVirtual) break;
1161
+ if (index > swiper.slides.length) break;
1144
1162
  activeSlides.push(getSlideByIndex(index));
1145
1163
  }
1146
1164
  }
@@ -1149,18 +1167,23 @@
1149
1167
  }
1150
1168
 
1151
1169
  // Find new height from highest slide in view
1152
- for (i = 0; i < activeSlides.length; i += 1) {
1170
+ let newHeight = 0;
1171
+ for (let i = 0; i < activeSlides.length; i += 1) {
1153
1172
  if (typeof activeSlides[i] !== 'undefined') {
1154
- const height = activeSlides[i].offsetHeight;
1173
+ const height = activeSlides[i].swiperSlideHeight ?? activeSlides[i]['offsetHeight'];
1155
1174
  newHeight = height > newHeight ? height : newHeight;
1156
1175
  }
1157
1176
  }
1158
-
1159
- // Update Height
1160
1177
  if (newHeight || newHeight === 0) swiper.wrapperEl.style.height = `${newHeight}px`;
1161
1178
  }
1162
1179
 
1163
- function updateSlidesOffset() {
1180
+ function updateSlidesOffset(params) {
1181
+ const {
1182
+ isCalculatedFromUpdateSlides = false
1183
+ } = params ?? {};
1184
+ if (isCalculatedFromUpdateSlides) {
1185
+ return;
1186
+ }
1164
1187
  const swiper = this;
1165
1188
  const slides = swiper.slides;
1166
1189
  // eslint-disable-next-line
@@ -1301,46 +1324,16 @@
1301
1324
  slidesEl,
1302
1325
  activeIndex
1303
1326
  } = swiper;
1304
- const isVirtual = swiper.virtual && params.virtual.enabled;
1305
- const gridEnabled = swiper.grid && params.grid && params.grid.rows > 1;
1306
- const getFilteredSlide = selector => {
1307
- return elementChildren(slidesEl, `.${params.slideClass}${selector}, swiper-slide${selector}`)[0];
1308
- };
1309
- let activeSlide;
1310
- let prevSlide;
1327
+ const getNextSlide = slideEl => elementNextAll(slideEl, `.${params.slideClass}, swiper-slide`)[0];
1328
+ const getPrevSlide = slideEl => elementPrevAll(slideEl, `.${params.slideClass}, swiper-slide`)[0];
1329
+ const activeSlide = slides[activeIndex];
1311
1330
  let nextSlide;
1312
- if (isVirtual) {
1313
- if (params.loop) {
1314
- let slideIndex = activeIndex - swiper.virtual.slidesBefore;
1315
- if (slideIndex < 0) slideIndex = swiper.virtual.slides.length + slideIndex;
1316
- if (slideIndex >= swiper.virtual.slides.length) slideIndex -= swiper.virtual.slides.length;
1317
- activeSlide = getFilteredSlide(`[data-swiper-slide-index="${slideIndex}"]`);
1318
- } else {
1319
- activeSlide = getFilteredSlide(`[data-swiper-slide-index="${activeIndex}"]`);
1320
- }
1321
- } else {
1322
- if (gridEnabled) {
1323
- activeSlide = slides.find(slideEl => slideEl.column === activeIndex);
1324
- nextSlide = slides.find(slideEl => slideEl.column === activeIndex + 1);
1325
- prevSlide = slides.find(slideEl => slideEl.column === activeIndex - 1);
1326
- } else {
1327
- activeSlide = slides[activeIndex];
1328
- }
1329
- }
1331
+ let prevSlide;
1330
1332
  if (activeSlide) {
1331
- if (!gridEnabled) {
1332
- // Next Slide
1333
- nextSlide = elementNextAll(activeSlide, `.${params.slideClass}, swiper-slide`)[0];
1334
- if (params.loop && !nextSlide) {
1335
- nextSlide = slides[0];
1336
- }
1337
-
1338
- // Prev Slide
1339
- prevSlide = elementPrevAll(activeSlide, `.${params.slideClass}, swiper-slide`)[0];
1340
- if (params.loop && !prevSlide === 0) {
1341
- prevSlide = slides[slides.length - 1];
1342
- }
1343
- }
1333
+ nextSlide = getNextSlide(activeSlide);
1334
+ prevSlide = getPrevSlide(activeSlide);
1335
+ if (params.loop && !nextSlide) nextSlide = slides[0];
1336
+ if (params.loop && !prevSlide) prevSlide = slides[slides.length - 1];
1344
1337
  }
1345
1338
  slides.forEach(slideEl => {
1346
1339
  toggleSlideClasses(slideEl, slideEl === activeSlide, params.slideActiveClass);
@@ -1431,7 +1424,6 @@
1431
1424
  activeIndex = i;
1432
1425
  }
1433
1426
  }
1434
- // Normalize slideIndex
1435
1427
  if (params.normalizeSlideIndex) {
1436
1428
  if (activeIndex < 0 || typeof activeIndex === 'undefined') activeIndex = 0;
1437
1429
  }
@@ -1449,16 +1441,6 @@
1449
1441
  } = swiper;
1450
1442
  let activeIndex = newActiveIndex;
1451
1443
  let snapIndex;
1452
- const getVirtualRealIndex = aIndex => {
1453
- let realIndex = aIndex - swiper.virtual.slidesBefore;
1454
- if (realIndex < 0) {
1455
- realIndex = swiper.virtual.slides.length + realIndex;
1456
- }
1457
- if (realIndex >= swiper.virtual.slides.length) {
1458
- realIndex -= swiper.virtual.slides.length;
1459
- }
1460
- return realIndex;
1461
- };
1462
1444
  if (typeof activeIndex === 'undefined') {
1463
1445
  activeIndex = getActiveIndexByTranslate(swiper);
1464
1446
  }
@@ -1476,32 +1458,12 @@
1476
1458
  }
1477
1459
  return;
1478
1460
  }
1479
- if (activeIndex === previousIndex && swiper.params.loop && swiper.virtual && swiper.params.virtual.enabled) {
1480
- swiper.realIndex = getVirtualRealIndex(activeIndex);
1481
- return;
1482
- }
1483
- const gridEnabled = swiper.grid && params.grid && params.grid.rows > 1;
1484
-
1485
- // Get real index
1486
- let realIndex;
1487
- if (swiper.virtual && params.virtual.enabled && params.loop) {
1488
- realIndex = getVirtualRealIndex(activeIndex);
1489
- } else if (gridEnabled) {
1490
- const firstSlideInColumn = swiper.slides.find(slideEl => slideEl.column === activeIndex);
1491
- let activeSlideIndex = parseInt(firstSlideInColumn.getAttribute('data-swiper-slide-index'), 10);
1492
- if (Number.isNaN(activeSlideIndex)) {
1493
- activeSlideIndex = Math.max(swiper.slides.indexOf(firstSlideInColumn), 0);
1494
- }
1495
- realIndex = Math.floor(activeSlideIndex / params.grid.rows);
1496
- } else if (swiper.slides[activeIndex]) {
1461
+ let realIndex = activeIndex;
1462
+ if (swiper.slides[activeIndex]) {
1497
1463
  const slideIndex = swiper.slides[activeIndex].getAttribute('data-swiper-slide-index');
1498
1464
  if (slideIndex) {
1499
1465
  realIndex = parseInt(slideIndex, 10);
1500
- } else {
1501
- realIndex = activeIndex;
1502
1466
  }
1503
- } else {
1504
- realIndex = activeIndex;
1505
1467
  }
1506
1468
  Object.assign(swiper, {
1507
1469
  previousSnapIndex,
@@ -1548,11 +1510,7 @@
1548
1510
  }
1549
1511
  if (slide && slideFound) {
1550
1512
  swiper.clickedSlide = slide;
1551
- if (swiper.virtual && swiper.params.virtual.enabled) {
1552
- swiper.clickedIndex = parseInt(slide.getAttribute('data-swiper-slide-index'), 10);
1553
- } else {
1554
- swiper.clickedIndex = slideIndex;
1555
- }
1513
+ swiper.clickedIndex = slideIndex;
1556
1514
  } else {
1557
1515
  swiper.clickedSlide = undefined;
1558
1516
  swiper.clickedIndex = undefined;
@@ -1586,9 +1544,6 @@
1586
1544
  translate,
1587
1545
  wrapperEl
1588
1546
  } = swiper;
1589
- if (params.virtualTranslate) {
1590
- return rtl ? -translate : translate;
1591
- }
1592
1547
  if (params.cssMode) {
1593
1548
  return translate;
1594
1549
  }
@@ -1622,7 +1577,7 @@
1622
1577
  swiper.translate = swiper.isHorizontal() ? x : y;
1623
1578
  if (params.cssMode) {
1624
1579
  wrapperEl[swiper.isHorizontal() ? 'scrollLeft' : 'scrollTop'] = swiper.isHorizontal() ? -x : -y;
1625
- } else if (!params.virtualTranslate) {
1580
+ } else {
1626
1581
  if (swiper.isHorizontal()) {
1627
1582
  x -= swiper.cssOverflowAdjustment();
1628
1583
  } else {
@@ -1859,7 +1814,6 @@
1859
1814
  let snapIndex = skip + Math.floor((slideIndex - skip) / swiper.params.slidesPerGroup);
1860
1815
  if (snapIndex >= snapGrid.length) snapIndex = snapGrid.length - 1;
1861
1816
  const translate = -snapGrid[snapIndex];
1862
- // Normalize slideIndex
1863
1817
  if (params.normalizeSlideIndex) {
1864
1818
  for (let i = 0; i < slidesGrid.length; i += 1) {
1865
1819
  const normalizedTranslate = -Math.floor(translate * 100);
@@ -1876,33 +1830,24 @@
1876
1830
  }
1877
1831
  }
1878
1832
  }
1833
+
1879
1834
  // Directions locks
1880
1835
  if (swiper.initialized && slideIndex !== activeIndex) {
1881
1836
  if (!swiper.allowSlideNext && (rtl ? translate > swiper.translate && translate > swiper.minTranslate() : translate < swiper.translate && translate < swiper.minTranslate())) {
1882
1837
  return false;
1883
1838
  }
1884
1839
  if (!swiper.allowSlidePrev && translate > swiper.translate && translate > swiper.maxTranslate()) {
1885
- if ((activeIndex || 0) !== slideIndex) {
1886
- return false;
1887
- }
1840
+ if ((activeIndex || 0) !== slideIndex) return false;
1888
1841
  }
1889
1842
  }
1890
1843
  if (slideIndex !== (previousIndex || 0) && runCallbacks) {
1891
1844
  swiper.emit('beforeSlideChangeStart');
1892
1845
  }
1893
-
1894
- // Update progress
1895
1846
  swiper.updateProgress(translate);
1896
1847
  let direction;
1897
1848
  if (slideIndex > activeIndex) direction = 'next';else if (slideIndex < activeIndex) direction = 'prev';else direction = 'reset';
1898
-
1899
- // initial virtual
1900
- const isVirtual = swiper.virtual && swiper.params.virtual.enabled;
1901
- const isInitialVirtual = isVirtual && initial;
1902
- // Update Index
1903
- if (!isInitialVirtual && (rtl && -translate === swiper.translate || !rtl && translate === swiper.translate)) {
1849
+ if (rtl && -translate === swiper.translate || !rtl && translate === swiper.translate) {
1904
1850
  swiper.updateActiveIndex(slideIndex);
1905
- // Update Height
1906
1851
  if (params.autoHeight) {
1907
1852
  swiper.updateAutoHeight();
1908
1853
  }
@@ -1920,24 +1865,7 @@
1920
1865
  const isH = swiper.isHorizontal();
1921
1866
  const t = rtl ? translate : -translate;
1922
1867
  if (speed === 0) {
1923
- if (isVirtual) {
1924
- swiper.wrapperEl.style.scrollSnapType = 'none';
1925
- swiper._immediateVirtual = true;
1926
- }
1927
- if (isVirtual && !swiper._cssModeVirtualInitialSet && swiper.params.initialSlide > 0) {
1928
- swiper._cssModeVirtualInitialSet = true;
1929
- requestAnimationFrame(() => {
1930
- wrapperEl[isH ? 'scrollLeft' : 'scrollTop'] = t;
1931
- });
1932
- } else {
1933
- wrapperEl[isH ? 'scrollLeft' : 'scrollTop'] = t;
1934
- }
1935
- if (isVirtual) {
1936
- requestAnimationFrame(() => {
1937
- swiper.wrapperEl.style.scrollSnapType = '';
1938
- swiper._immediateVirtual = false;
1939
- });
1940
- }
1868
+ wrapperEl[isH ? 'scrollLeft' : 'scrollTop'] = t;
1941
1869
  } else {
1942
1870
  if (!swiper.support.smoothScroll) {
1943
1871
  animateCSSModeScroll({
@@ -1955,10 +1883,7 @@
1955
1883
  return true;
1956
1884
  }
1957
1885
  const browser = getBrowser();
1958
- const isSafari = browser.isSafari;
1959
- if (isVirtual && !initial && isSafari && swiper.isElement) {
1960
- swiper.virtual.update(false, false, slideIndex);
1961
- }
1886
+ browser.isSafari;
1962
1887
  swiper.setTransition(speed);
1963
1888
  swiper.setTranslate(translate);
1964
1889
  swiper.updateActiveIndex(slideIndex);
@@ -2129,8 +2054,6 @@
2129
2054
  if (swiper.params?.isSneakPeekCenter && slides.length > 1 && swiper.activeIndex === 0) {
2130
2055
  const gap = Math.abs(swiper.snapGrid[1] - swiper.snapGrid[0]);
2131
2056
  const swiperTranslate = JSON.parse(JSON.stringify(swiper.snapGrid[1]));
2132
-
2133
- // Move last item to first position only if active slide is the first slide
2134
2057
  const lastSlide = slides[slides.length - 1];
2135
2058
  lastSlide.swiperLoopMoveDOM = true;
2136
2059
  swiper.slidesEl.prepend(lastSlide);
@@ -2165,11 +2088,8 @@
2165
2088
  perGroup = Math.max(swiper.slidesPerViewDynamic('current', true), 1);
2166
2089
  }
2167
2090
  const increment = swiper.activeIndex < params.slidesPerGroupSkip ? 1 : perGroup;
2168
- const isVirtual = swiper.virtual && params.virtual.enabled;
2169
2091
  if (params.loop) {
2170
- if (animating && !isVirtual && params.loopPreventsSliding) return false;
2171
-
2172
- // Kiểm tra xem loop có bị disable không
2092
+ if (animating && params.loopPreventsSliding) return false;
2173
2093
  const currentSlidesPerView = params.slidesPerView === 'auto' ? swiper.slidesPerViewDynamic() : Math.ceil(parseFloat(params.slidesPerView, 10));
2174
2094
  if (swiper.slides.length >= currentSlidesPerView) {
2175
2095
  swiper.loopFix({
@@ -2196,7 +2116,6 @@
2196
2116
  const gap = Math.abs(swiper.snapGrid[lastSnapGridIndex] - swiper.snapGrid[lastSnapGridIndex - 1]);
2197
2117
  const swiperTranslate = structuredClone(swiper.snapGrid[lastSnapGridIndex - 1]);
2198
2118
  if (!swiper.params.loop) return;
2199
- // Move first item to last position only if active slide is the last slide
2200
2119
  const firstSlide = slides[0];
2201
2120
  firstSlide.swiperLoopMoveDOM = true;
2202
2121
  swiper.slidesEl.append(firstSlide);
@@ -2221,17 +2140,14 @@
2221
2140
  params,
2222
2141
  snapGrid,
2223
2142
  slidesGrid,
2224
- rtlTranslate,
2225
- enabled,
2226
- animating
2143
+ rtlTranslate: rtlTranslate,
2144
+ enabled
2227
2145
  } = swiper;
2228
2146
  if (!enabled || swiper.destroyed) return swiper;
2229
2147
  if (typeof speed === 'undefined') {
2230
2148
  speed = swiper.params.speed;
2231
2149
  }
2232
- swiper.virtual && params.virtual.enabled;
2233
2150
  if (params.loop) {
2234
- // Kiểm tra xem loop có bị disable không
2235
2151
  const currentSlidesPerView = params.slidesPerView === 'auto' ? swiper.slidesPerViewDynamic() : Math.ceil(parseFloat(params.slidesPerView, 10));
2236
2152
  if (swiper.slides.length >= currentSlidesPerView) {
2237
2153
  swiper.loopFix({
@@ -2248,18 +2164,16 @@
2248
2164
  }
2249
2165
  const normalizedTranslate = normalize(translate);
2250
2166
  const normalizedSnapGrid = snapGrid.map(val => normalize(val));
2251
- const isFreeMode = params.freeMode && params.freeMode.enabled;
2252
2167
  let prevSnap = snapGrid[normalizedSnapGrid.indexOf(normalizedTranslate) - 1];
2253
- if (typeof prevSnap === 'undefined' && (params.cssMode || isFreeMode)) {
2168
+ if (typeof prevSnap === 'undefined' && params.cssMode) {
2254
2169
  let prevSnapIndex;
2255
2170
  snapGrid.forEach((snap, snapIndex) => {
2256
2171
  if (normalizedTranslate >= snap) {
2257
- // prevSnap = snap;
2258
2172
  prevSnapIndex = snapIndex;
2259
2173
  }
2260
2174
  });
2261
2175
  if (typeof prevSnapIndex !== 'undefined') {
2262
- prevSnap = isFreeMode ? snapGrid[prevSnapIndex] : snapGrid[prevSnapIndex > 0 ? prevSnapIndex - 1 : prevSnapIndex];
2176
+ prevSnap = snapGrid[prevSnapIndex > 0 ? prevSnapIndex - 1 : prevSnapIndex];
2263
2177
  }
2264
2178
  }
2265
2179
  let prevIndex = 0;
@@ -2272,7 +2186,7 @@
2272
2186
  }
2273
2187
  }
2274
2188
  if (params.rewind && swiper.isBeginning) {
2275
- const lastIndex = swiper.params.virtual && swiper.params.virtual.enabled && swiper.virtual ? swiper.virtual.slides.length - 1 : swiper.slides.length - 1;
2189
+ const lastIndex = swiper.slides.length - 1;
2276
2190
  return swiper.slideTo(lastIndex, speed, runCallbacks, internal);
2277
2191
  } else if (params.loop && swiper.activeIndex === 0 && params.cssMode) {
2278
2192
  requestAnimationFrame(() => {
@@ -2286,8 +2200,6 @@
2286
2200
  if (swiper.params?.isSneakPeekCenter && slides.length > 1 && swiper.activeIndex === 0) {
2287
2201
  const gap = Math.abs(swiper.snapGrid[1] - swiper.snapGrid[0]);
2288
2202
  const swiperTranslate = JSON.parse(JSON.stringify(swiper.snapGrid[1]));
2289
-
2290
- // Move last item to first position only if active slide is the first slide
2291
2203
  if (!swiper.params.loop) return;
2292
2204
  const lastSlide = slides[slides.length - 1];
2293
2205
  lastSlide.swiperLoopMoveDOM = true;
@@ -2364,20 +2276,19 @@
2364
2276
  slidesEl
2365
2277
  } = swiper;
2366
2278
  const slidesPerView = params.slidesPerView === 'auto' ? swiper.slidesPerViewDynamic() : params.slidesPerView;
2367
- let slideToIndex = swiper.getSlideIndexWhenGrid(swiper.clickedIndex);
2279
+ const slideToIndex = swiper.clickedIndex;
2368
2280
  let realIndex;
2369
2281
  const slideSelector = swiper.isElement ? `swiper-slide` : `.${params.slideClass}`;
2370
- const isGrid = swiper.grid && swiper.params.grid && swiper.params.grid.rows > 1;
2371
2282
  if (params.loop) {
2372
2283
  if (swiper.animating) return;
2373
2284
  realIndex = parseInt(swiper.clickedSlide.getAttribute('data-swiper-slide-index'), 10);
2374
2285
  if (params.centeredSlides) {
2375
2286
  swiper.slideToLoop(realIndex);
2376
- } else if (slideToIndex > (isGrid ? (swiper.slides.length - slidesPerView) / 2 - (swiper.params.grid.rows - 1) : swiper.slides.length - slidesPerView)) {
2287
+ } else if (slideToIndex > swiper.slides.length - slidesPerView) {
2377
2288
  swiper.loopFix();
2378
- slideToIndex = swiper.getSlideIndex(elementChildren(slidesEl, `${slideSelector}[data-swiper-slide-index="${realIndex}"]`)[0]);
2289
+ const clickedEl = elementChildren(slidesEl, `${slideSelector}[data-swiper-slide-index="${realIndex}"]`)[0];
2379
2290
  nextTick(() => {
2380
- swiper.slideTo(slideToIndex);
2291
+ if (clickedEl) swiper.slideTo(swiper.getSlideIndex(clickedEl));
2381
2292
  });
2382
2293
  } else {
2383
2294
  swiper.slideTo(slideToIndex);
@@ -2404,7 +2315,7 @@
2404
2315
  params,
2405
2316
  slidesEl
2406
2317
  } = swiper;
2407
- if (!params.loop || swiper.virtual && swiper.params.virtual.enabled) return;
2318
+ if (!params.loop) return;
2408
2319
  const initSlides = () => {
2409
2320
  const slides = elementChildren(slidesEl, `.${params.slideClass}, swiper-slide`);
2410
2321
  slides.forEach((el, index) => {
@@ -2413,21 +2324,17 @@
2413
2324
  };
2414
2325
  const clearBlankSlides = () => {
2415
2326
  const slides = elementChildren(slidesEl, `.${params.slideBlankClass}`);
2416
- slides.forEach(el => {
2417
- el.remove();
2418
- });
2327
+ slides.forEach(el => el.remove());
2419
2328
  if (slides.length > 0) {
2420
2329
  swiper.recalcSlides();
2421
2330
  swiper.updateSlides();
2422
2331
  }
2423
2332
  };
2424
- const gridEnabled = swiper.grid && params.grid && params.grid.rows > 1;
2425
- if (params.loopAddBlankSlides && (params.slidesPerGroup > 1 || gridEnabled)) {
2333
+ if (params.loopAddBlankSlides && params.slidesPerGroup > 1) {
2426
2334
  clearBlankSlides();
2427
2335
  }
2428
- const slidesPerGroup = params.slidesPerGroup * (gridEnabled ? params.grid.rows : 1);
2336
+ const slidesPerGroup = params.slidesPerGroup;
2429
2337
  const shouldFillGroup = swiper.slides.length % slidesPerGroup !== 0;
2430
- const shouldFillGrid = gridEnabled && swiper.slides.length % params.grid.rows !== 0;
2431
2338
  const addBlankSlides = amountOfSlides => {
2432
2339
  for (let i = 0; i < amountOfSlides; i += 1) {
2433
2340
  const slideEl = swiper.isElement ? createElement('swiper-slide', [params.slideBlankClass]) : createElement('div', [params.slideClass, params.slideBlankClass]);
@@ -2444,16 +2351,6 @@
2444
2351
  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)');
2445
2352
  }
2446
2353
  initSlides();
2447
- } else if (shouldFillGrid) {
2448
- if (params.loopAddBlankSlides) {
2449
- const slidesToAdd = params.grid.rows - swiper.slides.length % params.grid.rows;
2450
- addBlankSlides(slidesToAdd);
2451
- swiper.recalcSlides();
2452
- swiper.updateSlides();
2453
- } else {
2454
- 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)');
2455
- }
2456
- initSlides();
2457
2354
  } else {
2458
2355
  initSlides();
2459
2356
  }
@@ -2472,13 +2369,12 @@
2472
2369
  setTranslate,
2473
2370
  activeSlideIndex,
2474
2371
  initial,
2475
- byController,
2476
2372
  byMousewheel
2477
2373
  } = _temp === void 0 ? {} : _temp;
2478
2374
  const swiper = this;
2479
2375
  if (!swiper.params.loop) return;
2480
2376
 
2481
- // Disable loop mode nếu số slides ít hơn slidesPerView
2377
+ // Disable loop mode if number of slides is smaller than slidesPerView
2482
2378
  const currentSlidesPerView = swiper.params.slidesPerView === 'auto' ? swiper.slidesPerViewDynamic() : Math.ceil(parseFloat(swiper.params.slidesPerView, 10));
2483
2379
  if (swiper.slides.length < currentSlidesPerView) {
2484
2380
  console.warn('Swiper: Loop mode disabled - slides.length < slidesPerView');
@@ -2498,21 +2394,6 @@
2498
2394
  } = params;
2499
2395
  swiper.allowSlidePrev = true;
2500
2396
  swiper.allowSlideNext = true;
2501
- if (swiper.virtual && params.virtual.enabled) {
2502
- if (slideTo) {
2503
- if (!params.centeredSlides && swiper.snapIndex === 0) {
2504
- swiper.slideTo(swiper.virtual.slides.length, 0, false, true);
2505
- } else if (params.centeredSlides && swiper.snapIndex < params.slidesPerView) {
2506
- swiper.slideTo(swiper.virtual.slides.length + swiper.snapIndex, 0, false, true);
2507
- } else if (swiper.snapIndex === swiper.snapGrid.length - 1) {
2508
- swiper.slideTo(swiper.virtual.slidesBefore, 0, false, true);
2509
- }
2510
- }
2511
- swiper.allowSlidePrev = allowSlidePrev;
2512
- swiper.allowSlideNext = allowSlideNext;
2513
- swiper.emit('loopFix');
2514
- return;
2515
- }
2516
2397
  let slidesPerView = params.slidesPerView;
2517
2398
  if (slidesPerView === 'auto') {
2518
2399
  slidesPerView = swiper.slidesPerViewDynamic();
@@ -2522,22 +2403,19 @@
2522
2403
  slidesPerView = slidesPerView + 1;
2523
2404
  }
2524
2405
  }
2525
- const slidesPerGroup = params.slidesPerGroupAuto ? slidesPerView : params.slidesPerGroup;
2406
+ const slidesPerGroup = params.slidesPerGroup;
2526
2407
  let loopedSlides = centeredSlides ? Math.max(slidesPerGroup, Math.ceil(slidesPerView / 2)) : slidesPerGroup;
2527
2408
  if (loopedSlides % slidesPerGroup !== 0) {
2528
2409
  loopedSlides += slidesPerGroup - loopedSlides % slidesPerGroup;
2529
2410
  }
2530
2411
  loopedSlides += params.loopAdditionalSlides;
2531
2412
  swiper.loopedSlides = loopedSlides;
2532
- const gridEnabled = swiper.grid && params.grid && params.grid.rows > 1;
2533
- if (slides.length < slidesPerView + loopedSlides || swiper.params.effect === 'cards' && slides.length < slidesPerView + loopedSlides * 2) {
2413
+ if (slides.length < slidesPerView + loopedSlides) {
2534
2414
  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');
2535
- } else if (gridEnabled && params.grid.fill === 'row') {
2536
- showWarning('Swiper Loop Warning: Loop mode is not compatible with grid.fill = `row`');
2537
2415
  }
2538
2416
  const prependSlidesIndexes = [];
2539
2417
  const appendSlidesIndexes = [];
2540
- const cols = gridEnabled ? Math.ceil(slides.length / params.grid.rows) : slides.length;
2418
+ const cols = slides.length;
2541
2419
  const isInitialOverflow = initial && cols - initialSlide < slidesPerView && !centeredSlides;
2542
2420
  let activeIndex = isInitialOverflow ? initialSlide : swiper.activeIndex;
2543
2421
  if (typeof activeSlideIndex === 'undefined') {
@@ -2549,24 +2427,15 @@
2549
2427
  const isPrev = direction === 'prev' || !direction;
2550
2428
  let slidesPrepended = 0;
2551
2429
  let slidesAppended = 0;
2552
- const activeColIndex = gridEnabled ? slides[activeSlideIndex].column : activeSlideIndex;
2430
+ const activeColIndex = activeSlideIndex;
2553
2431
  const activeColIndexWithShift = activeColIndex + (centeredSlides && typeof setTranslate === 'undefined' ? -slidesPerView / 2 + 0.5 : 0);
2432
+
2554
2433
  // prepend last slides before start
2555
2434
  if (activeColIndexWithShift < loopedSlides) {
2556
2435
  slidesPrepended = Math.max(loopedSlides - activeColIndexWithShift, slidesPerGroup);
2557
2436
  for (let i = 0; i < loopedSlides - activeColIndexWithShift; i += 1) {
2558
2437
  const index = i - Math.floor(i / cols) * cols;
2559
- if (gridEnabled) {
2560
- const colIndexToPrepend = cols - index - 1;
2561
- for (let i = slides.length - 1; i >= 0; i -= 1) {
2562
- if (slides[i].column === colIndexToPrepend) prependSlidesIndexes.push(i);
2563
- }
2564
- // slides.forEach((slide, slideIndex) => {
2565
- // if (slide.column === colIndexToPrepend) prependSlidesIndexes.push(slideIndex);
2566
- // });
2567
- } else {
2568
- prependSlidesIndexes.push(cols - index - 1);
2569
- }
2438
+ prependSlidesIndexes.push(cols - index - 1);
2570
2439
  }
2571
2440
  } else if (activeColIndexWithShift + slidesPerView > cols - loopedSlides) {
2572
2441
  slidesAppended = Math.max(activeColIndexWithShift - (cols - loopedSlides * 2), slidesPerGroup);
@@ -2575,27 +2444,13 @@
2575
2444
  }
2576
2445
  for (let i = 0; i < slidesAppended; i += 1) {
2577
2446
  const index = i - Math.floor(i / cols) * cols;
2578
- if (gridEnabled) {
2579
- slides.forEach((slide, slideIndex) => {
2580
- if (slide.column === index) appendSlidesIndexes.push(slideIndex);
2581
- });
2582
- } else {
2583
- appendSlidesIndexes.push(index);
2584
- }
2447
+ appendSlidesIndexes.push(index);
2585
2448
  }
2586
2449
  }
2587
2450
  swiper.__preventObserver__ = true;
2588
2451
  requestAnimationFrame(() => {
2589
2452
  swiper.__preventObserver__ = false;
2590
2453
  });
2591
- if (swiper.params.effect === 'cards' && slides.length < slidesPerView + loopedSlides * 2) {
2592
- if (appendSlidesIndexes.includes(activeSlideIndex)) {
2593
- appendSlidesIndexes.splice(appendSlidesIndexes.indexOf(activeSlideIndex), 1);
2594
- }
2595
- if (prependSlidesIndexes.includes(activeSlideIndex)) {
2596
- prependSlidesIndexes.splice(prependSlidesIndexes.indexOf(activeSlideIndex), 1);
2597
- }
2598
- }
2599
2454
  if (isPrev) {
2600
2455
  prependSlidesIndexes.forEach(index => {
2601
2456
  slides[index].swiperLoopMoveDOM = true;
@@ -2613,13 +2468,11 @@
2613
2468
  swiper.recalcSlides();
2614
2469
  if (params.slidesPerView === 'auto') {
2615
2470
  swiper.updateSlides();
2616
- } else if (gridEnabled && (prependSlidesIndexes.length > 0 && isPrev || appendSlidesIndexes.length > 0 && isNext)) {
2617
- swiper.slides.forEach((slide, slideIndex) => {
2618
- swiper.grid.updateSlide(slideIndex, slide, swiper.slides);
2619
- });
2620
2471
  }
2621
2472
  if (params.watchSlidesProgress) {
2622
- swiper.updateSlidesOffset();
2473
+ swiper.updateSlidesOffset({
2474
+ isCalculatedFromUpdateSlides: params.slidesPerView === 'auto'
2475
+ });
2623
2476
  }
2624
2477
  if (slideTo) {
2625
2478
  if (prependSlidesIndexes.length > 0 && isPrev) {
@@ -2636,12 +2489,10 @@
2636
2489
  swiper.touchEventsData.currentTranslate = swiper.touchEventsData.currentTranslate - diff;
2637
2490
  }
2638
2491
  }
2639
- } else {
2640
- if (setTranslate) {
2641
- const shift = gridEnabled ? prependSlidesIndexes.length / params.grid.rows : prependSlidesIndexes.length;
2642
- swiper.slideTo(swiper.activeIndex + shift, 0, false, true);
2643
- swiper.touchEventsData.currentTranslate = swiper.translate;
2644
- }
2492
+ } else if (setTranslate) {
2493
+ const shift = prependSlidesIndexes.length;
2494
+ swiper.slideTo(swiper.activeIndex + shift, 0, false, true);
2495
+ swiper.touchEventsData.currentTranslate = swiper.translate;
2645
2496
  }
2646
2497
  } else if (appendSlidesIndexes.length > 0 && isNext) {
2647
2498
  if (typeof slideRealIndex === 'undefined') {
@@ -2657,36 +2508,14 @@
2657
2508
  swiper.touchEventsData.currentTranslate = swiper.touchEventsData.currentTranslate - diff;
2658
2509
  }
2659
2510
  }
2660
- } else {
2661
- const shift = gridEnabled ? appendSlidesIndexes.length / params.grid.rows : appendSlidesIndexes.length;
2511
+ } else if (setTranslate) {
2512
+ const shift = appendSlidesIndexes.length;
2662
2513
  swiper.slideTo(swiper.activeIndex - shift, 0, false, true);
2663
2514
  }
2664
2515
  }
2665
2516
  }
2666
2517
  swiper.allowSlidePrev = allowSlidePrev;
2667
2518
  swiper.allowSlideNext = allowSlideNext;
2668
- if (swiper.controller && swiper.controller.control && !byController) {
2669
- const loopParams = {
2670
- slideRealIndex,
2671
- direction,
2672
- setTranslate,
2673
- activeSlideIndex,
2674
- byController: true
2675
- };
2676
- if (Array.isArray(swiper.controller.control)) {
2677
- swiper.controller.control.forEach(c => {
2678
- if (!c.destroyed && c.params.loop) c.loopFix({
2679
- ...loopParams,
2680
- slideTo: c.params.slidesPerView === params.slidesPerView ? slideTo : false
2681
- });
2682
- });
2683
- } else if (swiper.controller.control instanceof swiper.constructor && swiper.controller.control.params.loop) {
2684
- swiper.controller.control.loopFix({
2685
- ...loopParams,
2686
- slideTo: swiper.controller.control.params.slidesPerView === params.slidesPerView ? slideTo : false
2687
- });
2688
- }
2689
- }
2690
2519
  swiper.emit('loopFix');
2691
2520
  }
2692
2521
 
@@ -2703,7 +2532,7 @@
2703
2532
  const swiper = this;
2704
2533
  if (!swiper.params.loop) return;
2705
2534
 
2706
- // Disable loop mode nếu số slides ít hơn slidesPerView
2535
+ // Disable loop mode if number of slides is smaller than slidesPerView
2707
2536
  const currentSlidesPerView = swiper.params.slidesPerView === 'auto' ? swiper.slidesPerViewDynamic() : Math.ceil(parseFloat(swiper.params.slidesPerView, 10));
2708
2537
  if (swiper.slides.length < currentSlidesPerView) {
2709
2538
  console.warn('Swiper: Loop mode disabled - slides.length < slidesPerView');
@@ -2742,7 +2571,7 @@
2742
2571
  }
2743
2572
  loopedSlides += params.loopAdditionalSlides;
2744
2573
  swiper.loopedSlides = loopedSlides;
2745
- if (slides.length < slidesPerView + loopedSlides || swiper.params.effect === 'cards' && slides.length < slidesPerView + loopedSlides * 2) {
2574
+ if (slides.length < slidesPerView + loopedSlides) {
2746
2575
  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');
2747
2576
  }
2748
2577
  const isNext = direction === 'next' || !direction;
@@ -2768,20 +2597,16 @@
2768
2597
  activeSlideIndex = swiper.getSlideIndex(slides.find(el => el.classList.contains(params.slideActiveClass)));
2769
2598
  }
2770
2599
 
2771
- // Tạo DocumentFragment để chứa các slide clone
2600
+ // DocumentFragment to hold slide clones
2772
2601
  const cloneFragment = document.createDocumentFragment();
2773
2602
 
2774
- // Clone các slide theo numberOfSlidesNeedClone (đã đảo ngược) và thêm vào fragment
2603
+ // Clone slides according to numberOfSlidesNeedClone and append to fragment
2775
2604
  (isNext ? numberOfSlidesNeedClone : numberOfSlidesNeedClone.reverse()).forEach(index => {
2776
2605
  if (slides[index]) {
2777
2606
  const originalSlide = slides[index];
2778
2607
  const clonedSlide = originalSlide.cloneNode(true);
2779
-
2780
- // Đánh dấu slide clone
2781
2608
  clonedSlide.setAttribute('data-swiper-clone', 'true');
2782
2609
  clonedSlide.classList.add('swiper-slide-clone');
2783
-
2784
- // Thêm clone vào fragment
2785
2610
  cloneFragment.appendChild(clonedSlide);
2786
2611
  }
2787
2612
  });
@@ -2802,32 +2627,28 @@
2802
2627
  });
2803
2628
  }
2804
2629
 
2805
- // Sắp xếp cloneFragment theo data-swiper-slide-index tăng dần
2630
+ // Sort cloned slides by data-swiper-slide-index
2806
2631
  const clonedSlides = Array.from(cloneFragment.children);
2807
2632
  clonedSlides.sort((a, b) => {
2808
2633
  const indexA = parseInt(a.getAttribute('data-swiper-slide-index')) || 0;
2809
2634
  const indexB = parseInt(b.getAttribute('data-swiper-slide-index')) || 0;
2810
2635
  return indexA - indexB;
2811
2636
  });
2812
-
2813
- // Xóa tất cả children cũ và thêm lại theo thứ tự đã sắp xếp
2814
2637
  cloneFragment.innerHTML = '';
2815
2638
  clonedSlides.forEach(slide => {
2816
2639
  cloneFragment.appendChild(slide);
2817
2640
  });
2818
2641
 
2819
- // Thêm fragment vào vị trí phù hợp
2642
+ // Place fragment into the right position
2820
2643
  if (isPrev) {
2821
- // Nếu là prev, thêm fragment vào cuối slidesEl
2822
2644
  slidesEl.appendChild(cloneFragment);
2823
2645
  } else if (isNext) {
2824
- // Nếu là next, thêm fragment vào đầu slidesEl
2825
2646
  slidesEl.insertBefore(cloneFragment, slidesEl.firstChild);
2826
2647
  }
2827
2648
  swiper.recalcSlides();
2828
2649
  swiper.updateSlides();
2829
2650
 
2830
- // Tìm slide data-swiper-slide-index tương ứng
2651
+ // Find old active slide index after recalculation
2831
2652
  let oldActiveIndex = null;
2832
2653
  for (let i = 0; i < slidesEl.children.length; i++) {
2833
2654
  const child = slidesEl.children[i];
@@ -2840,7 +2661,7 @@
2840
2661
  swiper.slideTo(oldActiveIndex, 0);
2841
2662
  }
2842
2663
 
2843
- // Tìm vị trí slide sau khi remove clone để set lại translate tạo hiệu ứng animate
2664
+ // Update translate after removing clones for animation
2844
2665
  const skip = Math.min(swiper.params.slidesPerGroupSkip, newIndex);
2845
2666
  let snapIndex = skip + Math.floor((newIndex - skip) / swiper.params.slidesPerGroup);
2846
2667
  if (snapIndex >= swiper.snapGrid.length) snapIndex = swiper.snapGrid.length - 1;
@@ -2866,7 +2687,8 @@
2866
2687
  }
2867
2688
  swiper.setTranslate(updateTranslate);
2868
2689
  }
2869
- // Remove slide clone ra khỏi slidesEl sau khi slideTo hoàn thành
2690
+
2691
+ // Remove clones
2870
2692
  const cloneSlides = slidesEl.querySelectorAll('[data-swiper-clone="true"]');
2871
2693
  cloneSlides.forEach(cloneSlide => {
2872
2694
  if (cloneSlide.parentNode) {
@@ -2896,7 +2718,7 @@
2896
2718
  params,
2897
2719
  slidesEl
2898
2720
  } = swiper;
2899
- if (!params.loop || !slidesEl || swiper.virtual && swiper.params.virtual.enabled) return;
2721
+ if (!params.loop || !slidesEl) return;
2900
2722
  swiper.recalcSlides();
2901
2723
  const newSlidesOrder = [];
2902
2724
  swiper.slides.forEach(slideEl => {
@@ -2957,7 +2779,6 @@
2957
2779
  unsetGrabCursor
2958
2780
  };
2959
2781
 
2960
- // Modified from https://stackoverflow.com/questions/54520554/custom-element-getrootnode-closest-function-crossing-multiple-parent-shadowd
2961
2782
  function closestElement(selector, base) {
2962
2783
  if (base === void 0) {
2963
2784
  base = this;
@@ -2966,9 +2787,7 @@
2966
2787
  if (!el || el === getDocument() || el === getWindow()) return null;
2967
2788
  if (el.assignedSlot) el = el.assignedSlot;
2968
2789
  const found = el.closest(selector);
2969
- if (!found && !el.getRootNode) {
2970
- return null;
2971
- }
2790
+ if (!found && !el.getRootNode) return null;
2972
2791
  return found || __closestFrom(el.getRootNode().host);
2973
2792
  }
2974
2793
  return __closestFrom(base);
@@ -2996,9 +2815,7 @@
2996
2815
  if (e.originalEvent) e = e.originalEvent;
2997
2816
  const data = swiper.touchEventsData;
2998
2817
  if (e.type === 'pointerdown') {
2999
- if (data.pointerId !== null && data.pointerId !== e.pointerId) {
3000
- return;
3001
- }
2818
+ if (data.pointerId !== null && data.pointerId !== e.pointerId) return;
3002
2819
  data.pointerId = e.pointerId;
3003
2820
  } else if (e.type === 'touchstart' && e.targetTouches.length === 1) {
3004
2821
  data.touchId = e.targetTouches[0].identifier;
@@ -3015,9 +2832,7 @@
3015
2832
  } = swiper;
3016
2833
  if (!enabled) return;
3017
2834
  if (!params.simulateTouch && e.pointerType === 'mouse') return;
3018
- if (swiper.animating && params.preventInteractionOnTransition) {
3019
- return;
3020
- }
2835
+ if (swiper.animating && params.preventInteractionOnTransition) return;
3021
2836
  if (!swiper.animating && params.cssMode && params.loop) {
3022
2837
  swiper.loopFix();
3023
2838
  }
@@ -3028,8 +2843,6 @@
3028
2843
  if ('which' in e && e.which === 3) return;
3029
2844
  if ('button' in e && e.button > 0) return;
3030
2845
  if (data.isTouched && data.isMoved) return;
3031
-
3032
- // change target el for shadow root component
3033
2846
  const swipingClassHasValue = !!params.noSwipingClass && params.noSwipingClass !== '';
3034
2847
  // eslint-disable-next-line
3035
2848
  const eventPath = e.composedPath ? e.composedPath() : e.path;
@@ -3038,8 +2851,6 @@
3038
2851
  }
3039
2852
  const noSwipingSelector = params.noSwipingSelector ? params.noSwipingSelector : `.${params.noSwipingClass}`;
3040
2853
  const isTargetShadow = !!(e.target && e.target.shadowRoot);
3041
-
3042
- // use closestElement for shadow root element to get the actual closest for nested shadow root element
3043
2854
  if (params.noSwiping && (isTargetShadow ? closestElement(noSwipingSelector, targetEl) : targetEl.closest(noSwipingSelector))) {
3044
2855
  swiper.allowClick = true;
3045
2856
  return;
@@ -3051,12 +2862,7 @@
3051
2862
  touches.currentY = e.pageY;
3052
2863
  const startX = touches.currentX;
3053
2864
  const startY = touches.currentY;
3054
-
3055
- // Do NOT start if iOS edge swipe is detected. Otherwise iOS app cannot swipe-to-go-back anymore
3056
-
3057
- if (!preventEdgeSwipe(swiper, e, startX)) {
3058
- return;
3059
- }
2865
+ if (!preventEdgeSwipe(swiper, e, startX)) return;
3060
2866
  Object.assign(data, {
3061
2867
  isTouched: true,
3062
2868
  isMoved: false,
@@ -3085,9 +2891,6 @@
3085
2891
  if ((params.touchStartForcePreventDefault || shouldPreventDefault) && !targetEl.isContentEditable) {
3086
2892
  e.preventDefault();
3087
2893
  }
3088
- if (params.freeMode && params.freeMode.enabled && swiper.freeMode && swiper.animating && !params.cssMode) {
3089
- swiper.freeMode.onTouchStart();
3090
- }
3091
2894
  swiper.emit('touchStart', e);
3092
2895
  }
3093
2896
 
@@ -3106,7 +2909,7 @@
3106
2909
  let e = event;
3107
2910
  if (e.originalEvent) e = e.originalEvent;
3108
2911
  if (e.type === 'pointermove') {
3109
- if (data.touchId !== null) return; // return from pointer if we use touch
2912
+ if (data.touchId !== null) return;
3110
2913
  const id = e.pointerId;
3111
2914
  if (id !== data.pointerId) return;
3112
2915
  }
@@ -3147,7 +2950,6 @@
3147
2950
  }
3148
2951
  if (params.touchReleaseOnEdges && !params.loop) {
3149
2952
  if (swiper.isVertical()) {
3150
- // Vertical
3151
2953
  if (pageY < touches.startY && swiper.translate <= swiper.maxTranslate() || pageY > touches.startY && swiper.translate >= swiper.minTranslate()) {
3152
2954
  data.isTouched = false;
3153
2955
  data.isMoved = false;
@@ -3249,7 +3051,6 @@
3249
3051
  swiper.wrapperEl.dispatchEvent(evt);
3250
3052
  }
3251
3053
  data.allowMomentumBounce = false;
3252
- // Grab Cursor
3253
3054
  if (params.grabCursor && (swiper.allowSlideNext === true || swiper.allowSlidePrev === true)) {
3254
3055
  swiper.setGrabCursor(true);
3255
3056
  }
@@ -3320,8 +3121,6 @@
3320
3121
  if (!swiper.allowSlidePrev && !swiper.allowSlideNext) {
3321
3122
  data.currentTranslate = data.startTranslate;
3322
3123
  }
3323
-
3324
- // Threshold
3325
3124
  if (params.threshold > 0) {
3326
3125
  if (Math.abs(diff) > params.threshold || data.allowThresholdMove) {
3327
3126
  if (!data.allowThresholdMove) {
@@ -3339,17 +3138,12 @@
3339
3138
  }
3340
3139
  if (!params.followFinger || params.cssMode) return;
3341
3140
 
3342
- // Update active index in free mode
3343
- if (params.freeMode && params.freeMode.enabled && swiper.freeMode || params.watchSlidesProgress) {
3141
+ // core-lite: no optional feature updates; only watchSlidesProgress
3142
+ if (params.watchSlidesProgress) {
3344
3143
  swiper.updateActiveIndex();
3345
3144
  swiper.updateSlidesClasses();
3346
3145
  }
3347
- if (params.freeMode && params.freeMode.enabled && swiper.freeMode) {
3348
- swiper.freeMode.onTouchMove();
3349
- }
3350
- // Update progress
3351
3146
  swiper.updateProgress(data.currentTranslate);
3352
- // Update translate
3353
3147
  swiper.setTranslate(data.currentTranslate);
3354
3148
  }
3355
3149
 
@@ -3361,7 +3155,7 @@
3361
3155
  let targetTouch;
3362
3156
  const isTouchEvent = e.type === 'touchend' || e.type === 'touchcancel';
3363
3157
  if (!isTouchEvent) {
3364
- if (data.touchId !== null) return; // return from pointer if we use touch
3158
+ if (data.touchId !== null) return;
3365
3159
  if (e.pointerId !== data.pointerId) return;
3366
3160
  targetTouch = e;
3367
3161
  } else {
@@ -3370,9 +3164,7 @@
3370
3164
  }
3371
3165
  if (['pointercancel', 'pointerout', 'pointerleave', 'contextmenu'].includes(e.type)) {
3372
3166
  const proceed = ['pointercancel', 'contextmenu'].includes(e.type) && (swiper.browser.isSafari || swiper.browser.isWebView);
3373
- if (!proceed) {
3374
- return;
3375
- }
3167
+ if (!proceed) return;
3376
3168
  }
3377
3169
  data.pointerId = null;
3378
3170
  data.touchId = null;
@@ -3390,9 +3182,7 @@
3390
3182
  }
3391
3183
  data.allowTouchCallbacks = false;
3392
3184
  if (!data.isTouched) {
3393
- if (data.isMoved && params.grabCursor) {
3394
- swiper.setGrabCursor(false);
3395
- }
3185
+ if (data.isMoved && params.grabCursor) swiper.setGrabCursor(false);
3396
3186
  data.isMoved = false;
3397
3187
  data.startMoving = false;
3398
3188
  return;
@@ -3402,8 +3192,6 @@
3402
3192
  if (params.grabCursor && data.isMoved && data.isTouched && (swiper.allowSlideNext === true || swiper.allowSlidePrev === true)) {
3403
3193
  swiper.setGrabCursor(false);
3404
3194
  }
3405
-
3406
- // Time diff
3407
3195
  const touchEndTime = now();
3408
3196
  const timeDiff = touchEndTime - data.touchStartTime;
3409
3197
 
@@ -3430,20 +3218,8 @@
3430
3218
  data.isMoved = false;
3431
3219
  data.startMoving = false;
3432
3220
  let currentPos;
3433
- if (params.followFinger) {
3434
- currentPos = rtl ? swiper.translate : -swiper.translate;
3435
- } else {
3436
- currentPos = -data.currentTranslate;
3437
- }
3438
- if (params.cssMode) {
3439
- return;
3440
- }
3441
- if (params.freeMode && params.freeMode.enabled) {
3442
- swiper.freeMode.onTouchEnd({
3443
- currentPos
3444
- });
3445
- return;
3446
- }
3221
+ if (params.followFinger) currentPos = rtl ? swiper.translate : -swiper.translate;else currentPos = -data.currentTranslate;
3222
+ if (params.cssMode) return;
3447
3223
 
3448
3224
  // Find current slide
3449
3225
  const swipeToLast = currentPos >= -swiper.maxTranslate() && !swiper.params.loop;
@@ -3465,22 +3241,22 @@
3465
3241
  let rewindLastIndex = null;
3466
3242
  if (params.rewind) {
3467
3243
  if (swiper.isBeginning) {
3468
- rewindLastIndex = params.virtual && params.virtual.enabled && swiper.virtual ? swiper.virtual.slides.length - 1 : swiper.slides.length - 1;
3244
+ rewindLastIndex = swiper.slides.length - 1;
3469
3245
  } else if (swiper.isEnd) {
3470
3246
  rewindFirstIndex = 0;
3471
3247
  }
3472
3248
  }
3473
- // Find current slide size
3474
3249
  const ratio = (currentPos - slidesGrid[stopIndex]) / groupSize;
3475
3250
  const increment = stopIndex < params.slidesPerGroupSkip - 1 ? 1 : params.slidesPerGroup;
3476
3251
  if (timeDiff > params.longSwipesMs) {
3477
- // Long touches
3478
3252
  if (!params.longSwipes) {
3479
3253
  swiper.slideTo(swiper.activeIndex);
3480
3254
  return;
3481
3255
  }
3482
3256
  if (swiper.swipeDirection === 'next') {
3483
- if (ratio >= params.longSwipesRatio) swiper.slideTo(params.rewind && swiper.isEnd ? rewindFirstIndex : stopIndex + increment);else swiper.slideTo(stopIndex);
3257
+ if (ratio >= params.longSwipesRatio) {
3258
+ swiper.slideTo(params.rewind && swiper.isEnd ? rewindFirstIndex : stopIndex + increment);
3259
+ } else swiper.slideTo(stopIndex);
3484
3260
  }
3485
3261
  if (swiper.swipeDirection === 'prev') {
3486
3262
  if (ratio > 1 - params.longSwipesRatio) {
@@ -3532,7 +3308,6 @@
3532
3308
  allowSlidePrev,
3533
3309
  snapGrid
3534
3310
  } = swiper;
3535
- const isVirtual = swiper.virtual && swiper.params.virtual.enabled;
3536
3311
 
3537
3312
  // Disable locks on resize
3538
3313
  swiper.allowSlideNext = true;
@@ -3540,15 +3315,12 @@
3540
3315
  swiper.updateSize();
3541
3316
  swiper.updateSlides();
3542
3317
  swiper.updateSlidesClasses();
3543
- const isVirtualLoop = isVirtual && params.loop;
3544
- if ((params.slidesPerView === 'auto' || params.slidesPerView > 1) && swiper.isEnd && !swiper.isBeginning && !swiper.params.centeredSlides && !isVirtualLoop) {
3318
+ if ((params.slidesPerView === 'auto' || params.slidesPerView > 1) && swiper.isEnd && !swiper.isBeginning && !swiper.params.centeredSlides) {
3545
3319
  swiper.slideTo(swiper.slides.length - 1, 0, false, true);
3320
+ } else if (swiper.params.loop) {
3321
+ swiper.slideToLoop(swiper.realIndex, 0, false, true);
3546
3322
  } else {
3547
- if (swiper.params.loop && !isVirtual) {
3548
- swiper.slideToLoop(swiper.realIndex, 0, false, true);
3549
- } else {
3550
- swiper.slideTo(swiper.activeIndex, 0, false, true);
3551
- }
3323
+ swiper.slideTo(swiper.activeIndex, 0, false, true);
3552
3324
  }
3553
3325
  if (swiper.autoplay && swiper.autoplay.running && swiper.autoplay.paused) {
3554
3326
  clearTimeout(swiper.autoplay.resizeTimeout);
@@ -3558,10 +3330,11 @@
3558
3330
  }
3559
3331
  }, 500);
3560
3332
  }
3333
+
3561
3334
  // Return locks after resize
3562
3335
  swiper.allowSlidePrev = allowSlidePrev;
3563
3336
  swiper.allowSlideNext = allowSlideNext;
3564
- if (swiper.params.watchOverflow && snapGrid !== swiper.snapGrid) {
3337
+ if (params.watchOverflow && snapGrid !== swiper.snapGrid) {
3565
3338
  swiper.checkOverflow();
3566
3339
  }
3567
3340
  }
@@ -3615,6 +3388,10 @@
3615
3388
  if (swiper.params.cssMode || swiper.params.slidesPerView !== 'auto' && !swiper.params.autoHeight) {
3616
3389
  return;
3617
3390
  }
3391
+ const el = e?.target;
3392
+ // IMG, IFRAME, EMBED with width/height attributes don't change slide size — no need to call swiper.update()
3393
+ if (!el || !['IMG', 'IFRAME', 'EMBED'].includes(el.tagName)) return;
3394
+ if (el.hasAttribute('width') && el.hasAttribute('height')) return;
3618
3395
  swiper.update();
3619
3396
  }
3620
3397
 
@@ -3726,8 +3503,15 @@
3726
3503
  detachEvents
3727
3504
  };
3728
3505
 
3729
- const isGridEnabled = (swiper, params) => {
3730
- return swiper.grid && params.grid && params.grid.rows > 1;
3506
+ const toggleModule = (swiper, params, breakpointParams, prop) => {
3507
+ const wasModuleEnabled = params[prop] && params[prop].enabled;
3508
+ const isModuleEnabled = breakpointParams[prop] && breakpointParams[prop].enabled;
3509
+ if (wasModuleEnabled && !isModuleEnabled) {
3510
+ swiper[prop].disable();
3511
+ }
3512
+ if (!wasModuleEnabled && isModuleEnabled) {
3513
+ swiper[prop].enable();
3514
+ }
3731
3515
  };
3732
3516
  function setBreakpoint() {
3733
3517
  const swiper = this;
@@ -3748,38 +3532,20 @@
3748
3532
  if (!breakpoint || swiper.currentBreakpoint === breakpoint) return;
3749
3533
  const breakpointOnlyParams = breakpoint in breakpoints ? breakpoints[breakpoint] : undefined;
3750
3534
  const breakpointParams = breakpointOnlyParams || swiper.originalParams;
3751
- const wasMultiRow = isGridEnabled(swiper, params);
3752
- const isMultiRow = isGridEnabled(swiper, breakpointParams);
3753
3535
  const wasGrabCursor = swiper.params.grabCursor;
3754
3536
  const isGrabCursor = breakpointParams.grabCursor;
3755
3537
  const wasEnabled = params.enabled;
3756
- if (wasMultiRow && !isMultiRow) {
3757
- el.classList.remove(`${params.containerModifierClass}grid`, `${params.containerModifierClass}grid-column`);
3758
- swiper.emitContainerClasses();
3759
- } else if (!wasMultiRow && isMultiRow) {
3760
- el.classList.add(`${params.containerModifierClass}grid`);
3761
- if (breakpointParams.grid.fill && breakpointParams.grid.fill === 'column' || !breakpointParams.grid.fill && params.grid.fill === 'column') {
3762
- el.classList.add(`${params.containerModifierClass}grid-column`);
3763
- }
3764
- swiper.emitContainerClasses();
3765
- }
3766
3538
  if (wasGrabCursor && !isGrabCursor) {
3767
3539
  swiper.unsetGrabCursor();
3768
3540
  } else if (!wasGrabCursor && isGrabCursor) {
3769
3541
  swiper.setGrabCursor();
3770
3542
  }
3771
3543
 
3772
- // Toggle navigation, pagination, scrollbar
3773
- ['navigation', 'pagination', 'scrollbar'].forEach(prop => {
3544
+ // Core-lite: toggle navigation & pagination only.
3545
+ const modules = ['navigation', 'pagination'];
3546
+ modules.forEach(prop => {
3774
3547
  if (typeof breakpointParams[prop] === 'undefined') return;
3775
- const wasModuleEnabled = params[prop] && params[prop].enabled;
3776
- const isModuleEnabled = breakpointParams[prop] && breakpointParams[prop].enabled;
3777
- if (wasModuleEnabled && !isModuleEnabled) {
3778
- swiper[prop].disable();
3779
- }
3780
- if (!wasModuleEnabled && isModuleEnabled) {
3781
- swiper[prop].enable();
3782
- }
3548
+ toggleModule(swiper, params, breakpointParams, prop);
3783
3549
  });
3784
3550
  const directionChanged = breakpointParams.direction && breakpointParams.direction !== params.direction;
3785
3551
  const needsReLoop = params.loop && (breakpointParams.slidesPerView !== params.slidesPerView || directionChanged);
@@ -3861,7 +3627,7 @@
3861
3627
  getBreakpoint
3862
3628
  };
3863
3629
 
3864
- function prepareClasses(entries, prefix) {
3630
+ const prepareClasses = (entries, prefix) => {
3865
3631
  const resultClasses = [];
3866
3632
  entries.forEach(item => {
3867
3633
  if (typeof item === 'object') {
@@ -3875,7 +3641,7 @@
3875
3641
  }
3876
3642
  });
3877
3643
  return resultClasses;
3878
- }
3644
+ };
3879
3645
  function addClasses() {
3880
3646
  const swiper = this;
3881
3647
  const {
@@ -3885,17 +3651,12 @@
3885
3651
  el,
3886
3652
  device
3887
3653
  } = swiper;
3654
+ // core-lite: removed module-specific classes
3888
3655
  // prettier-ignore
3889
3656
  const suffixes = prepareClasses(['initialized', params.direction, {
3890
- 'free-mode': swiper.params.freeMode && params.freeMode.enabled
3891
- }, {
3892
3657
  'autoheight': params.autoHeight
3893
3658
  }, {
3894
3659
  'rtl': rtl
3895
- }, {
3896
- 'grid': params.grid && params.grid.rows > 1
3897
- }, {
3898
- 'grid-column': params.grid && params.grid.rows > 1 && params.grid.fill === 'column'
3899
3660
  }, {
3900
3661
  'android': device.android
3901
3662
  }, {
@@ -3992,16 +3753,12 @@
3992
3753
  autoHeight: false,
3993
3754
  // Set wrapper width
3994
3755
  setWrapperSize: false,
3995
- // Virtual Translate
3996
- virtualTranslate: false,
3997
- // Effects
3756
+ // Effects (core-lite only supports `slide`)
3998
3757
  effect: 'slide',
3999
- // 'slide' or 'fade' or 'cube' or 'coverflow' or 'flip'
4000
-
4001
3758
  // Breakpoints
4002
3759
  breakpoints: undefined,
4003
3760
  breakpointsBase: 'window',
4004
- // Slides grid
3761
+ // Slides
4005
3762
  spaceBetween: 0,
4006
3763
  slidesPerView: 1,
4007
3764
  slidesPerGroup: 1,
@@ -4104,7 +3861,9 @@
4104
3861
  if (moduleParamName === 'navigation' && params[moduleParamName] && params[moduleParamName].enabled && !params[moduleParamName].prevEl && !params[moduleParamName].nextEl) {
4105
3862
  params[moduleParamName].auto = true;
4106
3863
  }
4107
- if (['pagination', 'scrollbar'].indexOf(moduleParamName) >= 0 && params[moduleParamName] && params[moduleParamName].enabled && !params[moduleParamName].el) {
3864
+
3865
+ // Core-lite: keep only pagination auto-init.
3866
+ if (moduleParamName === 'pagination' && params[moduleParamName] && params[moduleParamName].enabled && !params[moduleParamName].el) {
4108
3867
  params[moduleParamName].auto = true;
4109
3868
  }
4110
3869
  if (!(moduleParamName in params && 'enabled' in moduleParams)) {
@@ -4230,7 +3989,6 @@
4230
3989
  // Indexes
4231
3990
  activeIndex: 0,
4232
3991
  realIndex: 0,
4233
- //
4234
3992
  isBeginning: true,
4235
3993
  isEnd: false,
4236
3994
  // Props
@@ -4257,12 +4015,9 @@
4257
4015
  currentTranslate: undefined,
4258
4016
  startTranslate: undefined,
4259
4017
  allowThresholdMove: undefined,
4260
- // Form elements to match
4261
4018
  focusableElements: swiper.params.focusableElements,
4262
- // Last click time
4263
4019
  lastClickTime: 0,
4264
4020
  clickTimeout: undefined,
4265
- // Velocities
4266
4021
  velocities: [],
4267
4022
  allowMomentumBounce: undefined,
4268
4023
  startMoving: undefined,
@@ -4282,7 +4037,8 @@
4282
4037
  },
4283
4038
  // Images
4284
4039
  imagesToLoad: [],
4285
- imagesLoaded: 0
4040
+ imagesLoaded: 0,
4041
+ rtl: params?.rtl
4286
4042
  });
4287
4043
  swiper.emit('_swiper');
4288
4044
 
@@ -4291,7 +4047,6 @@
4291
4047
  swiper.init();
4292
4048
  }
4293
4049
 
4294
- // Return app instance
4295
4050
  // eslint-disable-next-line no-constructor-return
4296
4051
  return swiper;
4297
4052
  }
@@ -4323,16 +4078,6 @@
4323
4078
  getSlideIndexByData(index) {
4324
4079
  return this.getSlideIndex(this.slides.find(slideEl => slideEl.getAttribute('data-swiper-slide-index') * 1 === index));
4325
4080
  }
4326
- getSlideIndexWhenGrid(index) {
4327
- if (this.grid && this.params.grid && this.params.grid.rows > 1) {
4328
- if (this.params.grid.fill === 'column') {
4329
- index = Math.floor(index / this.params.grid.rows);
4330
- } else if (this.params.grid.fill === 'row') {
4331
- index = index % Math.ceil(this.slides.length / this.params.grid.rows);
4332
- }
4333
- }
4334
- return index;
4335
- }
4336
4081
  recalcSlides() {
4337
4082
  const swiper = this;
4338
4083
  const {
@@ -4434,21 +4179,15 @@
4434
4179
  }
4435
4180
  }
4436
4181
  } else {
4437
- // eslint-disable-next-line
4438
4182
  if (view === 'current') {
4439
4183
  for (let i = activeIndex + 1; i < slides.length; i += 1) {
4440
4184
  const slideInView = exact ? slidesGrid[i] + slidesSizesGrid[i] - slidesGrid[activeIndex] < swiperSize : slidesGrid[i] - slidesGrid[activeIndex] < swiperSize;
4441
- if (slideInView) {
4442
- spv += 1;
4443
- }
4185
+ if (slideInView) spv += 1;
4444
4186
  }
4445
4187
  } else {
4446
- // previous
4447
4188
  for (let i = activeIndex - 1; i >= 0; i -= 1) {
4448
4189
  const slideInView = slidesGrid[activeIndex] - slidesGrid[i] < swiperSize;
4449
- if (slideInView) {
4450
- spv += 1;
4451
- }
4190
+ if (slideInView) spv += 1;
4452
4191
  }
4453
4192
  }
4454
4193
  }
@@ -4461,14 +4200,11 @@
4461
4200
  snapGrid,
4462
4201
  params
4463
4202
  } = swiper;
4464
- // Breakpoints
4465
4203
  if (params.breakpoints) {
4466
4204
  swiper.setBreakpoint();
4467
4205
  }
4468
4206
  [...swiper.el.querySelectorAll('[loading="lazy"]')].forEach(imageEl => {
4469
- if (imageEl.complete) {
4470
- processLazyPreloader(swiper, imageEl);
4471
- }
4207
+ if (imageEl.complete) processLazyPreloader(swiper, imageEl);
4472
4208
  });
4473
4209
  swiper.updateSize();
4474
4210
  swiper.updateSlides();
@@ -4482,22 +4218,12 @@
4482
4218
  swiper.updateSlidesClasses();
4483
4219
  }
4484
4220
  let translated;
4485
- if (params.freeMode && params.freeMode.enabled && !params.cssMode) {
4486
- setTranslate();
4487
- if (params.autoHeight) {
4488
- swiper.updateAutoHeight();
4489
- }
4221
+ if ((params.slidesPerView === 'auto' || params.slidesPerView > 1) && swiper.isEnd && !params.centeredSlides) {
4222
+ translated = swiper.slideTo(swiper.slides.length - 1, 0, false, true);
4490
4223
  } else {
4491
- if ((params.slidesPerView === 'auto' || params.slidesPerView > 1) && swiper.isEnd && !params.centeredSlides) {
4492
- const slides = swiper.virtual && params.virtual.enabled ? swiper.virtual.slides : swiper.slides;
4493
- translated = swiper.slideTo(slides.length - 1, 0, false, true);
4494
- } else {
4495
- translated = swiper.slideTo(swiper.activeIndex, 0, false, true);
4496
- }
4497
- if (!translated) {
4498
- setTranslate();
4499
- }
4224
+ translated = swiper.slideTo(swiper.activeIndex, 0, false, true);
4500
4225
  }
4226
+ if (!translated) setTranslate();
4501
4227
  if (params.watchOverflow && snapGrid !== swiper.snapGrid) {
4502
4228
  swiper.checkOverflow();
4503
4229
  }
@@ -4510,7 +4236,6 @@
4510
4236
  const swiper = this;
4511
4237
  const currentDirection = swiper.params.direction;
4512
4238
  if (!newDirection) {
4513
- // eslint-disable-next-line
4514
4239
  newDirection = currentDirection === 'horizontal' ? 'vertical' : 'horizontal';
4515
4240
  }
4516
4241
  if (newDirection === currentDirection || newDirection !== 'horizontal' && newDirection !== 'vertical') {
@@ -4548,15 +4273,11 @@
4548
4273
  mount(element) {
4549
4274
  const swiper = this;
4550
4275
  if (swiper.mounted) return true;
4551
-
4552
- // Find el
4553
4276
  let el = element || swiper.params.el;
4554
4277
  if (typeof el === 'string') {
4555
4278
  el = document.querySelector(el);
4556
4279
  }
4557
- if (!el) {
4558
- return false;
4559
- }
4280
+ if (!el) return false;
4560
4281
  el.swiper = swiper;
4561
4282
  if (el.parentNode && el.parentNode.host && el.parentNode.host.nodeName === swiper.params.swiperElementNodeName.toUpperCase()) {
4562
4283
  swiper.isElement = true;
@@ -4567,12 +4288,10 @@
4567
4288
  const getWrapper = () => {
4568
4289
  if (el && el.shadowRoot && el.shadowRoot.querySelector) {
4569
4290
  const res = el.shadowRoot.querySelector(getWrapperSelector());
4570
- // Children needs to return slot items
4571
4291
  return res;
4572
4292
  }
4573
4293
  return elementChildren(el, getWrapperSelector())[0];
4574
4294
  };
4575
- // Find Wrapper
4576
4295
  let wrapperEl = getWrapper();
4577
4296
  if (!wrapperEl && swiper.params.createElements) {
4578
4297
  wrapperEl = createElement('div', swiper.params.wrapperClass);
@@ -4581,6 +4300,8 @@
4581
4300
  wrapperEl.append(slideEl);
4582
4301
  });
4583
4302
  }
4303
+ const rtl = swiper.params.rtl ?? (el.dir.toLowerCase() === 'rtl' || elementStyle(el, 'direction') === 'rtl');
4304
+ const wrongRTL = false;
4584
4305
  Object.assign(swiper, {
4585
4306
  el,
4586
4307
  wrapperEl,
@@ -4588,9 +4309,9 @@
4588
4309
  hostEl: swiper.isElement ? el.parentNode.host : el,
4589
4310
  mounted: true,
4590
4311
  // RTL
4591
- rtl: el.dir.toLowerCase() === 'rtl' || elementStyle(el, 'direction') === 'rtl',
4592
- rtlTranslate: swiper.params.direction === 'horizontal' && (el.dir.toLowerCase() === 'rtl' || elementStyle(el, 'direction') === 'rtl'),
4593
- wrongRTL: elementStyle(wrapperEl, 'display') === '-webkit-box'
4312
+ rtl,
4313
+ rtlTranslate: swiper.params.direction === 'horizontal' && rtl,
4314
+ wrongRTL
4594
4315
  });
4595
4316
  return true;
4596
4317
  }
@@ -4607,7 +4328,6 @@
4607
4328
  const gap = Math.abs(swiper.snapGrid[1] - swiper.snapGrid[0]);
4608
4329
  const swiperTranslate = structuredClone(swiper.snapGrid[1]);
4609
4330
  if (isFirstSlide) {
4610
- // Move last item to first position when at first slide
4611
4331
  const lastSlide = slides.at(-1);
4612
4332
  lastSlide.swiperLoopMoveDOM = true;
4613
4333
  swiper.slidesEl.prepend(lastSlide);
@@ -4619,7 +4339,6 @@
4619
4339
  swiper.setTransition(speed);
4620
4340
  swiper.setTranslate(-swiperTranslate);
4621
4341
  } else if (isLastSlide) {
4622
- // Move first item to last position when at last slide
4623
4342
  const firstSlide = slides[0];
4624
4343
  firstSlide.swiperLoopMoveDOM = true;
4625
4344
  swiper.slidesEl.append(firstSlide);
@@ -4640,42 +4359,24 @@
4640
4359
  const mounted = swiper.mount(el);
4641
4360
  if (mounted === false) return swiper;
4642
4361
  swiper.emit('beforeInit');
4643
-
4644
- // Set breakpoint
4645
4362
  if (swiper.params.breakpoints) {
4646
4363
  swiper.setBreakpoint();
4647
4364
  }
4648
-
4649
- // Add Classes
4650
4365
  swiper.addClasses();
4651
-
4652
- // Update size
4653
4366
  swiper.updateSize();
4654
-
4655
- // Update slides
4656
4367
  swiper.updateSlides();
4657
4368
  if (swiper.params.watchOverflow) {
4658
4369
  swiper.checkOverflow();
4659
4370
  }
4660
-
4661
- // Set Grab Cursor
4662
4371
  if (swiper.params.grabCursor && swiper.enabled) {
4663
4372
  swiper.setGrabCursor();
4664
4373
  }
4665
4374
 
4666
- // Slide To Initial Slide
4667
- if (swiper.params.loop && swiper.virtual && swiper.params.virtual.enabled) {
4668
- swiper.slideTo(swiper.params.initialSlide + swiper.virtual.slidesBefore, 0, swiper.params.runCallbacksOnInit, false, true);
4669
- } else {
4670
- swiper.slideTo(swiper.params.initialSlide, 0, swiper.params.runCallbacksOnInit, false, true);
4671
- }
4672
-
4673
- // Create loop
4375
+ // Slide to initial slide (core-lite: no optional feature initial offsets)
4376
+ swiper.slideTo(swiper.params.initialSlide, 0, swiper.params.runCallbacksOnInit, false, true);
4674
4377
  if (swiper.params.loop) {
4675
4378
  swiper.loopCreate(undefined, true);
4676
4379
  }
4677
-
4678
- // Attach events
4679
4380
  swiper.attachEvents();
4680
4381
  const lazyElements = [...swiper.el.querySelectorAll('[loading="lazy"]')];
4681
4382
  if (swiper.isElement) {
@@ -4685,16 +4386,11 @@
4685
4386
  if (imageEl.complete) {
4686
4387
  processLazyPreloader(swiper, imageEl);
4687
4388
  } else {
4688
- imageEl.addEventListener('load', e => {
4689
- processLazyPreloader(swiper, e.target);
4690
- });
4389
+ imageEl.addEventListener('load', e => processLazyPreloader(swiper, e.target));
4691
4390
  }
4692
4391
  });
4693
4392
  preload(swiper);
4694
-
4695
- // Init Flag
4696
4393
  swiper.initialized = true;
4697
- preload(swiper);
4698
4394
 
4699
4395
  // Emit
4700
4396
  swiper.emit('init');
@@ -4719,27 +4415,15 @@
4719
4415
  return null;
4720
4416
  }
4721
4417
  swiper.emit('beforeDestroy');
4722
-
4723
- // Init Flag
4724
4418
  swiper.initialized = false;
4725
-
4726
- // Detach events
4727
4419
  swiper.detachEvents();
4728
-
4729
- // Destroy loop
4730
4420
  if (params.loop) {
4731
4421
  swiper.loopDestroy();
4732
4422
  }
4733
-
4734
- // Cleanup styles
4735
4423
  if (cleanStyles) {
4736
4424
  swiper.removeClasses();
4737
- if (el && typeof el !== 'string') {
4738
- el.removeAttribute('style');
4739
- }
4740
- if (wrapperEl) {
4741
- wrapperEl.removeAttribute('style');
4742
- }
4425
+ if (el && typeof el !== 'string') el.removeAttribute('style');
4426
+ if (wrapperEl) wrapperEl.removeAttribute('style');
4743
4427
  if (slides && slides.length) {
4744
4428
  slides.forEach(slideEl => {
4745
4429
  slideEl.classList.remove(params.slideVisibleClass, params.slideFullyVisibleClass, params.slideActiveClass, params.slideNextClass, params.slidePrevClass);
@@ -4749,8 +4433,6 @@
4749
4433
  }
4750
4434
  }
4751
4435
  swiper.emit('destroy');
4752
-
4753
- // Detach emitter events
4754
4436
  Object.keys(swiper.eventsListeners).forEach(eventName => {
4755
4437
  swiper.off(eventName);
4756
4438
  });
@@ -5121,7 +4803,7 @@
5121
4803
  }
5122
4804
 
5123
4805
  /**
5124
- * Swiper Custom Element 0.0.15
4806
+ * Swiper Custom Element 0.0.16-dev.1
5125
4807
  * Gem SDK - Swiper, Customized of swiper
5126
4808
  * https://swiperjs.com
5127
4809
  *