@evermade/overflow-slider 1.0.0 → 2.0.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 (78) hide show
  1. package/README.md +74 -8
  2. package/dist/core/details.esm.js +35 -0
  3. package/dist/core/details.min.js +1 -0
  4. package/dist/core/overflow-slider.esm.js +26 -0
  5. package/dist/core/overflow-slider.min.js +1 -0
  6. package/dist/core/slider.esm.js +260 -0
  7. package/dist/core/slider.min.js +1 -0
  8. package/dist/core/utils.esm.js +22 -0
  9. package/dist/core/utils.min.js +1 -0
  10. package/dist/index.esm.js +1 -694
  11. package/dist/index.min.js +1 -2
  12. package/dist/overflow-slider.css +1 -1
  13. package/dist/plugins/arrows/arrows/index.esm.js +82 -0
  14. package/dist/plugins/arrows/arrows/index.min.js +1 -0
  15. package/dist/plugins/dots/dots/index.esm.js +99 -0
  16. package/dist/plugins/dots/dots/index.min.js +1 -0
  17. package/dist/plugins/drag-scrolling/drag-scrolling/index.esm.js +70 -0
  18. package/dist/plugins/drag-scrolling/drag-scrolling/index.min.js +1 -0
  19. package/dist/plugins/full-width/full-width/index.esm.js +31 -0
  20. package/dist/plugins/full-width/full-width/index.min.js +1 -0
  21. package/dist/plugins/scroll-indicator/scroll-indicator/index.esm.js +133 -0
  22. package/dist/plugins/scroll-indicator/scroll-indicator/index.min.js +1 -0
  23. package/dist/plugins/skip-links/skip-links/index.esm.js +42 -0
  24. package/dist/plugins/skip-links/skip-links/index.min.js +1 -0
  25. package/dist/plugins/thumbnails/thumbnails/index.esm.js +41 -0
  26. package/dist/plugins/thumbnails/thumbnails/index.min.js +1 -0
  27. package/docs/assets/demo.css +151 -5
  28. package/docs/assets/demo.js +107 -10
  29. package/docs/dist/core/details.esm.js +35 -0
  30. package/docs/dist/core/details.min.js +1 -0
  31. package/docs/dist/core/overflow-slider.esm.js +26 -0
  32. package/docs/dist/core/overflow-slider.min.js +1 -0
  33. package/docs/dist/core/slider.esm.js +260 -0
  34. package/docs/dist/core/slider.min.js +1 -0
  35. package/docs/dist/core/utils.esm.js +22 -0
  36. package/docs/dist/core/utils.min.js +1 -0
  37. package/docs/dist/index.esm.js +1 -0
  38. package/docs/dist/index.min.js +1 -0
  39. package/docs/dist/overflow-slider.css +1 -1
  40. package/docs/dist/plugins/arrows/arrows/index.esm.js +82 -0
  41. package/docs/dist/plugins/arrows/arrows/index.min.js +1 -0
  42. package/docs/dist/plugins/dots/dots/index.esm.js +99 -0
  43. package/docs/dist/plugins/dots/dots/index.min.js +1 -0
  44. package/docs/dist/plugins/drag-scrolling/drag-scrolling/index.esm.js +70 -0
  45. package/docs/dist/plugins/drag-scrolling/drag-scrolling/index.min.js +1 -0
  46. package/docs/dist/plugins/full-width/full-width/index.esm.js +31 -0
  47. package/docs/dist/plugins/full-width/full-width/index.min.js +1 -0
  48. package/docs/dist/plugins/scroll-indicator/scroll-indicator/index.esm.js +133 -0
  49. package/docs/dist/plugins/scroll-indicator/scroll-indicator/index.min.js +1 -0
  50. package/docs/dist/plugins/skip-links/skip-links/index.esm.js +42 -0
  51. package/docs/dist/plugins/skip-links/skip-links/index.min.js +1 -0
  52. package/docs/dist/plugins/thumbnails/thumbnails/index.esm.js +41 -0
  53. package/docs/dist/plugins/thumbnails/thumbnails/index.min.js +1 -0
  54. package/docs/index.html +136 -2
  55. package/package.json +35 -6
  56. package/rollup.config.js +58 -32
  57. package/src/core/details.ts +1 -1
  58. package/src/{overflow-slider.ts → core/overflow-slider.ts} +3 -2
  59. package/src/core/slider.ts +62 -16
  60. package/src/core/types.ts +9 -1
  61. package/src/index.ts +1 -12
  62. package/src/overflow-slider.scss +10 -183
  63. package/src/plugins/{arrows.ts → arrows/index.ts} +13 -4
  64. package/src/plugins/arrows/styles.scss +29 -0
  65. package/src/plugins/{dots.ts → dots/index.ts} +1 -1
  66. package/src/plugins/dots/styles.scss +56 -0
  67. package/src/plugins/{drag-scrolling.ts → drag-scrolling/index.ts} +39 -35
  68. package/src/plugins/drag-scrolling/styles.scss +12 -0
  69. package/src/plugins/full-width/index.ts +43 -0
  70. package/src/plugins/{scroll-indicator.ts → scroll-indicator/index.ts} +36 -20
  71. package/src/plugins/scroll-indicator/styles.scss +59 -0
  72. package/src/plugins/{skip-links.ts → skip-links/index.ts} +2 -2
  73. package/src/plugins/skip-links/styles.scss +35 -0
  74. package/src/plugins/thumbnails/index.ts +53 -0
  75. package/tsconfig.json +14 -2
  76. package/dist/index.esm.min.js +0 -2
  77. package/dist/index.js +0 -709
  78. package/docs/dist/overflow-slider.esm.js +0 -694
@@ -3,7 +3,7 @@
3
3
  */
4
4
 
5
5
  /* --------------------------------------------------------------
6
- # Container
6
+ # Core
7
7
  -------------------------------------------------------------- */
8
8
 
9
9
  .overflow-slider {
@@ -14,9 +14,12 @@
14
14
  grid-auto-flow: column;
15
15
  grid-template-columns: max-content;
16
16
  max-width: max-content;
17
+ // hide native scrollbars
17
18
  &::-webkit-scrollbar {
18
19
  display: none;
19
20
  }
21
+ -ms-overflow-style: none;
22
+ scrollbar-width: none;
20
23
  & > * {
21
24
  scroll-snap-align: start;
22
25
  outline-offset: -2px;
@@ -24,190 +27,14 @@
24
27
  }
25
28
 
26
29
  /* --------------------------------------------------------------
27
- # ArrowsPlugin
30
+ # Plugins
28
31
  -------------------------------------------------------------- */
29
32
 
30
- :root {
31
- --overflow-slider-arrows-size: 1.5rem;
32
- --overflow-slider-arrows-gap: .5rem;
33
- --overflow-slider-arrows-inactive-opacity: 0.5;
34
- }
35
-
36
- .overflow-slider__arrows {
37
- display: flex;
38
- gap: var(--overflow-slider-arrows-gap);
39
- }
40
-
41
- .overflow-slider__arrows-button {
42
- display: flex;
43
- align-items: center;
44
- outline-offset: -2px;
45
- cursor: pointer;
46
- svg {
47
- width: var(--overflow-slider-arrows-size);
48
- height: var(--overflow-slider-arrows-size);
49
-
50
- }
51
- &[data-has-content="false"] {
52
- opacity: var(--overflow-slider-arrows-inactive-opacity);
53
- }
54
- }
55
-
56
- /* --------------------------------------------------------------
57
- # DotsPlugin
58
- -------------------------------------------------------------- */
33
+ @import 'plugins/arrows/styles.scss';
34
+ @import 'plugins/dots/styles.scss';
35
+ @import 'plugins/drag-scrolling/styles.scss';
36
+ @import 'plugins/scroll-indicator/styles.scss';
37
+ @import 'plugins/skip-links/styles.scss';
59
38
 
60
- :root {
61
- --overflow-slider-dots-gap: 0.5rem;
62
- --overflow-slider-dot-size: 0.75rem;
63
- --overflow-slider-dot-inactive-color: hsla(0, 0%, 0%, 0.1);
64
- --overflow-slider-dot-active-color: hsla(0, 0%, 0%, 0.8);
65
- }
66
-
67
- .overflow-slider__dots {
68
- display: flex;
69
- justify-content: center;
70
- align-items: center;
71
- ul {
72
- list-style: none;
73
- padding: 0;
74
- margin: 0;
75
- display: flex;
76
- flex-wrap: wrap;
77
- gap: var(--overflow-slider-dots-gap);
78
- }
79
- li {
80
- line-height: 0;
81
- padding: 0;
82
- margin: 0;
83
- }
84
- }
85
-
86
- .overflow-slider__dot-item {
87
- padding: 0;
88
- margin: 0;
89
- cursor: pointer;
90
- outline-offset: 2px;
91
- width: var(--overflow-slider-dot-size);
92
- height: var(--overflow-slider-dot-size);
93
- border-radius: 50%;
94
- background: var(--overflow-slider-dot-inactive-color);
95
- position: relative;
96
- // increase clickable area
97
- &::after {
98
- content: '';
99
- display: block;
100
- left: calc(-1 * var(--overflow-slider-dots-gap));
101
- top: calc(-1 * var(--overflow-slider-dots-gap));
102
- right: calc(-1 * var(--overflow-slider-dots-gap));
103
- bottom: calc(-1 * var(--overflow-slider-dots-gap));
104
- position: absolute;
105
- }
106
- &[aria-pressed="true"],
107
- &:focus,
108
- &:hover {
109
- background: var(--overflow-slider-dot-active-color);
110
- }
111
- }
112
-
113
- /* --------------------------------------------------------------
114
- # DragScrollingPlugin
115
- -------------------------------------------------------------- */
116
-
117
- // nothing to style
118
-
119
- /* --------------------------------------------------------------
120
- # ScrollIndicatorPlugin
121
- -------------------------------------------------------------- */
122
-
123
- :root {
124
- --overflow-slider-scroll-indicator-button-height: 4px;
125
- --overflow-slider-scroll-indicator-padding: 1rem;
126
- --overflow-slider-scroll-indicator-button-color: hsla(0, 0%, 0%, 0.75);
127
- --overflow-slider-scroll-indicator-bar-color: hsla(0, 0%, 0%, 0.25);
128
- }
129
-
130
- .overflow-slider__scroll-indicator {
131
- width: 100%;
132
- padding-block: var(--overflow-slider-scroll-indicator-padding);
133
- cursor: pointer;
134
- position: relative;
135
- outline: 0;
136
- &[data-has-overflow="false"] {
137
- display: none;
138
- }
139
- &:focus-visible .overflow-slider__scroll-indicator-button {
140
- outline: 2px solid;
141
- outline-offset: 2px;
142
- }
143
- }
144
-
145
- .overflow-slider__scroll-indicator-bar {
146
- height: 2px;
147
- background: var(--overflow-slider-scroll-indicator-bar-color);
148
- width: 100%;
149
- border-radius: 3px;
150
- position: absolute;
151
- top: 50%;
152
- left: 0;
153
- transform: translateY(-50%);
154
- }
155
-
156
- .overflow-slider__scroll-indicator-button {
157
- height: var(--overflow-slider-scroll-indicator-button-height);
158
- background: var(--overflow-slider-scroll-indicator-button-color);
159
- position: absolute;
160
- top: calc(50% - calc( var( --overflow-slider-scroll-indicator-button-height ) / 2 ));
161
- left: 0;
162
- border-radius: 3px;
163
- cursor: grab;
164
- &[data-is-grabbed="true"],
165
- &:hover {
166
- --overflow-slider-scroll-indicator-button-height: 6px;
167
- }
168
- // increase clickable area to fill container in y-axis
169
- &::after {
170
- content: '';
171
- display: block;
172
- position: absolute;
173
- top: calc(-1 * var(--overflow-slider-scroll-indicator-padding));
174
- bottom: calc(-1 * var(--overflow-slider-scroll-indicator-padding));
175
- width: 100%;
176
- }
177
- }
178
-
179
- /* --------------------------------------------------------------
180
- # SkipLinksPlugin
181
- -------------------------------------------------------------- */
182
39
 
183
- // You need a .screen-reader-text class so something like this:
184
40
 
185
- // .screen-reader-text {
186
- // border: 0;
187
- // clip: rect(1px, 1px, 1px, 1px);
188
- // clip-path: inset(50%);
189
- // height: 1px;
190
- // margin: -1px;
191
- // overflow: hidden;
192
- // padding: 0;
193
- // position: absolute;
194
- // width: 1px;
195
- // word-wrap: normal !important;
196
- // &:focus {
197
- // background-color: #000;
198
- // clip: auto !important;
199
- // clip-path: none;
200
- // color: #fff;
201
- // display: block;
202
- // font-weight: 700;
203
- // height: auto;
204
- // outline-offset: -2px;
205
- // padding: 1rem 1.5rem;
206
- // text-decoration: none;
207
- // width: fit-content;
208
- // z-index: 100000;
209
- // position: relative;
210
- // margin-top: 1rem;
211
- // margin-bottom: 1rem;
212
- // }
213
- // }
@@ -1,4 +1,4 @@
1
- import { Slider } from '../core/types';
1
+ import { Slider } from '../../core/types';
2
2
 
3
3
  const DEFAULT_TEXTS = {
4
4
  buttonPrevious: 'Previous items',
@@ -31,6 +31,8 @@ export type ArrowsOptions = {
31
31
  nextButton: string;
32
32
  },
33
33
  container: HTMLElement | null,
34
+ containerPrev: HTMLElement | null,
35
+ containerNext: HTMLElement | null,
34
36
  };
35
37
 
36
38
  export default function ArrowsPlugin( args: { [key: string]: any } ) {
@@ -50,6 +52,8 @@ export default function ArrowsPlugin( args: { [key: string]: any } ) {
50
52
  ...args?.classNames || []
51
53
  },
52
54
  container: args?.container ?? null,
55
+ containerPrev: args?.containerPrev ?? null,
56
+ containerNext: args?.containerNext ?? null,
53
57
  };
54
58
 
55
59
  const nav = document.createElement( 'div' );
@@ -93,10 +97,15 @@ export default function ArrowsPlugin( args: { [key: string]: any } ) {
93
97
  }
94
98
  };
95
99
 
96
- if ( options.container ) {
97
- options.container.appendChild( nav );
100
+ if ( options.containerNext && options.containerPrev ) {
101
+ options.containerPrev.appendChild( prev );
102
+ options.containerNext.appendChild( next );
98
103
  } else {
99
- slider.container.parentNode?.insertBefore( nav, slider.container.nextSibling );
104
+ if ( options.container ) {
105
+ options.container.appendChild( nav );
106
+ } else {
107
+ slider.container.parentNode?.insertBefore( nav, slider.container.nextSibling );
108
+ }
100
109
  }
101
110
 
102
111
  update();
@@ -0,0 +1,29 @@
1
+ /* --------------------------------------------------------------
2
+ # ArrowsPlugin
3
+ -------------------------------------------------------------- */
4
+
5
+ :root {
6
+ --overflow-slider-arrows-size: 1.5rem;
7
+ --overflow-slider-arrows-gap: .5rem;
8
+ --overflow-slider-arrows-inactive-opacity: 0.5;
9
+ }
10
+
11
+ .overflow-slider__arrows {
12
+ display: flex;
13
+ gap: var(--overflow-slider-arrows-gap);
14
+ }
15
+
16
+ .overflow-slider__arrows-button {
17
+ display: flex;
18
+ align-items: center;
19
+ outline-offset: -2px;
20
+ cursor: pointer;
21
+ svg {
22
+ width: var(--overflow-slider-arrows-size);
23
+ height: var(--overflow-slider-arrows-size);
24
+
25
+ }
26
+ &[data-has-content="false"] {
27
+ opacity: var(--overflow-slider-arrows-inactive-opacity);
28
+ }
29
+ }
@@ -1,4 +1,4 @@
1
- import { Slider } from '../core/types';
1
+ import { Slider } from '../../core/types';
2
2
 
3
3
  export type DotsOptions = {
4
4
  texts: {
@@ -0,0 +1,56 @@
1
+ /* --------------------------------------------------------------
2
+ # DotsPlugin
3
+ -------------------------------------------------------------- */
4
+
5
+ :root {
6
+ --overflow-slider-dots-gap: 0.5rem;
7
+ --overflow-slider-dot-size: 0.75rem;
8
+ --overflow-slider-dot-inactive-color: hsla(0, 0%, 0%, 0.1);
9
+ --overflow-slider-dot-active-color: hsla(0, 0%, 0%, 0.8);
10
+ }
11
+
12
+ .overflow-slider__dots {
13
+ display: flex;
14
+ justify-content: center;
15
+ align-items: center;
16
+ ul {
17
+ list-style: none;
18
+ padding: 0;
19
+ margin: 0;
20
+ display: flex;
21
+ flex-wrap: wrap;
22
+ gap: var(--overflow-slider-dots-gap);
23
+ }
24
+ li {
25
+ line-height: 0;
26
+ padding: 0;
27
+ margin: 0;
28
+ }
29
+ }
30
+
31
+ .overflow-slider__dot-item {
32
+ padding: 0;
33
+ margin: 0;
34
+ cursor: pointer;
35
+ outline-offset: 2px;
36
+ width: var(--overflow-slider-dot-size);
37
+ height: var(--overflow-slider-dot-size);
38
+ border-radius: 50%;
39
+ background: var(--overflow-slider-dot-inactive-color);
40
+ position: relative;
41
+ // increase clickable area
42
+ &::after {
43
+ content: '';
44
+ display: block;
45
+ left: calc(-1 * var(--overflow-slider-dots-gap));
46
+ top: calc(-1 * var(--overflow-slider-dots-gap));
47
+ right: calc(-1 * var(--overflow-slider-dots-gap));
48
+ bottom: calc(-1 * var(--overflow-slider-dots-gap));
49
+ position: absolute;
50
+ }
51
+ &[aria-pressed="true"],
52
+ &:focus,
53
+ &:hover {
54
+ background: var(--overflow-slider-dot-active-color);
55
+ }
56
+ }
@@ -1,4 +1,4 @@
1
- import { Slider } from '../core/types';
1
+ import { Slider } from '../../core/types';
2
2
 
3
3
  const DEFAULT_DRAGGED_DISTANCE_THAT_PREVENTS_CLICK = 20;
4
4
 
@@ -15,45 +15,31 @@ export default function DragScrollingPlugin( args: { [key: string]: any } ) {
15
15
  let startX = 0;
16
16
  let scrollLeft = 0;
17
17
 
18
- const hasOverflow = () => {
19
- return slider.details.hasOverflow;
20
- }
18
+ // add data attribute to container
19
+ slider.container.setAttribute( 'data-has-drag-scrolling', 'true' );
21
20
 
22
- slider.container.addEventListener('mousedown', (e) => {
23
- if ( ! hasOverflow() ) {
21
+ const mouseDown = (e: MouseEvent) => {
22
+ if ( ! slider.details.hasOverflow ) {
24
23
  return;
25
24
  }
25
+ if ( ! slider.container.contains( e.target as Node ) ) {
26
+ return;
27
+ }
28
+
26
29
  isMouseDown = true;
27
30
  startX = e.pageX - slider.container.offsetLeft;
28
31
  scrollLeft = slider.container.scrollLeft;
29
32
  // change cursor to grabbing
30
33
  slider.container.style.cursor = 'grabbing';
31
34
  slider.container.style.scrollSnapType = 'none';
32
- // prevent pointer events on the slides
33
- // const slides = slider.container.querySelectorAll( ':scope > *' );
34
- // slides.forEach((slide) => {
35
- // (<HTMLElement>slide).style.pointerEvents = 'none';
36
- // });
35
+ slider.container.style.scrollBehavior = 'auto';
37
36
  // prevent focus going to the slides
38
- // e.preventDefault();
39
- // e.stopPropagation();
40
- });
41
- window.addEventListener('mouseup', () => {
42
- if ( ! hasOverflow() ) {
43
- return;
44
- }
45
- isMouseDown = false;
46
- slider.container.style.cursor = '';
47
- slider.container.style.scrollSnapType = '';
48
- setTimeout(() => {
49
- const slides = slider.container.querySelectorAll( ':scope > *' );
50
- slides.forEach((slide) => {
51
- (<HTMLElement>slide).style.pointerEvents = '';
52
- });
53
- }, 50);
54
- });
55
- window.addEventListener('mousemove', (e) => {
56
- if ( ! hasOverflow() ) {
37
+ e.preventDefault();
38
+ e.stopPropagation();
39
+ };
40
+
41
+ const mouseMove = (e: MouseEvent) => {
42
+ if ( ! slider.details.hasOverflow ) {
57
43
  return;
58
44
  }
59
45
  if (!isMouseDown) {
@@ -64,15 +50,33 @@ export default function DragScrollingPlugin( args: { [key: string]: any } ) {
64
50
  const walk = (x - startX);
65
51
  slider.container.scrollLeft = scrollLeft - walk;
66
52
 
67
- // if walk is more than 30px, don't allow click event
68
- // e.preventDefault();
69
-
70
53
  const absWalk = Math.abs(walk);
71
- const slides = slider.container.querySelectorAll( ':scope > *' );
54
+ const slides = slider.container.querySelectorAll( slider.options.slidesSelector );
72
55
  const pointerEvents = absWalk > options.draggedDistanceThatPreventsClick ? 'none' : '';
73
56
  slides.forEach((slide) => {
74
57
  (<HTMLElement>slide).style.pointerEvents = pointerEvents;
75
58
  });
76
- });
59
+ };
60
+
61
+ const mouseUp = () => {
62
+ if ( ! slider.details.hasOverflow ) {
63
+ return;
64
+ }
65
+ isMouseDown = false;
66
+ slider.container.style.cursor = '';
67
+ setTimeout(() => {
68
+ slider.container.style.scrollSnapType = '';
69
+ slider.container.style.scrollBehavior = '';
70
+ const slides = slider.container.querySelectorAll( slider.options.slidesSelector );
71
+ slides.forEach((slide) => {
72
+ (<HTMLElement>slide).style.pointerEvents = '';
73
+ });
74
+ }, 50);
75
+ };
76
+
77
+ window.addEventListener('mousedown', mouseDown);
78
+ window.addEventListener('mousemove', mouseMove);
79
+ window.addEventListener('mouseup', mouseUp);
80
+
77
81
  };
78
82
  };
@@ -0,0 +1,12 @@
1
+ /* --------------------------------------------------------------
2
+ # DragScrollingPlugin
3
+ -------------------------------------------------------------- */
4
+
5
+ [data-has-drag-scrolling] {
6
+ &[data-has-overflow="true"] {
7
+ // show grab cursor if has drag scrolling
8
+ cursor: grab;
9
+ // selecting text might make scrolling difficult
10
+ user-select: none;
11
+ }
12
+ }
@@ -0,0 +1,43 @@
1
+ import { Slider } from '../../core/types';
2
+
3
+ const DEFAULT_TARGET_WIDTH = ( slider: Slider ) => slider.container.parentElement?.offsetWidth ?? window.innerWidth;
4
+
5
+ export type FullWidthOptions = {
6
+ targetWidth: ( slider: Slider ) => number,
7
+ addMarginBefore: boolean,
8
+ addMarginAfter: boolean,
9
+ };
10
+
11
+ export default function FullWidthPlugin( args: { [key: string]: any } ) {
12
+ return ( slider: Slider ) => {
13
+
14
+ const options = <FullWidthOptions>{
15
+ targetWidth: args?.targetWidth ?? DEFAULT_TARGET_WIDTH,
16
+ addMarginBefore: args?.addMarginBefore ?? true,
17
+ addMarginAfter: args?.addMarginAfter ?? true,
18
+ };
19
+
20
+ const update = () => {
21
+ const slides = slider.container.querySelectorAll( slider.options.slidesSelector );
22
+
23
+ if ( ! slides.length ) {
24
+ return;
25
+ }
26
+
27
+ const firstSlide = slides[0] as HTMLElement;
28
+ const lastSlide = slides[slides.length - 1] as HTMLElement;
29
+
30
+ const marginAmount = Math.floor((window.innerWidth - options.targetWidth(slider)) / 2);
31
+ if ( options.addMarginBefore ) {
32
+ firstSlide.style.marginLeft = `${marginAmount}px`;
33
+ }
34
+ if ( options.addMarginAfter ) {
35
+ lastSlide.style.marginRight = `${marginAmount}px`;
36
+ }
37
+ };
38
+
39
+ update();
40
+ slider.on( 'contentsChanged', update );
41
+ slider.on( 'containerSizeChanged', update );
42
+ };
43
+ }
@@ -1,4 +1,4 @@
1
- import { Slider } from '../core/types';
1
+ import { Slider } from '../../core/types';
2
2
 
3
3
  const DEFAULT_CLASS_NAMES = {
4
4
  scrollIndicator: 'overflow-slider__scroll-indicator',
@@ -53,8 +53,8 @@ export default function ScrollIndicatorPlugin( args: { [key: string]: any } ) {
53
53
  setDataAttributes();
54
54
 
55
55
  const getScrollbarButtonLeftOffset = () => {
56
- const scrollbarRatio = slider.container.offsetWidth / slider.container.scrollWidth;
57
- return slider.container.scrollLeft * scrollbarRatio;
56
+ const contentRatio = scrollbarButton.offsetWidth / slider.details.containerWidth;
57
+ return slider.container.scrollLeft * contentRatio;
58
58
  };
59
59
 
60
60
  // scrollbarbutton width and position is calculated based on the scroll position and available width
@@ -65,7 +65,8 @@ export default function ScrollIndicatorPlugin( args: { [key: string]: any } ) {
65
65
  }
66
66
 
67
67
  requestId = window.requestAnimationFrame(() => {
68
- const scrollbarButtonWidth = (slider.container.offsetWidth / slider.container.scrollWidth) * 100;
68
+ const scrollbarButtonWidth = (slider.details.containerWidth / slider.details.scrollableAreaWidth) * 100;
69
+
69
70
  const scrollLeftInPortion = getScrollbarButtonLeftOffset();
70
71
  scrollbarButton.style.width = `${scrollbarButtonWidth}%`;
71
72
  scrollbarButton.style.transform = `translateX(${scrollLeftInPortion}px)`;
@@ -116,13 +117,14 @@ export default function ScrollIndicatorPlugin( args: { [key: string]: any } ) {
116
117
  });
117
118
 
118
119
  // make scrollbar button draggable via mouse/touch and update the scroll position
119
- let isMouseDown = false;
120
+ let isInteractionDown = false;
120
121
  let startX = 0;
121
122
  let scrollLeft = 0;
122
123
 
123
- scrollbarButton.addEventListener('mousedown', (e) => {
124
- isMouseDown = true;
125
- startX = e.pageX - scrollbarContainer.offsetLeft;
124
+ const onInteractionDown = (e: MouseEvent | TouchEvent) => {
125
+ isInteractionDown = true;
126
+ const pageX = (e as MouseEvent).pageX || (e as TouchEvent).touches[0].pageX;
127
+ startX = pageX - scrollbarContainer.offsetLeft;
126
128
  scrollLeft = slider.container.scrollLeft;
127
129
  // change cursor to grabbing
128
130
  scrollbarButton.style.cursor = 'grabbing';
@@ -131,22 +133,36 @@ export default function ScrollIndicatorPlugin( args: { [key: string]: any } ) {
131
133
 
132
134
  e.preventDefault();
133
135
  e.stopPropagation();
134
- });
135
- window.addEventListener('mouseup', () => {
136
- isMouseDown = false;
137
- scrollbarButton.style.cursor = '';
138
- slider.container.style.scrollSnapType = '';
139
- scrollbarButton.setAttribute( 'data-is-grabbed', 'false' );
140
- });
141
- window.addEventListener('mousemove', (e) => {
142
- if (!isMouseDown) {
136
+ };
137
+
138
+ const onInteractionMove = (e: MouseEvent | TouchEvent) => {
139
+ if (!isInteractionDown) {
143
140
  return;
144
141
  }
145
142
  e.preventDefault();
146
- const x = e.pageX - scrollbarContainer.offsetLeft;
147
- const scrollingFactor = slider.container.scrollWidth / scrollbarContainer.offsetWidth;
143
+ const pageX = (e as MouseEvent).pageX || (e as TouchEvent).touches[0].pageX;
144
+ const x = pageX - scrollbarContainer.offsetLeft;
145
+ const scrollingFactor = slider.details.scrollableAreaWidth / scrollbarContainer.offsetWidth;
146
+
148
147
  const walk = (x - startX) * scrollingFactor;
149
148
  slider.container.scrollLeft = scrollLeft + walk;
150
- });
149
+ };
150
+
151
+ const onInteractionUp = () => {
152
+ isInteractionDown = false;
153
+ scrollbarButton.style.cursor = '';
154
+ slider.container.style.scrollSnapType = '';
155
+ scrollbarButton.setAttribute( 'data-is-grabbed', 'false' );
156
+ };
157
+
158
+ scrollbarButton.addEventListener('mousedown', onInteractionDown);
159
+ scrollbarButton.addEventListener('touchstart', onInteractionDown);
160
+
161
+ window.addEventListener('mousemove', onInteractionMove);
162
+ window.addEventListener('touchmove', onInteractionMove, { passive: false });
163
+
164
+ window.addEventListener('mouseup', onInteractionUp);
165
+ window.addEventListener('touchend', onInteractionUp);
166
+
151
167
  };
152
168
  }
@@ -0,0 +1,59 @@
1
+ /* --------------------------------------------------------------
2
+ # ScrollIndicatorPlugin
3
+ -------------------------------------------------------------- */
4
+
5
+ :root {
6
+ --overflow-slider-scroll-indicator-button-height: 4px;
7
+ --overflow-slider-scroll-indicator-padding: 1rem;
8
+ --overflow-slider-scroll-indicator-button-color: hsla(0, 0%, 0%, 0.75);
9
+ --overflow-slider-scroll-indicator-bar-color: hsla(0, 0%, 0%, 0.25);
10
+ }
11
+
12
+ .overflow-slider__scroll-indicator {
13
+ width: 100%;
14
+ padding-block: var(--overflow-slider-scroll-indicator-padding);
15
+ cursor: pointer;
16
+ position: relative;
17
+ outline: 0;
18
+ &[data-has-overflow="false"] {
19
+ display: none;
20
+ }
21
+ &:focus-visible .overflow-slider__scroll-indicator-button {
22
+ outline: 2px solid;
23
+ outline-offset: 2px;
24
+ }
25
+ }
26
+
27
+ .overflow-slider__scroll-indicator-bar {
28
+ height: 2px;
29
+ background: var(--overflow-slider-scroll-indicator-bar-color);
30
+ width: 100%;
31
+ border-radius: 3px;
32
+ position: absolute;
33
+ top: 50%;
34
+ left: 0;
35
+ transform: translateY(-50%);
36
+ }
37
+
38
+ .overflow-slider__scroll-indicator-button {
39
+ height: var(--overflow-slider-scroll-indicator-button-height);
40
+ background: var(--overflow-slider-scroll-indicator-button-color);
41
+ position: absolute;
42
+ top: calc(50% - calc( var( --overflow-slider-scroll-indicator-button-height ) / 2 ));
43
+ left: 0;
44
+ border-radius: 3px;
45
+ cursor: grab;
46
+ &[data-is-grabbed="true"],
47
+ &:hover {
48
+ --overflow-slider-scroll-indicator-button-height: 6px;
49
+ }
50
+ // increase clickable area to fill container in y-axis
51
+ &::after {
52
+ content: '';
53
+ display: block;
54
+ position: absolute;
55
+ top: calc(-1 * var(--overflow-slider-scroll-indicator-padding));
56
+ bottom: calc(-1 * var(--overflow-slider-scroll-indicator-padding));
57
+ width: 100%;
58
+ }
59
+ }
@@ -1,5 +1,5 @@
1
- import { Slider } from '../core/types';
2
- import { generateId } from '../core/utils';
1
+ import { Slider } from '../../core/types';
2
+ import { generateId } from '../../core/utils';
3
3
 
4
4
  const DEFAULT_TEXTS = {
5
5
  skipList: 'Skip list'