@shower/core 3.2.0 → 3.3.1
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/LICENSE.md +5 -17
- package/README.md +7 -3
- package/dist/index.js +838 -0
- package/lib/default-options.js +11 -9
- package/lib/{start.js → index.js} +5 -5
- package/lib/modules/a11y.js +31 -29
- package/lib/modules/install.js +24 -22
- package/lib/modules/keys.js +96 -96
- package/lib/modules/location.js +51 -51
- package/lib/modules/mouse.js +41 -0
- package/lib/modules/next.js +39 -39
- package/lib/modules/parse-timing.js +28 -0
- package/lib/modules/progress.js +16 -16
- package/lib/modules/timer.js +25 -25
- package/lib/modules/title.js +15 -15
- package/lib/modules/touch.js +30 -30
- package/lib/modules/view.js +52 -52
- package/lib/shower.js +164 -164
- package/lib/slide.js +94 -94
- package/lib/utils.js +14 -14
- package/package.json +38 -61
- package/CHANGELOG.md +0 -13
- package/dist/shower.js +0 -791
- package/lib/modules/parse-timing.mjs +0 -28
package/lib/modules/progress.js
CHANGED
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
export default (shower) => {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
const { progressSelector } = shower.options;
|
|
3
|
+
const bar = shower.container.querySelector(progressSelector);
|
|
4
|
+
if (!bar) return;
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
bar.setAttribute('role', 'progressbar');
|
|
7
|
+
bar.setAttribute('aria-valuemin', 0);
|
|
8
|
+
bar.setAttribute('aria-valuemax', 100);
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
10
|
+
const updateProgress = () => {
|
|
11
|
+
const index = shower.activeSlideIndex;
|
|
12
|
+
const { length } = shower.slides;
|
|
13
|
+
const progress = (index / (length - 1)) * 100;
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
15
|
+
bar.style.width = `${progress}%`;
|
|
16
|
+
bar.setAttribute('aria-valuenow', progress);
|
|
17
|
+
bar.setAttribute('aria-valuetext', `Slideshow progress: ${progress}%`);
|
|
18
|
+
};
|
|
19
19
|
|
|
20
|
-
|
|
21
|
-
|
|
20
|
+
shower.addEventListener('start', updateProgress);
|
|
21
|
+
shower.addEventListener('slidechange', updateProgress);
|
|
22
22
|
};
|
package/lib/modules/timer.js
CHANGED
|
@@ -1,34 +1,34 @@
|
|
|
1
|
-
import parseTiming from './parse-timing';
|
|
1
|
+
import parseTiming from './parse-timing.js';
|
|
2
2
|
|
|
3
3
|
export default (shower) => {
|
|
4
|
-
|
|
4
|
+
let id;
|
|
5
5
|
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
6
|
+
const resetTimer = () => {
|
|
7
|
+
clearTimeout(id);
|
|
8
|
+
if (shower.isListMode) return;
|
|
9
9
|
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
10
|
+
const slide = shower.activeSlide;
|
|
11
|
+
const { visitCount, innerStepCount } = slide.state;
|
|
12
|
+
if (visitCount > 1) return;
|
|
13
13
|
|
|
14
|
-
|
|
15
|
-
|
|
14
|
+
const timing = parseTiming(slide.element.dataset.timing);
|
|
15
|
+
if (!timing) return;
|
|
16
16
|
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
17
|
+
if (innerStepCount) {
|
|
18
|
+
const stepTiming = timing / (innerStepCount + 1);
|
|
19
|
+
id = setInterval(() => shower.next(), stepTiming);
|
|
20
|
+
} else {
|
|
21
|
+
id = setTimeout(() => shower.next(), timing);
|
|
22
|
+
}
|
|
23
|
+
};
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
25
|
+
shower.addEventListener('start', resetTimer);
|
|
26
|
+
shower.addEventListener('modechange', resetTimer);
|
|
27
|
+
shower.addEventListener('slidechange', resetTimer);
|
|
28
28
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
29
|
+
shower.container.addEventListener('keydown', (event) => {
|
|
30
|
+
if (!event.defaultPrevented) {
|
|
31
|
+
clearTimeout(id);
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
34
|
};
|
package/lib/modules/title.js
CHANGED
|
@@ -1,21 +1,21 @@
|
|
|
1
1
|
const mdash = '\u2014';
|
|
2
2
|
|
|
3
3
|
export default (shower) => {
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
4
|
+
const { title } = document;
|
|
5
|
+
const updateTitle = () => {
|
|
6
|
+
if (shower.isFullMode) {
|
|
7
|
+
const slide = shower.activeSlide;
|
|
8
|
+
const slideTitle = slide.title;
|
|
9
|
+
if (slideTitle) {
|
|
10
|
+
document.title = `${slideTitle} ${mdash} ${title}`;
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
|
|
15
|
+
document.title = title;
|
|
16
|
+
};
|
|
17
17
|
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
18
|
+
shower.addEventListener('start', updateTitle);
|
|
19
|
+
shower.addEventListener('modechange', updateTitle);
|
|
20
|
+
shower.addEventListener('slidechange', updateTitle);
|
|
21
21
|
};
|
package/lib/modules/touch.js
CHANGED
|
@@ -1,34 +1,34 @@
|
|
|
1
1
|
export default (shower) => {
|
|
2
|
-
|
|
3
|
-
|
|
2
|
+
let exitFullScreen = false;
|
|
3
|
+
let clickable = false;
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
5
|
+
document.addEventListener('touchstart', (event) => {
|
|
6
|
+
if (event.touches.length === 1) {
|
|
7
|
+
const touch = event.touches[0];
|
|
8
|
+
const x = touch.clientX;
|
|
9
|
+
const { target } = touch;
|
|
10
|
+
clickable = target.tabIndex !== -1;
|
|
11
|
+
if (!clickable) {
|
|
12
|
+
if (shower.isFullMode) {
|
|
13
|
+
if (event.cancelable) event.preventDefault();
|
|
14
|
+
if (window.innerWidth / 2 < x) {
|
|
15
|
+
shower.next();
|
|
16
|
+
} else {
|
|
17
|
+
shower.prev();
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
} else if (event.touches.length === 3) {
|
|
22
|
+
exitFullScreen = true;
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
25
|
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
26
|
+
shower.container.addEventListener('touchend', (event) => {
|
|
27
|
+
if (exitFullScreen) {
|
|
28
|
+
event.preventDefault();
|
|
29
|
+
exitFullScreen = false;
|
|
30
|
+
shower.exitFullMode();
|
|
31
|
+
} else if (event.touches.length === 1 && !clickable && shower.isFullMode)
|
|
32
|
+
event.preventDefault();
|
|
33
|
+
});
|
|
34
34
|
};
|
package/lib/modules/view.js
CHANGED
|
@@ -1,54 +1,54 @@
|
|
|
1
1
|
export default (shower) => {
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
2
|
+
const { container } = shower;
|
|
3
|
+
const { fullModeClass, listModeClass } = shower.options;
|
|
4
|
+
|
|
5
|
+
if (container.classList.contains(fullModeClass)) {
|
|
6
|
+
shower.enterFullMode();
|
|
7
|
+
} else {
|
|
8
|
+
container.classList.add(listModeClass);
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
const updateScale = () => {
|
|
12
|
+
const firstSlide = shower.slides[0];
|
|
13
|
+
if (!firstSlide) return;
|
|
14
|
+
|
|
15
|
+
const { innerWidth, innerHeight } = window;
|
|
16
|
+
const { offsetWidth, offsetHeight } = firstSlide.element;
|
|
17
|
+
|
|
18
|
+
const listScale = 1 / (offsetWidth / innerWidth);
|
|
19
|
+
const fullScale = 1 / Math.max(offsetWidth / innerWidth, offsetHeight / innerHeight);
|
|
20
|
+
|
|
21
|
+
container.style.setProperty('--shower-list-scale', listScale);
|
|
22
|
+
container.style.setProperty('--shower-full-scale', fullScale);
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const updateModeView = () => {
|
|
26
|
+
if (shower.isFullMode) {
|
|
27
|
+
container.classList.remove(listModeClass);
|
|
28
|
+
container.classList.add(fullModeClass);
|
|
29
|
+
} else {
|
|
30
|
+
container.classList.remove(fullModeClass);
|
|
31
|
+
container.classList.add(listModeClass);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
updateScale();
|
|
35
|
+
|
|
36
|
+
if (shower.isFullMode) return;
|
|
37
|
+
|
|
38
|
+
const slide = shower.activeSlide;
|
|
39
|
+
if (slide) {
|
|
40
|
+
slide.element.scrollIntoView({ block: 'center' });
|
|
41
|
+
}
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
shower.addEventListener('start', updateModeView);
|
|
45
|
+
shower.addEventListener('modechange', updateModeView);
|
|
46
|
+
shower.addEventListener('slidechange', () => {
|
|
47
|
+
if (shower.isFullMode) return;
|
|
48
|
+
|
|
49
|
+
const slide = shower.activeSlide;
|
|
50
|
+
slide.element.scrollIntoView({ block: 'nearest' });
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
window.addEventListener('resize', updateScale);
|
|
54
54
|
};
|
package/lib/shower.js
CHANGED
|
@@ -1,169 +1,169 @@
|
|
|
1
|
-
import defaultOptions from './default-options';
|
|
2
|
-
import Slide from './slide';
|
|
3
|
-
import { defineReadOnly, ShowerError } from './utils';
|
|
4
|
-
import installModules from './modules/install';
|
|
1
|
+
import defaultOptions from './default-options.js';
|
|
2
|
+
import Slide from './slide.js';
|
|
3
|
+
import { defineReadOnly, ShowerError } from './utils.js';
|
|
4
|
+
import installModules from './modules/install.js';
|
|
5
5
|
|
|
6
6
|
class Shower extends EventTarget {
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
7
|
+
/**
|
|
8
|
+
* @param {object=} options
|
|
9
|
+
*/
|
|
10
|
+
constructor(options) {
|
|
11
|
+
super();
|
|
12
|
+
|
|
13
|
+
defineReadOnly(this, {
|
|
14
|
+
options: { ...defaultOptions, ...options },
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
this._mode = 'list';
|
|
18
|
+
this._isStarted = false;
|
|
19
|
+
this._container = null;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* @param {object=} options
|
|
24
|
+
* @throws {ShowerError}
|
|
25
|
+
*/
|
|
26
|
+
configure(options) {
|
|
27
|
+
if (this._isStarted) {
|
|
28
|
+
throw new ShowerError('Shower should be configured before it is started.');
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
Object.assign(this.options, options);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* @throws {ShowerError}
|
|
36
|
+
* @emits Shower#start
|
|
37
|
+
*/
|
|
38
|
+
start() {
|
|
39
|
+
if (this._isStarted) return;
|
|
40
|
+
|
|
41
|
+
const { containerSelector } = this.options;
|
|
42
|
+
this._container = document.querySelector(containerSelector);
|
|
43
|
+
if (!this._container) {
|
|
44
|
+
throw new ShowerError(
|
|
45
|
+
`Shower container with selector '${containerSelector}' was not found.`,
|
|
46
|
+
);
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
this._initSlides();
|
|
50
|
+
installModules(this);
|
|
51
|
+
|
|
52
|
+
this._isStarted = true;
|
|
53
|
+
this.dispatchEvent(new Event('start'));
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
_initSlides() {
|
|
57
|
+
const visibleSlideSelector = `${this.options.slideSelector}:not([hidden])`;
|
|
58
|
+
const visibleSlideElements = this._container.querySelectorAll(visibleSlideSelector);
|
|
59
|
+
|
|
60
|
+
this.slides = Array.from(visibleSlideElements, (slideElement, index) => {
|
|
61
|
+
if (!slideElement.id) {
|
|
62
|
+
slideElement.id = index + 1;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
return new Slide(this, slideElement);
|
|
66
|
+
});
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
_setMode(mode) {
|
|
70
|
+
if (mode === this._mode) return;
|
|
71
|
+
|
|
72
|
+
this._mode = mode;
|
|
73
|
+
this.dispatchEvent(new Event('modechange'));
|
|
74
|
+
}
|
|
75
|
+
|
|
76
|
+
/**
|
|
77
|
+
* @param {Event} event
|
|
78
|
+
*/
|
|
79
|
+
dispatchEvent(event) {
|
|
80
|
+
if (!this._isStarted) return false;
|
|
81
|
+
|
|
82
|
+
return super.dispatchEvent(event);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
get container() {
|
|
86
|
+
return this._container;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
get isFullMode() {
|
|
90
|
+
return this._mode === 'full';
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
get isListMode() {
|
|
94
|
+
return this._mode === 'list';
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
get activeSlide() {
|
|
98
|
+
return this.slides.find((slide) => slide.isActive);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
get activeSlideIndex() {
|
|
102
|
+
return this.slides.findIndex((slide) => slide.isActive);
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
/**
|
|
106
|
+
* Slide fills the maximum area.
|
|
107
|
+
* @emits Shower#modechange
|
|
108
|
+
*/
|
|
109
|
+
enterFullMode() {
|
|
110
|
+
this._setMode('full');
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Shower returns into list mode.
|
|
115
|
+
* @emits Shower#modechange
|
|
116
|
+
*/
|
|
117
|
+
exitFullMode() {
|
|
118
|
+
this._setMode('list');
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* @param {number} index
|
|
123
|
+
*/
|
|
124
|
+
goTo(index) {
|
|
125
|
+
const slide = this.slides[index];
|
|
126
|
+
if (slide) {
|
|
127
|
+
slide.activate();
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/**
|
|
132
|
+
* @param {number} delta
|
|
133
|
+
*/
|
|
134
|
+
goBy(delta) {
|
|
135
|
+
this.goTo(this.activeSlideIndex + delta);
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* @param {boolean} [isForce=false]
|
|
140
|
+
* @emits Shower#prev
|
|
141
|
+
*/
|
|
142
|
+
prev(isForce) {
|
|
143
|
+
const prev = new Event('prev', { cancelable: !isForce });
|
|
144
|
+
if (this.dispatchEvent(prev)) {
|
|
145
|
+
this.goBy(-1);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
/**
|
|
150
|
+
* @param {boolean} [isForce=false]
|
|
151
|
+
* @emits Shower#next
|
|
152
|
+
*/
|
|
153
|
+
next(isForce) {
|
|
154
|
+
const next = new Event('next', { cancelable: !isForce });
|
|
155
|
+
if (this.dispatchEvent(next)) {
|
|
156
|
+
this.goBy(1);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
first() {
|
|
161
|
+
this.goTo(0);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
last() {
|
|
165
|
+
this.goTo(this.slides.length - 1);
|
|
166
|
+
}
|
|
167
167
|
}
|
|
168
168
|
|
|
169
169
|
export default Shower;
|