@evermade/overflow-slider 3.0.0 → 3.2.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 (63) hide show
  1. package/README.md +73 -8
  2. package/dist/core/details.esm.js +5 -5
  3. package/dist/core/details.min.js +1 -1
  4. package/dist/core/overflow-slider.esm.js +1 -0
  5. package/dist/core/overflow-slider.min.js +1 -1
  6. package/dist/core/slider.esm.js +113 -44
  7. package/dist/core/slider.min.js +1 -1
  8. package/dist/core/utils.esm.js +15 -1
  9. package/dist/core/utils.min.js +1 -1
  10. package/dist/overflow-slider.css +1 -1
  11. package/dist/plugins/arrows/arrows/index.esm.js +20 -10
  12. package/dist/plugins/arrows/arrows/index.min.js +1 -1
  13. package/dist/plugins/dots/dots/index.esm.js +0 -4
  14. package/dist/plugins/drag-scrolling/drag-scrolling/index.esm.js +1 -1
  15. package/dist/plugins/drag-scrolling/drag-scrolling/index.min.js +1 -1
  16. package/dist/plugins/fade/fade/index.esm.js +7 -7
  17. package/dist/plugins/fade/fade/index.min.js +1 -1
  18. package/dist/plugins/full-width/full-width/index.esm.js +7 -2
  19. package/dist/plugins/full-width/full-width/index.min.js +1 -1
  20. package/dist/plugins/scroll-indicator/scroll-indicator/index.esm.js +22 -22
  21. package/dist/plugins/scroll-indicator/scroll-indicator/index.min.js +1 -1
  22. package/dist/plugins/thumbnails/thumbnails/index.esm.js +7 -4
  23. package/dist/plugins/thumbnails/thumbnails/index.min.js +1 -1
  24. package/docs/assets/demo.css +11 -1
  25. package/docs/assets/demo.js +38 -12
  26. package/docs/dist/core/details.esm.js +5 -5
  27. package/docs/dist/core/details.min.js +1 -1
  28. package/docs/dist/core/overflow-slider.esm.js +1 -0
  29. package/docs/dist/core/overflow-slider.min.js +1 -1
  30. package/docs/dist/core/slider.esm.js +113 -44
  31. package/docs/dist/core/slider.min.js +1 -1
  32. package/docs/dist/core/utils.esm.js +15 -1
  33. package/docs/dist/core/utils.min.js +1 -1
  34. package/docs/dist/overflow-slider.css +1 -1
  35. package/docs/dist/plugins/arrows/arrows/index.esm.js +20 -10
  36. package/docs/dist/plugins/arrows/arrows/index.min.js +1 -1
  37. package/docs/dist/plugins/dots/dots/index.esm.js +0 -4
  38. package/docs/dist/plugins/drag-scrolling/drag-scrolling/index.esm.js +1 -1
  39. package/docs/dist/plugins/drag-scrolling/drag-scrolling/index.min.js +1 -1
  40. package/docs/dist/plugins/fade/fade/index.esm.js +7 -7
  41. package/docs/dist/plugins/fade/fade/index.min.js +1 -1
  42. package/docs/dist/plugins/full-width/full-width/index.esm.js +7 -2
  43. package/docs/dist/plugins/full-width/full-width/index.min.js +1 -1
  44. package/docs/dist/plugins/scroll-indicator/scroll-indicator/index.esm.js +22 -22
  45. package/docs/dist/plugins/scroll-indicator/scroll-indicator/index.min.js +1 -1
  46. package/docs/dist/plugins/thumbnails/thumbnails/index.esm.js +7 -4
  47. package/docs/dist/plugins/thumbnails/thumbnails/index.min.js +1 -1
  48. package/docs/index-rtl.html +396 -0
  49. package/docs/index.html +1 -1
  50. package/package.json +1 -1
  51. package/src/core/details.ts +5 -5
  52. package/src/core/overflow-slider.ts +1 -0
  53. package/src/core/slider.ts +125 -47
  54. package/src/core/types.ts +5 -0
  55. package/src/core/utils.ts +19 -1
  56. package/src/plugins/arrows/index.ts +20 -10
  57. package/src/plugins/dots/index.ts +0 -4
  58. package/src/plugins/drag-scrolling/index.ts +1 -1
  59. package/src/plugins/fade/index.ts +7 -8
  60. package/src/plugins/fade/styles.scss +10 -0
  61. package/src/plugins/full-width/index.ts +8 -2
  62. package/src/plugins/scroll-indicator/index.ts +62 -64
  63. package/src/plugins/thumbnails/index.ts +7 -5
@@ -15,8 +15,8 @@ export type ScrollIndicatorOptions = {
15
15
  container: HTMLElement | null,
16
16
  };
17
17
 
18
- export default function ScrollIndicatorPlugin( args: { [key: string]: any } ) {
19
- return ( slider: Slider ) => {
18
+ export default function ScrollIndicatorPlugin(args: { [key: string]: any }) {
19
+ return (slider: Slider) => {
20
20
 
21
21
  const options = <ScrollIndicatorOptions>{
22
22
  classNames: {
@@ -26,109 +26,107 @@ export default function ScrollIndicatorPlugin( args: { [key: string]: any } ) {
26
26
  container: args?.container ?? null,
27
27
  };
28
28
 
29
+ const scrollbarContainer = document.createElement('div');
30
+ scrollbarContainer.setAttribute('class', options.classNames.scrollIndicator);
31
+ scrollbarContainer.setAttribute('tabindex', '0');
32
+ scrollbarContainer.setAttribute('role', 'scrollbar');
33
+ scrollbarContainer.setAttribute('aria-controls', slider.container.getAttribute('id') ?? '');
34
+ scrollbarContainer.setAttribute('aria-orientation', 'horizontal');
35
+ scrollbarContainer.setAttribute('aria-valuemax', '100');
36
+ scrollbarContainer.setAttribute('aria-valuemin', '0');
37
+ scrollbarContainer.setAttribute('aria-valuenow', '0');
29
38
 
30
- const scrollbarContainer = document.createElement( 'div' );
31
- scrollbarContainer.setAttribute( 'class', options.classNames.scrollIndicator );
32
- scrollbarContainer.setAttribute( 'tabindex', '0' );
33
- scrollbarContainer.setAttribute( 'role', 'scrollbar' );
34
- scrollbarContainer.setAttribute( 'aria-controls', slider.container.getAttribute( 'id' ) ?? '' );
35
- scrollbarContainer.setAttribute( 'aria-orientation', 'horizontal' );
36
- scrollbarContainer.setAttribute( 'aria-valuemax', '100' );
37
- scrollbarContainer.setAttribute( 'aria-valuemin', '0' );
38
- scrollbarContainer.setAttribute( 'aria-valuenow', '0' );
39
+ const scrollbar = document.createElement('div');
40
+ scrollbar.setAttribute('class', options.classNames.scrollIndicatorBar);
39
41
 
40
- const scrollbar = document.createElement( 'div' );
41
- scrollbar.setAttribute( 'class', options.classNames.scrollIndicatorBar );
42
+ const scrollbarButton = document.createElement('div');
43
+ scrollbarButton.setAttribute('class', options.classNames.scrollIndicatorButton);
44
+ scrollbarButton.setAttribute('data-is-grabbed', 'false');
42
45
 
43
- const scrollbarButton = document.createElement( 'div' );
44
- scrollbarButton.setAttribute( 'class', options.classNames.scrollIndicatorButton );
45
- scrollbarButton.setAttribute( 'data-is-grabbed', 'false' );
46
-
47
- scrollbar.appendChild( scrollbarButton );
48
- scrollbarContainer.appendChild( scrollbar );
46
+ scrollbar.appendChild(scrollbarButton);
47
+ scrollbarContainer.appendChild(scrollbar);
49
48
 
50
49
  const setDataAttributes = () => {
51
- scrollbarContainer.setAttribute( 'data-has-overflow', slider.details.hasOverflow.toString() );
50
+ scrollbarContainer.setAttribute('data-has-overflow', slider.details.hasOverflow.toString());
52
51
  }
53
52
  setDataAttributes();
54
53
 
55
54
  const getScrollbarButtonLeftOffset = () => {
56
- const contentRatio = scrollbarButton.offsetWidth / slider.details.containerWidth;
57
- return slider.container.scrollLeft * contentRatio;
55
+ const contentRatio = scrollbarButton.offsetWidth / slider.details.containerWidth;
56
+ const scrollAmount = slider.getScrollLeft() * contentRatio;
57
+ if (slider.options.rtl) {
58
+ return scrollbar.offsetWidth - scrollbarButton.offsetWidth - scrollAmount;
59
+ }
60
+ return scrollAmount;
58
61
  };
59
62
 
60
- // scrollbarbutton width and position is calculated based on the scroll position and available width
61
63
  let requestId = 0;
62
64
  const update = () => {
63
- if ( requestId ) {
64
- window.cancelAnimationFrame( requestId );
65
+ if (requestId) {
66
+ window.cancelAnimationFrame(requestId);
65
67
  }
66
68
 
67
69
  requestId = window.requestAnimationFrame(() => {
68
- const scrollbarButtonWidth = (slider.details.containerWidth / slider.details.scrollableAreaWidth) * 100;
70
+ const scrollbarButtonWidth = (slider.details.containerWidth / slider.container.scrollWidth) * 100;
69
71
 
70
72
  const scrollLeftInPortion = getScrollbarButtonLeftOffset();
71
73
  scrollbarButton.style.width = `${scrollbarButtonWidth}%`;
72
74
  scrollbarButton.style.transform = `translateX(${scrollLeftInPortion}px)`;
73
75
 
74
- // aria-valuenow
75
- const scrollLeft = slider.container.scrollLeft;
76
- const scrollWidth = slider.container.scrollWidth;
76
+ const scrollLeft = slider.getScrollLeft();
77
+ const scrollWidth = slider.getInclusiveScrollWidth();
77
78
  const containerWidth = slider.container.offsetWidth;
78
79
  const scrollPercentage = (scrollLeft / (scrollWidth - containerWidth)) * 100;
79
- scrollbarContainer.setAttribute( 'aria-valuenow', Math.round(Number.isNaN(scrollPercentage) ? 0 : scrollPercentage).toString() );
80
+ scrollbarContainer.setAttribute('aria-valuenow', Math.round(Number.isNaN(scrollPercentage) ? 0 : scrollPercentage).toString());
80
81
  });
81
82
  };
82
83
 
83
- // insert to DOM
84
- if ( options.container ) {
85
- options.container.appendChild( scrollbarContainer );
84
+ if (options.container) {
85
+ options.container.appendChild(scrollbarContainer);
86
86
  } else {
87
- slider.container.parentNode?.insertBefore( scrollbarContainer, slider.container.nextSibling );
87
+ slider.container.parentNode?.insertBefore(scrollbarContainer, slider.container.nextSibling);
88
88
  }
89
89
 
90
- // update the scrollbar when the slider is scrolled
91
90
  update();
92
- slider.on( 'scroll', update );
93
- slider.on( 'contentsChanged', update );
94
- slider.on( 'containerSizeChanged', update );
95
- slider.on( 'detailsChanged', setDataAttributes );
96
-
97
- // handle arrow keys while focused
98
- scrollbarContainer.addEventListener( 'keydown', (e) => {
99
- if ( e.key === 'ArrowLeft' ) {
100
- slider.moveToDirection( 'prev' );
101
- } else if ( e.key === 'ArrowRight' ) {
102
- slider.moveToDirection( 'next' );
91
+ slider.on('scroll', update);
92
+ slider.on('contentsChanged', update);
93
+ slider.on('containerSizeChanged', update);
94
+ slider.on('detailsChanged', setDataAttributes);
95
+
96
+ scrollbarContainer.addEventListener('keydown', (e) => {
97
+ if (e.key === 'ArrowLeft') {
98
+ slider.moveToDirection('prev');
99
+ } else if (e.key === 'ArrowRight') {
100
+ slider.moveToDirection('next');
103
101
  }
104
102
  });
105
103
 
106
- // handle click to before or after the scrollbar button
107
- scrollbarContainer.addEventListener( 'click', (e) => {
104
+ let isInteractionDown = false;
105
+ let startX = 0;
106
+ let scrollLeft = slider.getScrollLeft();
107
+
108
+ scrollbarContainer.addEventListener('click', (e) => {
109
+ if ( e.target == scrollbarButton ) {
110
+ return;
111
+ }
108
112
  const scrollbarButtonWidth = scrollbarButton.offsetWidth;
109
113
  const scrollbarButtonLeft = getScrollbarButtonLeftOffset();
110
114
  const scrollbarButtonRight = scrollbarButtonLeft + scrollbarButtonWidth;
111
- const clickX = e.pageX - scrollbarContainer.offsetLeft;
112
- if ( clickX < scrollbarButtonLeft ) {
113
- slider.moveToDirection( 'prev' );
114
- } else if ( clickX > scrollbarButtonRight ) {
115
- slider.moveToDirection( 'next' );
115
+ const clickX = e.pageX - Math.abs( scrollbarContainer.offsetLeft );
116
+ if (Math.floor(clickX) < Math.floor(scrollbarButtonLeft)) {
117
+ slider.moveToDirection(slider.options.rtl ? 'next' : 'prev');
118
+ } else if (Math.floor(clickX) > Math.floor(scrollbarButtonRight)) {
119
+ slider.moveToDirection(slider.options.rtl ? 'prev' : 'next');
116
120
  }
117
121
  });
118
122
 
119
- // make scrollbar button draggable via mouse/touch and update the scroll position
120
- let isInteractionDown = false;
121
- let startX = 0;
122
- let scrollLeft = 0;
123
-
124
123
  const onInteractionDown = (e: MouseEvent | TouchEvent) => {
125
124
  isInteractionDown = true;
126
125
  const pageX = (e as MouseEvent).pageX || (e as TouchEvent).touches[0].pageX;
127
126
  startX = pageX - scrollbarContainer.offsetLeft;
128
- scrollLeft = slider.container.scrollLeft;
129
- // change cursor to grabbing
127
+ scrollLeft = slider.getScrollLeft();
130
128
  scrollbarButton.style.cursor = 'grabbing';
131
- scrollbarButton.setAttribute( 'data-is-grabbed', 'true' );
129
+ scrollbarButton.setAttribute('data-is-grabbed', 'true');
132
130
 
133
131
  e.preventDefault();
134
132
  e.stopPropagation();
@@ -144,13 +142,14 @@ export default function ScrollIndicatorPlugin( args: { [key: string]: any } ) {
144
142
  const scrollingFactor = slider.details.scrollableAreaWidth / scrollbarContainer.offsetWidth;
145
143
 
146
144
  const walk = (x - startX) * scrollingFactor;
147
- slider.container.scrollLeft = scrollLeft + walk;
145
+ const distance = slider.options.rtl ? scrollLeft - walk : scrollLeft + walk;
146
+ slider.setScrollLeft(distance);
148
147
  };
149
148
 
150
149
  const onInteractionUp = () => {
151
150
  isInteractionDown = false;
152
151
  scrollbarButton.style.cursor = '';
153
- scrollbarButton.setAttribute( 'data-is-grabbed', 'false' );
152
+ scrollbarButton.setAttribute('data-is-grabbed', 'false');
154
153
  };
155
154
 
156
155
  scrollbarButton.addEventListener('mousedown', onInteractionDown);
@@ -161,6 +160,5 @@ export default function ScrollIndicatorPlugin( args: { [key: string]: any } ) {
161
160
 
162
161
  window.addEventListener('mouseup', onInteractionUp);
163
162
  window.addEventListener('touchend', onInteractionUp);
164
-
165
163
  };
166
164
  }
@@ -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;
@@ -40,13 +39,16 @@ export default function FullWidthPlugin( args: { [key: string]: any } ) {
40
39
  setActiveThumbnail();
41
40
  addClickListeners();
42
41
 
43
- // @todo debounce on scroll
44
42
  mainSlider.on( 'scrollEnd', () => {
45
43
  setTimeout(() => {
46
- const activeSlideIdx = mainSlider.activeSlideIdx;
47
- const activeThumbnail = slider.slides[activeSlideIdx] as HTMLElement;
44
+ const mainActiveSlideIdx = mainSlider.activeSlideIdx;
45
+ const thumbActiveSlideIdx = slider.activeSlideIdx;
46
+ if ( thumbActiveSlideIdx === mainActiveSlideIdx ) {
47
+ return;
48
+ }
49
+ const activeThumbnail = slider.slides[mainActiveSlideIdx] as HTMLElement;
48
50
  setActiveThumbnail(activeThumbnail);
49
- slider.moveToSlide(activeSlideIdx);
51
+ slider.moveToSlide(mainActiveSlideIdx);
50
52
  }, 50);
51
53
  });
52
54