@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/docs/assets/demo.css
CHANGED
|
@@ -94,7 +94,7 @@ textarea {
|
|
|
94
94
|
}
|
|
95
95
|
|
|
96
96
|
body {
|
|
97
|
-
background-color: #
|
|
97
|
+
background-color: #fff;
|
|
98
98
|
}
|
|
99
99
|
|
|
100
100
|
a {
|
|
@@ -104,8 +104,7 @@ a {
|
|
|
104
104
|
}
|
|
105
105
|
|
|
106
106
|
a:hover,
|
|
107
|
-
a:focus-visible
|
|
108
|
-
a:active {
|
|
107
|
+
a:focus-visible {
|
|
109
108
|
color: var(--color-primary);
|
|
110
109
|
}
|
|
111
110
|
|
|
@@ -366,9 +365,9 @@ h3:before {
|
|
|
366
365
|
Content
|
|
367
366
|
=========================================================================== */
|
|
368
367
|
|
|
369
|
-
.
|
|
370
|
-
gap: var(--slide-gap);
|
|
368
|
+
.overflow-slider {
|
|
371
369
|
margin-top: 1.5rem;
|
|
370
|
+
gap: 1rem;
|
|
372
371
|
}
|
|
373
372
|
|
|
374
373
|
.example-item {
|
|
@@ -486,6 +485,24 @@ h3:before {
|
|
|
486
485
|
scroll-snap-type: x proximity;
|
|
487
486
|
}
|
|
488
487
|
|
|
488
|
+
.example-container-3-entrance-animation a {
|
|
489
|
+
animation: slideEntrance, slideEntrance;
|
|
490
|
+
animation-direction: normal, reverse;
|
|
491
|
+
animation-timeline: view(inline);
|
|
492
|
+
animation-range: entry, exit;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
@keyframes slideEntrance {
|
|
496
|
+
0% {
|
|
497
|
+
transform: scale(.75);
|
|
498
|
+
opacity: 0;
|
|
499
|
+
}
|
|
500
|
+
100% {
|
|
501
|
+
transform: scale(1);
|
|
502
|
+
opacity: 1;
|
|
503
|
+
}
|
|
504
|
+
}
|
|
505
|
+
|
|
489
506
|
.overflow-slider__dots {
|
|
490
507
|
margin-top: 1.5rem;
|
|
491
508
|
}
|
|
@@ -511,3 +528,132 @@ h3:before {
|
|
|
511
528
|
width: 1.625rem !important;
|
|
512
529
|
height: 1.625rem !important;
|
|
513
530
|
}
|
|
531
|
+
|
|
532
|
+
/* ===========================================================================
|
|
533
|
+
Example 4: Filters
|
|
534
|
+
=========================================================================== */
|
|
535
|
+
|
|
536
|
+
.example-4-filters-wrapper {
|
|
537
|
+
display: flex;
|
|
538
|
+
align-items: center;
|
|
539
|
+
gap: .5rem;
|
|
540
|
+
margin-top: 1.5rem;
|
|
541
|
+
position: relative;
|
|
542
|
+
}
|
|
543
|
+
|
|
544
|
+
.example-container-4-filters {
|
|
545
|
+
gap: .75rem;
|
|
546
|
+
margin: 0;
|
|
547
|
+
}
|
|
548
|
+
|
|
549
|
+
.example-4-filters-previous,
|
|
550
|
+
.example-4-filters-next {
|
|
551
|
+
transition: .1s ease-in-out;
|
|
552
|
+
position: absolute;
|
|
553
|
+
top: 0;
|
|
554
|
+
bottom: 0;
|
|
555
|
+
width: var(--example-4-arrow-size);
|
|
556
|
+
display: flex;
|
|
557
|
+
align-items: center;
|
|
558
|
+
background: #fff;
|
|
559
|
+
padding-inline: .5rem;
|
|
560
|
+
}
|
|
561
|
+
|
|
562
|
+
.example-4-filters-previous {
|
|
563
|
+
left: 0;
|
|
564
|
+
}
|
|
565
|
+
|
|
566
|
+
.example-4-filters-next {
|
|
567
|
+
right: 0;
|
|
568
|
+
}
|
|
569
|
+
|
|
570
|
+
.example-4-filters-previous:has([data-has-content="false"]),
|
|
571
|
+
.example-4-filters-next:has([data-has-content="false"]) {
|
|
572
|
+
opacity: 0;
|
|
573
|
+
pointer-events: none;
|
|
574
|
+
visibility: hidden;
|
|
575
|
+
}
|
|
576
|
+
|
|
577
|
+
.example-filter {
|
|
578
|
+
padding: .5rem 1rem;
|
|
579
|
+
border-radius: 2rem;
|
|
580
|
+
background: var(--color-grey-100);
|
|
581
|
+
cursor: pointer;
|
|
582
|
+
color: var(--color-grey-800);
|
|
583
|
+
white-space: nowrap;
|
|
584
|
+
text-decoration: none;
|
|
585
|
+
}
|
|
586
|
+
|
|
587
|
+
.example-filter:hover,
|
|
588
|
+
.example-filter:focus-visible {
|
|
589
|
+
background: var(--color-grey-800);
|
|
590
|
+
color: var(--color-white);
|
|
591
|
+
}
|
|
592
|
+
|
|
593
|
+
/* ===========================================================================
|
|
594
|
+
Example 4: Grid On Desktop
|
|
595
|
+
=========================================================================== */
|
|
596
|
+
|
|
597
|
+
@media (min-width: 768px) {
|
|
598
|
+
.example-container-4-grid-or-slider {
|
|
599
|
+
width: 100%;
|
|
600
|
+
max-width: 100%;
|
|
601
|
+
grid-template-columns: repeat(4, minmax(0, 1fr));
|
|
602
|
+
grid-auto-flow: row;
|
|
603
|
+
overflow: clip;
|
|
604
|
+
}
|
|
605
|
+
|
|
606
|
+
.example-container-4-grid-or-slider .example-item {
|
|
607
|
+
width: 100%;
|
|
608
|
+
}
|
|
609
|
+
}
|
|
610
|
+
|
|
611
|
+
/* ===========================================================================
|
|
612
|
+
Example 4: Full Width
|
|
613
|
+
=========================================================================== */
|
|
614
|
+
|
|
615
|
+
.example-container-4-full-width {
|
|
616
|
+
width: 100vw;
|
|
617
|
+
margin-left: calc(-50vw + 50%);
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
/* ===========================================================================
|
|
621
|
+
Example 4: Synced Sliders
|
|
622
|
+
=========================================================================== */
|
|
623
|
+
|
|
624
|
+
.example-container-4-thumbnails-wrapper {
|
|
625
|
+
|
|
626
|
+
}
|
|
627
|
+
|
|
628
|
+
.example-container-4-synced-main {
|
|
629
|
+
grid-template-columns: repeat(var(--slider-slides-count, 1), var(--slider-container-width, 900px));
|
|
630
|
+
scroll-snap-type: x mandatory;
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
.example-container-4-synced-main .example-item {
|
|
634
|
+
aspect-ratio: 16/8;
|
|
635
|
+
width: 100%;
|
|
636
|
+
max-width: 100%;
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
.example-container-4-synced-thumbnails {
|
|
640
|
+
scroll-snap-type: x proximity;
|
|
641
|
+
}
|
|
642
|
+
|
|
643
|
+
.example-container-4-synced-thumbnails .example-item {
|
|
644
|
+
aspect-ratio: 1/1;
|
|
645
|
+
font-size: 1.5rem;
|
|
646
|
+
width: 120px;
|
|
647
|
+
opacity: .5;
|
|
648
|
+
cursor: pointer;
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
.example-container-4-synced-thumbnails .example-item:hover {
|
|
652
|
+
opacity: .875;
|
|
653
|
+
}
|
|
654
|
+
|
|
655
|
+
.example-container-4-synced-thumbnails .example-item[aria-current="true"] {
|
|
656
|
+
opacity: 1 !important;
|
|
657
|
+
background: var(--color-grey-800);
|
|
658
|
+
color: #fff;
|
|
659
|
+
}
|
package/docs/assets/demo.js
CHANGED
|
@@ -1,11 +1,23 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
/**
|
|
2
|
+
* Hello!
|
|
3
|
+
*
|
|
4
|
+
* This is not how you import files in real project. This is only done this way
|
|
5
|
+
* to make it work with the demo page that cannot import the package from npm.
|
|
6
|
+
*
|
|
7
|
+
* In a real project, you would do something like this:
|
|
8
|
+
*
|
|
9
|
+
* import { OverflowSlider } from '@overflow-slider/core';
|
|
10
|
+
* import DragScrollingPlugin from '@overflow-slider/plugins/drag-scrolling';
|
|
11
|
+
* import SkipLinksPlugin from '@overflow-slider/plugins/skip-links';
|
|
12
|
+
*/
|
|
13
|
+
import { OverflowSlider } from '../dist/index.esm.js';
|
|
14
|
+
import DragScrollingPlugin from '../dist/plugins/drag-scrolling/drag-scrolling/index.esm.js';
|
|
15
|
+
import SkipLinksPlugin from '../dist/plugins/skip-links/skip-links/index.esm.js';
|
|
16
|
+
import ArrowsPlugin from '../dist/plugins/arrows/arrows/index.esm.js';
|
|
17
|
+
import ScrollIndicatorPlugin from '../dist/plugins/scroll-indicator/scroll-indicator/index.esm.js';
|
|
18
|
+
import DotsPlugin from '../dist/plugins/dots/dots/index.esm.js';
|
|
19
|
+
import FullWidthPlugin from '../dist/plugins/full-width/full-width/index.esm.js';
|
|
20
|
+
import ThumbnailsPlugin from '../dist/plugins/thumbnails/thumbnails/index.esm.js';
|
|
9
21
|
|
|
10
22
|
(function () {
|
|
11
23
|
const init = () => {
|
|
@@ -16,14 +28,24 @@ import {
|
|
|
16
28
|
console.log( '1-css', example1CSS );
|
|
17
29
|
|
|
18
30
|
const example1DragScrolling = new OverflowSlider(
|
|
19
|
-
document.querySelector( '.example-container-1-drag-scrolling' ),
|
|
31
|
+
document.querySelector( '.example-container-1-drag-scrolling-clickable' ),
|
|
20
32
|
{},
|
|
21
33
|
[
|
|
22
34
|
DragScrollingPlugin(),
|
|
23
35
|
SkipLinksPlugin(),
|
|
24
36
|
]
|
|
25
37
|
);
|
|
26
|
-
console.log( '1-drag-scrolling', example1DragScrolling );
|
|
38
|
+
console.log( '1-drag-scrolling-clickable', example1DragScrolling );
|
|
39
|
+
|
|
40
|
+
const example1DragScrollingNotClickable = new OverflowSlider(
|
|
41
|
+
document.querySelector( '.example-container-1-drag-scrolling-not-clickable' ),
|
|
42
|
+
{},
|
|
43
|
+
[
|
|
44
|
+
DragScrollingPlugin(),
|
|
45
|
+
SkipLinksPlugin(),
|
|
46
|
+
]
|
|
47
|
+
);
|
|
48
|
+
console.log( '1-drag-scrolling-not-clickable', example1DragScrollingNotClickable );
|
|
27
49
|
|
|
28
50
|
const example1Arrows = new OverflowSlider(
|
|
29
51
|
document.querySelector( '.example-container-1-arrows' ),
|
|
@@ -107,6 +129,81 @@ import {
|
|
|
107
129
|
]
|
|
108
130
|
);
|
|
109
131
|
console.log( '3-scroll-snapping-proximity', example3ScrollSnappingProximity );
|
|
132
|
+
|
|
133
|
+
const example3EntranceAnimation = new OverflowSlider(
|
|
134
|
+
document.querySelector( '.example-container-3-entrance-animation' ),
|
|
135
|
+
{},
|
|
136
|
+
[
|
|
137
|
+
DragScrollingPlugin(),
|
|
138
|
+
ScrollIndicatorPlugin(),
|
|
139
|
+
]
|
|
140
|
+
);
|
|
141
|
+
console.log( '3-entrance-animation', example3EntranceAnimation );
|
|
142
|
+
|
|
143
|
+
const example4Filters = new OverflowSlider(
|
|
144
|
+
document.querySelector( '.example-container-4-filters' ),
|
|
145
|
+
{},
|
|
146
|
+
[
|
|
147
|
+
DragScrollingPlugin(),
|
|
148
|
+
ArrowsPlugin({
|
|
149
|
+
containerPrev: document.querySelector( '.example-4-filters-previous' ),
|
|
150
|
+
containerNext: document.querySelector( '.example-4-filters-next' ),
|
|
151
|
+
})
|
|
152
|
+
]
|
|
153
|
+
);
|
|
154
|
+
console.log( '4-filters', example4Filters );
|
|
155
|
+
|
|
156
|
+
const example4GridOrSliders = new OverflowSlider(
|
|
157
|
+
document.querySelector( '.example-container-4-grid-or-slider' ),
|
|
158
|
+
{},
|
|
159
|
+
[
|
|
160
|
+
DragScrollingPlugin(),
|
|
161
|
+
ScrollIndicatorPlugin(),
|
|
162
|
+
]
|
|
163
|
+
);
|
|
164
|
+
console.log( '4-grid-or-slider', example4GridOrSliders );
|
|
165
|
+
|
|
166
|
+
const example4FullWidth = new OverflowSlider(
|
|
167
|
+
document.querySelector( '.example-container-4-full-width' ),
|
|
168
|
+
{},
|
|
169
|
+
[
|
|
170
|
+
DragScrollingPlugin(),
|
|
171
|
+
FullWidthPlugin(
|
|
172
|
+
{
|
|
173
|
+
targetWidth: (slider) => {
|
|
174
|
+
// copy the width of the parent element
|
|
175
|
+
return slider.container.parentElement.clientWidth;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
),
|
|
179
|
+
ScrollIndicatorPlugin(),
|
|
180
|
+
]
|
|
181
|
+
);
|
|
182
|
+
console.log( '4-full-width', example4FullWidth );
|
|
183
|
+
|
|
184
|
+
const example4SyncedMain = new OverflowSlider(
|
|
185
|
+
document.querySelector( '.example-container-4-synced-main' ),
|
|
186
|
+
{},
|
|
187
|
+
[
|
|
188
|
+
DragScrollingPlugin(),
|
|
189
|
+
]
|
|
190
|
+
);
|
|
191
|
+
console.log( '4-synced-main', example4SyncedMain );
|
|
192
|
+
|
|
193
|
+
const example4SyncedThumbnails = new OverflowSlider(
|
|
194
|
+
document.querySelector( '.example-container-4-synced-thumbnails' ),
|
|
195
|
+
{},
|
|
196
|
+
[
|
|
197
|
+
DragScrollingPlugin(),
|
|
198
|
+
ThumbnailsPlugin({
|
|
199
|
+
mainSlider: example4SyncedMain,
|
|
200
|
+
}),
|
|
201
|
+
]
|
|
202
|
+
);
|
|
203
|
+
console.log( '4-synced-thumbnails', example4SyncedThumbnails );
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
|
|
110
207
|
};
|
|
111
208
|
|
|
112
209
|
init();
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
function details(slider) {
|
|
2
|
+
var _a;
|
|
3
|
+
let instance;
|
|
4
|
+
let hasOverflow = false;
|
|
5
|
+
let slideCount = 0;
|
|
6
|
+
let containerWidth = 0;
|
|
7
|
+
let scrollableAreaWidth = 0;
|
|
8
|
+
let amountOfPages = 0;
|
|
9
|
+
let currentPage = 1;
|
|
10
|
+
if (slider.container.scrollWidth > slider.container.clientWidth) {
|
|
11
|
+
hasOverflow = true;
|
|
12
|
+
}
|
|
13
|
+
slideCount = (_a = slider.slides.length) !== null && _a !== void 0 ? _a : 0;
|
|
14
|
+
containerWidth = slider.container.offsetWidth;
|
|
15
|
+
scrollableAreaWidth = slider.container.scrollWidth;
|
|
16
|
+
amountOfPages = Math.ceil(scrollableAreaWidth / containerWidth);
|
|
17
|
+
if (slider.container.scrollLeft >= 0) {
|
|
18
|
+
currentPage = Math.floor(slider.container.scrollLeft / containerWidth);
|
|
19
|
+
// consider as last page if the scrollLeft + containerWidth is equal to scrollWidth
|
|
20
|
+
if (slider.container.scrollLeft + containerWidth === scrollableAreaWidth) {
|
|
21
|
+
currentPage = amountOfPages - 1;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
instance = {
|
|
25
|
+
hasOverflow,
|
|
26
|
+
slideCount,
|
|
27
|
+
containerWidth,
|
|
28
|
+
scrollableAreaWidth,
|
|
29
|
+
amountOfPages,
|
|
30
|
+
currentPage,
|
|
31
|
+
};
|
|
32
|
+
return instance;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
export { details as default };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function t(t){var e;let n,l=!1,o=0,r=0,i=0,a=0,c=1;return t.container.scrollWidth>t.container.clientWidth&&(l=!0),o=null!==(e=t.slides.length)&&void 0!==e?e:0,r=t.container.offsetWidth,i=t.container.scrollWidth,a=Math.ceil(i/r),t.container.scrollLeft>=0&&(c=Math.floor(t.container.scrollLeft/r),t.container.scrollLeft+r===i&&(c=a-1)),n={hasOverflow:l,slideCount:o,containerWidth:r,scrollableAreaWidth:i,amountOfPages:a,currentPage:c},n}export{t as default};
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import Slider from './slider.esm.js';
|
|
2
|
+
|
|
3
|
+
function OverflowSlider(container, options, plugins) {
|
|
4
|
+
try {
|
|
5
|
+
// check that container HTML element
|
|
6
|
+
if (!(container instanceof Element)) {
|
|
7
|
+
throw new Error(`Container must be HTML element, found ${typeof container}`);
|
|
8
|
+
}
|
|
9
|
+
const defaults = {
|
|
10
|
+
scrollBehavior: "smooth",
|
|
11
|
+
scrollStrategy: "fullSlide",
|
|
12
|
+
slidesSelector: ":scope > *",
|
|
13
|
+
};
|
|
14
|
+
const sliderOptions = Object.assign(Object.assign({}, defaults), options);
|
|
15
|
+
// disable smooth scrolling if user prefers reduced motion
|
|
16
|
+
if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
|
|
17
|
+
sliderOptions.scrollBehavior = "auto";
|
|
18
|
+
}
|
|
19
|
+
return Slider(container, sliderOptions, plugins);
|
|
20
|
+
}
|
|
21
|
+
catch (e) {
|
|
22
|
+
console.error(e);
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
export { OverflowSlider as default };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import e from"./slider.min.js";function o(o,r,t){try{if(!(o instanceof Element))throw new Error("Container must be HTML element, found "+typeof o);const s={scrollBehavior:"smooth",scrollStrategy:"fullSlide",slidesSelector:":scope > *"},n=Object.assign(Object.assign({},s),r);return window.matchMedia("(prefers-reduced-motion: reduce)").matches&&(n.scrollBehavior="auto"),e(o,n,t)}catch(e){console.error(e)}}export{o as default};
|
|
@@ -0,0 +1,260 @@
|
|
|
1
|
+
import details from './details.esm.js';
|
|
2
|
+
import { generateId, objectsAreEqual } from './utils.esm.js';
|
|
3
|
+
|
|
4
|
+
function Slider(container, options, plugins) {
|
|
5
|
+
let slider;
|
|
6
|
+
let subs = {};
|
|
7
|
+
function init() {
|
|
8
|
+
slider.container = container;
|
|
9
|
+
// ensure container has id
|
|
10
|
+
let containerId = container.getAttribute('id');
|
|
11
|
+
if (containerId === null) {
|
|
12
|
+
containerId = generateId('overflow-slider');
|
|
13
|
+
container.setAttribute('id', containerId);
|
|
14
|
+
}
|
|
15
|
+
setSlides();
|
|
16
|
+
setDetails(true);
|
|
17
|
+
setActiveSlideIdx();
|
|
18
|
+
slider.on('contentsChanged', () => {
|
|
19
|
+
setSlides();
|
|
20
|
+
setDetails();
|
|
21
|
+
setActiveSlideIdx();
|
|
22
|
+
});
|
|
23
|
+
slider.on('containerSizeChanged', () => setDetails());
|
|
24
|
+
let requestId = 0;
|
|
25
|
+
const setDetailsDebounce = () => {
|
|
26
|
+
if (requestId) {
|
|
27
|
+
window.cancelAnimationFrame(requestId);
|
|
28
|
+
}
|
|
29
|
+
requestId = window.requestAnimationFrame(() => {
|
|
30
|
+
setDetails();
|
|
31
|
+
setActiveSlideIdx();
|
|
32
|
+
});
|
|
33
|
+
};
|
|
34
|
+
slider.on('scroll', setDetailsDebounce);
|
|
35
|
+
addEventListeners();
|
|
36
|
+
setDataAttributes();
|
|
37
|
+
setCSSVariables();
|
|
38
|
+
if (plugins) {
|
|
39
|
+
for (const plugin of plugins) {
|
|
40
|
+
plugin(slider);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
slider.on('detailsChanged', () => {
|
|
44
|
+
setDataAttributes();
|
|
45
|
+
setCSSVariables();
|
|
46
|
+
});
|
|
47
|
+
slider.emit('created');
|
|
48
|
+
slider.container.setAttribute('data-ready', 'true');
|
|
49
|
+
}
|
|
50
|
+
function setDetails(isInit = false) {
|
|
51
|
+
const oldDetails = slider.details;
|
|
52
|
+
const newDetails = details(slider);
|
|
53
|
+
slider.details = newDetails;
|
|
54
|
+
if (!isInit && !objectsAreEqual(oldDetails, newDetails)) {
|
|
55
|
+
slider.emit('detailsChanged');
|
|
56
|
+
}
|
|
57
|
+
else if (isInit) {
|
|
58
|
+
slider.emit('detailsChanged');
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
function setSlides() {
|
|
62
|
+
slider.slides = Array.from(slider.container.querySelectorAll(slider.options.slidesSelector));
|
|
63
|
+
}
|
|
64
|
+
function addEventListeners() {
|
|
65
|
+
// changes to DOM
|
|
66
|
+
const observer = new MutationObserver(() => slider.emit('contentsChanged'));
|
|
67
|
+
observer.observe(slider.container, { childList: true });
|
|
68
|
+
// container size changes
|
|
69
|
+
const resizeObserver = new ResizeObserver(() => slider.emit('containerSizeChanged'));
|
|
70
|
+
resizeObserver.observe(slider.container);
|
|
71
|
+
// scroll event with debouncing
|
|
72
|
+
slider.container.addEventListener('scroll', () => slider.emit('scroll'));
|
|
73
|
+
// Listen for mouse down and touch start events on the document
|
|
74
|
+
// This handles both mouse clicks and touch interactions
|
|
75
|
+
let wasInteractedWith = false;
|
|
76
|
+
slider.container.addEventListener('mousedown', () => {
|
|
77
|
+
wasInteractedWith = true;
|
|
78
|
+
});
|
|
79
|
+
slider.container.addEventListener('touchstart', () => {
|
|
80
|
+
wasInteractedWith = true;
|
|
81
|
+
}, { passive: true });
|
|
82
|
+
slider.container.addEventListener('focusin', (e) => {
|
|
83
|
+
// move target parents as long as they are not the container
|
|
84
|
+
// but only if focus didn't start from mouse or touch
|
|
85
|
+
if (!wasInteractedWith) {
|
|
86
|
+
let target = e.target;
|
|
87
|
+
while (target.parentElement !== slider.container) {
|
|
88
|
+
if (target.parentElement) {
|
|
89
|
+
target = target.parentElement;
|
|
90
|
+
}
|
|
91
|
+
else {
|
|
92
|
+
break;
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
ensureSlideIsInView(target);
|
|
96
|
+
}
|
|
97
|
+
wasInteractedWith = false;
|
|
98
|
+
});
|
|
99
|
+
}
|
|
100
|
+
function setCSSVariables() {
|
|
101
|
+
slider.container.style.setProperty('--slider-container-width', `${slider.details.containerWidth}px`);
|
|
102
|
+
slider.container.style.setProperty('--slider-scrollable-width', `${slider.details.scrollableAreaWidth}px`);
|
|
103
|
+
slider.container.style.setProperty('--slider-slides-count', `${slider.details.slideCount}`);
|
|
104
|
+
}
|
|
105
|
+
function setDataAttributes() {
|
|
106
|
+
slider.container.setAttribute('data-has-overflow', slider.details.hasOverflow ? 'true' : 'false');
|
|
107
|
+
}
|
|
108
|
+
function ensureSlideIsInView(slide) {
|
|
109
|
+
const slideRect = slide.getBoundingClientRect();
|
|
110
|
+
const sliderRect = slider.container.getBoundingClientRect();
|
|
111
|
+
const containerWidth = slider.container.offsetWidth;
|
|
112
|
+
const scrollLeft = slider.container.scrollLeft;
|
|
113
|
+
const slideStart = slideRect.left - sliderRect.left + scrollLeft;
|
|
114
|
+
const slideEnd = slideStart + slideRect.width;
|
|
115
|
+
let scrollTarget = null;
|
|
116
|
+
if (slideStart < scrollLeft) {
|
|
117
|
+
scrollTarget = slideStart;
|
|
118
|
+
}
|
|
119
|
+
else if (slideEnd > scrollLeft + containerWidth) {
|
|
120
|
+
scrollTarget = slideEnd - containerWidth;
|
|
121
|
+
}
|
|
122
|
+
else if (slideStart === 0) {
|
|
123
|
+
scrollTarget = 0;
|
|
124
|
+
}
|
|
125
|
+
if (scrollTarget !== null) {
|
|
126
|
+
slider.container.style.scrollSnapType = 'none';
|
|
127
|
+
slider.container.scrollLeft = scrollTarget;
|
|
128
|
+
// @todo resume scroll snapping but at least proximity gives a lot of trouble
|
|
129
|
+
// and it's not really needed for this use case but it would be nice to have
|
|
130
|
+
// it back in case it's needed. We need to calculate scrollLeft some other way
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
function setActiveSlideIdx() {
|
|
134
|
+
const sliderRect = slider.container.getBoundingClientRect();
|
|
135
|
+
const scrollLeft = slider.container.scrollLeft;
|
|
136
|
+
const slides = slider.slides;
|
|
137
|
+
let activeSlideIdx = 0;
|
|
138
|
+
for (let i = 0; i < slides.length; i++) {
|
|
139
|
+
const slideRect = slides[i].getBoundingClientRect();
|
|
140
|
+
const slideStart = slideRect.left - sliderRect.left + scrollLeft + getGapSize();
|
|
141
|
+
if (slideStart > scrollLeft) {
|
|
142
|
+
activeSlideIdx = i;
|
|
143
|
+
break;
|
|
144
|
+
}
|
|
145
|
+
}
|
|
146
|
+
const oldActiveSlideIdx = slider.activeSlideIdx;
|
|
147
|
+
slider.activeSlideIdx = activeSlideIdx;
|
|
148
|
+
if (oldActiveSlideIdx !== activeSlideIdx) {
|
|
149
|
+
slider.emit('activeSlideChanged');
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
function moveToSlide(idx) {
|
|
153
|
+
const slide = slider.slides[idx];
|
|
154
|
+
if (slide) {
|
|
155
|
+
ensureSlideIsInView(slide);
|
|
156
|
+
}
|
|
157
|
+
}
|
|
158
|
+
function getGapSize() {
|
|
159
|
+
let gapSize = 0;
|
|
160
|
+
if (slider.slides.length > 1) {
|
|
161
|
+
const firstSlideRect = slider.slides[0].getBoundingClientRect();
|
|
162
|
+
const secondSlideRect = slider.slides[1].getBoundingClientRect();
|
|
163
|
+
gapSize = secondSlideRect.left - firstSlideRect.right;
|
|
164
|
+
}
|
|
165
|
+
return gapSize;
|
|
166
|
+
}
|
|
167
|
+
function moveToDirection(direction = "prev") {
|
|
168
|
+
const scrollStrategy = slider.options.scrollStrategy;
|
|
169
|
+
const scrollLeft = slider.container.scrollLeft;
|
|
170
|
+
const sliderRect = slider.container.getBoundingClientRect();
|
|
171
|
+
const containerWidth = slider.container.offsetWidth;
|
|
172
|
+
let targetScrollPosition = scrollLeft;
|
|
173
|
+
if (direction === 'prev') {
|
|
174
|
+
targetScrollPosition = Math.max(0, scrollLeft - slider.container.offsetWidth);
|
|
175
|
+
}
|
|
176
|
+
else if (direction === 'next') {
|
|
177
|
+
targetScrollPosition = Math.min(slider.container.scrollWidth, scrollLeft + slider.container.offsetWidth);
|
|
178
|
+
}
|
|
179
|
+
if (scrollStrategy === 'fullSlide') {
|
|
180
|
+
let fullSldeTargetScrollPosition = null;
|
|
181
|
+
// extend targetScrollPosition to include gap
|
|
182
|
+
if (direction === 'prev') {
|
|
183
|
+
fullSldeTargetScrollPosition = Math.max(0, targetScrollPosition - getGapSize());
|
|
184
|
+
}
|
|
185
|
+
else {
|
|
186
|
+
fullSldeTargetScrollPosition = Math.min(slider.container.scrollWidth, targetScrollPosition + getGapSize());
|
|
187
|
+
}
|
|
188
|
+
if (direction === 'next') {
|
|
189
|
+
let partialSlideFound = false;
|
|
190
|
+
for (let slide of slider.slides) {
|
|
191
|
+
const slideRect = slide.getBoundingClientRect();
|
|
192
|
+
const slideStart = slideRect.left - sliderRect.left + scrollLeft;
|
|
193
|
+
const slideEnd = slideStart + slideRect.width;
|
|
194
|
+
if (slideStart < targetScrollPosition && slideEnd > targetScrollPosition) {
|
|
195
|
+
fullSldeTargetScrollPosition = slideStart;
|
|
196
|
+
partialSlideFound = true;
|
|
197
|
+
break;
|
|
198
|
+
}
|
|
199
|
+
}
|
|
200
|
+
if (!partialSlideFound) {
|
|
201
|
+
fullSldeTargetScrollPosition = Math.min(targetScrollPosition, slider.container.scrollWidth - slider.container.offsetWidth);
|
|
202
|
+
}
|
|
203
|
+
if (fullSldeTargetScrollPosition && fullSldeTargetScrollPosition > scrollLeft) {
|
|
204
|
+
targetScrollPosition = fullSldeTargetScrollPosition;
|
|
205
|
+
}
|
|
206
|
+
}
|
|
207
|
+
else {
|
|
208
|
+
let partialSlideFound = false;
|
|
209
|
+
for (let slide of slider.slides) {
|
|
210
|
+
const slideRect = slide.getBoundingClientRect();
|
|
211
|
+
const slideStart = slideRect.left - sliderRect.left + scrollLeft;
|
|
212
|
+
const slideEnd = slideStart + slideRect.width;
|
|
213
|
+
if (slideStart < scrollLeft && slideEnd > scrollLeft) {
|
|
214
|
+
fullSldeTargetScrollPosition = slideEnd - containerWidth;
|
|
215
|
+
partialSlideFound = true;
|
|
216
|
+
break;
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
if (!partialSlideFound) {
|
|
220
|
+
fullSldeTargetScrollPosition = Math.max(0, scrollLeft - containerWidth);
|
|
221
|
+
}
|
|
222
|
+
if (fullSldeTargetScrollPosition && fullSldeTargetScrollPosition < scrollLeft) {
|
|
223
|
+
targetScrollPosition = fullSldeTargetScrollPosition;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
slider.container.style.scrollBehavior = slider.options.scrollBehavior;
|
|
228
|
+
slider.container.scrollLeft = targetScrollPosition;
|
|
229
|
+
setTimeout(() => slider.container.style.scrollBehavior = '', 50);
|
|
230
|
+
}
|
|
231
|
+
function on(name, cb) {
|
|
232
|
+
if (!subs[name]) {
|
|
233
|
+
subs[name] = [];
|
|
234
|
+
}
|
|
235
|
+
subs[name].push(cb);
|
|
236
|
+
}
|
|
237
|
+
function emit(name) {
|
|
238
|
+
var _a;
|
|
239
|
+
if (subs && subs[name]) {
|
|
240
|
+
subs[name].forEach(cb => {
|
|
241
|
+
cb(slider);
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
const optionCallBack = (_a = slider === null || slider === void 0 ? void 0 : slider.options) === null || _a === void 0 ? void 0 : _a[name];
|
|
245
|
+
if (typeof optionCallBack === 'function') {
|
|
246
|
+
optionCallBack(slider);
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
slider = {
|
|
250
|
+
emit,
|
|
251
|
+
moveToDirection,
|
|
252
|
+
moveToSlide,
|
|
253
|
+
on,
|
|
254
|
+
options,
|
|
255
|
+
};
|
|
256
|
+
init();
|
|
257
|
+
return slider;
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
export { Slider as default };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import e from"./details.min.js";import{generateId as t,objectsAreEqual as n}from"./utils.min.js";function i(i,o,l){let r,s={};function a(t=!1){const i=r.details,o=e(r);r.details=o,t||n(i,o)?t&&r.emit("detailsChanged"):r.emit("detailsChanged")}function c(){r.slides=Array.from(r.container.querySelectorAll(r.options.slidesSelector))}function d(){r.container.style.setProperty("--slider-container-width",`${r.details.containerWidth}px`),r.container.style.setProperty("--slider-scrollable-width",`${r.details.scrollableAreaWidth}px`),r.container.style.setProperty("--slider-slides-count",`${r.details.slideCount}`)}function f(){r.container.setAttribute("data-has-overflow",r.details.hasOverflow?"true":"false")}function u(e){const t=e.getBoundingClientRect(),n=r.container.getBoundingClientRect(),i=r.container.offsetWidth,o=r.container.scrollLeft,l=t.left-n.left+o,s=l+t.width;let a=null;l<o?a=l:s>o+i?a=s-i:0===l&&(a=0),null!==a&&(r.container.style.scrollSnapType="none",r.container.scrollLeft=a)}function h(){const e=r.container.getBoundingClientRect(),t=r.container.scrollLeft,n=r.slides;let i=0;for(let o=0;o<n.length;o++){if(n[o].getBoundingClientRect().left-e.left+t+g()>t){i=o;break}}const o=r.activeSlideIdx;r.activeSlideIdx=i,o!==i&&r.emit("activeSlideChanged")}function g(){let e=0;if(r.slides.length>1){const t=r.slides[0].getBoundingClientRect();e=r.slides[1].getBoundingClientRect().left-t.right}return e}return r={emit:function(e){var t;s&&s[e]&&s[e].forEach((e=>{e(r)}));const n=null===(t=null==r?void 0:r.options)||void 0===t?void 0:t[e];"function"==typeof n&&n(r)},moveToDirection:function(e="prev"){const t=r.options.scrollStrategy,n=r.container.scrollLeft,i=r.container.getBoundingClientRect(),o=r.container.offsetWidth;let l=n;if("prev"===e?l=Math.max(0,n-r.container.offsetWidth):"next"===e&&(l=Math.min(r.container.scrollWidth,n+r.container.offsetWidth)),"fullSlide"===t){let t=null;if(t="prev"===e?Math.max(0,l-g()):Math.min(r.container.scrollWidth,l+g()),"next"===e){let e=!1;for(let o of r.slides){const r=o.getBoundingClientRect(),s=r.left-i.left+n,a=s+r.width;if(s<l&&a>l){t=s,e=!0;break}}e||(t=Math.min(l,r.container.scrollWidth-r.container.offsetWidth)),t&&t>n&&(l=t)}else{let e=!1;for(let l of r.slides){const r=l.getBoundingClientRect(),s=r.left-i.left+n,a=s+r.width;if(s<n&&a>n){t=a-o,e=!0;break}}e||(t=Math.max(0,n-o)),t&&t<n&&(l=t)}}r.container.style.scrollBehavior=r.options.scrollBehavior,r.container.scrollLeft=l,setTimeout((()=>r.container.style.scrollBehavior=""),50)},moveToSlide:function(e){const t=r.slides[e];t&&u(t)},on:function(e,t){s[e]||(s[e]=[]),s[e].push(t)},options:o},function(){r.container=i;let e=i.getAttribute("id");null===e&&(e=t("overflow-slider"),i.setAttribute("id",e)),c(),a(!0),h(),r.on("contentsChanged",(()=>{c(),a(),h()})),r.on("containerSizeChanged",(()=>a()));let n=0;if(r.on("scroll",(()=>{n&&window.cancelAnimationFrame(n),n=window.requestAnimationFrame((()=>{a(),h()}))})),function(){new MutationObserver((()=>r.emit("contentsChanged"))).observe(r.container,{childList:!0});new ResizeObserver((()=>r.emit("containerSizeChanged"))).observe(r.container),r.container.addEventListener("scroll",(()=>r.emit("scroll")));let e=!1;r.container.addEventListener("mousedown",(()=>{e=!0})),r.container.addEventListener("touchstart",(()=>{e=!0}),{passive:!0}),r.container.addEventListener("focusin",(t=>{if(!e){let e=t.target;for(;e.parentElement!==r.container&&e.parentElement;)e=e.parentElement;u(e)}e=!1}))}(),f(),d(),l)for(const e of l)e(r);r.on("detailsChanged",(()=>{f(),d()})),r.emit("created"),r.container.setAttribute("data-ready","true")}(),r}export{i as default};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
function generateId(prefix, i = 1) {
|
|
2
|
+
const id = `${prefix}-${i}`;
|
|
3
|
+
if (document.getElementById(id)) {
|
|
4
|
+
return generateId(prefix, i + 1);
|
|
5
|
+
}
|
|
6
|
+
return id;
|
|
7
|
+
}
|
|
8
|
+
function objectsAreEqual(obj1, obj2) {
|
|
9
|
+
const keys1 = Object.keys(obj1);
|
|
10
|
+
const keys2 = Object.keys(obj2);
|
|
11
|
+
if (keys1.length !== keys2.length) {
|
|
12
|
+
return false;
|
|
13
|
+
}
|
|
14
|
+
for (let key of keys1) {
|
|
15
|
+
if (obj2.hasOwnProperty(key) === false || obj1[key] !== obj2[key]) {
|
|
16
|
+
return false;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
return true;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export { generateId, objectsAreEqual };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
function t(e,n=1){const r=`${e}-${n}`;return document.getElementById(r)?t(e,n+1):r}function e(t,e){const n=Object.keys(t),r=Object.keys(e);if(n.length!==r.length)return!1;for(let r of n)if(!1===e.hasOwnProperty(r)||t[r]!==e[r])return!1;return!0}export{t as generateId,e as objectsAreEqual};
|