@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.
- package/README.md +74 -8
- package/dist/core/details.esm.js +35 -0
- package/dist/core/details.min.js +1 -0
- package/dist/core/overflow-slider.esm.js +26 -0
- package/dist/core/overflow-slider.min.js +1 -0
- package/dist/core/slider.esm.js +260 -0
- package/dist/core/slider.min.js +1 -0
- package/dist/core/utils.esm.js +22 -0
- package/dist/core/utils.min.js +1 -0
- package/dist/index.esm.js +1 -694
- package/dist/index.min.js +1 -2
- package/dist/overflow-slider.css +1 -1
- package/dist/plugins/arrows/arrows/index.esm.js +82 -0
- package/dist/plugins/arrows/arrows/index.min.js +1 -0
- package/dist/plugins/dots/dots/index.esm.js +99 -0
- package/dist/plugins/dots/dots/index.min.js +1 -0
- package/dist/plugins/drag-scrolling/drag-scrolling/index.esm.js +70 -0
- package/dist/plugins/drag-scrolling/drag-scrolling/index.min.js +1 -0
- package/dist/plugins/full-width/full-width/index.esm.js +31 -0
- package/dist/plugins/full-width/full-width/index.min.js +1 -0
- package/dist/plugins/scroll-indicator/scroll-indicator/index.esm.js +133 -0
- package/dist/plugins/scroll-indicator/scroll-indicator/index.min.js +1 -0
- package/dist/plugins/skip-links/skip-links/index.esm.js +42 -0
- package/dist/plugins/skip-links/skip-links/index.min.js +1 -0
- package/dist/plugins/thumbnails/thumbnails/index.esm.js +41 -0
- package/dist/plugins/thumbnails/thumbnails/index.min.js +1 -0
- package/docs/assets/demo.css +151 -5
- package/docs/assets/demo.js +107 -10
- package/docs/dist/core/details.esm.js +35 -0
- package/docs/dist/core/details.min.js +1 -0
- package/docs/dist/core/overflow-slider.esm.js +26 -0
- package/docs/dist/core/overflow-slider.min.js +1 -0
- package/docs/dist/core/slider.esm.js +260 -0
- package/docs/dist/core/slider.min.js +1 -0
- package/docs/dist/core/utils.esm.js +22 -0
- package/docs/dist/core/utils.min.js +1 -0
- package/docs/dist/index.esm.js +1 -0
- package/docs/dist/index.min.js +1 -0
- package/docs/dist/overflow-slider.css +1 -1
- package/docs/dist/plugins/arrows/arrows/index.esm.js +82 -0
- package/docs/dist/plugins/arrows/arrows/index.min.js +1 -0
- package/docs/dist/plugins/dots/dots/index.esm.js +99 -0
- package/docs/dist/plugins/dots/dots/index.min.js +1 -0
- package/docs/dist/plugins/drag-scrolling/drag-scrolling/index.esm.js +70 -0
- package/docs/dist/plugins/drag-scrolling/drag-scrolling/index.min.js +1 -0
- package/docs/dist/plugins/full-width/full-width/index.esm.js +31 -0
- package/docs/dist/plugins/full-width/full-width/index.min.js +1 -0
- package/docs/dist/plugins/scroll-indicator/scroll-indicator/index.esm.js +133 -0
- package/docs/dist/plugins/scroll-indicator/scroll-indicator/index.min.js +1 -0
- package/docs/dist/plugins/skip-links/skip-links/index.esm.js +42 -0
- package/docs/dist/plugins/skip-links/skip-links/index.min.js +1 -0
- package/docs/dist/plugins/thumbnails/thumbnails/index.esm.js +41 -0
- package/docs/dist/plugins/thumbnails/thumbnails/index.min.js +1 -0
- package/docs/index.html +136 -2
- package/package.json +35 -6
- package/rollup.config.js +58 -32
- package/src/core/details.ts +1 -1
- package/src/{overflow-slider.ts → core/overflow-slider.ts} +3 -2
- package/src/core/slider.ts +62 -16
- package/src/core/types.ts +9 -1
- package/src/index.ts +1 -12
- package/src/overflow-slider.scss +10 -183
- package/src/plugins/{arrows.ts → arrows/index.ts} +13 -4
- package/src/plugins/arrows/styles.scss +29 -0
- package/src/plugins/{dots.ts → dots/index.ts} +1 -1
- package/src/plugins/dots/styles.scss +56 -0
- package/src/plugins/{drag-scrolling.ts → drag-scrolling/index.ts} +39 -35
- package/src/plugins/drag-scrolling/styles.scss +12 -0
- package/src/plugins/full-width/index.ts +43 -0
- package/src/plugins/{scroll-indicator.ts → scroll-indicator/index.ts} +36 -20
- package/src/plugins/scroll-indicator/styles.scss +59 -0
- package/src/plugins/{skip-links.ts → skip-links/index.ts} +2 -2
- package/src/plugins/skip-links/styles.scss +35 -0
- package/src/plugins/thumbnails/index.ts +53 -0
- package/tsconfig.json +14 -2
- package/dist/index.esm.min.js +0 -2
- package/dist/index.js +0 -709
- package/docs/dist/overflow-slider.esm.js +0 -694
package/src/overflow-slider.scss
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
/* --------------------------------------------------------------
|
|
6
|
-
#
|
|
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
|
-
#
|
|
30
|
+
# Plugins
|
|
28
31
|
-------------------------------------------------------------- */
|
|
29
32
|
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
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 '
|
|
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.
|
|
97
|
-
options.
|
|
100
|
+
if ( options.containerNext && options.containerPrev ) {
|
|
101
|
+
options.containerPrev.appendChild( prev );
|
|
102
|
+
options.containerNext.appendChild( next );
|
|
98
103
|
} else {
|
|
99
|
-
|
|
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
|
+
}
|
|
@@ -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 '
|
|
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
|
-
|
|
19
|
-
|
|
20
|
-
}
|
|
18
|
+
// add data attribute to container
|
|
19
|
+
slider.container.setAttribute( 'data-has-drag-scrolling', 'true' );
|
|
21
20
|
|
|
22
|
-
|
|
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
|
-
|
|
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
|
-
|
|
39
|
-
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
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(
|
|
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 '
|
|
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
|
|
57
|
-
return slider.container.scrollLeft *
|
|
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.
|
|
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
|
|
120
|
+
let isInteractionDown = false;
|
|
120
121
|
let startX = 0;
|
|
121
122
|
let scrollLeft = 0;
|
|
122
123
|
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
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
|
-
|
|
136
|
-
|
|
137
|
-
|
|
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
|
|
147
|
-
const
|
|
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
|
+
}
|