@natachah/vanilla-frontend 0.1.14 → 0.1.15
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/docs/main.js +3 -1
- package/docs/pages/components/drawer.html +5 -1
- package/docs/pages/components/slider.html +62 -85
- package/docs/src/js/demo.js +11 -4
- package/docs/src/js/doc-layout.js +1 -1
- package/js/_drawer.js +33 -25
- package/js/_slider.js +122 -141
- package/js/tests/slider.test.js +50 -96
- package/natachah-vanilla-frontend-0.1.15.tgz +0 -0
- package/package.json +1 -1
- package/scss/components/_slider.scss +8 -7
- package/natachah-vanilla-frontend-0.1.14.tgz +0 -0
package/docs/main.js
CHANGED
|
@@ -24,7 +24,9 @@ if (current.startsWith('/pages/')) document.querySelectorAll(`#sidebar a[href*="
|
|
|
24
24
|
// My awsome sidebar !!!
|
|
25
25
|
import Drawer from './../js/_drawer.js'
|
|
26
26
|
const sidebar = document.getElementById('sidebar')
|
|
27
|
-
if (sidebar) new Drawer(sidebar
|
|
27
|
+
if (sidebar) new Drawer(sidebar, {
|
|
28
|
+
cookie: 'demo-confort'
|
|
29
|
+
})
|
|
28
30
|
|
|
29
31
|
// Code group
|
|
30
32
|
import Tabpanel from './../js/_tabpanel.js'
|
|
@@ -57,7 +57,7 @@
|
|
|
57
57
|
<doc-code id="js" data-type="js" role="tabpanel">
|
|
58
58
|
import Drawer from '@natachah/vanilla-frontend/js/utilities/_drawer.js'
|
|
59
59
|
const drawer = document.getElementById('drawer')
|
|
60
|
-
if (drawer) new Drawer(drawer, { breakpoint : 960 })
|
|
60
|
+
if (drawer) new Drawer(drawer, { breakpoint : 960, cookie: 'name-of-my-cookie' })
|
|
61
61
|
</doc-code>
|
|
62
62
|
</div>
|
|
63
63
|
|
|
@@ -114,6 +114,10 @@
|
|
|
114
114
|
<p>This documentation use the drawer as an exemple for the sidebar on the left !</p>
|
|
115
115
|
</blockquote>
|
|
116
116
|
|
|
117
|
+
<blockquote class="warning">
|
|
118
|
+
<p>If your website use the <b>Comfort</b> JS component, you should use the same cookie name for both as it will combine the values.</p>
|
|
119
|
+
</blockquote>
|
|
120
|
+
|
|
117
121
|
</doc-layout>
|
|
118
122
|
<script type="module" src="/main.js"></script>
|
|
119
123
|
</body>
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
<p>The slider is using the a <code><div></code> tag with the class <code>.slider</code>.</p>
|
|
15
15
|
<p>Each slide must be a <code><div></code> with <code>role="tabpanel"</code> and <code>aria-hidden="true"</code> attributes.</p>
|
|
16
16
|
<doc-demo>
|
|
17
|
-
<div id="
|
|
17
|
+
<div id="sliderFull" class="slider demo-slider">
|
|
18
18
|
<div id="slide1" role="tabpanel" aria-hidden="false"><img src="https://fakeimg.pl/760x506/?text=one" alt="Image 1"></div>
|
|
19
19
|
<div id="slide2" role="tabpanel" aria-hidden="true"><img src="https://fakeimg.pl/760x506/?text=two" alt="Image 2"></div>
|
|
20
20
|
<div id="slide3" role="tabpanel" aria-hidden="true"><img src="https://fakeimg.pl/760x506/?text=three" alt="Image 3"></div>
|
|
@@ -22,15 +22,25 @@
|
|
|
22
22
|
<div id="slide5" role="tabpanel" aria-hidden="true"><img src="https://fakeimg.pl/760x506/?text=five" alt="Image 5"></div>
|
|
23
23
|
<div id="slide6" role="tabpanel" aria-hidden="true"><img src="https://fakeimg.pl/760x506/?text=six" alt="Image 6"></div>
|
|
24
24
|
</div>
|
|
25
|
+
<button aria-controls="sliderFull" data-slider-prev>previous</button>
|
|
26
|
+
<div aria-controls="sliderFull" role="tablist">
|
|
27
|
+
<button role="tab" aria-controls="slide1" aria-selected="true">1</button>
|
|
28
|
+
<button role="tab" aria-controls="slide2" aria-selected="false">2</button>
|
|
29
|
+
<button role="tab" aria-controls="slide3" aria-selected="false">3</button>
|
|
30
|
+
<button role="tab" aria-controls="slide4" aria-selected="false">4</button>
|
|
31
|
+
<button role="tab" aria-controls="slide5" aria-selected="false">5</button>
|
|
32
|
+
<button role="tab" aria-controls="slide6" aria-selected="false">6</button>
|
|
33
|
+
</div>
|
|
34
|
+
<button aria-controls="sliderFull" data-slider-next>next</button>
|
|
25
35
|
</doc-demo>
|
|
26
36
|
<div class="code-group">
|
|
27
37
|
<div role="tablist">
|
|
28
|
-
<button role="tab" aria-controls="html">HTML</button>
|
|
38
|
+
<button role="tab" aria-controls="html" aria-selected="true">HTML</button>
|
|
29
39
|
<button role="tab" aria-controls="scss">SCSS</button>
|
|
30
40
|
<button role="tab" aria-controls="css">CSS</button>
|
|
31
41
|
<button role="tab" aria-controls="js">JS</button>
|
|
32
42
|
</div>
|
|
33
|
-
<doc-code id="html" data-type="html" role="tabpanel">
|
|
43
|
+
<doc-code id="html" data-type="html" role="tabpanel" aria-hidden="false">
|
|
34
44
|
<div id="slider" class="slider">
|
|
35
45
|
<div id="slide1" role="tabpanel" aria-hidden="false"><img src="https://fakeimg.pl/760x506/?text=one" alt="Image 1"></div>
|
|
36
46
|
<div id="slide2" role="tabpanel" aria-hidden="true"><img src="https://fakeimg.pl/760x506/?text=two" alt="Image 2"></div>
|
|
@@ -39,6 +49,16 @@
|
|
|
39
49
|
<div id="slide5" role="tabpanel" aria-hidden="true"><img src="https://fakeimg.pl/760x506/?text=five" alt="Image 5"></div>
|
|
40
50
|
<div id="slide6" role="tabpanel" aria-hidden="true"><img src="https://fakeimg.pl/760x506/?text=six" alt="Image 6"></div>
|
|
41
51
|
</div>
|
|
52
|
+
<button aria-controls="slider" data-slider-prev>previous</button>
|
|
53
|
+
<div aria-controls="slider" role="tablist">
|
|
54
|
+
<button role="tab" aria-controls="slide1" aria-selected="true">1</button>
|
|
55
|
+
<button role="tab" aria-controls="slide2" aria-selected="false">2</button>
|
|
56
|
+
<button role="tab" aria-controls="slide3" aria-selected="false">3</button>
|
|
57
|
+
<button role="tab" aria-controls="slide4" aria-selected="false">4</button>
|
|
58
|
+
<button role="tab" aria-controls="slide5" aria-selected="false">5</button>
|
|
59
|
+
<button role="tab" aria-controls="slide6" aria-selected="false">6</button>
|
|
60
|
+
</div>
|
|
61
|
+
<button aria-controls="slider" data-slider-next>next</button>
|
|
42
62
|
</doc-code>
|
|
43
63
|
<doc-code id="scss" data-type="scss" role="tabpanel">
|
|
44
64
|
@use '@natachah/vanilla-frontend/scss/components/slider';
|
|
@@ -50,31 +70,14 @@
|
|
|
50
70
|
<doc-code id="js" data-type="js" role="tabpanel">
|
|
51
71
|
import Slider from "@natachah/vanilla-frontend/js/_slider"
|
|
52
72
|
const slider = document.getElementById('slider')
|
|
53
|
-
if (slider) const mySliderObj = new Slider(
|
|
73
|
+
if (slider) const mySliderObj = new Slider(slider, {loop: true})
|
|
54
74
|
</doc-code>
|
|
55
75
|
</div>
|
|
56
76
|
|
|
57
77
|
<h2>Indicators</h2>
|
|
58
78
|
<p>You can create some indicators with a <code><div></code> tag with the <code>aria-controls="IdOfSlider"</code> and <code>role="tablist"</code> attributes.</p>
|
|
59
79
|
<p>Inside you must insert each slides indicators as <code><button></code> tag with <code>role="tab"</code>, <code>aria-controls="IdOfSlide"</code> and <code>aria-selected="false"</code> attributes.</p>
|
|
60
|
-
|
|
61
|
-
<div id="sliderTabs" class="slider demo-slider">
|
|
62
|
-
<div id="slide1" role="tabpanel" aria-hidden="false"><img src="https://fakeimg.pl/760x506/?text=one" alt="Image 1"></div>
|
|
63
|
-
<div id="slide2" role="tabpanel" aria-hidden="true"><img src="https://fakeimg.pl/760x506/?text=two" alt="Image 2"></div>
|
|
64
|
-
<div id="slide3" role="tabpanel" aria-hidden="true"><img src="https://fakeimg.pl/760x506/?text=three" alt="Image 3"></div>
|
|
65
|
-
<div id="slide4" role="tabpanel" aria-hidden="true"><img src="https://fakeimg.pl/760x506/?text=four" alt="Image 4"></div>
|
|
66
|
-
<div id="slide5" role="tabpanel" aria-hidden="true"><img src="https://fakeimg.pl/760x506/?text=five" alt="Image 5"></div>
|
|
67
|
-
<div id="slide6" role="tabpanel" aria-hidden="true"><img src="https://fakeimg.pl/760x506/?text=six" alt="Image 6"></div>
|
|
68
|
-
</div>
|
|
69
|
-
<div aria-controls="sliderTabs" role="tablist">
|
|
70
|
-
<button role="tab" aria-controls="slide1" aria-selected="true">1</button>
|
|
71
|
-
<button role="tab" aria-controls="slide2" aria-selected="false">2</button>
|
|
72
|
-
<button role="tab" aria-controls="slide3" aria-selected="false">3</button>
|
|
73
|
-
<button role="tab" aria-controls="slide4" aria-selected="false">4</button>
|
|
74
|
-
<button role="tab" aria-controls="slide5" aria-selected="false">5</button>
|
|
75
|
-
<button role="tab" aria-controls="slide6" aria-selected="false">6</button>
|
|
76
|
-
</div>
|
|
77
|
-
</doc-demo>
|
|
80
|
+
|
|
78
81
|
<doc-code>
|
|
79
82
|
<div aria-controls="slider" role="tablist">
|
|
80
83
|
<button role="tab" aria-controls="slide1" aria-selected="true">1</button>
|
|
@@ -88,18 +91,6 @@
|
|
|
88
91
|
|
|
89
92
|
<h2>Navigation</h2>
|
|
90
93
|
<p>You can create some prev/next navigation with some <code><button></code> tag with the <code>aria-controls="IdOfSlider"</code> and <code>data-slider-prev</code> or <code>data-slider-next</code> attributes.</p>
|
|
91
|
-
<doc-demo>
|
|
92
|
-
<div id="sliderNav" class="slider demo-slider">
|
|
93
|
-
<div id="slide1" role="tabpanel" aria-hidden="false"><img src="https://fakeimg.pl/760x506/?text=one" alt="Image 1"></div>
|
|
94
|
-
<div id="slide2" role="tabpanel" aria-hidden="true"><img src="https://fakeimg.pl/760x506/?text=two" alt="Image 2"></div>
|
|
95
|
-
<div id="slide3" role="tabpanel" aria-hidden="true"><img src="https://fakeimg.pl/760x506/?text=three" alt="Image 3"></div>
|
|
96
|
-
<div id="slide4" role="tabpanel" aria-hidden="true"><img src="https://fakeimg.pl/760x506/?text=four" alt="Image 4"></div>
|
|
97
|
-
<div id="slide5" role="tabpanel" aria-hidden="true"><img src="https://fakeimg.pl/760x506/?text=five" alt="Image 5"></div>
|
|
98
|
-
<div id="slide6" role="tabpanel" aria-hidden="true"><img src="https://fakeimg.pl/760x506/?text=six" alt="Image 6"></div>
|
|
99
|
-
</div>
|
|
100
|
-
<button aria-controls="sliderNav" data-slider-prev>previous</button>
|
|
101
|
-
<button aria-controls="sliderNav" data-slider-next>next</button>
|
|
102
|
-
</doc-demo>
|
|
103
94
|
<doc-code>
|
|
104
95
|
<button aria-controls="slider" data-slider-prev>previous</button>
|
|
105
96
|
<button aria-controls="slider" data-slider-next>next</button>
|
|
@@ -108,14 +99,11 @@
|
|
|
108
99
|
<h2>Variants</h2>
|
|
109
100
|
<h3>Fade effect</h3>
|
|
110
101
|
<p>You can change the CSS and JS to create a sort of fade effect, but it's not optimal.</p>
|
|
111
|
-
<blockquote class="todo">
|
|
112
|
-
<p>This functionality is not working good on mobile and with prev/next arrow.</p>
|
|
113
|
-
</blockquote>
|
|
114
102
|
<doc-demo>
|
|
115
|
-
<div id="sliderFade" class="slider slider-fade-demo">
|
|
116
|
-
<div id="
|
|
117
|
-
<div id="
|
|
118
|
-
<div id="
|
|
103
|
+
<div id="sliderFade" class="slider slider-fade-demo" style="background-image: url(https://fakeimg.pl/760x506/?text=one);">
|
|
104
|
+
<div id="slide1" role="tabpanel" aria-hidden="false"><img src="https://fakeimg.pl/760x506/?text=one" alt="Image 1"></div>
|
|
105
|
+
<div id="slide2" role="tabpanel" aria-hidden="true"><img src="https://fakeimg.pl/760x506/?text=two" alt="Image 2"></div>
|
|
106
|
+
<div id="slide3" role="tabpanel" aria-hidden="true"><img src="https://fakeimg.pl/760x506/?text=three" alt="Image 3"></div>
|
|
119
107
|
</div>
|
|
120
108
|
</doc-demo>
|
|
121
109
|
<div class="code-group">
|
|
@@ -125,29 +113,29 @@
|
|
|
125
113
|
<button role="tab" aria-controls="js">JS</button>
|
|
126
114
|
</div>
|
|
127
115
|
<doc-code id="html" data-type="html" role="tabpanel">
|
|
128
|
-
<div id="
|
|
129
|
-
<div id="
|
|
130
|
-
<div id="
|
|
131
|
-
<div id="
|
|
116
|
+
<div id="sliderFade" class="slider slider-fade-demo" style="background-image: url(https://fakeimg.pl/760x506/?text=one);">
|
|
117
|
+
<div id="slide1" role="tabpanel" aria-hidden="false"><img src="https://fakeimg.pl/760x506/?text=one" alt="Image 1"></div>
|
|
118
|
+
<div id="slide2" role="tabpanel" aria-hidden="true"><img src="https://fakeimg.pl/760x506/?text=two" alt="Image 2"></div>
|
|
119
|
+
<div id="slide3" role="tabpanel" aria-hidden="true"><img src="https://fakeimg.pl/760x506/?text=three" alt="Image 3"></div>
|
|
132
120
|
</div>
|
|
133
121
|
</doc-code>
|
|
134
122
|
<doc-code id="css" data-type="css" role="tabpanel">
|
|
135
123
|
.slider-fade-demo {
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
124
|
+
--image-width: 100%;
|
|
125
|
+
--image-ratio: 4/3;
|
|
126
|
+
background-position: center;
|
|
127
|
+
background-repeat: no-repeat;
|
|
128
|
+
background-size: cover;
|
|
129
|
+
> * {
|
|
130
|
+
transition: all 2s ease-out;
|
|
131
|
+
&[aria-hidden=true] {
|
|
132
|
+
filter: blur(1rem);
|
|
133
|
+
opacity: 0;
|
|
134
|
+
}
|
|
135
|
+
&[aria-hidden=false] {
|
|
136
|
+
opacity: 1;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
151
139
|
}
|
|
152
140
|
</doc-code>
|
|
153
141
|
<doc-code id="js" data-type="js" role="tabpanel">
|
|
@@ -155,16 +143,16 @@
|
|
|
155
143
|
const sliderFade = document.getElementById('mySlider')
|
|
156
144
|
if (sliderFade) {
|
|
157
145
|
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
146
|
+
const mySliderObj = new Slider(sliderFade, {
|
|
147
|
+
behavior: 'instant',
|
|
148
|
+
autoplay: 4000
|
|
149
|
+
})
|
|
162
150
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
151
|
+
sliderFade.addEventListener('slider:changing', (ev) => {
|
|
152
|
+
const currentSlide = mySliderObj._slides[ev.detail.previous]
|
|
153
|
+
const src = currentSlide.querySelector('img').getAttribute('src')
|
|
154
|
+
sliderFade.style.backgroundImage = `url("${src}")`
|
|
155
|
+
})
|
|
168
156
|
|
|
169
157
|
}
|
|
170
158
|
</doc-code>
|
|
@@ -221,9 +209,9 @@
|
|
|
221
209
|
</table>
|
|
222
210
|
<doc-code data-type="js">
|
|
223
211
|
new Slider(mySliderDiv, {
|
|
224
|
-
|
|
225
|
-
|
|
226
|
-
|
|
212
|
+
behavior: 'smooth',
|
|
213
|
+
loop: false,
|
|
214
|
+
autoplay: false
|
|
227
215
|
})
|
|
228
216
|
</doc-code>
|
|
229
217
|
|
|
@@ -273,17 +261,6 @@
|
|
|
273
261
|
</tr>
|
|
274
262
|
</thead>
|
|
275
263
|
<tbody>
|
|
276
|
-
<tr>
|
|
277
|
-
<td data-label="Event">
|
|
278
|
-
<p>slider:changing</p>
|
|
279
|
-
</td>
|
|
280
|
-
<td data-label="Description">
|
|
281
|
-
<p>This event is fired when the slide is changing</p>
|
|
282
|
-
</td>
|
|
283
|
-
<td data-label="Value">
|
|
284
|
-
<p><code>current</code> as a <code>index number</code></p>
|
|
285
|
-
</td>
|
|
286
|
-
</tr>
|
|
287
264
|
<tr>
|
|
288
265
|
<td data-label="Event">
|
|
289
266
|
<p>slider:changed</p>
|
|
@@ -299,8 +276,8 @@
|
|
|
299
276
|
</table>
|
|
300
277
|
<doc-code data-type="js">
|
|
301
278
|
document.getElementById('mySliderId').addEventListener('slider:changed', (e) => {
|
|
302
|
-
|
|
303
|
-
|
|
279
|
+
const theSlide = e.detail.current
|
|
280
|
+
...
|
|
304
281
|
})
|
|
305
282
|
</doc-code>
|
|
306
283
|
|
package/docs/src/js/demo.js
CHANGED
|
@@ -27,17 +27,24 @@ const dropdowns = document.querySelectorAll('.demo-dropdown')
|
|
|
27
27
|
if (dropdowns) dropdowns.forEach(dropdown => new Dropdown(dropdown))
|
|
28
28
|
|
|
29
29
|
import Slider from './../../../js/_slider.js'
|
|
30
|
-
|
|
31
|
-
|
|
30
|
+
//if (sliders) sliders.forEach(slider => new Slider(slider))
|
|
31
|
+
const sliderFull = document.getElementById('sliderFull')
|
|
32
|
+
if (sliderFull) new Slider(sliderFull, {
|
|
33
|
+
//behavior: 'instant',
|
|
34
|
+
loop: true,
|
|
35
|
+
//autoplay: 1500
|
|
36
|
+
})
|
|
32
37
|
|
|
33
38
|
const sliderFade = document.getElementById('sliderFade')
|
|
34
39
|
if (sliderFade) {
|
|
35
40
|
const mySliderObj = new Slider(sliderFade, {
|
|
36
41
|
behavior: 'instant',
|
|
42
|
+
loop: true,
|
|
37
43
|
autoplay: 4000
|
|
38
44
|
})
|
|
39
|
-
sliderFade.addEventListener('slider:
|
|
40
|
-
|
|
45
|
+
sliderFade.addEventListener('slider:changed', (ev) => {
|
|
46
|
+
console.log(ev)
|
|
47
|
+
const src = mySliderObj._slides[ev.detail.previous].querySelector('img').getAttribute('src')
|
|
41
48
|
sliderFade.style.backgroundImage = `url("${src}")`
|
|
42
49
|
})
|
|
43
50
|
}
|
|
@@ -18,7 +18,7 @@ class DocLayout extends HTMLElement {
|
|
|
18
18
|
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" fill="currentColor" class="bi bi-pin-angle" viewBox="0 0 16 16">
|
|
19
19
|
<path d="M9.828.722a.5.5 0 0 1 .354.146l4.95 4.95a.5.5 0 0 1 0 .707c-.48.48-1.072.588-1.503.588-.177 0-.335-.018-.46-.039l-3.134 3.134a6 6 0 0 1 .16 1.013c.046.702-.032 1.687-.72 2.375a.5.5 0 0 1-.707 0l-2.829-2.828-3.182 3.182c-.195.195-1.219.902-1.414.707s.512-1.22.707-1.414l3.182-3.182-2.828-2.829a.5.5 0 0 1 0-.707c.688-.688 1.673-.767 2.375-.72a6 6 0 0 1 1.013.16l3.134-3.133a3 3 0 0 1-.04-.461c0-.43.108-1.022.589-1.503a.5.5 0 0 1 .353-.146m.122 2.112v-.002zm0-.002v.002a.5.5 0 0 1-.122.51L6.293 6.878a.5.5 0 0 1-.511.12H5.78l-.014-.004a5 5 0 0 0-.288-.076 5 5 0 0 0-.765-.116c-.422-.028-.836.008-1.175.15l5.51 5.509c.141-.34.177-.753.149-1.175a5 5 0 0 0-.192-1.054l-.004-.013v-.001a.5.5 0 0 1 .12-.512l3.536-3.535a.5.5 0 0 1 .532-.115l.096.022c.087.017.208.034.344.034q.172.002.343-.04L9.927 2.028q-.042.172-.04.343a1.8 1.8 0 0 0 .062.46z"/>
|
|
20
20
|
</svg>
|
|
21
|
-
0.1.
|
|
21
|
+
0.1.15
|
|
22
22
|
</span>
|
|
23
23
|
</li>
|
|
24
24
|
<li>
|
package/js/_drawer.js
CHANGED
|
@@ -31,6 +31,7 @@ export default class Drawer extends BaseComponent {
|
|
|
31
31
|
constructor(el, options = {}) {
|
|
32
32
|
|
|
33
33
|
if (options.breakpoint && typeof options.breakpoint !== 'number') throw new Error(ErrorMessage.typeOf('options.breakpoint', 'number'))
|
|
34
|
+
if (options.cookie && typeof options.cookie !== 'string') throw new Error(ErrorMessage.typeOf('options.cookie', 'string'))
|
|
34
35
|
|
|
35
36
|
// Run the SUPER constructor from BaseComponent
|
|
36
37
|
super(el, options, 'drawer')
|
|
@@ -60,53 +61,52 @@ export default class Drawer extends BaseComponent {
|
|
|
60
61
|
*/
|
|
61
62
|
#init() {
|
|
62
63
|
|
|
63
|
-
|
|
64
|
+
// Set the cookie by default
|
|
65
|
+
if (this._cookie && !this._cookie.has('drawer-is-open')) this._cookie.set({ ...this._cookie.value, 'drawer-is-open': this._isOpen })
|
|
64
66
|
|
|
65
|
-
//
|
|
66
|
-
|
|
67
|
+
// Define the default state on bigger screen
|
|
68
|
+
const shouldBeOpen = this._cookie ? this._cookie.get('drawer-is-open') : true
|
|
67
69
|
|
|
68
|
-
//
|
|
69
|
-
|
|
70
|
+
// Window is bigger than breakpoint
|
|
71
|
+
// -> Show/Hide the drawer by the cookie
|
|
72
|
+
if (window.innerWidth > this._options.breakpoint) this.toggle(shouldBeOpen)
|
|
70
73
|
|
|
71
|
-
//
|
|
74
|
+
// Window is smaller than breakpoint
|
|
75
|
+
// -> Hide the drawer
|
|
76
|
+
if (window.innerWidth < this._options.breakpoint) this.toggle(false)
|
|
77
|
+
|
|
78
|
+
// On window resize
|
|
79
|
+
// -> Toggle the drawer
|
|
72
80
|
window.onresize = () => {
|
|
73
81
|
clearTimeout(this._timeout)
|
|
74
82
|
this._timeout = setTimeout(() => {
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
83
|
+
|
|
84
|
+
// Bigger than breakpoint
|
|
85
|
+
if (window.innerWidth > this._options.breakpoint && (!this._isOpen && shouldBeOpen)) this.toggle(true)
|
|
86
|
+
|
|
87
|
+
// Smaller than breakpoint -> Invisible
|
|
88
|
+
if (window.innerWidth < this._options.breakpoint && this._isOpen) this.toggle(false)
|
|
89
|
+
|
|
79
90
|
}, 250)
|
|
80
91
|
}
|
|
81
92
|
|
|
82
93
|
// On click on the button toggle the drawer
|
|
83
|
-
this._buttons.forEach((button) => button.addEventListener('click', () =>
|
|
84
|
-
this.toggle()
|
|
85
|
-
if (window.innerWidth > this._options.breakpoint) this.#resetCookie()
|
|
86
|
-
if (this._focus && this._isOpen) this._focus.focus()
|
|
87
|
-
}))
|
|
94
|
+
this._buttons.forEach((button) => button.addEventListener('click', () => this.toggle()))
|
|
88
95
|
|
|
89
96
|
// On click on the backdrop, close the drawer
|
|
90
97
|
if (this._backdrop) this._backdrop.addEventListener('click', () => this.toggle())
|
|
91
98
|
|
|
92
99
|
}
|
|
93
100
|
|
|
94
|
-
/**
|
|
95
|
-
* Reset the cookie
|
|
96
|
-
*
|
|
97
|
-
*/
|
|
98
|
-
#resetCookie() {
|
|
99
|
-
if (this._cookie) this._cookie.set({ 'open': this._isOpen })
|
|
100
|
-
}
|
|
101
|
-
|
|
102
101
|
/**
|
|
103
102
|
* Toggle the drawer
|
|
104
103
|
*
|
|
104
|
+
* @param {boolean} value
|
|
105
105
|
*/
|
|
106
|
-
toggle() {
|
|
106
|
+
toggle(value = !this._isOpen) {
|
|
107
107
|
|
|
108
108
|
// Change the state
|
|
109
|
-
this._isOpen =
|
|
109
|
+
this._isOpen = value
|
|
110
110
|
|
|
111
111
|
// Change the [aria-pressed] & [aria-expanded] attribute on the <button>
|
|
112
112
|
this._buttons.forEach((button) => {
|
|
@@ -117,6 +117,14 @@ export default class Drawer extends BaseComponent {
|
|
|
117
117
|
// Change the [hidden] attribute on the drawer
|
|
118
118
|
this._element.hidden = !this._isOpen
|
|
119
119
|
|
|
120
|
+
// Change the cookie
|
|
121
|
+
if (this._cookie && (this._cookie.get('drawer-is-open') !== this._isOpen) && window.innerWidth > this._options.breakpoint) {
|
|
122
|
+
this._cookie.set({ ...this._cookie.value, 'drawer-is-open': this._isOpen })
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// Add the focus if open
|
|
126
|
+
if (this._focus && this._isOpen) this._focus.focus()
|
|
127
|
+
|
|
120
128
|
}
|
|
121
129
|
|
|
122
130
|
|
package/js/_slider.js
CHANGED
|
@@ -2,12 +2,12 @@
|
|
|
2
2
|
* ------------------------------------------------------------------
|
|
3
3
|
* Slider
|
|
4
4
|
* ------------------------------------------------------------------
|
|
5
|
-
* This class
|
|
5
|
+
* This class enables the functionality to make an element slider
|
|
6
6
|
*
|
|
7
7
|
* @author Natacha Herth
|
|
8
8
|
* @copyright Natacha Herth, design & web development
|
|
9
9
|
*
|
|
10
|
-
*
|
|
10
|
+
* Keep check on the scrollend event: https://caniuse.com/?search=scrollend
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
13
|
import BaseComponent from './utilities/_base-component'
|
|
@@ -16,34 +16,52 @@ import ErrorMessage from "./utilities/_error"
|
|
|
16
16
|
export default class Slider extends BaseComponent {
|
|
17
17
|
|
|
18
18
|
static OPTIONS = {
|
|
19
|
-
behavior: 'smooth', // Can be auto, smooth or instant
|
|
19
|
+
behavior: 'smooth', // Can be auto, smooth, or instant
|
|
20
20
|
loop: false,
|
|
21
21
|
autoplay: false
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
/**
|
|
25
|
-
* Creates an instance
|
|
25
|
+
* Creates an instance of Slider.
|
|
26
26
|
*
|
|
27
27
|
* @param {HTMLElement} el - The HTML element
|
|
28
|
-
* @param {object} options -
|
|
28
|
+
* @param {object} options - Custom options
|
|
29
29
|
* @constructor
|
|
30
30
|
*/
|
|
31
31
|
constructor(el, options = {}) {
|
|
32
32
|
|
|
33
|
-
// Check for errors
|
|
34
|
-
if (options.behavior && !['auto', 'smooth', 'instant'].includes(options.behavior))
|
|
35
|
-
|
|
36
|
-
|
|
33
|
+
// Check for errors in the options
|
|
34
|
+
if (options.behavior && !['auto', 'smooth', 'instant'].includes(options.behavior)) {
|
|
35
|
+
throw new Error(ErrorMessage.enumOf('options.behavior', 'auto|smooth|instant'))
|
|
36
|
+
}
|
|
37
|
+
if (options.loop && typeof options.loop !== 'boolean') {
|
|
38
|
+
throw new Error(ErrorMessage.typeOf('options.loop', 'boolean'))
|
|
39
|
+
}
|
|
40
|
+
if (options.autoplay && (typeof options.autoplay !== 'boolean' && typeof options.autoplay !== 'number')) {
|
|
41
|
+
throw new Error(ErrorMessage.typeOf('options.autoplay', 'boolean|number'))
|
|
42
|
+
}
|
|
37
43
|
|
|
38
44
|
// Run the SUPER constructor from BaseComponent
|
|
39
45
|
super(el, options, 'slider')
|
|
40
46
|
|
|
41
|
-
//
|
|
42
|
-
const isReduced = window.matchMedia(
|
|
47
|
+
// Handle reduced motion preferences
|
|
48
|
+
const isReduced = window.matchMedia('(prefers-reduced-motion: reduce)').matches
|
|
43
49
|
if (isReduced) this._options.behavior = 'instant'
|
|
44
50
|
|
|
45
|
-
//
|
|
46
|
-
|
|
51
|
+
// Get slides and buttons
|
|
52
|
+
this._slides = Array.from(this._element.querySelectorAll('[role=tabpanel]'))
|
|
53
|
+
|
|
54
|
+
this._buttons = {
|
|
55
|
+
prev: document.querySelector(`[aria-controls=${this._element.id}][data-slider-prev]`),
|
|
56
|
+
next: document.querySelector(`[aria-controls=${this._element.id}][data-slider-next]`),
|
|
57
|
+
tabs: document.querySelectorAll(`[aria-controls=${this._element.id}][role=tablist] [role=tab]`)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
this._current = 0
|
|
61
|
+
this._interval = null
|
|
62
|
+
|
|
63
|
+
// Clone first and last slides if loop is enabled
|
|
64
|
+
if (this._options.loop && this._options.behavior == 'smooth') {
|
|
47
65
|
|
|
48
66
|
const cloneFirst = this._element.firstElementChild.cloneNode(true)
|
|
49
67
|
const cloneLast = this._element.lastElementChild.cloneNode(true)
|
|
@@ -60,189 +78,152 @@ export default class Slider extends BaseComponent {
|
|
|
60
78
|
|
|
61
79
|
}
|
|
62
80
|
|
|
63
|
-
//
|
|
64
|
-
this._slides = this._element.querySelectorAll('[role=tabpanel]')
|
|
65
|
-
|
|
66
|
-
this._buttons = {
|
|
67
|
-
prev: document.querySelector(`[aria-controls=${this._element.id}][data-slider-prev]`),
|
|
68
|
-
next: document.querySelector(`[aria-controls=${this._element.id}][data-slider-next]`),
|
|
69
|
-
tabs: document.querySelectorAll(`[aria-controls=${this._element.id}][role=tablist] [role=tab]`)
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
this._current = 0
|
|
73
|
-
|
|
74
|
-
this._interval = null
|
|
75
|
-
|
|
81
|
+
// Initialize event listeners and functionality
|
|
76
82
|
this.#init()
|
|
77
|
-
|
|
78
83
|
}
|
|
79
84
|
|
|
80
85
|
/**
|
|
81
|
-
*
|
|
86
|
+
* Initialize event listeners and autoplay functionality.
|
|
82
87
|
*
|
|
83
88
|
* @private
|
|
84
89
|
*/
|
|
85
90
|
#init() {
|
|
86
91
|
|
|
87
|
-
//
|
|
88
|
-
if (this._options.autoplay)
|
|
92
|
+
// Handle autoplay
|
|
93
|
+
if (this._options.autoplay) {
|
|
94
|
+
this._interval = setInterval(() => this.next(), this._options.autoplay)
|
|
95
|
+
}
|
|
89
96
|
|
|
90
|
-
//
|
|
97
|
+
// Add event listeners for next and prev buttons
|
|
91
98
|
if (this._buttons.next) this._buttons.next.addEventListener('click', () => this.next())
|
|
92
|
-
|
|
93
|
-
// CLICK prev
|
|
94
99
|
if (this._buttons.prev) this._buttons.prev.addEventListener('click', () => this.prev())
|
|
95
100
|
|
|
96
|
-
//
|
|
97
|
-
if (this._buttons.tabs.length)
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
this._element.addEventListener('scroll', () => {
|
|
101
|
-
|
|
102
|
-
// Clear timeout to avoid multiple request
|
|
103
|
-
clearTimeout(this._element.scrollTimeout)
|
|
104
|
-
|
|
105
|
-
// Run event before changed
|
|
106
|
-
this.emmitEvent('changing', { current: this._current })
|
|
107
|
-
|
|
108
|
-
// Set the timeout
|
|
109
|
-
this._element.scrollTimeout = setTimeout(() => {
|
|
110
|
-
|
|
111
|
-
// Check loop on scrolling
|
|
112
|
-
if (this._options.loop) this.#loop()
|
|
113
|
-
|
|
114
|
-
// Toggle the attributes
|
|
115
|
-
this.#change()
|
|
116
|
-
|
|
117
|
-
}, 150)
|
|
101
|
+
// Add event listeners for tabs
|
|
102
|
+
if (this._buttons.tabs.length) {
|
|
103
|
+
this._buttons.tabs.forEach((tab, index) => tab.addEventListener('click', () => this.goTo(index)))
|
|
104
|
+
}
|
|
118
105
|
|
|
119
|
-
|
|
120
|
-
|
|
106
|
+
// Handle autoplay reset after user interaction
|
|
107
|
+
if (this._options.autoplay) {
|
|
108
|
+
this._element.addEventListener('click', () => {
|
|
121
109
|
clearInterval(this._interval)
|
|
122
110
|
this._interval = setInterval(() => this.next(), this._options.autoplay)
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
})
|
|
126
|
-
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* Change the current slide and toggle the attributes
|
|
131
|
-
*
|
|
132
|
-
* @private
|
|
133
|
-
*/
|
|
134
|
-
#change() {
|
|
135
|
-
|
|
136
|
-
// Define the index
|
|
137
|
-
const index = this._slides.length - [...this._slides].reverse().findIndex((slide) => this._element.scrollLeft >= slide.offsetLeft) - 1
|
|
138
|
-
|
|
139
|
-
// Check if index change to avoid multiple call
|
|
140
|
-
if (index !== this._current) {
|
|
141
|
-
|
|
142
|
-
// Define the new current
|
|
143
|
-
this._current = index
|
|
144
|
-
|
|
145
|
-
// Change the [aria-selected] attribute on tabs
|
|
146
|
-
this._buttons.tabs.forEach((tab, index) => tab.setAttribute('aria-selected', index === this._current))
|
|
147
|
-
|
|
148
|
-
// Change the [aria-hidden] attribute on slide
|
|
149
|
-
this._slides.forEach((slide, index) => slide.setAttribute('aria-hidden', index !== this._current))
|
|
111
|
+
})
|
|
112
|
+
}
|
|
150
113
|
|
|
151
|
-
|
|
152
|
-
|
|
114
|
+
// Enable swipe functionality on touch devices.
|
|
115
|
+
if (!this._options.autoplay) {
|
|
116
|
+
let startX = 0
|
|
153
117
|
|
|
154
|
-
|
|
155
|
-
|
|
118
|
+
const onTouchStart = (event) => {
|
|
119
|
+
startX = event.touches[0].clientX
|
|
120
|
+
}
|
|
156
121
|
|
|
157
|
-
|
|
158
|
-
|
|
122
|
+
const onTouchEnd = (event) => {
|
|
123
|
+
const endX = event.changedTouches[0].clientX
|
|
124
|
+
if (startX > endX + 50) {
|
|
125
|
+
this.next()
|
|
126
|
+
} else if (startX < endX - 50) {
|
|
127
|
+
this.prev()
|
|
128
|
+
}
|
|
129
|
+
}
|
|
159
130
|
|
|
131
|
+
this._element.addEventListener('touchstart', onTouchStart)
|
|
132
|
+
this._element.addEventListener('touchend', onTouchEnd)
|
|
160
133
|
}
|
|
161
|
-
|
|
162
134
|
}
|
|
163
135
|
|
|
164
136
|
/**
|
|
165
|
-
*
|
|
137
|
+
* Go to a specific slide by index.
|
|
166
138
|
*
|
|
167
|
-
* @
|
|
168
|
-
* @private
|
|
139
|
+
* @param {int} index - The index of the slide
|
|
169
140
|
*/
|
|
170
|
-
|
|
141
|
+
goTo(index) {
|
|
171
142
|
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
this._element.scrollTo(this._slides[this._slides.length - 1].offsetLeft, 0)
|
|
175
|
-
return
|
|
143
|
+
if (typeof index !== 'number') {
|
|
144
|
+
throw new Error(ErrorMessage.typeOf('index', 'number'))
|
|
176
145
|
}
|
|
177
146
|
|
|
178
|
-
|
|
179
|
-
if (this._element.scrollWidth - this._element.scrollLeft <= this._element.offsetWidth) {
|
|
180
|
-
this._element.scrollTo(this._slides[0].offsetLeft, 0)
|
|
181
|
-
return
|
|
182
|
-
}
|
|
147
|
+
const previous = this._current
|
|
183
148
|
|
|
184
|
-
|
|
149
|
+
let clone
|
|
185
150
|
|
|
186
|
-
|
|
187
|
-
* Go to a slide by index
|
|
188
|
-
*
|
|
189
|
-
* @param {int} index - The index number of the slide
|
|
190
|
-
*/
|
|
191
|
-
goTo(index) {
|
|
151
|
+
if (this._options.loop && (index < 0 || index >= this._slides.length)) {
|
|
192
152
|
|
|
193
|
-
|
|
194
|
-
|
|
153
|
+
// Go to the correct slide index
|
|
154
|
+
this._current = index < 0 ? this._slides.length - 1 : 0
|
|
195
155
|
|
|
196
|
-
|
|
197
|
-
|
|
156
|
+
// If scroll behavior go to the clone offset
|
|
157
|
+
if (this._options.behavior == 'smooth') {
|
|
158
|
+
clone = this._current == 0 ? this._element.lastElementChild : this._element.firstElementChild
|
|
159
|
+
}
|
|
198
160
|
|
|
199
|
-
if (this._options.loop && (index < 0 || index > this._slides.length - 1)) {
|
|
200
|
-
offset = this._element.children[index + 1].offsetLeft
|
|
201
161
|
} else {
|
|
202
|
-
|
|
203
|
-
|
|
162
|
+
// Otherwise go to the index
|
|
163
|
+
this._current = index
|
|
204
164
|
}
|
|
205
165
|
|
|
206
|
-
//
|
|
166
|
+
// Define the offset
|
|
167
|
+
const offset = clone ? clone.offsetLeft : this._slides[this._current].offsetLeft
|
|
168
|
+
|
|
169
|
+
// Go to the slide
|
|
207
170
|
this._element.scrollTo({
|
|
208
171
|
left: offset,
|
|
209
172
|
behavior: this._options.behavior
|
|
210
173
|
})
|
|
211
174
|
|
|
175
|
+
// If clone offset, then go to the right slide instant
|
|
176
|
+
if (clone) {
|
|
177
|
+
setTimeout(() => {
|
|
178
|
+
this._element.scrollTo({
|
|
179
|
+
left: this._slides[this._current].offsetLeft,
|
|
180
|
+
behavior: 'instant'
|
|
181
|
+
})
|
|
182
|
+
}, 500)
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
// Update the [aria-selected] attribute on tabs
|
|
186
|
+
this._buttons.tabs.forEach((tab, idx) => tab.setAttribute('aria-selected', idx === this._current))
|
|
187
|
+
|
|
188
|
+
// Update the [aria-hidden] attribute on slides
|
|
189
|
+
this._slides.forEach((slide, idx) => slide.setAttribute('aria-hidden', idx !== this._current))
|
|
190
|
+
|
|
191
|
+
// Disable next and prev buttons if necessary
|
|
192
|
+
if (this._buttons.next && !this._options.loop) {
|
|
193
|
+
this._buttons.next.disabled = this._current === this._slides.length - 1
|
|
194
|
+
}
|
|
195
|
+
if (this._buttons.prev && !this._options.loop) {
|
|
196
|
+
this._buttons.prev.disabled = this._current === 0
|
|
197
|
+
}
|
|
198
|
+
|
|
199
|
+
// Emit "changed" event after the slide has changed
|
|
200
|
+
this.emmitEvent('changed', { current: this._current, previous: previous })
|
|
212
201
|
}
|
|
213
202
|
|
|
214
203
|
/**
|
|
215
|
-
* Go to the next slide
|
|
216
|
-
*
|
|
204
|
+
* Go to the next slide.
|
|
217
205
|
*/
|
|
218
206
|
next() {
|
|
207
|
+
const nextIndex = this._current + 1
|
|
219
208
|
|
|
220
|
-
//
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
// If last item => return
|
|
224
|
-
if (!this._options.loop && !this._options.autoplay && index === this._slides.length) return
|
|
225
|
-
|
|
226
|
-
// Run method goTo()
|
|
227
|
-
this.goTo(index)
|
|
209
|
+
// Prevent scrolling if at the last slide and looping is disabled
|
|
210
|
+
if (!this._options.loop && nextIndex >= this._slides.length) return
|
|
228
211
|
|
|
212
|
+
// Move to the next slide
|
|
213
|
+
this.goTo(nextIndex)
|
|
229
214
|
}
|
|
230
215
|
|
|
231
216
|
/**
|
|
232
|
-
* Go to the previous slide
|
|
233
|
-
*
|
|
217
|
+
* Go to the previous slide.
|
|
234
218
|
*/
|
|
235
219
|
prev() {
|
|
220
|
+
const prevIndex = this._current - 1
|
|
236
221
|
|
|
237
|
-
//
|
|
238
|
-
|
|
239
|
-
|
|
240
|
-
// If first item => return
|
|
241
|
-
if (!this._options.loop && index < 0) return
|
|
242
|
-
|
|
243
|
-
// Run method goTo()
|
|
244
|
-
this.goTo(index)
|
|
222
|
+
// Prevent scrolling if at the first slide and looping is disabled
|
|
223
|
+
if (!this._options.loop && prevIndex < 0) return
|
|
245
224
|
|
|
225
|
+
// Move to the previous slide
|
|
226
|
+
this.goTo(prevIndex)
|
|
246
227
|
}
|
|
247
228
|
|
|
248
|
-
}
|
|
229
|
+
}
|
package/js/tests/slider.test.js
CHANGED
|
@@ -9,21 +9,18 @@
|
|
|
9
9
|
* - Constructor: Return the correct properties
|
|
10
10
|
* - #Init(): Loop will clone the first and last slide
|
|
11
11
|
* - #Init(): Autoplay will emmit next() method every X ms
|
|
12
|
-
* - #Init(): Scroll will change the current attributes
|
|
13
12
|
* - #Init(): Click on <button> with [role=tab] emmit the goTo() method
|
|
14
13
|
* - #Init(): Click on <button> with [data-slider-prev] emmit the prev() method
|
|
15
14
|
* - #Init(): Click on <button> with [data-slider-next] emmit the next() method
|
|
16
15
|
* - GoTo(): Passing the correct parameters
|
|
17
|
-
* - GoTo():
|
|
16
|
+
* - GoTo(): Go to the first or last slide via toGo() method
|
|
17
|
+
* - GoTo(): Change the [aria-selected], [aria-hidden] and [disabled] attributes
|
|
18
|
+
* - GoTo(): Emmit the slider:changed events
|
|
18
19
|
* - Prev(): Emmit the goTo() method with correct index
|
|
19
20
|
* - Prev(): Don't emmit the goTo() method if already first slide
|
|
20
21
|
* - Next(): Emmit the goTo() method with correct index
|
|
21
22
|
* - Next(): Don't emmit the goTo() method if already last slide
|
|
22
|
-
|
|
23
|
-
* - #Change(): Emmit the slider:changing and slider:changed events
|
|
24
|
-
* - #Loop(): Go to the last slide if too much left
|
|
25
|
-
* - #Loop(): Go to the first slide if too much right
|
|
26
|
-
* - #Loop(): Go to the first or last slide via toGo() method
|
|
23
|
+
|
|
27
24
|
*/
|
|
28
25
|
|
|
29
26
|
import { describe, test, expect, beforeAll, vi, afterAll } from "vitest"
|
|
@@ -33,12 +30,6 @@ import ErrorMessage from "../utilities/_error"
|
|
|
33
30
|
|
|
34
31
|
let fakeDiv, fakeSlider, fakeDivLoop, fakeSliderLoop
|
|
35
32
|
|
|
36
|
-
function setScroll(value = 0, el = fakeDiv) {
|
|
37
|
-
Object.assign(el, { scrollLeft: value })
|
|
38
|
-
fireEvent.scroll(el, { target: { scrollX: value } })
|
|
39
|
-
vi.runAllTimers()
|
|
40
|
-
}
|
|
41
|
-
|
|
42
33
|
/**
|
|
43
34
|
* Before all tests
|
|
44
35
|
*
|
|
@@ -111,6 +102,7 @@ describe('Structure of the class', () => {
|
|
|
111
102
|
})
|
|
112
103
|
|
|
113
104
|
test('Constructor: Return the correct properties', () => {
|
|
105
|
+
console.log(document.querySelectorAll('#slider [role=tabpanel]') == fakeSlider._slides)
|
|
114
106
|
expect(fakeSlider).toHaveProperty('_element')
|
|
115
107
|
expect(fakeSlider).toHaveProperty('_options')
|
|
116
108
|
expect(fakeSlider).toHaveProperty('_slides')
|
|
@@ -118,7 +110,7 @@ describe('Structure of the class', () => {
|
|
|
118
110
|
expect(fakeSlider).toHaveProperty('_current')
|
|
119
111
|
expect(fakeSlider).toHaveProperty('_interval')
|
|
120
112
|
expect(fakeSlider._slides).toBeTypeOf('object')
|
|
121
|
-
expect(fakeSlider._slides).toStrictEqual(document.querySelectorAll('#slider [role=tabpanel]'))
|
|
113
|
+
expect(fakeSlider._slides).toStrictEqual(Array.from(document.querySelectorAll('#slider [role=tabpanel]')))
|
|
122
114
|
expect(fakeSlider._buttons).toBeTypeOf('object')
|
|
123
115
|
expect(fakeSlider._buttons.prev).toBeTypeOf('object')
|
|
124
116
|
expect(fakeSlider._buttons.next).toBeTypeOf('object')
|
|
@@ -150,12 +142,6 @@ describe('#Init()', () => {
|
|
|
150
142
|
clearInterval(fakeSliderAuto._interval)
|
|
151
143
|
})
|
|
152
144
|
|
|
153
|
-
test('Scroll will change the current attributes', () => {
|
|
154
|
-
expect(fakeSlider._current).toBe(0)
|
|
155
|
-
setScroll(100)
|
|
156
|
-
expect(fakeSlider._current).toBe(1)
|
|
157
|
-
})
|
|
158
|
-
|
|
159
145
|
test('Click on <button> with [role=tab] emmit the goTo() method', () => {
|
|
160
146
|
const fakeTab = fakeSlider._buttons.tabs[0]
|
|
161
147
|
const methodSpy = vi.spyOn(fakeSlider, 'goTo')
|
|
@@ -185,22 +171,62 @@ describe('GoTo()', () => {
|
|
|
185
171
|
expect(() => fakeSlider.goTo()).toThrowError(ErrorMessage.typeOf('index', 'number'))
|
|
186
172
|
})
|
|
187
173
|
|
|
188
|
-
test('
|
|
189
|
-
const scrollSpy = vi.spyOn(fakeDiv, 'scroll')
|
|
174
|
+
test('Toggle the [aria-selected], [aria-hidden] and [disabled] attributes', () => {
|
|
190
175
|
fakeSlider.goTo(0)
|
|
176
|
+
expect(fakeSlider._current).toBe(0)
|
|
177
|
+
expect(fakeSlider._slides[0].getAttribute('aria-hidden')).toBe('false')
|
|
178
|
+
expect(fakeSlider._buttons.tabs[0].getAttribute('aria-selected')).toBe('true')
|
|
179
|
+
expect(fakeSlider._buttons.prev.hasAttribute('disabled')).toBeTruthy()
|
|
180
|
+
fakeSlider.goTo(1)
|
|
181
|
+
expect(fakeSlider._current).toBe(1)
|
|
182
|
+
expect(fakeSlider._slides[0].getAttribute('aria-hidden')).toBe('true')
|
|
183
|
+
expect(fakeSlider._slides[1].getAttribute('aria-hidden')).toBe('false')
|
|
184
|
+
expect(fakeSlider._buttons.tabs[0].getAttribute('aria-selected')).toBe('false')
|
|
185
|
+
expect(fakeSlider._buttons.tabs[1].getAttribute('aria-selected')).toBe('true')
|
|
186
|
+
expect(fakeSlider._buttons.prev.hasAttribute('disabled')).toBeFalsy()
|
|
187
|
+
fakeSlider.goTo(2)
|
|
188
|
+
expect(fakeSlider._current).toBe(2)
|
|
189
|
+
expect(fakeSlider._slides[1].getAttribute('aria-hidden')).toBe('true')
|
|
190
|
+
expect(fakeSlider._slides[2].getAttribute('aria-hidden')).toBe('false')
|
|
191
|
+
expect(fakeSlider._buttons.tabs[1].getAttribute('aria-selected')).toBe('false')
|
|
192
|
+
expect(fakeSlider._buttons.tabs[2].getAttribute('aria-selected')).toBe('true')
|
|
193
|
+
expect(fakeSlider._buttons.next.hasAttribute('disabled')).toBeTruthy()
|
|
194
|
+
})
|
|
195
|
+
|
|
196
|
+
test('Go to the first or last slide via toGo() method', () => {
|
|
197
|
+
|
|
198
|
+
const scrollSpy = vi.spyOn(fakeDivLoop, 'scroll')
|
|
199
|
+
|
|
200
|
+
fakeSliderLoop.goTo(-1)
|
|
201
|
+
|
|
191
202
|
expect(scrollSpy).toHaveBeenCalledWith({
|
|
192
203
|
behavior: "smooth",
|
|
193
204
|
left: 0,
|
|
194
205
|
}, undefined)
|
|
206
|
+
|
|
207
|
+
fakeSliderLoop.goTo(3)
|
|
208
|
+
|
|
209
|
+
expect(scrollSpy).toHaveBeenCalledWith({
|
|
210
|
+
behavior: "smooth",
|
|
211
|
+
left: 400,
|
|
212
|
+
}, undefined)
|
|
213
|
+
|
|
214
|
+
})
|
|
215
|
+
|
|
216
|
+
test('Emmit the slider:changed events', () => {
|
|
217
|
+
const eventSpy = vi.spyOn(fakeSlider, 'emmitEvent')
|
|
218
|
+
fakeSlider.goTo(0)
|
|
219
|
+
expect(eventSpy).toHaveBeenCalledWith('changed', { current: 0, previous: 2 })
|
|
195
220
|
})
|
|
196
221
|
|
|
197
222
|
})
|
|
198
223
|
|
|
199
224
|
describe('Prev()', () => {
|
|
200
225
|
|
|
201
|
-
afterAll(() =>
|
|
226
|
+
afterAll(() => fakeSlider.goTo(0))
|
|
202
227
|
|
|
203
228
|
test('Emit a goTo() method with correct index', () => {
|
|
229
|
+
fakeSlider.goTo(1)
|
|
204
230
|
const methodSpy = vi.spyOn(fakeSlider, 'goTo')
|
|
205
231
|
fakeSlider.prev()
|
|
206
232
|
expect(methodSpy).toHaveBeenCalledWith(0)
|
|
@@ -217,7 +243,7 @@ describe('Prev()', () => {
|
|
|
217
243
|
|
|
218
244
|
describe('Next()', () => {
|
|
219
245
|
|
|
220
|
-
afterAll(() =>
|
|
246
|
+
afterAll(() => fakeSlider.goTo(0))
|
|
221
247
|
|
|
222
248
|
test('Emit a goTo() method and index is X', () => {
|
|
223
249
|
const methodSpy = vi.spyOn(fakeSlider, 'goTo')
|
|
@@ -232,76 +258,4 @@ describe('Next()', () => {
|
|
|
232
258
|
expect(methodSpy).not.toHaveBeenCalled()
|
|
233
259
|
})
|
|
234
260
|
|
|
235
|
-
})
|
|
236
|
-
|
|
237
|
-
describe('#Change()', () => {
|
|
238
|
-
|
|
239
|
-
test('Toggle the [aria-selected], [aria-hidden] and [disabled] attributes', () => {
|
|
240
|
-
expect(fakeSlider._current).toBe(0)
|
|
241
|
-
expect(fakeSlider._slides[0].getAttribute('aria-hidden')).toBe('false')
|
|
242
|
-
expect(fakeSlider._buttons.tabs[0].getAttribute('aria-selected')).toBe('true')
|
|
243
|
-
expect(fakeSlider._buttons.prev.hasAttribute('disabled')).toBeTruthy()
|
|
244
|
-
setScroll(100)
|
|
245
|
-
expect(fakeSlider._current).toBe(1)
|
|
246
|
-
expect(fakeSlider._slides[0].getAttribute('aria-hidden')).toBe('true')
|
|
247
|
-
expect(fakeSlider._slides[1].getAttribute('aria-hidden')).toBe('false')
|
|
248
|
-
expect(fakeSlider._buttons.tabs[0].getAttribute('aria-selected')).toBe('false')
|
|
249
|
-
expect(fakeSlider._buttons.tabs[1].getAttribute('aria-selected')).toBe('true')
|
|
250
|
-
expect(fakeSlider._buttons.prev.hasAttribute('disabled')).toBeFalsy()
|
|
251
|
-
setScroll(200)
|
|
252
|
-
expect(fakeSlider._current).toBe(2)
|
|
253
|
-
expect(fakeSlider._slides[1].getAttribute('aria-hidden')).toBe('true')
|
|
254
|
-
expect(fakeSlider._slides[2].getAttribute('aria-hidden')).toBe('false')
|
|
255
|
-
expect(fakeSlider._buttons.tabs[1].getAttribute('aria-selected')).toBe('false')
|
|
256
|
-
expect(fakeSlider._buttons.tabs[2].getAttribute('aria-selected')).toBe('true')
|
|
257
|
-
expect(fakeSlider._buttons.next.hasAttribute('disabled')).toBeTruthy()
|
|
258
|
-
})
|
|
259
|
-
|
|
260
|
-
test('Emmit the slider:changing and slider:changed events', () => {
|
|
261
|
-
const eventSpy = vi.spyOn(fakeSlider, 'emmitEvent')
|
|
262
|
-
setScroll(0)
|
|
263
|
-
expect(eventSpy).toHaveBeenCalledWith('changing', { current: 2 })
|
|
264
|
-
expect(eventSpy).toHaveBeenCalledWith('changed', { current: 0 })
|
|
265
|
-
})
|
|
266
|
-
|
|
267
|
-
})
|
|
268
|
-
|
|
269
|
-
describe('#Loop()', () => {
|
|
270
|
-
|
|
271
|
-
test('Go to the last slide if too much left', () => {
|
|
272
|
-
const scrollSpy = vi.spyOn(fakeDivLoop, 'scroll')
|
|
273
|
-
expect(fakeSliderLoop._current).toBe(0)
|
|
274
|
-
setScroll(0, fakeDivLoop)
|
|
275
|
-
expect(fakeSliderLoop._current).toBe(2)
|
|
276
|
-
expect(scrollSpy).toHaveBeenCalledWith(300, 0)
|
|
277
|
-
})
|
|
278
|
-
|
|
279
|
-
test('Go to the first slide if too much right', () => {
|
|
280
|
-
const scrollSpy = vi.spyOn(fakeDivLoop, 'scroll')
|
|
281
|
-
expect(fakeSliderLoop._current).toBe(2)
|
|
282
|
-
setScroll(400, fakeDivLoop)
|
|
283
|
-
expect(fakeSliderLoop._current).toBe(0)
|
|
284
|
-
expect(scrollSpy).toHaveBeenCalledWith(100, 0)
|
|
285
|
-
})
|
|
286
|
-
|
|
287
|
-
test('Go to the first or last slide via toGo() method', () => {
|
|
288
|
-
|
|
289
|
-
const scrollSpy = vi.spyOn(fakeDivLoop, 'scroll')
|
|
290
|
-
|
|
291
|
-
fakeSliderLoop.goTo(-1)
|
|
292
|
-
|
|
293
|
-
expect(scrollSpy).toHaveBeenCalledWith({
|
|
294
|
-
behavior: "smooth",
|
|
295
|
-
left: 0,
|
|
296
|
-
}, undefined)
|
|
297
|
-
|
|
298
|
-
fakeSliderLoop.goTo(3)
|
|
299
|
-
|
|
300
|
-
expect(scrollSpy).toHaveBeenCalledWith({
|
|
301
|
-
behavior: "smooth",
|
|
302
|
-
left: 400,
|
|
303
|
-
}, undefined)
|
|
304
|
-
|
|
305
|
-
})
|
|
306
|
-
|
|
307
261
|
})
|
|
Binary file
|
package/package.json
CHANGED
|
@@ -18,17 +18,18 @@
|
|
|
18
18
|
grid-auto-flow: column;
|
|
19
19
|
grid-auto-columns: calc((100% / var(--slider-columns, 1)) - var(--slider-gap, 0rem));
|
|
20
20
|
gap: var(--slider-gap, 0);
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
21
|
+
overflow: hidden;
|
|
22
|
+
//overscroll-behavior-inline: contain;
|
|
23
|
+
//overflow-x: auto;
|
|
24
|
+
//scroll-snap-type: inline mandatory;
|
|
24
25
|
|
|
25
26
|
// Remove Scrollbar
|
|
26
|
-
scrollbar-width: none;
|
|
27
|
-
|
|
27
|
+
//scrollbar-width: none;
|
|
28
|
+
//-ms-overflow-style: none;
|
|
28
29
|
|
|
29
30
|
> * {
|
|
30
|
-
scroll-snap-align: start;
|
|
31
|
-
scroll-padding-inline: 0;
|
|
31
|
+
//scroll-snap-align: start;
|
|
32
|
+
//scroll-padding-inline: 0;
|
|
32
33
|
}
|
|
33
34
|
|
|
34
35
|
}
|
|
Binary file
|