@evermade/overflow-slider 3.0.0 → 3.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/README.md +14 -2
  2. package/dist/core/details.esm.js +4 -4
  3. package/dist/core/details.min.js +1 -1
  4. package/dist/core/slider.esm.js +53 -30
  5. package/dist/core/slider.min.js +1 -1
  6. package/dist/core/utils.esm.js +15 -1
  7. package/dist/core/utils.min.js +1 -1
  8. package/dist/plugins/arrows/arrows/index.esm.js +15 -8
  9. package/dist/plugins/arrows/arrows/index.min.js +1 -1
  10. package/dist/plugins/drag-scrolling/drag-scrolling/index.esm.js +1 -1
  11. package/dist/plugins/drag-scrolling/drag-scrolling/index.min.js +1 -1
  12. package/dist/plugins/fade/fade/index.esm.js +4 -4
  13. package/dist/plugins/fade/fade/index.min.js +1 -1
  14. package/dist/plugins/scroll-indicator/scroll-indicator/index.esm.js +4 -4
  15. package/dist/plugins/scroll-indicator/scroll-indicator/index.min.js +1 -1
  16. package/dist/plugins/thumbnails/thumbnails/index.esm.js +1 -1
  17. package/dist/plugins/thumbnails/thumbnails/index.min.js +1 -1
  18. package/docs/dist/core/details.esm.js +4 -4
  19. package/docs/dist/core/details.min.js +1 -1
  20. package/docs/dist/core/slider.esm.js +53 -30
  21. package/docs/dist/core/slider.min.js +1 -1
  22. package/docs/dist/core/utils.esm.js +15 -1
  23. package/docs/dist/core/utils.min.js +1 -1
  24. package/docs/dist/plugins/arrows/arrows/index.esm.js +15 -8
  25. package/docs/dist/plugins/arrows/arrows/index.min.js +1 -1
  26. package/docs/dist/plugins/drag-scrolling/drag-scrolling/index.esm.js +1 -1
  27. package/docs/dist/plugins/drag-scrolling/drag-scrolling/index.min.js +1 -1
  28. package/docs/dist/plugins/fade/fade/index.esm.js +4 -4
  29. package/docs/dist/plugins/fade/fade/index.min.js +1 -1
  30. package/docs/dist/plugins/scroll-indicator/scroll-indicator/index.esm.js +4 -4
  31. package/docs/dist/plugins/scroll-indicator/scroll-indicator/index.min.js +1 -1
  32. package/docs/dist/plugins/thumbnails/thumbnails/index.esm.js +1 -1
  33. package/docs/dist/plugins/thumbnails/thumbnails/index.min.js +1 -1
  34. package/package.json +1 -1
  35. package/src/core/details.ts +4 -4
  36. package/src/core/slider.ts +60 -32
  37. package/src/core/types.ts +2 -0
  38. package/src/core/utils.ts +19 -1
  39. package/src/plugins/arrows/index.ts +16 -8
  40. package/src/plugins/drag-scrolling/index.ts +1 -1
  41. package/src/plugins/fade/index.ts +4 -5
  42. package/src/plugins/scroll-indicator/index.ts +4 -4
  43. package/src/plugins/thumbnails/index.ts +1 -2
@@ -1,6 +1,6 @@
1
1
  import { Slider, SliderOptions, SliderPlugin } from './types';
2
2
  import details from './details';
3
- import { generateId, objectsAreEqual } from './utils';
3
+ import { generateId, objectsAreEqual, getOutermostChildrenEdgeMarginSum } from './utils';
4
4
 
5
5
  export default function Slider( container: HTMLElement, options : SliderOptions, plugins? : SliderPlugin[] ) {
6
6
  let slider: Slider;
@@ -94,7 +94,7 @@ export default function Slider( container: HTMLElement, options : SliderOptions,
94
94
  // any scroll
95
95
  slider.container.addEventListener('scroll', () => {
96
96
  const newScrollLeft = slider.container.scrollLeft;
97
- if (scrollLeft !== newScrollLeft) {
97
+ if ( Math.floor( scrollLeft ) !== Math.floor( newScrollLeft ) ) {
98
98
  if (!isScrolling) {
99
99
  isScrolling = true;
100
100
  slider.emit('scrollStart');
@@ -116,7 +116,7 @@ export default function Slider( container: HTMLElement, options : SliderOptions,
116
116
  // user initted scroll (touchmove, mouse wheel, etc.)
117
117
  const nativeScrollHandler = () => {
118
118
  const newScrollLeft = slider.container.scrollLeft;
119
- if (nativeScrollLeft !== newScrollLeft && !isProgrammaticScrolling) {
119
+ if ( Math.floor( nativeScrollLeft ) !== Math.floor( newScrollLeft ) && ! isProgrammaticScrolling ) {
120
120
  if (!isUserScrolling) {
121
121
  slider.emit('nativeScrollStart');
122
122
  isUserScrolling = true;
@@ -145,7 +145,7 @@ export default function Slider( container: HTMLElement, options : SliderOptions,
145
145
 
146
146
  slider.container.addEventListener('scroll', () => {
147
147
  const newScrollLeft = slider.container.scrollLeft;
148
- if (programmaticScrollLeft !== newScrollLeft && !isUserScrolling && isProgrammaticScrolling) {
148
+ if ( Math.floor( programmaticScrollLeft ) !== Math.floor( newScrollLeft ) && !isUserScrolling && isProgrammaticScrolling) {
149
149
  programmaticScrollLeft = newScrollLeft;
150
150
  clearTimeout(programmaticScrollTimeout);
151
151
  programmaticScrollTimeout = setTimeout(() => {
@@ -218,11 +218,11 @@ export default function Slider( container: HTMLElement, options : SliderOptions,
218
218
  const slideStart = slideRect.left - sliderRect.left + scrollLeft;
219
219
  const slideEnd = slideStart + slideRect.width;
220
220
  let scrollTarget = null;
221
- if (slideStart < scrollLeft) {
221
+ if ( Math.floor( slideStart ) < Math.floor( scrollLeft ) ) {
222
222
  scrollTarget = slideStart;
223
- } else if (slideEnd > scrollLeft + containerWidth) {
223
+ } else if ( Math.floor( slideEnd ) > Math.floor( scrollLeft ) + Math.floor( containerWidth ) ) {
224
224
  scrollTarget = slideEnd - containerWidth;
225
- } else if (slideStart === 0) {
225
+ } else if ( Math.floor( slideStart ) === 0) {
226
226
  scrollTarget = 0;
227
227
  } else {
228
228
  scrollTarget = slideStart;
@@ -240,24 +240,34 @@ export default function Slider( container: HTMLElement, options : SliderOptions,
240
240
  const scrollLeft = slider.container.scrollLeft;
241
241
  const slides = slider.slides;
242
242
  let activeSlideIdx = 0;
243
+ let scrolledPastLastSlide = false;
243
244
 
244
245
  for (let i = 0; i < slides.length; i++) {
245
246
  const slideRect = slides[i].getBoundingClientRect();
246
247
  const slideStart = slideRect.left - sliderRect.left + scrollLeft + getGapSize();
247
248
 
248
- if (slideStart > scrollLeft) {
249
+ if ( Math.floor( slideStart ) >= Math.floor( scrollLeft ) ) {
249
250
  activeSlideIdx = i;
250
251
  break;
251
252
  }
253
+ if ( i === slides.length - 1 ) {
254
+ scrolledPastLastSlide = true;
255
+ }
256
+ }
257
+
258
+ if ( scrolledPastLastSlide ) {
259
+ activeSlideIdx = slides.length - 1;
252
260
  }
253
261
 
254
262
  const oldActiveSlideIdx = slider.activeSlideIdx;
255
263
  slider.activeSlideIdx = activeSlideIdx;
264
+
256
265
  if (oldActiveSlideIdx !== activeSlideIdx) {
257
266
  slider.emit('activeSlideChanged');
258
267
  }
259
268
  }
260
269
 
270
+
261
271
  function moveToSlide( idx: number ) {
262
272
  const slide = slider.slides[idx];
263
273
  if (slide) {
@@ -265,12 +275,20 @@ export default function Slider( container: HTMLElement, options : SliderOptions,
265
275
  }
266
276
  };
267
277
 
278
+ function getInclusiveScrollWidth() : number {
279
+ return slider.container.scrollWidth + getOutermostChildrenEdgeMarginSum(slider.container);
280
+ };
281
+
282
+ function getInclusiveClientWidth() : number {
283
+ return slider.container.clientWidth + getOutermostChildrenEdgeMarginSum(slider.container);
284
+ }
285
+
268
286
  function getGapSize() : number {
269
287
  let gapSize = 0;
270
288
  if (slider.slides.length > 1) {
271
289
  const firstSlideRect = slider.slides[0].getBoundingClientRect();
272
290
  const secondSlideRect = slider.slides[1].getBoundingClientRect();
273
- gapSize = secondSlideRect.left - firstSlideRect.right;
291
+ gapSize = Math.floor( secondSlideRect.left - firstSlideRect.right );
274
292
  }
275
293
  return gapSize;
276
294
  };
@@ -281,7 +299,7 @@ export default function Slider( container: HTMLElement, options : SliderOptions,
281
299
  if (fullWidthOffset) {
282
300
  offset = parseInt(fullWidthOffset);
283
301
  }
284
- return offset;
302
+ return Math.floor( offset );
285
303
  };
286
304
 
287
305
  function moveToDirection(direction = "prev") {
@@ -293,16 +311,16 @@ export default function Slider( container: HTMLElement, options : SliderOptions,
293
311
  if (direction === 'prev') {
294
312
  targetScrollPosition = Math.max(0, scrollLeft - slider.container.offsetWidth);
295
313
  } else if (direction === 'next') {
296
- targetScrollPosition = Math.min(slider.container.scrollWidth, scrollLeft + slider.container.offsetWidth);
314
+ targetScrollPosition = Math.min(slider.getInclusiveScrollWidth(), scrollLeft + slider.container.offsetWidth);
297
315
  }
298
316
  if (scrollStrategy === 'fullSlide') {
299
- let fullSldeTargetScrollPosition = null;
317
+ let fullSlideTargetScrollPosition = null;
300
318
 
301
319
  // extend targetScrollPosition to include gap
302
320
  if (direction === 'prev') {
303
- fullSldeTargetScrollPosition = Math.max(0, targetScrollPosition - getGapSize());
321
+ fullSlideTargetScrollPosition = Math.max(0, targetScrollPosition - getGapSize());
304
322
  } else {
305
- fullSldeTargetScrollPosition = Math.min(slider.container.scrollWidth, targetScrollPosition + getGapSize());
323
+ fullSlideTargetScrollPosition = Math.min(slider.getInclusiveScrollWidth(), targetScrollPosition + getGapSize());
306
324
  }
307
325
 
308
326
  if (direction === 'next') {
@@ -311,42 +329,50 @@ export default function Slider( container: HTMLElement, options : SliderOptions,
311
329
  const slideRect = slide.getBoundingClientRect();
312
330
  const slideStart = slideRect.left - sliderRect.left + scrollLeft;
313
331
  const slideEnd = slideStart + slideRect.width;
314
- if (slideStart < targetScrollPosition && slideEnd > targetScrollPosition) {
315
- fullSldeTargetScrollPosition = slideStart;
332
+ if ( Math.floor( slideStart ) < Math.floor( targetScrollPosition ) && Math.floor( slideEnd ) > Math.floor( targetScrollPosition ) ) {
333
+ fullSlideTargetScrollPosition = slideStart;
316
334
  partialSlideFound = true;
317
335
  break;
318
336
  }
319
337
  }
320
- if (!partialSlideFound) {
321
- fullSldeTargetScrollPosition = Math.min(targetScrollPosition, slider.container.scrollWidth - slider.container.offsetWidth);
338
+ if ( ! partialSlideFound ) {
339
+ fullSlideTargetScrollPosition = Math.min(targetScrollPosition, slider.getInclusiveScrollWidth() - slider.container.offsetWidth);
322
340
  }
323
- if (fullSldeTargetScrollPosition && fullSldeTargetScrollPosition > scrollLeft) {
324
- targetScrollPosition = fullSldeTargetScrollPosition;
341
+ if ( fullSlideTargetScrollPosition ) {
342
+ if ( Math.floor( fullSlideTargetScrollPosition ) > Math.floor( scrollLeft ) ) {
343
+ // make sure fullSlideTargetScrollPosition is possible considering the container width
344
+ const maxScrollPosition = Math.floor( slider.getInclusiveScrollWidth() ) - Math.floor( containerWidth );
345
+ targetScrollPosition = Math.min( fullSlideTargetScrollPosition, maxScrollPosition );
346
+ } else {
347
+ // cannot snap to slide, move one page worth of distance
348
+ targetScrollPosition = Math.min(slider.getInclusiveScrollWidth(), scrollLeft + containerWidth);
349
+ }
325
350
  }
351
+
326
352
  } else {
327
353
  let partialSlideFound = false;
328
354
  for (let slide of slider.slides) {
329
355
  const slideRect = slide.getBoundingClientRect();
330
356
  const slideStart = slideRect.left - sliderRect.left + scrollLeft;
331
357
  const slideEnd = slideStart + slideRect.width;
332
- if (slideStart < scrollLeft && slideEnd > scrollLeft) {
333
- fullSldeTargetScrollPosition = slideEnd - containerWidth;
358
+ if ( Math.floor( slideStart ) < Math.floor( scrollLeft ) && Math.floor( slideEnd ) > Math.floor( scrollLeft ) ) {
359
+ fullSlideTargetScrollPosition = slideEnd - containerWidth;
334
360
  partialSlideFound = true;
335
361
  break;
336
362
  }
337
363
  }
338
- if (!partialSlideFound) {
339
- fullSldeTargetScrollPosition = Math.max(0, scrollLeft - containerWidth);
364
+ if ( ! partialSlideFound ) {
365
+ fullSlideTargetScrollPosition = Math.max(0, scrollLeft - containerWidth);
340
366
  }
341
- if (fullSldeTargetScrollPosition && fullSldeTargetScrollPosition < scrollLeft) {
342
- targetScrollPosition = fullSldeTargetScrollPosition;
367
+ if ( fullSlideTargetScrollPosition && Math.floor( fullSlideTargetScrollPosition ) < Math.floor( scrollLeft ) ) {
368
+ targetScrollPosition = fullSlideTargetScrollPosition;
343
369
  }
344
370
  }
345
371
  }
346
372
 
347
373
  // add left offset
348
374
  const offsettedTargetScrollPosition = targetScrollPosition - getLeftOffset();
349
- if (offsettedTargetScrollPosition >= 0) {
375
+ if ( Math.floor( offsettedTargetScrollPosition ) >= 0) {
350
376
  targetScrollPosition = offsettedTargetScrollPosition;
351
377
  }
352
378
 
@@ -380,11 +406,11 @@ export default function Slider( container: HTMLElement, options : SliderOptions,
380
406
  if (isMovingForward) {
381
407
  for (let i = 0; i < slideReference.length; i++) {
382
408
  const item = slideReference[i];
383
- if ( i === 0 && scrollPosition <= item.trigger ) {
409
+ if ( i === 0 && Math.floor( scrollPosition ) <= Math.floor( item.trigger ) ) {
384
410
  snapTarget = 0;
385
411
  break;
386
412
  }
387
- if (slider.container.scrollLeft <= item.trigger) {
413
+ if ( Math.floor( slider.container.scrollLeft ) <= Math.floor( item.trigger ) ) {
388
414
  snapTarget = item.start;
389
415
  break;
390
416
  }
@@ -392,11 +418,11 @@ export default function Slider( container: HTMLElement, options : SliderOptions,
392
418
  } else {
393
419
  for (let i = slideReference.length - 1; i >= 0; i--) {
394
420
  const item = slideReference[i];
395
- if ( i === slideReference.length - 1 && scrollPosition >= item.trigger ) {
421
+ if ( i === slideReference.length - 1 && Math.floor( scrollPosition ) >= Math.floor( item.trigger ) ) {
396
422
  snapTarget = item.start;
397
423
  break;
398
424
  }
399
- if (slider.container.scrollLeft >= item.trigger) {
425
+ if ( Math.floor( slider.container.scrollLeft ) >= Math.floor( item.trigger ) ) {
400
426
  snapTarget = item.start;
401
427
  break;
402
428
  }
@@ -404,7 +430,7 @@ export default function Slider( container: HTMLElement, options : SliderOptions,
404
430
  }
405
431
  if ( snapTarget !== null ) {
406
432
  const offsettedSnapTarget = snapTarget - getLeftOffset();
407
- if (offsettedSnapTarget >= 0) {
433
+ if ( Math.floor( offsettedSnapTarget ) >= 0 ) {
408
434
  snapTarget = offsettedSnapTarget;
409
435
  }
410
436
 
@@ -440,6 +466,8 @@ export default function Slider( container: HTMLElement, options : SliderOptions,
440
466
  moveToDirection,
441
467
  moveToSlide,
442
468
  snapToClosestSlide,
469
+ getInclusiveScrollWidth,
470
+ getInclusiveClientWidth,
443
471
  on,
444
472
  options,
445
473
  };
package/src/core/types.ts CHANGED
@@ -11,6 +11,8 @@ export type Slider<O = {}, C = {}, H extends string = string> = {
11
11
  moveToSlide: (
12
12
  index: number
13
13
  ) => void
14
+ getInclusiveScrollWidth: () => number
15
+ getInclusiveClientWidth: () => number
14
16
  on: (
15
17
  name: H | SliderHooks,
16
18
  cb: (props: Slider<O, C, H>) => void
package/src/core/utils.ts CHANGED
@@ -21,4 +21,22 @@ function objectsAreEqual( obj1: any, obj2: any ) {
21
21
  return true;
22
22
  }
23
23
 
24
- export { generateId, objectsAreEqual };
24
+ function getOutermostChildrenEdgeMarginSum( el: HTMLElement ): number {
25
+ if (el.children.length === 0) {
26
+ return 0;
27
+ }
28
+
29
+ // get the first child and its left margin
30
+ const firstChild = el.children[0];
31
+ const firstChildStyle = getComputedStyle(firstChild);
32
+ const firstChildMarginLeft = parseFloat(firstChildStyle.marginLeft);
33
+
34
+ // Get the last child and its right margin
35
+ const lastChild = el.children[el.children.length - 1];
36
+ const lastChildStyle = getComputedStyle(lastChild);
37
+ const lastChildMarginRight = parseFloat(lastChildStyle.marginRight);
38
+
39
+ return firstChildMarginLeft + lastChildMarginRight;
40
+ }
41
+
42
+ export { generateId, objectsAreEqual, getOutermostChildrenEdgeMarginSum };
@@ -66,7 +66,11 @@ export default function ArrowsPlugin( args: { [key: string]: any } ) {
66
66
  prev.setAttribute( 'aria-controls', slider.container.getAttribute( 'id' ) ?? '');
67
67
  prev.setAttribute( 'data-type', 'prev' );
68
68
  prev.innerHTML = options.icons.prev;
69
- prev.addEventListener( 'click', () => slider.moveToDirection( 'prev' ) );
69
+ prev.addEventListener( 'click', () => {
70
+ if ( prev.getAttribute('data-has-content') === 'true' ) {
71
+ slider.moveToDirection( 'prev' );
72
+ }
73
+ } );
70
74
 
71
75
  const next = document.createElement( 'button' );
72
76
  next.setAttribute( 'class', options.classNames.nextButton );
@@ -75,7 +79,11 @@ export default function ArrowsPlugin( args: { [key: string]: any } ) {
75
79
  next.setAttribute( 'aria-controls', slider.container.getAttribute( 'id' ) ?? '');
76
80
  next.setAttribute( 'data-type', 'next' );
77
81
  next.innerHTML = options.icons.next;
78
- next.addEventListener( 'click', () => slider.moveToDirection( 'next' ) );
82
+ next.addEventListener( 'click', () => {
83
+ if ( next.getAttribute('data-has-content') === 'true' ) {
84
+ slider.moveToDirection( 'next' );
85
+ }
86
+ } );
79
87
 
80
88
  // insert buttons to the nav
81
89
  nav.appendChild( prev );
@@ -83,15 +91,15 @@ export default function ArrowsPlugin( args: { [key: string]: any } ) {
83
91
 
84
92
  const update = () => {
85
93
  const scrollLeft = slider.container.scrollLeft;
86
- const scrollWidth = slider.container.scrollWidth;
87
- const clientWidth = slider.container.clientWidth;
88
- const buffer = 1;
89
- if ( scrollLeft === 0 ) {
94
+ const scrollWidth = slider.getInclusiveScrollWidth();
95
+ const clientWidth = slider.getInclusiveClientWidth();
96
+ const buffer = 0;
97
+ if ( Math.floor( scrollLeft ) === 0 ) {
90
98
  prev.setAttribute( 'data-has-content', 'false' );
91
99
  } else {
92
100
  prev.setAttribute( 'data-has-content', 'true' );
93
101
  }
94
- if ( scrollLeft + clientWidth >= scrollWidth - buffer ) {
102
+ if ( Math.floor( scrollLeft + clientWidth ) >= Math.floor( scrollWidth ) ) {
95
103
  next.setAttribute( 'data-has-content', 'false' );
96
104
  } else {
97
105
  next.setAttribute( 'data-has-content', 'true' );
@@ -110,7 +118,7 @@ export default function ArrowsPlugin( args: { [key: string]: any } ) {
110
118
  }
111
119
 
112
120
  update();
113
- slider.on( 'scroll', update );
121
+ slider.on( 'scrollEnd', update );
114
122
  slider.on( 'contentsChanged', update );
115
123
  slider.on( 'containerSizeChanged', update );
116
124
  };
@@ -59,7 +59,7 @@ export default function DragScrollingPlugin( args: { [key: string]: any } ) {
59
59
  const walk = (x - startX);
60
60
  const newScrollLeft = scrollLeft - walk;
61
61
  mayNeedToSnap = true;
62
- if ( slider.container.scrollLeft !== newScrollLeft ) {
62
+ if ( Math.floor( slider.container.scrollLeft ) !== Math.floor( newScrollLeft ) ) {
63
63
  isMovingForward = slider.container.scrollLeft < newScrollLeft;
64
64
  }
65
65
  slider.container.scrollLeft = newScrollLeft;
@@ -53,21 +53,21 @@ export default function FadePlugin( args: { [key: string]: any } ) {
53
53
 
54
54
  const fadeAtStartOpacity = () => {
55
55
  const position = slider.container.scrollLeft;
56
- if ( position <= fadeItemStart.offsetWidth ) {
56
+ if ( Math.floor( position ) <= Math.floor( fadeItemStart.offsetWidth ) ) {
57
57
  return position / Math.max(fadeItemStart.offsetWidth, 1);
58
58
  }
59
59
  return 1;
60
60
  }
61
61
 
62
62
  const hasFadeAtEnd = () => {
63
- return slider.container.scrollLeft < (slider.container.scrollWidth - slider.container.clientWidth - fadeItemEnd.offsetWidth);
63
+ return Math.floor( slider.container.scrollLeft ) < Math.floor( slider.getInclusiveScrollWidth() - slider.getInclusiveClientWidth() - fadeItemEnd.offsetWidth );
64
64
  }
65
65
 
66
66
  const fadeAtEndOpacity = () => {
67
67
  const position = slider.container.scrollLeft;
68
- const maxPosition = slider.container.scrollWidth - slider.container.clientWidth;
68
+ const maxPosition = slider.getInclusiveScrollWidth() - slider.getInclusiveClientWidth();
69
69
  const maxFadePosition = maxPosition - fadeItemEnd.offsetWidth;
70
- if ( position >= maxFadePosition ) {
70
+ if ( Math.floor( position ) >= Math.floor( maxFadePosition ) ) {
71
71
  return ( ( maxFadePosition - position ) / Math.max(fadeItemEnd.offsetWidth, 1) ) + 1;
72
72
  }
73
73
  return 1;
@@ -97,6 +97,5 @@ export default function FadePlugin( args: { [key: string]: any } ) {
97
97
  };
98
98
  slider.on('scroll', debouncedUpdate);
99
99
 
100
-
101
100
  };
102
101
  }
@@ -65,7 +65,7 @@ export default function ScrollIndicatorPlugin( args: { [key: string]: any } ) {
65
65
  }
66
66
 
67
67
  requestId = window.requestAnimationFrame(() => {
68
- const scrollbarButtonWidth = (slider.details.containerWidth / slider.details.scrollableAreaWidth) * 100;
68
+ const scrollbarButtonWidth = (slider.details.containerWidth / slider.container.scrollWidth) * 100;
69
69
 
70
70
  const scrollLeftInPortion = getScrollbarButtonLeftOffset();
71
71
  scrollbarButton.style.width = `${scrollbarButtonWidth}%`;
@@ -73,7 +73,7 @@ export default function ScrollIndicatorPlugin( args: { [key: string]: any } ) {
73
73
 
74
74
  // aria-valuenow
75
75
  const scrollLeft = slider.container.scrollLeft;
76
- const scrollWidth = slider.container.scrollWidth;
76
+ const scrollWidth = slider.getInclusiveScrollWidth();
77
77
  const containerWidth = slider.container.offsetWidth;
78
78
  const scrollPercentage = (scrollLeft / (scrollWidth - containerWidth)) * 100;
79
79
  scrollbarContainer.setAttribute( 'aria-valuenow', Math.round(Number.isNaN(scrollPercentage) ? 0 : scrollPercentage).toString() );
@@ -109,9 +109,9 @@ export default function ScrollIndicatorPlugin( args: { [key: string]: any } ) {
109
109
  const scrollbarButtonLeft = getScrollbarButtonLeftOffset();
110
110
  const scrollbarButtonRight = scrollbarButtonLeft + scrollbarButtonWidth;
111
111
  const clickX = e.pageX - scrollbarContainer.offsetLeft;
112
- if ( clickX < scrollbarButtonLeft ) {
112
+ if ( Math.floor( clickX ) < Math.floor( scrollbarButtonLeft ) ) {
113
113
  slider.moveToDirection( 'prev' );
114
- } else if ( clickX > scrollbarButtonRight ) {
114
+ } else if ( Math.floor( clickX ) > Math.floor( scrollbarButtonRight ) ) {
115
115
  slider.moveToDirection( 'next' );
116
116
  }
117
117
  });
@@ -13,7 +13,6 @@ export default function FullWidthPlugin( args: { [key: string]: any } ) {
13
13
 
14
14
  const mainSlider = options.mainSlider;
15
15
 
16
-
17
16
  const setActiveThumbnail = (slide: HTMLElement | null = null) => {
18
17
  if ( slide === null && slider.slides.length > 0 ) {
19
18
  slide = slider.slides[0] as HTMLElement;
@@ -41,7 +40,7 @@ export default function FullWidthPlugin( args: { [key: string]: any } ) {
41
40
  addClickListeners();
42
41
 
43
42
  // @todo debounce on scroll
44
- mainSlider.on( 'scrollEnd', () => {
43
+ mainSlider.on( 'activeSlideChanged', () => {
45
44
  setTimeout(() => {
46
45
  const activeSlideIdx = mainSlider.activeSlideIdx;
47
46
  const activeThumbnail = slider.slides[activeSlideIdx] as HTMLElement;