@evermade/overflow-slider 2.0.2 → 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 (64) hide show
  1. package/.nvmrc +1 -1
  2. package/README.md +26 -4
  3. package/dist/core/details.esm.js +4 -4
  4. package/dist/core/details.min.js +1 -1
  5. package/dist/core/overflow-slider.esm.js +2 -0
  6. package/dist/core/overflow-slider.min.js +1 -1
  7. package/dist/core/slider.esm.js +202 -29
  8. package/dist/core/slider.min.js +1 -1
  9. package/dist/core/utils.esm.js +15 -1
  10. package/dist/core/utils.min.js +1 -1
  11. package/dist/overflow-slider.css +1 -1
  12. package/dist/plugins/arrows/arrows/index.esm.js +15 -8
  13. package/dist/plugins/arrows/arrows/index.min.js +1 -1
  14. package/dist/plugins/dots/dots/index.esm.js +21 -22
  15. package/dist/plugins/dots/dots/index.min.js +1 -1
  16. package/dist/plugins/drag-scrolling/drag-scrolling/index.esm.js +30 -3
  17. package/dist/plugins/drag-scrolling/drag-scrolling/index.min.js +1 -1
  18. package/dist/plugins/fade/fade/index.esm.js +81 -0
  19. package/dist/plugins/fade/fade/index.min.js +1 -0
  20. package/dist/plugins/full-width/full-width/index.esm.js +1 -0
  21. package/dist/plugins/full-width/full-width/index.min.js +1 -1
  22. package/dist/plugins/scroll-indicator/scroll-indicator/index.esm.js +4 -6
  23. package/dist/plugins/scroll-indicator/scroll-indicator/index.min.js +1 -1
  24. package/dist/plugins/thumbnails/thumbnails/index.esm.js +1 -0
  25. package/docs/assets/demo.css +16 -0
  26. package/docs/assets/demo.js +44 -7
  27. package/docs/dist/core/details.esm.js +4 -4
  28. package/docs/dist/core/details.min.js +1 -1
  29. package/docs/dist/core/overflow-slider.esm.js +2 -0
  30. package/docs/dist/core/overflow-slider.min.js +1 -1
  31. package/docs/dist/core/slider.esm.js +202 -29
  32. package/docs/dist/core/slider.min.js +1 -1
  33. package/docs/dist/core/utils.esm.js +15 -1
  34. package/docs/dist/core/utils.min.js +1 -1
  35. package/docs/dist/overflow-slider.css +1 -1
  36. package/docs/dist/plugins/arrows/arrows/index.esm.js +15 -8
  37. package/docs/dist/plugins/arrows/arrows/index.min.js +1 -1
  38. package/docs/dist/plugins/dots/dots/index.esm.js +21 -22
  39. package/docs/dist/plugins/dots/dots/index.min.js +1 -1
  40. package/docs/dist/plugins/drag-scrolling/drag-scrolling/index.esm.js +30 -3
  41. package/docs/dist/plugins/drag-scrolling/drag-scrolling/index.min.js +1 -1
  42. package/docs/dist/plugins/fade/fade/index.esm.js +81 -0
  43. package/docs/dist/plugins/fade/fade/index.min.js +1 -0
  44. package/docs/dist/plugins/full-width/full-width/index.esm.js +1 -0
  45. package/docs/dist/plugins/full-width/full-width/index.min.js +1 -1
  46. package/docs/dist/plugins/scroll-indicator/scroll-indicator/index.esm.js +4 -6
  47. package/docs/dist/plugins/scroll-indicator/scroll-indicator/index.min.js +1 -1
  48. package/docs/dist/plugins/thumbnails/thumbnails/index.esm.js +1 -0
  49. package/docs/index.html +39 -7
  50. package/package.json +5 -1
  51. package/src/core/details.ts +4 -4
  52. package/src/core/overflow-slider.ts +2 -0
  53. package/src/core/slider.ts +226 -36
  54. package/src/core/types.ts +33 -1
  55. package/src/core/utils.ts +19 -1
  56. package/src/overflow-slider.scss +2 -1
  57. package/src/plugins/arrows/index.ts +16 -8
  58. package/src/plugins/dots/index.ts +21 -23
  59. package/src/plugins/drag-scrolling/index.ts +34 -5
  60. package/src/plugins/fade/index.ts +101 -0
  61. package/src/plugins/fade/styles.scss +27 -0
  62. package/src/plugins/full-width/index.ts +1 -0
  63. package/src/plugins/scroll-indicator/index.ts +4 -6
  64. package/src/plugins/thumbnails/index.ts +1 -1
@@ -8,9 +8,13 @@ function DragScrollingPlugin(args) {
8
8
  let isMouseDown = false;
9
9
  let startX = 0;
10
10
  let scrollLeft = 0;
11
+ let isMovingForward = false;
12
+ let programmaticScrollStarted = false;
13
+ let mayNeedToSnap = false;
11
14
  // add data attribute to container
12
15
  slider.container.setAttribute('data-has-drag-scrolling', 'true');
13
16
  const mouseDown = (e) => {
17
+ programmaticScrollStarted = false;
14
18
  if (!slider.details.hasOverflow) {
15
19
  return;
16
20
  }
@@ -22,7 +26,6 @@ function DragScrollingPlugin(args) {
22
26
  scrollLeft = slider.container.scrollLeft;
23
27
  // change cursor to grabbing
24
28
  slider.container.style.cursor = 'grabbing';
25
- slider.container.style.scrollSnapType = 'none';
26
29
  slider.container.style.scrollBehavior = 'auto';
27
30
  // prevent focus going to the slides
28
31
  e.preventDefault();
@@ -30,15 +33,26 @@ function DragScrollingPlugin(args) {
30
33
  };
31
34
  const mouseMove = (e) => {
32
35
  if (!slider.details.hasOverflow) {
36
+ programmaticScrollStarted = false;
33
37
  return;
34
38
  }
35
39
  if (!isMouseDown) {
40
+ programmaticScrollStarted = false;
36
41
  return;
37
42
  }
38
43
  e.preventDefault();
44
+ if (!programmaticScrollStarted) {
45
+ programmaticScrollStarted = true;
46
+ slider.emit('programmaticScrollStart');
47
+ }
39
48
  const x = e.pageX - slider.container.offsetLeft;
40
49
  const walk = (x - startX);
41
- slider.container.scrollLeft = scrollLeft - walk;
50
+ const newScrollLeft = scrollLeft - walk;
51
+ mayNeedToSnap = true;
52
+ if (Math.floor(slider.container.scrollLeft) !== Math.floor(newScrollLeft)) {
53
+ isMovingForward = slider.container.scrollLeft < newScrollLeft;
54
+ }
55
+ slider.container.scrollLeft = newScrollLeft;
42
56
  const absWalk = Math.abs(walk);
43
57
  const slides = slider.container.querySelectorAll(slider.options.slidesSelector);
44
58
  const pointerEvents = absWalk > options.draggedDistanceThatPreventsClick ? 'none' : '';
@@ -48,12 +62,13 @@ function DragScrollingPlugin(args) {
48
62
  };
49
63
  const mouseUp = () => {
50
64
  if (!slider.details.hasOverflow) {
65
+ programmaticScrollStarted = false;
51
66
  return;
52
67
  }
53
68
  isMouseDown = false;
54
69
  slider.container.style.cursor = '';
55
70
  setTimeout(() => {
56
- slider.container.style.scrollSnapType = '';
71
+ programmaticScrollStarted = false;
57
72
  slider.container.style.scrollBehavior = '';
58
73
  const slides = slider.container.querySelectorAll(slider.options.slidesSelector);
59
74
  slides.forEach((slide) => {
@@ -64,6 +79,18 @@ function DragScrollingPlugin(args) {
64
79
  window.addEventListener('mousedown', mouseDown);
65
80
  window.addEventListener('mousemove', mouseMove);
66
81
  window.addEventListener('mouseup', mouseUp);
82
+ // emulate scroll snapping
83
+ if (slider.options.emulateScrollSnap) {
84
+ const snap = () => {
85
+ if (!mayNeedToSnap || isMouseDown) {
86
+ return;
87
+ }
88
+ mayNeedToSnap = false;
89
+ slider.snapToClosestSlide(isMovingForward ? 'next' : 'prev');
90
+ };
91
+ slider.on('programmaticScrollEnd', snap);
92
+ window.addEventListener('mouseup', snap);
93
+ }
67
94
  };
68
95
  }
69
96
 
@@ -1 +1 @@
1
- function e(e){var t;const n=null!==(t=null==e?void 0:e.draggedDistanceThatPreventsClick)&&void 0!==t?t:20;return e=>{let t=!1,o=0,r=0;e.container.setAttribute("data-has-drag-scrolling","true");window.addEventListener("mousedown",(n=>{e.details.hasOverflow&&e.container.contains(n.target)&&(t=!0,o=n.pageX-e.container.offsetLeft,r=e.container.scrollLeft,e.container.style.cursor="grabbing",e.container.style.scrollSnapType="none",e.container.style.scrollBehavior="auto",n.preventDefault(),n.stopPropagation())})),window.addEventListener("mousemove",(a=>{if(!e.details.hasOverflow)return;if(!t)return;a.preventDefault();const s=a.pageX-e.container.offsetLeft-o;e.container.scrollLeft=r-s;const l=Math.abs(s),i=e.container.querySelectorAll(e.options.slidesSelector),c=l>n?"none":"";i.forEach((e=>{e.style.pointerEvents=c}))})),window.addEventListener("mouseup",(()=>{e.details.hasOverflow&&(t=!1,e.container.style.cursor="",setTimeout((()=>{e.container.style.scrollSnapType="",e.container.style.scrollBehavior="";e.container.querySelectorAll(e.options.slidesSelector).forEach((e=>{e.style.pointerEvents=""}))}),50))}))}}export{e as default};
1
+ function e(e){var t;const o=null!==(t=null==e?void 0:e.draggedDistanceThatPreventsClick)&&void 0!==t?t:20;return e=>{let t=!1,n=0,r=0,a=!1,l=!1,s=!1;e.container.setAttribute("data-has-drag-scrolling","true");if(window.addEventListener("mousedown",(o=>{l=!1,e.details.hasOverflow&&e.container.contains(o.target)&&(t=!0,n=o.pageX-e.container.offsetLeft,r=e.container.scrollLeft,e.container.style.cursor="grabbing",e.container.style.scrollBehavior="auto",o.preventDefault(),o.stopPropagation())})),window.addEventListener("mousemove",(i=>{if(!e.details.hasOverflow)return void(l=!1);if(!t)return void(l=!1);i.preventDefault(),l||(l=!0,e.emit("programmaticScrollStart"));const c=i.pageX-e.container.offsetLeft-n,d=r-c;s=!0,Math.floor(e.container.scrollLeft)!==Math.floor(d)&&(a=e.container.scrollLeft<d),e.container.scrollLeft=d;const f=Math.abs(c),u=e.container.querySelectorAll(e.options.slidesSelector),v=f>o?"none":"";u.forEach((e=>{e.style.pointerEvents=v}))})),window.addEventListener("mouseup",(()=>{e.details.hasOverflow?(t=!1,e.container.style.cursor="",setTimeout((()=>{l=!1,e.container.style.scrollBehavior="";e.container.querySelectorAll(e.options.slidesSelector).forEach((e=>{e.style.pointerEvents=""}))}),50)):l=!1})),e.options.emulateScrollSnap){const o=()=>{s&&!t&&(s=!1,e.snapToClosestSlide(a?"next":"prev"))};e.on("programmaticScrollEnd",o),window.addEventListener("mouseup",o)}}}export{e as default};
@@ -0,0 +1,81 @@
1
+ function FadePlugin(args) {
2
+ return (slider) => {
3
+ var _a, _b, _c;
4
+ const options = {
5
+ classNames: {
6
+ fadeItem: 'overflow-slider-fade',
7
+ fadeItemStart: 'overflow-slider-fade--start',
8
+ fadeItemEnd: 'overflow-slider-fade--end',
9
+ },
10
+ container: (_a = args === null || args === void 0 ? void 0 : args.container) !== null && _a !== void 0 ? _a : null,
11
+ containerStart: (_b = args === null || args === void 0 ? void 0 : args.containerStart) !== null && _b !== void 0 ? _b : null,
12
+ containerEnd: (_c = args === null || args === void 0 ? void 0 : args.containerEnd) !== null && _c !== void 0 ? _c : null,
13
+ };
14
+ const fadeItemStart = document.createElement('div');
15
+ fadeItemStart.classList.add(options.classNames.fadeItem, options.classNames.fadeItemStart);
16
+ fadeItemStart.setAttribute('aria-hidden', 'true');
17
+ fadeItemStart.setAttribute('tabindex', '-1');
18
+ const fadeItemEnd = document.createElement('div');
19
+ fadeItemEnd.classList.add(options.classNames.fadeItem, options.classNames.fadeItemEnd);
20
+ fadeItemEnd.setAttribute('aria-hidden', 'true');
21
+ fadeItemEnd.setAttribute('tabindex', '-1');
22
+ if (options.containerStart) {
23
+ options.containerStart.appendChild(fadeItemStart);
24
+ }
25
+ else if (options.container) {
26
+ options.container.appendChild(fadeItemStart);
27
+ }
28
+ if (options.containerEnd) {
29
+ options.containerEnd.appendChild(fadeItemEnd);
30
+ }
31
+ else if (options.container) {
32
+ options.container.appendChild(fadeItemEnd);
33
+ }
34
+ const hasFadeAtStart = () => {
35
+ return slider.container.scrollLeft > fadeItemStart.offsetWidth;
36
+ };
37
+ const fadeAtStartOpacity = () => {
38
+ const position = slider.container.scrollLeft;
39
+ if (Math.floor(position) <= Math.floor(fadeItemStart.offsetWidth)) {
40
+ return position / Math.max(fadeItemStart.offsetWidth, 1);
41
+ }
42
+ return 1;
43
+ };
44
+ const hasFadeAtEnd = () => {
45
+ return Math.floor(slider.container.scrollLeft) < Math.floor(slider.getInclusiveScrollWidth() - slider.getInclusiveClientWidth() - fadeItemEnd.offsetWidth);
46
+ };
47
+ const fadeAtEndOpacity = () => {
48
+ const position = slider.container.scrollLeft;
49
+ const maxPosition = slider.getInclusiveScrollWidth() - slider.getInclusiveClientWidth();
50
+ const maxFadePosition = maxPosition - fadeItemEnd.offsetWidth;
51
+ if (Math.floor(position) >= Math.floor(maxFadePosition)) {
52
+ return ((maxFadePosition - position) / Math.max(fadeItemEnd.offsetWidth, 1)) + 1;
53
+ }
54
+ return 1;
55
+ };
56
+ const update = () => {
57
+ fadeItemStart.setAttribute('data-has-fade', hasFadeAtStart().toString());
58
+ fadeItemStart.style.opacity = fadeAtStartOpacity().toString();
59
+ fadeItemEnd.setAttribute('data-has-fade', hasFadeAtEnd().toString());
60
+ fadeItemEnd.style.opacity = fadeAtEndOpacity().toString();
61
+ };
62
+ update();
63
+ slider.on('created', update);
64
+ slider.on('contentsChanged', update);
65
+ slider.on('containerSizeChanged', update);
66
+ slider.on('scrollEnd', update);
67
+ slider.on('scrollStart', update);
68
+ let requestId = 0;
69
+ const debouncedUpdate = () => {
70
+ if (requestId) {
71
+ window.cancelAnimationFrame(requestId);
72
+ }
73
+ requestId = window.requestAnimationFrame(() => {
74
+ update();
75
+ });
76
+ };
77
+ slider.on('scroll', debouncedUpdate);
78
+ };
79
+ }
80
+
81
+ export { FadePlugin as default };
@@ -0,0 +1 @@
1
+ function t(t){return e=>{var n,a,o;const i={classNames:{fadeItem:"overflow-slider-fade",fadeItemStart:"overflow-slider-fade--start",fadeItemEnd:"overflow-slider-fade--end"},container:null!==(n=null==t?void 0:t.container)&&void 0!==n?n:null,containerStart:null!==(a=null==t?void 0:t.containerStart)&&void 0!==a?a:null,containerEnd:null!==(o=null==t?void 0:t.containerEnd)&&void 0!==o?o:null},r=document.createElement("div");r.classList.add(i.classNames.fadeItem,i.classNames.fadeItemStart),r.setAttribute("aria-hidden","true"),r.setAttribute("tabindex","-1");const l=document.createElement("div");l.classList.add(i.classNames.fadeItem,i.classNames.fadeItemEnd),l.setAttribute("aria-hidden","true"),l.setAttribute("tabindex","-1"),i.containerStart?i.containerStart.appendChild(r):i.container&&i.container.appendChild(r),i.containerEnd?i.containerEnd.appendChild(l):i.container&&i.container.appendChild(l);const d=()=>{r.setAttribute("data-has-fade",(e.container.scrollLeft>r.offsetWidth).toString()),r.style.opacity=(()=>{const t=e.container.scrollLeft;return Math.floor(t)<=Math.floor(r.offsetWidth)?t/Math.max(r.offsetWidth,1):1})().toString(),l.setAttribute("data-has-fade",(Math.floor(e.container.scrollLeft)<Math.floor(e.getInclusiveScrollWidth()-e.getInclusiveClientWidth()-l.offsetWidth)).toString()),l.style.opacity=(()=>{const t=e.container.scrollLeft,n=e.getInclusiveScrollWidth()-e.getInclusiveClientWidth()-l.offsetWidth;return Math.floor(t)>=Math.floor(n)?(n-t)/Math.max(l.offsetWidth,1)+1:1})().toString()};d(),e.on("created",d),e.on("contentsChanged",d),e.on("containerSizeChanged",d),e.on("scrollEnd",d),e.on("scrollStart",d);let s=0;e.on("scroll",(()=>{s&&window.cancelAnimationFrame(s),s=window.requestAnimationFrame((()=>{d()}))}))}}export{t as default};
@@ -21,6 +21,7 @@ function FullWidthPlugin(args) {
21
21
  if (options.addMarginAfter) {
22
22
  lastSlide.style.marginRight = `${marginAmount}px`;
23
23
  }
24
+ slider.container.setAttribute('data-full-width-offset', marginAmount.toString());
24
25
  };
25
26
  update();
26
27
  slider.on('contentsChanged', update);
@@ -1 +1 @@
1
- const n=n=>{var t,e;return null!==(e=null===(t=n.container.parentElement)||void 0===t?void 0:t.offsetWidth)&&void 0!==e?e:window.innerWidth};function t(t){return e=>{var i,r,d;const o={targetWidth:null!==(i=null==t?void 0:t.targetWidth)&&void 0!==i?i:n,addMarginBefore:null===(r=null==t?void 0:t.addMarginBefore)||void 0===r||r,addMarginAfter:null===(d=null==t?void 0:t.addMarginAfter)||void 0===d||d},a=()=>{const n=e.container.querySelectorAll(e.options.slidesSelector);if(!n.length)return;const t=n[0],i=n[n.length-1],r=Math.floor((window.innerWidth-o.targetWidth(e))/2);o.addMarginBefore&&(t.style.marginLeft=`${r}px`),o.addMarginAfter&&(i.style.marginRight=`${r}px`)};a(),e.on("contentsChanged",a),e.on("containerSizeChanged",a)}}export{t as default};
1
+ const t=t=>{var n,e;return null!==(e=null===(n=t.container.parentElement)||void 0===n?void 0:n.offsetWidth)&&void 0!==e?e:window.innerWidth};function n(n){return e=>{var i,r,o;const d={targetWidth:null!==(i=null==n?void 0:n.targetWidth)&&void 0!==i?i:t,addMarginBefore:null===(r=null==n?void 0:n.addMarginBefore)||void 0===r||r,addMarginAfter:null===(o=null==n?void 0:n.addMarginAfter)||void 0===o||o},a=()=>{const t=e.container.querySelectorAll(e.options.slidesSelector);if(!t.length)return;const n=t[0],i=t[t.length-1],r=Math.floor((window.innerWidth-d.targetWidth(e))/2);d.addMarginBefore&&(n.style.marginLeft=`${r}px`),d.addMarginAfter&&(i.style.marginRight=`${r}px`),e.container.setAttribute("data-full-width-offset",r.toString())};a(),e.on("contentsChanged",a),e.on("containerSizeChanged",a)}}export{n as default};
@@ -41,13 +41,13 @@ function ScrollIndicatorPlugin(args) {
41
41
  window.cancelAnimationFrame(requestId);
42
42
  }
43
43
  requestId = window.requestAnimationFrame(() => {
44
- const scrollbarButtonWidth = (slider.details.containerWidth / slider.details.scrollableAreaWidth) * 100;
44
+ const scrollbarButtonWidth = (slider.details.containerWidth / slider.container.scrollWidth) * 100;
45
45
  const scrollLeftInPortion = getScrollbarButtonLeftOffset();
46
46
  scrollbarButton.style.width = `${scrollbarButtonWidth}%`;
47
47
  scrollbarButton.style.transform = `translateX(${scrollLeftInPortion}px)`;
48
48
  // aria-valuenow
49
49
  const scrollLeft = slider.container.scrollLeft;
50
- const scrollWidth = slider.container.scrollWidth;
50
+ const scrollWidth = slider.getInclusiveScrollWidth();
51
51
  const containerWidth = slider.container.offsetWidth;
52
52
  const scrollPercentage = (scrollLeft / (scrollWidth - containerWidth)) * 100;
53
53
  scrollbarContainer.setAttribute('aria-valuenow', Math.round(Number.isNaN(scrollPercentage) ? 0 : scrollPercentage).toString());
@@ -81,10 +81,10 @@ function ScrollIndicatorPlugin(args) {
81
81
  const scrollbarButtonLeft = getScrollbarButtonLeftOffset();
82
82
  const scrollbarButtonRight = scrollbarButtonLeft + scrollbarButtonWidth;
83
83
  const clickX = e.pageX - scrollbarContainer.offsetLeft;
84
- if (clickX < scrollbarButtonLeft) {
84
+ if (Math.floor(clickX) < Math.floor(scrollbarButtonLeft)) {
85
85
  slider.moveToDirection('prev');
86
86
  }
87
- else if (clickX > scrollbarButtonRight) {
87
+ else if (Math.floor(clickX) > Math.floor(scrollbarButtonRight)) {
88
88
  slider.moveToDirection('next');
89
89
  }
90
90
  });
@@ -99,7 +99,6 @@ function ScrollIndicatorPlugin(args) {
99
99
  scrollLeft = slider.container.scrollLeft;
100
100
  // change cursor to grabbing
101
101
  scrollbarButton.style.cursor = 'grabbing';
102
- slider.container.style.scrollSnapType = 'none';
103
102
  scrollbarButton.setAttribute('data-is-grabbed', 'true');
104
103
  e.preventDefault();
105
104
  e.stopPropagation();
@@ -118,7 +117,6 @@ function ScrollIndicatorPlugin(args) {
118
117
  const onInteractionUp = () => {
119
118
  isInteractionDown = false;
120
119
  scrollbarButton.style.cursor = '';
121
- slider.container.style.scrollSnapType = '';
122
120
  scrollbarButton.setAttribute('data-is-grabbed', 'false');
123
121
  };
124
122
  scrollbarButton.addEventListener('mousedown', onInteractionDown);
@@ -1 +1 @@
1
- const t={scrollIndicator:"overflow-slider__scroll-indicator",scrollIndicatorBar:"overflow-slider__scroll-indicator-bar",scrollIndicatorButton:"overflow-slider__scroll-indicator-button"};function e(e){return n=>{var o,r,a;const i={classNames:Object.assign(Object.assign({},t),(null==e?void 0:e.classNames)||[]),container:null!==(o=null==e?void 0:e.container)&&void 0!==o?o:null},s=document.createElement("div");s.setAttribute("class",i.classNames.scrollIndicator),s.setAttribute("tabindex","0"),s.setAttribute("role","scrollbar"),s.setAttribute("aria-controls",null!==(r=n.container.getAttribute("id"))&&void 0!==r?r:""),s.setAttribute("aria-orientation","horizontal"),s.setAttribute("aria-valuemax","100"),s.setAttribute("aria-valuemin","0"),s.setAttribute("aria-valuenow","0");const l=document.createElement("div");l.setAttribute("class",i.classNames.scrollIndicatorBar);const c=document.createElement("div");c.setAttribute("class",i.classNames.scrollIndicatorButton),c.setAttribute("data-is-grabbed","false"),l.appendChild(c),s.appendChild(l);const d=()=>{s.setAttribute("data-has-overflow",n.details.hasOverflow.toString())};d();const u=()=>{const t=c.offsetWidth/n.details.containerWidth;return n.container.scrollLeft*t};let v=0;const f=()=>{v&&window.cancelAnimationFrame(v),v=window.requestAnimationFrame((()=>{const t=n.details.containerWidth/n.details.scrollableAreaWidth*100,e=u();c.style.width=`${t}%`,c.style.transform=`translateX(${e}px)`;const o=n.container.scrollLeft/(n.container.scrollWidth-n.container.offsetWidth)*100;s.setAttribute("aria-valuenow",Math.round(Number.isNaN(o)?0:o).toString())}))};i.container?i.container.appendChild(s):null===(a=n.container.parentNode)||void 0===a||a.insertBefore(s,n.container.nextSibling),f(),n.on("scroll",f),n.on("contentsChanged",f),n.on("containerSizeChanged",f),n.on("detailsChanged",d),s.addEventListener("keydown",(t=>{"ArrowLeft"===t.key?n.moveToDirection("prev"):"ArrowRight"===t.key&&n.moveToDirection("next")})),s.addEventListener("click",(t=>{const e=c.offsetWidth,o=u(),r=o+e,a=t.pageX-s.offsetLeft;a<o?n.moveToDirection("prev"):a>r&&n.moveToDirection("next")}));let b=!1,m=0,h=0;const p=t=>{b=!0;const e=t.pageX||t.touches[0].pageX;m=e-s.offsetLeft,h=n.container.scrollLeft,c.style.cursor="grabbing",n.container.style.scrollSnapType="none",c.setAttribute("data-is-grabbed","true"),t.preventDefault(),t.stopPropagation()},w=t=>{if(!b)return;t.preventDefault();const e=(t.pageX||t.touches[0].pageX)-s.offsetLeft,o=n.details.scrollableAreaWidth/s.offsetWidth,r=(e-m)*o;n.container.scrollLeft=h+r},A=()=>{b=!1,c.style.cursor="",n.container.style.scrollSnapType="",c.setAttribute("data-is-grabbed","false")};c.addEventListener("mousedown",p),c.addEventListener("touchstart",p),window.addEventListener("mousemove",w),window.addEventListener("touchmove",w,{passive:!1}),window.addEventListener("mouseup",A),window.addEventListener("touchend",A)}}export{e as default};
1
+ const t={scrollIndicator:"overflow-slider__scroll-indicator",scrollIndicatorBar:"overflow-slider__scroll-indicator-bar",scrollIndicatorButton:"overflow-slider__scroll-indicator-button"};function e(e){return o=>{var n,r,a;const i={classNames:Object.assign(Object.assign({},t),(null==e?void 0:e.classNames)||[]),container:null!==(n=null==e?void 0:e.container)&&void 0!==n?n:null},s=document.createElement("div");s.setAttribute("class",i.classNames.scrollIndicator),s.setAttribute("tabindex","0"),s.setAttribute("role","scrollbar"),s.setAttribute("aria-controls",null!==(r=o.container.getAttribute("id"))&&void 0!==r?r:""),s.setAttribute("aria-orientation","horizontal"),s.setAttribute("aria-valuemax","100"),s.setAttribute("aria-valuemin","0"),s.setAttribute("aria-valuenow","0");const l=document.createElement("div");l.setAttribute("class",i.classNames.scrollIndicatorBar);const c=document.createElement("div");c.setAttribute("class",i.classNames.scrollIndicatorButton),c.setAttribute("data-is-grabbed","false"),l.appendChild(c),s.appendChild(l);const d=()=>{s.setAttribute("data-has-overflow",o.details.hasOverflow.toString())};d();const u=()=>{const t=c.offsetWidth/o.details.containerWidth;return o.container.scrollLeft*t};let f=0;const v=()=>{f&&window.cancelAnimationFrame(f),f=window.requestAnimationFrame((()=>{const t=o.details.containerWidth/o.container.scrollWidth*100,e=u();c.style.width=`${t}%`,c.style.transform=`translateX(${e}px)`;const n=o.container.scrollLeft/(o.getInclusiveScrollWidth()-o.container.offsetWidth)*100;s.setAttribute("aria-valuenow",Math.round(Number.isNaN(n)?0:n).toString())}))};i.container?i.container.appendChild(s):null===(a=o.container.parentNode)||void 0===a||a.insertBefore(s,o.container.nextSibling),v(),o.on("scroll",v),o.on("contentsChanged",v),o.on("containerSizeChanged",v),o.on("detailsChanged",d),s.addEventListener("keydown",(t=>{"ArrowLeft"===t.key?o.moveToDirection("prev"):"ArrowRight"===t.key&&o.moveToDirection("next")})),s.addEventListener("click",(t=>{const e=c.offsetWidth,n=u(),r=n+e,a=t.pageX-s.offsetLeft;Math.floor(a)<Math.floor(n)?o.moveToDirection("prev"):Math.floor(a)>Math.floor(r)&&o.moveToDirection("next")}));let b=!1,h=0,m=0;const w=t=>{b=!0;const e=t.pageX||t.touches[0].pageX;h=e-s.offsetLeft,m=o.container.scrollLeft,c.style.cursor="grabbing",c.setAttribute("data-is-grabbed","true"),t.preventDefault(),t.stopPropagation()},g=t=>{if(!b)return;t.preventDefault();const e=(t.pageX||t.touches[0].pageX)-s.offsetLeft,n=o.details.scrollableAreaWidth/s.offsetWidth,r=(e-h)*n;o.container.scrollLeft=m+r},p=()=>{b=!1,c.style.cursor="",c.setAttribute("data-is-grabbed","false")};c.addEventListener("mousedown",w),c.addEventListener("touchstart",w),window.addEventListener("mousemove",g),window.addEventListener("touchmove",g,{passive:!1}),window.addEventListener("mouseup",p),window.addEventListener("touchend",p)}}export{e as default};
@@ -27,6 +27,7 @@ function FullWidthPlugin(args) {
27
27
  };
28
28
  setActiveThumbnail();
29
29
  addClickListeners();
30
+ // @todo debounce on scroll
30
31
  mainSlider.on('activeSlideChanged', () => {
31
32
  setTimeout(() => {
32
33
  const activeSlideIdx = mainSlider.activeSlideIdx;
package/docs/index.html CHANGED
@@ -69,7 +69,7 @@
69
69
  <a href="#12" class="example-item example-item--12">12</a>
70
70
  <a href="#13" class="example-item example-item--13">13</a>
71
71
  </div>
72
- <p style="margin-top:1.5rem;">These slides are not clickable</p>
72
+ <p style="margin-top:1.5rem;">These slides are not clickable.</p>
73
73
  <div class="overflow-slider example-container example-container-1-drag-scrolling-not-clickable">
74
74
  <div class="example-item example-item--1">1</div>
75
75
  <div class="example-item example-item--2">2</div>
@@ -85,6 +85,22 @@
85
85
  <div class="example-item example-item--12">12</div>
86
86
  <div class="example-item example-item--13">13</div>
87
87
  </div>
88
+ <p style="margin-top:1.5rem;">Scroll-snap emulation enabled.</p>
89
+ <div class="overflow-slider example-container example-container-1-drag-scrolling-scroll-snap">
90
+ <div class="example-item example-item--1">1</div>
91
+ <div class="example-item example-item--2">2</div>
92
+ <div class="example-item example-item--3">3</div>
93
+ <div class="example-item example-item--4">4</div>
94
+ <div class="example-item example-item--5">5</div>
95
+ <div class="example-item example-item--6">6</div>
96
+ <div class="example-item example-item--7">7</div>
97
+ <div class="example-item example-item--8">8</div>
98
+ <div class="example-item example-item--9">9</div>
99
+ <div class="example-item example-item--10">10</div>
100
+ <div class="example-item example-item--11">11</div>
101
+ <div class="example-item example-item--12">12</div>
102
+ <div class="example-item example-item--13">13</div>
103
+ </div>
88
104
  </div>
89
105
 
90
106
  <div class="entry__item">
@@ -134,13 +150,29 @@
134
150
  <a href="#4" class="example-item example-item--4">4</a>
135
151
  <a href="#5" class="example-item example-item--5">5</a>
136
152
  <a href="#6" class="example-item example-item--6">6</a>
137
- <a href="#7" class="example-item example-item--7">7</a>
138
- <a href="#8" class="example-item example-item--8">8</a>
139
- <a href="#9" class="example-item example-item--9">9</a>
140
- <a href="#10" class="example-item example-item--10">10</a>
141
153
  </div>
142
154
  </div>
143
155
 
156
+ <div class="entry__item">
157
+ <h3>Fade</h3>
158
+ <p>Display fade. Uses FadePlugin. Fade can be on both sides but having it only at end is more usable.</p>
159
+ <div class="example-container-1-fade-wrap">
160
+ <div class="example-container-1-fade__start"></div>
161
+ <div class="overflow-slider example-container example-container-1-fade">
162
+ <a href="#1" class="example-item example-item--1">1</a>
163
+ <a href="#2" class="example-item example-item--2">2</a>
164
+ <a href="#3" class="example-item example-item--3">3</a>
165
+ <a href="#4" class="example-item example-item--4">4</a>
166
+ <a href="#5" class="example-item example-item--5">5</a>
167
+ <a href="#6" class="example-item example-item--6">6</a>
168
+ <a href="#7" class="example-item example-item--7">7</a>
169
+ <a href="#8" class="example-item example-item--8">8</a>
170
+ <a href="#9" class="example-item example-item--9">9</a>
171
+ <a href="#10" class="example-item example-item--10">10</a>
172
+ </div>
173
+ <div class="example-container-1-fade__end"></div>
174
+ </div>
175
+ </div>
144
176
 
145
177
  </section>
146
178
 
@@ -231,8 +263,8 @@
231
263
  </div>
232
264
 
233
265
  <div class="entry__item">
234
- <h3>Entrance and Exit Animations</h3>
235
- <p>Animate slides when they appear and disappear.</p>
266
+ <h3>Entrance and Exit Animations (experimental)</h3>
267
+ <p>Animate slides when they appear and disappear. Seem to only work on Chrome.</p>
236
268
  <div class="overflow-slider example-container example-container-3-entrance-animation">
237
269
  <a href="#1" class="example-item example-item--1">1</a>
238
270
  <a href="#2" class="example-item example-item--2">2</a>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@evermade/overflow-slider",
3
- "version": "2.0.2",
3
+ "version": "3.1.0",
4
4
  "description": "Accessible slider tha works with overflow: auto.",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -39,6 +39,10 @@
39
39
  "import": "./dist/plugins/thumbnails/thumbnails/index.esm.js",
40
40
  "require": "./dist/plugins/thumbnails/thumbnails/index.min.js"
41
41
  },
42
+ "./plugins/fade": {
43
+ "import": "./dist/plugins/fade/fade/index.esm.js",
44
+ "require": "./dist/plugins/fade/fade/index.min.js"
45
+ },
42
46
  "./style.css": "./dist/overflow-slider.css"
43
47
  },
44
48
  "repository": {
@@ -11,7 +11,7 @@ export default function details( slider: Slider) {
11
11
  let amountOfPages = 0;
12
12
  let currentPage = 1;
13
13
 
14
- if (slider.container.scrollWidth > slider.container.clientWidth) {
14
+ if ( Math.floor( slider.getInclusiveScrollWidth() ) > Math.floor( slider.getInclusiveClientWidth() ) ) {
15
15
  hasOverflow = true;
16
16
  }
17
17
 
@@ -19,14 +19,14 @@ export default function details( slider: Slider) {
19
19
 
20
20
  containerWidth = slider.container.offsetWidth;
21
21
 
22
- scrollableAreaWidth = slider.container.scrollWidth;
22
+ scrollableAreaWidth = slider.getInclusiveScrollWidth();
23
23
 
24
24
  amountOfPages = Math.ceil(scrollableAreaWidth / containerWidth);
25
25
 
26
- if (slider.container.scrollLeft >= 0) {
26
+ if ( Math.floor( slider.container.scrollLeft ) >= 0) {
27
27
  currentPage = Math.floor(slider.container.scrollLeft / containerWidth);
28
28
  // consider as last page if the scrollLeft + containerWidth is equal to scrollWidth
29
- if (slider.container.scrollLeft + containerWidth === scrollableAreaWidth) {
29
+ if (Math.floor( slider.container.scrollLeft + containerWidth ) === Math.floor( scrollableAreaWidth ) ) {
30
30
  currentPage = amountOfPages - 1;
31
31
  }
32
32
  }
@@ -21,6 +21,8 @@ export default function OverflowSlider (
21
21
  scrollBehavior: "smooth",
22
22
  scrollStrategy: "fullSlide",
23
23
  slidesSelector: ":scope > *",
24
+ emulateScrollSnap: false,
25
+ emulateScrollSnapMaxThreshold: 64,
24
26
  };
25
27
 
26
28
  const sliderOptions = { ...defaults, ...options };