@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.
- package/.nvmrc +1 -1
- package/README.md +26 -4
- package/dist/core/details.esm.js +4 -4
- package/dist/core/details.min.js +1 -1
- package/dist/core/overflow-slider.esm.js +2 -0
- package/dist/core/overflow-slider.min.js +1 -1
- package/dist/core/slider.esm.js +202 -29
- package/dist/core/slider.min.js +1 -1
- package/dist/core/utils.esm.js +15 -1
- package/dist/core/utils.min.js +1 -1
- package/dist/overflow-slider.css +1 -1
- package/dist/plugins/arrows/arrows/index.esm.js +15 -8
- package/dist/plugins/arrows/arrows/index.min.js +1 -1
- package/dist/plugins/dots/dots/index.esm.js +21 -22
- package/dist/plugins/dots/dots/index.min.js +1 -1
- package/dist/plugins/drag-scrolling/drag-scrolling/index.esm.js +30 -3
- package/dist/plugins/drag-scrolling/drag-scrolling/index.min.js +1 -1
- package/dist/plugins/fade/fade/index.esm.js +81 -0
- package/dist/plugins/fade/fade/index.min.js +1 -0
- package/dist/plugins/full-width/full-width/index.esm.js +1 -0
- package/dist/plugins/full-width/full-width/index.min.js +1 -1
- package/dist/plugins/scroll-indicator/scroll-indicator/index.esm.js +4 -6
- package/dist/plugins/scroll-indicator/scroll-indicator/index.min.js +1 -1
- package/dist/plugins/thumbnails/thumbnails/index.esm.js +1 -0
- package/docs/assets/demo.css +16 -0
- package/docs/assets/demo.js +44 -7
- package/docs/dist/core/details.esm.js +4 -4
- package/docs/dist/core/details.min.js +1 -1
- package/docs/dist/core/overflow-slider.esm.js +2 -0
- package/docs/dist/core/overflow-slider.min.js +1 -1
- package/docs/dist/core/slider.esm.js +202 -29
- package/docs/dist/core/slider.min.js +1 -1
- package/docs/dist/core/utils.esm.js +15 -1
- package/docs/dist/core/utils.min.js +1 -1
- package/docs/dist/overflow-slider.css +1 -1
- package/docs/dist/plugins/arrows/arrows/index.esm.js +15 -8
- package/docs/dist/plugins/arrows/arrows/index.min.js +1 -1
- package/docs/dist/plugins/dots/dots/index.esm.js +21 -22
- package/docs/dist/plugins/dots/dots/index.min.js +1 -1
- package/docs/dist/plugins/drag-scrolling/drag-scrolling/index.esm.js +30 -3
- package/docs/dist/plugins/drag-scrolling/drag-scrolling/index.min.js +1 -1
- package/docs/dist/plugins/fade/fade/index.esm.js +81 -0
- package/docs/dist/plugins/fade/fade/index.min.js +1 -0
- package/docs/dist/plugins/full-width/full-width/index.esm.js +1 -0
- package/docs/dist/plugins/full-width/full-width/index.min.js +1 -1
- package/docs/dist/plugins/scroll-indicator/scroll-indicator/index.esm.js +4 -6
- package/docs/dist/plugins/scroll-indicator/scroll-indicator/index.min.js +1 -1
- package/docs/dist/plugins/thumbnails/thumbnails/index.esm.js +1 -0
- package/docs/index.html +39 -7
- package/package.json +5 -1
- package/src/core/details.ts +4 -4
- package/src/core/overflow-slider.ts +2 -0
- package/src/core/slider.ts +226 -36
- package/src/core/types.ts +33 -1
- package/src/core/utils.ts +19 -1
- package/src/overflow-slider.scss +2 -1
- package/src/plugins/arrows/index.ts +16 -8
- package/src/plugins/dots/index.ts +21 -23
- package/src/plugins/drag-scrolling/index.ts +34 -5
- package/src/plugins/fade/index.ts +101 -0
- package/src/plugins/fade/styles.scss +27 -0
- package/src/plugins/full-width/index.ts +1 -0
- package/src/plugins/scroll-indicator/index.ts +4 -6
- package/src/plugins/thumbnails/index.ts +1 -1
|
@@ -15,23 +15,26 @@ export default function DragScrollingPlugin( args: { [key: string]: any } ) {
|
|
|
15
15
|
let startX = 0;
|
|
16
16
|
let scrollLeft = 0;
|
|
17
17
|
|
|
18
|
+
let isMovingForward = false;
|
|
19
|
+
let programmaticScrollStarted = false;
|
|
20
|
+
let mayNeedToSnap = false;
|
|
21
|
+
|
|
18
22
|
// add data attribute to container
|
|
19
23
|
slider.container.setAttribute( 'data-has-drag-scrolling', 'true' );
|
|
20
24
|
|
|
21
25
|
const mouseDown = (e: MouseEvent) => {
|
|
26
|
+
programmaticScrollStarted = false;
|
|
22
27
|
if ( ! slider.details.hasOverflow ) {
|
|
23
28
|
return;
|
|
24
29
|
}
|
|
25
30
|
if ( ! slider.container.contains( e.target as Node ) ) {
|
|
26
31
|
return;
|
|
27
32
|
}
|
|
28
|
-
|
|
29
33
|
isMouseDown = true;
|
|
30
34
|
startX = e.pageX - slider.container.offsetLeft;
|
|
31
35
|
scrollLeft = slider.container.scrollLeft;
|
|
32
36
|
// change cursor to grabbing
|
|
33
37
|
slider.container.style.cursor = 'grabbing';
|
|
34
|
-
slider.container.style.scrollSnapType = 'none';
|
|
35
38
|
slider.container.style.scrollBehavior = 'auto';
|
|
36
39
|
// prevent focus going to the slides
|
|
37
40
|
e.preventDefault();
|
|
@@ -40,15 +43,26 @@ export default function DragScrollingPlugin( args: { [key: string]: any } ) {
|
|
|
40
43
|
|
|
41
44
|
const mouseMove = (e: MouseEvent) => {
|
|
42
45
|
if ( ! slider.details.hasOverflow ) {
|
|
46
|
+
programmaticScrollStarted = false;
|
|
43
47
|
return;
|
|
44
48
|
}
|
|
45
49
|
if (!isMouseDown) {
|
|
50
|
+
programmaticScrollStarted = false;
|
|
46
51
|
return;
|
|
47
52
|
}
|
|
48
53
|
e.preventDefault();
|
|
54
|
+
if (!programmaticScrollStarted) {
|
|
55
|
+
programmaticScrollStarted = true;
|
|
56
|
+
slider.emit('programmaticScrollStart');
|
|
57
|
+
}
|
|
49
58
|
const x = e.pageX - slider.container.offsetLeft;
|
|
50
59
|
const walk = (x - startX);
|
|
51
|
-
|
|
60
|
+
const newScrollLeft = scrollLeft - walk;
|
|
61
|
+
mayNeedToSnap = true;
|
|
62
|
+
if ( Math.floor( slider.container.scrollLeft ) !== Math.floor( newScrollLeft ) ) {
|
|
63
|
+
isMovingForward = slider.container.scrollLeft < newScrollLeft;
|
|
64
|
+
}
|
|
65
|
+
slider.container.scrollLeft = newScrollLeft;
|
|
52
66
|
|
|
53
67
|
const absWalk = Math.abs(walk);
|
|
54
68
|
const slides = slider.container.querySelectorAll( slider.options.slidesSelector );
|
|
@@ -59,13 +73,15 @@ export default function DragScrollingPlugin( args: { [key: string]: any } ) {
|
|
|
59
73
|
};
|
|
60
74
|
|
|
61
75
|
const mouseUp = () => {
|
|
62
|
-
if (
|
|
76
|
+
if (!slider.details.hasOverflow) {
|
|
77
|
+
programmaticScrollStarted = false;
|
|
63
78
|
return;
|
|
64
79
|
}
|
|
65
80
|
isMouseDown = false;
|
|
81
|
+
|
|
66
82
|
slider.container.style.cursor = '';
|
|
67
83
|
setTimeout(() => {
|
|
68
|
-
|
|
84
|
+
programmaticScrollStarted = false;
|
|
69
85
|
slider.container.style.scrollBehavior = '';
|
|
70
86
|
const slides = slider.container.querySelectorAll( slider.options.slidesSelector );
|
|
71
87
|
slides.forEach((slide) => {
|
|
@@ -78,5 +94,18 @@ export default function DragScrollingPlugin( args: { [key: string]: any } ) {
|
|
|
78
94
|
window.addEventListener('mousemove', mouseMove);
|
|
79
95
|
window.addEventListener('mouseup', mouseUp);
|
|
80
96
|
|
|
97
|
+
// emulate scroll snapping
|
|
98
|
+
if ( slider.options.emulateScrollSnap ) {
|
|
99
|
+
const snap = () => {
|
|
100
|
+
if (!mayNeedToSnap || isMouseDown) {
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
mayNeedToSnap = false;
|
|
104
|
+
slider.snapToClosestSlide(isMovingForward ? 'next' : 'prev');
|
|
105
|
+
};
|
|
106
|
+
slider.on( 'programmaticScrollEnd', snap );
|
|
107
|
+
window.addEventListener( 'mouseup', snap );
|
|
108
|
+
}
|
|
109
|
+
|
|
81
110
|
};
|
|
82
111
|
};
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import { Slider } from '../../core/types';
|
|
2
|
+
|
|
3
|
+
export type FadeOptions = {
|
|
4
|
+
classNames: {
|
|
5
|
+
fadeItem: string;
|
|
6
|
+
fadeItemStart: string;
|
|
7
|
+
fadeItemEnd: string;
|
|
8
|
+
},
|
|
9
|
+
container: HTMLElement | null,
|
|
10
|
+
containerStart: HTMLElement | null,
|
|
11
|
+
containerEnd: HTMLElement | null,
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
export default function FadePlugin( args: { [key: string]: any } ) {
|
|
15
|
+
return ( slider: Slider ) => {
|
|
16
|
+
|
|
17
|
+
const options = <FadeOptions>{
|
|
18
|
+
classNames: {
|
|
19
|
+
fadeItem: 'overflow-slider-fade',
|
|
20
|
+
fadeItemStart: 'overflow-slider-fade--start',
|
|
21
|
+
fadeItemEnd: 'overflow-slider-fade--end',
|
|
22
|
+
},
|
|
23
|
+
container: args?.container ?? null,
|
|
24
|
+
containerStart: args?.containerStart ?? null,
|
|
25
|
+
containerEnd: args?.containerEnd ?? null,
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
const fadeItemStart = document.createElement( 'div' );
|
|
29
|
+
fadeItemStart.classList.add( options.classNames.fadeItem, options.classNames.fadeItemStart );
|
|
30
|
+
fadeItemStart.setAttribute( 'aria-hidden', 'true' );
|
|
31
|
+
fadeItemStart.setAttribute( 'tabindex', '-1' );
|
|
32
|
+
|
|
33
|
+
const fadeItemEnd = document.createElement( 'div' );
|
|
34
|
+
fadeItemEnd.classList.add( options.classNames.fadeItem, options.classNames.fadeItemEnd );
|
|
35
|
+
fadeItemEnd.setAttribute( 'aria-hidden', 'true' );
|
|
36
|
+
fadeItemEnd.setAttribute( 'tabindex', '-1' );
|
|
37
|
+
|
|
38
|
+
if ( options.containerStart ) {
|
|
39
|
+
options.containerStart.appendChild( fadeItemStart );
|
|
40
|
+
} else if ( options.container ) {
|
|
41
|
+
options.container.appendChild( fadeItemStart );
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
if ( options.containerEnd ) {
|
|
45
|
+
options.containerEnd.appendChild( fadeItemEnd );
|
|
46
|
+
} else if ( options.container ) {
|
|
47
|
+
options.container.appendChild( fadeItemEnd );
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
const hasFadeAtStart = () => {
|
|
51
|
+
return slider.container.scrollLeft > fadeItemStart.offsetWidth;
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
const fadeAtStartOpacity = () => {
|
|
55
|
+
const position = slider.container.scrollLeft;
|
|
56
|
+
if ( Math.floor( position ) <= Math.floor( fadeItemStart.offsetWidth ) ) {
|
|
57
|
+
return position / Math.max(fadeItemStart.offsetWidth, 1);
|
|
58
|
+
}
|
|
59
|
+
return 1;
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const hasFadeAtEnd = () => {
|
|
63
|
+
return Math.floor( slider.container.scrollLeft ) < Math.floor( slider.getInclusiveScrollWidth() - slider.getInclusiveClientWidth() - fadeItemEnd.offsetWidth );
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
const fadeAtEndOpacity = () => {
|
|
67
|
+
const position = slider.container.scrollLeft;
|
|
68
|
+
const maxPosition = slider.getInclusiveScrollWidth() - slider.getInclusiveClientWidth();
|
|
69
|
+
const maxFadePosition = maxPosition - fadeItemEnd.offsetWidth;
|
|
70
|
+
if ( Math.floor( position ) >= Math.floor( maxFadePosition ) ) {
|
|
71
|
+
return ( ( maxFadePosition - position ) / Math.max(fadeItemEnd.offsetWidth, 1) ) + 1;
|
|
72
|
+
}
|
|
73
|
+
return 1;
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
const update = () => {
|
|
77
|
+
fadeItemStart.setAttribute( 'data-has-fade', hasFadeAtStart().toString() );
|
|
78
|
+
fadeItemStart.style.opacity = fadeAtStartOpacity().toString();
|
|
79
|
+
fadeItemEnd.setAttribute( 'data-has-fade', hasFadeAtEnd().toString() );
|
|
80
|
+
fadeItemEnd.style.opacity = fadeAtEndOpacity().toString();
|
|
81
|
+
};
|
|
82
|
+
|
|
83
|
+
update();
|
|
84
|
+
slider.on( 'created', update );
|
|
85
|
+
slider.on( 'contentsChanged', update );
|
|
86
|
+
slider.on( 'containerSizeChanged', update );
|
|
87
|
+
slider.on( 'scrollEnd', update );
|
|
88
|
+
slider.on( 'scrollStart', update );
|
|
89
|
+
let requestId = 0;
|
|
90
|
+
const debouncedUpdate = () => {
|
|
91
|
+
if ( requestId ) {
|
|
92
|
+
window.cancelAnimationFrame( requestId );
|
|
93
|
+
}
|
|
94
|
+
requestId = window.requestAnimationFrame(() => {
|
|
95
|
+
update();
|
|
96
|
+
});
|
|
97
|
+
};
|
|
98
|
+
slider.on('scroll', debouncedUpdate);
|
|
99
|
+
|
|
100
|
+
};
|
|
101
|
+
}
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/* --------------------------------------------------------------
|
|
2
|
+
# FadePlugin
|
|
3
|
+
-------------------------------------------------------------- */
|
|
4
|
+
|
|
5
|
+
:root {
|
|
6
|
+
--overflow-slider-fade-color: #fff;
|
|
7
|
+
--overflow-slider-fade-width: 3rem;
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
.overflow-slider-fade {
|
|
11
|
+
position: absolute;
|
|
12
|
+
top: 0;
|
|
13
|
+
width: var(--overflow-slider-fade-width);
|
|
14
|
+
height: 100%;
|
|
15
|
+
pointer-events: none;
|
|
16
|
+
z-index: 1;
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.overflow-slider-fade--start {
|
|
20
|
+
left: 0;
|
|
21
|
+
background: linear-gradient(to right, var(--overflow-slider-fade-color) 0%, transparent 100%);
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.overflow-slider-fade--end {
|
|
25
|
+
right: 0;
|
|
26
|
+
background: linear-gradient(to left, var(--overflow-slider-fade-color) 0%, transparent 100%);
|
|
27
|
+
}
|
|
@@ -34,6 +34,7 @@ export default function FullWidthPlugin( args: { [key: string]: any } ) {
|
|
|
34
34
|
if ( options.addMarginAfter ) {
|
|
35
35
|
lastSlide.style.marginRight = `${marginAmount}px`;
|
|
36
36
|
}
|
|
37
|
+
slider.container.setAttribute( 'data-full-width-offset', marginAmount.toString() );
|
|
37
38
|
};
|
|
38
39
|
|
|
39
40
|
update();
|
|
@@ -65,7 +65,7 @@ export default function ScrollIndicatorPlugin( args: { [key: string]: any } ) {
|
|
|
65
65
|
}
|
|
66
66
|
|
|
67
67
|
requestId = window.requestAnimationFrame(() => {
|
|
68
|
-
const scrollbarButtonWidth = (slider.details.containerWidth / slider.
|
|
68
|
+
const scrollbarButtonWidth = (slider.details.containerWidth / slider.container.scrollWidth) * 100;
|
|
69
69
|
|
|
70
70
|
const scrollLeftInPortion = getScrollbarButtonLeftOffset();
|
|
71
71
|
scrollbarButton.style.width = `${scrollbarButtonWidth}%`;
|
|
@@ -73,7 +73,7 @@ export default function ScrollIndicatorPlugin( args: { [key: string]: any } ) {
|
|
|
73
73
|
|
|
74
74
|
// aria-valuenow
|
|
75
75
|
const scrollLeft = slider.container.scrollLeft;
|
|
76
|
-
const scrollWidth = slider.
|
|
76
|
+
const scrollWidth = slider.getInclusiveScrollWidth();
|
|
77
77
|
const containerWidth = slider.container.offsetWidth;
|
|
78
78
|
const scrollPercentage = (scrollLeft / (scrollWidth - containerWidth)) * 100;
|
|
79
79
|
scrollbarContainer.setAttribute( 'aria-valuenow', Math.round(Number.isNaN(scrollPercentage) ? 0 : scrollPercentage).toString() );
|
|
@@ -109,9 +109,9 @@ export default function ScrollIndicatorPlugin( args: { [key: string]: any } ) {
|
|
|
109
109
|
const scrollbarButtonLeft = getScrollbarButtonLeftOffset();
|
|
110
110
|
const scrollbarButtonRight = scrollbarButtonLeft + scrollbarButtonWidth;
|
|
111
111
|
const clickX = e.pageX - scrollbarContainer.offsetLeft;
|
|
112
|
-
if ( clickX < scrollbarButtonLeft ) {
|
|
112
|
+
if ( Math.floor( clickX ) < Math.floor( scrollbarButtonLeft ) ) {
|
|
113
113
|
slider.moveToDirection( 'prev' );
|
|
114
|
-
} else if ( clickX > scrollbarButtonRight ) {
|
|
114
|
+
} else if ( Math.floor( clickX ) > Math.floor( scrollbarButtonRight ) ) {
|
|
115
115
|
slider.moveToDirection( 'next' );
|
|
116
116
|
}
|
|
117
117
|
});
|
|
@@ -128,7 +128,6 @@ export default function ScrollIndicatorPlugin( args: { [key: string]: any } ) {
|
|
|
128
128
|
scrollLeft = slider.container.scrollLeft;
|
|
129
129
|
// change cursor to grabbing
|
|
130
130
|
scrollbarButton.style.cursor = 'grabbing';
|
|
131
|
-
slider.container.style.scrollSnapType = 'none';
|
|
132
131
|
scrollbarButton.setAttribute( 'data-is-grabbed', 'true' );
|
|
133
132
|
|
|
134
133
|
e.preventDefault();
|
|
@@ -151,7 +150,6 @@ export default function ScrollIndicatorPlugin( args: { [key: string]: any } ) {
|
|
|
151
150
|
const onInteractionUp = () => {
|
|
152
151
|
isInteractionDown = false;
|
|
153
152
|
scrollbarButton.style.cursor = '';
|
|
154
|
-
slider.container.style.scrollSnapType = '';
|
|
155
153
|
scrollbarButton.setAttribute( 'data-is-grabbed', 'false' );
|
|
156
154
|
};
|
|
157
155
|
|
|
@@ -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,6 +39,7 @@ export default function FullWidthPlugin( args: { [key: string]: any } ) {
|
|
|
40
39
|
setActiveThumbnail();
|
|
41
40
|
addClickListeners();
|
|
42
41
|
|
|
42
|
+
// @todo debounce on scroll
|
|
43
43
|
mainSlider.on( 'activeSlideChanged', () => {
|
|
44
44
|
setTimeout(() => {
|
|
45
45
|
const activeSlideIdx = mainSlider.activeSlideIdx;
|