@schukai/monster 3.99.2 → 3.99.4

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.
@@ -10,19 +10,21 @@
10
10
  * For more information about purchasing a commercial license, please contact schukai GmbH.
11
11
  */
12
12
 
13
- import { instanceSymbol } from "../../constants.mjs";
14
- import { ATTRIBUTE_PREFIX, ATTRIBUTE_ROLE } from "../../dom/constants.mjs";
15
- import { CustomElement, getSlottedElements } from "../../dom/customelement.mjs";
13
+ import {instanceSymbol} from "../../constants.mjs";
14
+ import {ATTRIBUTE_PREFIX, ATTRIBUTE_ROLE} from "../../dom/constants.mjs";
15
+ import {CustomElement, getSlottedElements} from "../../dom/customelement.mjs";
16
16
  import {
17
- assembleMethodSymbol,
18
- registerCustomElement,
17
+ assembleMethodSymbol,
18
+ registerCustomElement,
19
19
  } from "../../dom/customelement.mjs";
20
- import { SliderStyleSheet } from "./stylesheet/slider.mjs";
21
- import { fireCustomEvent } from "../../dom/events.mjs";
20
+ import {SliderStyleSheet} from "./stylesheet/slider.mjs";
21
+ import {fireCustomEvent} from "../../dom/events.mjs";
22
22
 
23
- import { getWindow } from "../../dom/util.mjs";
23
+ import {getWindow} from "../../dom/util.mjs";
24
+ import {isObject, isInteger} from "../../types/is.mjs";
24
25
 
25
- export { Slider };
26
+
27
+ export {Slider};
26
28
 
27
29
  /**
28
30
  * @private
@@ -54,165 +56,177 @@ const nextElementSymbol = Symbol("nextElement");
54
56
  */
55
57
  const configSymbol = Symbol("config");
56
58
 
57
- /**
58
- * @private
59
- * @type {string}
60
- */
61
- const ATTRIBUTE_CLONE_FROM = ATTRIBUTE_PREFIX + "clone-from";
62
-
63
59
  /**
64
60
  * A Slider
65
61
  *
66
62
  * @fragments /fragments/components/layout/slider/
67
63
  *
68
64
  * @example /examples/components/layout/slider-simple
65
+ * @example /examples/components/layout/slider-carousel
66
+ * @example /examples/components/layout/slider-multiple
69
67
  *
70
68
  * @since 3.74.0
71
69
  * @copyright schukai GmbH
72
70
  * @summary A beautiful Slider that can make your life easier and also looks good.
73
71
  */
74
72
  class Slider extends CustomElement {
75
- /**
76
- * This method is called by the `instanceof` operator.
77
- * @return {symbol}
78
- */
79
- static get [instanceSymbol]() {
80
- return Symbol.for("@schukai/monster/components/layout/slider@@instance");
81
- }
82
-
83
- /**
84
- *
85
- * @return {Components.Layout.Slider
86
- */
87
- [assembleMethodSymbol]() {
88
- super[assembleMethodSymbol]();
89
-
90
- this[configSymbol] = {
91
- currentIndex: 0,
92
-
93
- isDragging: false,
94
- draggingPos: 0,
95
- startPos: 0,
96
- autoPlayInterval: null,
97
- };
98
-
99
- initControlReferences.call(this);
100
- initEventHandler.call(this);
101
- initStructure.call(this);
102
-
103
- return this;
104
- }
105
-
106
- /**
107
- * To set the options via the HTML tag, the attribute `data-monster-options` must be used.
108
- * @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control}
109
- *
110
- * The individual configuration values can be found in the table.
111
- *
112
- * @property {Object} templates Template definitions
113
- * @property {string} templates.main Main template
114
- * @property {string} actions.click="throw Error" Callback when clicked
115
- * @property {Object} features Features
116
- * @property {boolean} features.carousel=true Carousel feature
117
- * @property {boolean} features.autoPlay=true Auto play feature
118
- * @property {boolean} features.thumbnails=true Thumbnails feature
119
- * @property {boolean} features.drag=true Drag feature
120
- * @property {Object} autoPlay Auto play configuration
121
- * @property {number} autoPlay.delay=1500 Delay between slides
122
- * @property {number} autoPlay.startDelay=1000 Start delay
123
- * @property {string} autoPlay.direction="next" Direction of the autoplay
124
- * @property {boolean} autoPlay.mouseOverPause=true Pause on mouse over
125
- * @property {boolean} autoPlay.touchPause=true Pause on touch
126
- * @property {Object} classes CSS classes
127
- * @property {boolean} disabled=false Disabled state
128
- */
129
- get defaults() {
130
- return Object.assign({}, super.defaults, {
131
- templates: {
132
- main: getTemplate(),
133
- },
134
-
135
- classes: {},
136
- disabled: false,
137
-
138
- features: {
139
- carousel: true,
140
- autoPlay: true,
141
- thumbnails: true,
142
- drag: true,
143
- },
144
-
145
- autoPlay: {
146
- delay: 1500,
147
- startDelay: 1000,
148
- direction: "next",
149
- mouseOverPause: true,
150
- touchPause: true,
151
- },
152
- });
153
- }
154
-
155
- /**
156
- * @return {string}
157
- */
158
- static getTag() {
159
- return "monster-slider";
160
- }
161
-
162
- /**
163
- * @return {CSSStyleSheet[]}
164
- */
165
- static getCSSStyleSheet() {
166
- return [SliderStyleSheet];
167
- }
168
-
169
- /**
170
- * moves the slider to the given index
171
- *
172
- * @param index
173
- * @return {void}
174
- */
175
- moveTo(index) {
176
- return moveTo.call(this, index);
177
- }
178
-
179
- /**
180
- * shows the previous slide
181
- *
182
- * @return {void}
183
- */
184
- previous() {
185
- return prev.call(this);
186
- }
187
-
188
- /**
189
- * shows the next slide
190
- *
191
- * @return {void}
192
- */
193
- next() {
194
- return next.call(this);
195
- }
196
-
197
- /**
198
- * stops the auto play
199
- *
200
- * @return {void}
201
- */
202
- stopAutoPlay() {
203
- if (this[configSymbol].autoPlayInterval) {
204
- clearInterval(this[configSymbol].autoPlayInterval);
205
- }
206
- }
207
-
208
- /**
209
- * starts the auto play
210
- *
211
- * @return {void}
212
- */
213
- startAutoPlay() {
214
- initAutoPlay.call(this);
215
- }
73
+ /**
74
+ * This method is called by the `instanceof` operator.
75
+ * @return {symbol}
76
+ */
77
+ static get [instanceSymbol]() {
78
+ return Symbol.for("@schukai/monster/components/layout/slider@@instance");
79
+ }
80
+
81
+ /**
82
+ *
83
+ * @return {Components.Layout.Slider
84
+ */
85
+ [assembleMethodSymbol]() {
86
+ super[assembleMethodSymbol]();
87
+
88
+ this[configSymbol] = {
89
+ currentIndex: 0,
90
+
91
+ isDragging: false,
92
+ draggingPos: 0,
93
+ startPos: 0,
94
+ autoPlayInterval: null,
95
+ };
96
+
97
+ // set --monster-slides-width
98
+ const slides = this.shadowRoot.querySelector(`[${ATTRIBUTE_ROLE}="slider"]`);
99
+ const slidesVisible = getVisibleSlidesFromContainerWidth.call(this);
100
+ slides.style.setProperty("--monster-slides-width", `${100 / slidesVisible}%`);
101
+
102
+ initControlReferences.call(this);
103
+ initEventHandler.call(this);
104
+ initStructure.call(this);
105
+
106
+ return this;
107
+ }
108
+
109
+ /**
110
+ * To set the options via the HTML tag, the attribute `data-monster-options` must be used.
111
+ * @see {@link https://monsterjs.org/en/doc/#configurate-a-monster-control}
112
+ *
113
+ * The individual configuration values can be found in the table.
114
+ *
115
+ * @property {Object} templates Template definitions
116
+ * @property {string} templates.main Main template
117
+ * @property {string} actions.click Callback when clicked
118
+ * @property {Object} features Features
119
+ * @property {boolean} features.carousel Carousel feature
120
+ * @property {boolean} features.autoPlay Auto play feature
121
+ * @property {boolean} features.thumbnails Thumbnails feature
122
+ * @property {boolean} features.drag Drag feature
123
+ * @property {Object} slides Slides configuration, an object with breakpoints and the number of slides to show
124
+ * @property {Object} carousel Carousel configuration
125
+ * @property {number} carousel.transition Transition time between a full rotation of the carousel
126
+ * @property {Object} autoPlay Auto play configuration
127
+ * @property {number} autoPlay.delay Delay between slides
128
+ * @property {number} autoPlay.startDelay Start delay
129
+ * @property {string} autoPlay.direction Direction of the autoplay
130
+ * @property {boolean} autoPlay.mouseOverPause Pause on mouse over
131
+ * @property {boolean} autoPlay.touchPause Pause on touch
132
+ * @property {Object} classes CSS classes
133
+ * @property {boolean} disabled Disabled state
134
+ */
135
+ get defaults() {
136
+ return Object.assign({}, super.defaults, {
137
+ templates: {
138
+ main: getTemplate(),
139
+ },
140
+
141
+ classes: {},
142
+ disabled: false,
143
+
144
+ features: {
145
+ carousel: true,
146
+ autoPlay: true,
147
+ thumbnails: true,
148
+ drag: true,
149
+ },
150
+
151
+ slides: {
152
+ "0": 1,
153
+ },
154
+
155
+ carousel: {
156
+ transition: 250,
157
+ },
158
+
159
+ autoPlay: {
160
+ delay: 1500,
161
+ startDelay: 1000,
162
+ direction: "next",
163
+ mouseOverPause: true,
164
+ touchPause: true,
165
+ },
166
+ });
167
+ }
168
+
169
+ /**
170
+ * @return {string}
171
+ */
172
+ static getTag() {
173
+ return "monster-slider";
174
+ }
175
+
176
+ /**
177
+ * @return {CSSStyleSheet[]}
178
+ */
179
+ static getCSSStyleSheet() {
180
+ return [SliderStyleSheet];
181
+ }
182
+
183
+ /**
184
+ * moves the slider to the given index
185
+ *
186
+ * @param index
187
+ * @return {void}
188
+ */
189
+ moveTo(index) {
190
+ return moveTo.call(this, index);
191
+ }
192
+
193
+ /**
194
+ * shows the previous slide
195
+ *
196
+ * @return {void}
197
+ */
198
+ previous() {
199
+ return prev.call(this);
200
+ }
201
+
202
+ /**
203
+ * shows the next slide
204
+ *
205
+ * @return {void}
206
+ */
207
+ next() {
208
+ return next.call(this);
209
+ }
210
+
211
+ /**
212
+ * stops the auto play
213
+ *
214
+ * @return {void}
215
+ */
216
+ stopAutoPlay() {
217
+ if (this[configSymbol].autoPlayInterval) {
218
+ clearInterval(this[configSymbol].autoPlayInterval);
219
+ }
220
+ }
221
+
222
+ /**
223
+ * starts the auto play
224
+ *
225
+ * @return {void}
226
+ */
227
+ startAutoPlay() {
228
+ initAutoPlay.call(this);
229
+ }
216
230
  }
217
231
 
218
232
  /**
@@ -220,148 +234,185 @@ class Slider extends CustomElement {
220
234
  * @param name
221
235
  */
222
236
  function initNavigation(name) {
223
- const element = this.shadowRoot.querySelector("." + name + "");
224
- const elementHeight = element.offsetHeight;
225
- element.style.top = `calc(50% - ${elementHeight / 2}px)`;
237
+ const element = this.shadowRoot.querySelector("." + name + "");
238
+ const elementHeight = element.offsetHeight;
239
+ element.style.top = `calc(50% - ${elementHeight / 2}px)`;
226
240
  }
227
241
 
228
242
  /**
229
243
  * @private
230
244
  */
231
245
  function initStructure() {
232
- initNavigation.call(this, "next");
233
- initNavigation.call(this, "prev");
234
246
 
235
- if (this.getOption("features.thumbnails")) {
236
- initThumbnails.call(this);
237
- }
247
+ initNavigation.call(this, "next");
248
+ initNavigation.call(this, "prev");
238
249
 
239
- if (this.getOption("features.carousel")) {
240
- initCarousel.call(this);
241
- }
250
+ if (this.getOption("features.thumbnails")) {
251
+ initThumbnails.call(this);
252
+ }
242
253
 
243
- if (this.getOption("features.autoPlay")) {
244
- initAutoPlay.call(this);
245
- }
254
+ initShadows.call(this);
255
+
256
+ if (this.getOption("features.autoPlay")) {
257
+ initAutoPlay.call(this);
258
+ }
246
259
  }
247
260
 
248
261
  /**
249
262
  * @private
250
263
  */
251
264
  function initThumbnails() {
252
- const self = this;
253
- const thumbnails = this.shadowRoot.querySelector(
254
- "[data-monster-role='thumbnails']",
255
- );
256
- const slides = Array.from(getSlottedElements.call(this, ":scope", null));
257
-
258
- slides.forEach((slide, index) => {
259
- const thumbnail = document.createElement("div");
260
- thumbnail.classList.add("thumbnail");
261
- thumbnail.addEventListener("click", () => {
262
- if (self.getOption("features.carousel")) {
263
- this.moveTo(index + 1);
264
- } else {
265
- this.moveTo(index);
266
- }
267
- });
268
-
269
- thumbnails.appendChild(thumbnail);
270
- });
271
-
272
- this.addEventListener("monster-slider-moved", (e) => {
273
- const index = e.detail.index;
274
- const thumbnail = thumbnails.children[index];
275
-
276
- if (!thumbnail) {
277
- return;
278
- }
279
-
280
- Array.from(thumbnails.children).forEach((thumb) => {
281
- thumb.classList.remove("current");
282
- });
283
-
284
- thumbnail.classList.add("current");
285
- });
265
+ const self = this;
266
+ const thumbnails = this.shadowRoot.querySelector(
267
+ "[data-monster-role='thumbnails']",
268
+ );
269
+
270
+ const {originSlides} = getSlidesAndTotal.call(this);
271
+
272
+ originSlides.forEach((x, index) => {
273
+ const thumbnail = document.createElement("div");
274
+ thumbnail.classList.add("thumbnail");
275
+ thumbnail.addEventListener("click", () => {
276
+ this.moveTo(index);
277
+ });
278
+
279
+ thumbnails.appendChild(thumbnail);
280
+ });
281
+
282
+ this.addEventListener("monster-slider-moved", (e) => {
283
+ const index = e.detail.index;
284
+ const thumbnail = thumbnails.children[index];
285
+
286
+ if (!thumbnail) {
287
+ return;
288
+ }
289
+
290
+ Array.from(thumbnails.children).forEach((thumb) => {
291
+ thumb.classList.remove("current");
292
+ });
293
+
294
+ thumbnail.classList.add("current");
295
+ });
286
296
  }
287
297
 
288
298
  /**
289
299
  * @private
290
300
  */
291
301
  function initAutoPlay() {
292
- const self = this;
293
- const autoPlay = this.getOption("autoPlay");
294
- const delay = autoPlay.delay;
295
- const startDelay = autoPlay.startDelay;
296
- const direction = autoPlay.direction;
297
-
298
- function start() {
299
- if (self[configSymbol].autoPlayInterval) {
300
- clearInterval(self[configSymbol].autoPlayInterval);
301
- }
302
-
303
- self[configSymbol].autoPlayInterval = setInterval(() => {
304
- if (direction === "next") {
305
- if (self.next() === -1) {
306
- if (self.getOption("features.carousel")) {
307
- clearInterval(self[configSymbol].autoPlayInterval);
308
- }
309
- }
310
- } else {
311
- if (self.previous() === -1) {
312
- if (self.getOption("features.carousel")) {
313
- clearInterval(self[configSymbol].autoPlayInterval);
314
- }
315
- }
316
- }
317
- }, delay);
318
- }
319
-
320
- setTimeout(() => {
321
- start();
322
- }, startDelay);
323
-
324
- if (autoPlay.mouseOverPause) {
325
- this.addEventListener("mouseover", () => {
326
- clearInterval(this[configSymbol].autoPlayInterval);
327
- });
328
-
329
- this.addEventListener("mouseout", () => {
330
- if (this[configSymbol].isDragging) {
331
- return;
332
- }
333
- start();
334
- });
335
- }
336
-
337
- if (autoPlay.touchPause) {
338
- this.addEventListener("touchstart", () => {
339
- clearInterval(this[configSymbol].autoPlayInterval);
340
- });
341
-
342
- this.addEventListener("touchend", () => {
343
- start();
344
- });
345
- }
302
+ const self = this;
303
+ const autoPlay = this.getOption("autoPlay");
304
+ const delay = autoPlay.delay;
305
+ const startDelay = autoPlay.startDelay;
306
+ const direction = autoPlay.direction;
307
+
308
+ function start() {
309
+ if (self[configSymbol].autoPlayInterval) {
310
+ clearInterval(self[configSymbol].autoPlayInterval);
311
+ }
312
+
313
+ self[configSymbol].autoPlayInterval = setInterval(() => {
314
+
315
+ const {totalOriginSlides} = getSlidesAndTotal.call(self);
316
+
317
+ if (direction === "next") {
318
+ if (!self.getOption("features.carousel")&& self[configSymbol].currentIndex >= totalOriginSlides - 1) {
319
+ self[configSymbol].currentIndex = -1;
320
+ }
321
+ self.next();
322
+ } else {
323
+ if (!self.getOption("features.carousel") && self[configSymbol].currentIndex <= 0) {
324
+ self[configSymbol].currentIndex = totalOriginSlides;
325
+ }
326
+ self.previous();
327
+ }
328
+ }, delay);
329
+ }
330
+
331
+ setTimeout(() => {
332
+ start();
333
+ }, startDelay);
334
+
335
+ if (autoPlay.mouseOverPause) {
336
+ this.addEventListener("mouseover", () => {
337
+ clearInterval(this[configSymbol].autoPlayInterval);
338
+ });
339
+
340
+ this.addEventListener("mouseout", () => {
341
+ if (this[configSymbol].isDragging) {
342
+ return;
343
+ }
344
+ start();
345
+ });
346
+ }
347
+
348
+ if (autoPlay.touchPause) {
349
+ this.addEventListener("touchstart", () => {
350
+ clearInterval(this[configSymbol].autoPlayInterval);
351
+ });
352
+
353
+ this.addEventListener("touchend", () => {
354
+ start();
355
+ });
356
+ }
346
357
  }
347
358
 
348
- /**
349
- * @private
350
- */
351
- function initCarousel() {
352
- const { slides, totalSlides } = getSlidesAndTotal.call(this);
353
- if (this.getOption("features.carousel") && totalSlides > 2) {
354
- const firstElement = slides[0].cloneNode(true);
355
- firstElement.setAttribute(ATTRIBUTE_CLONE_FROM, 1);
359
+ function getVisibleSlidesFromContainerWidth() {
360
+
361
+ const containerWidth = this.shadowRoot.querySelector(`[${ATTRIBUTE_ROLE}="slider"]`).offsetWidth;
362
+ const slides = this.getOption("slides");
363
+ let visibleSlides = 1;
364
+
365
+ if (!isObject(slides)) {
366
+ return visibleSlides;
367
+ }
356
368
 
357
- const lastElement = slides[totalSlides - 1].cloneNode(true);
358
- lastElement.setAttribute(ATTRIBUTE_CLONE_FROM, totalSlides);
359
- slides[totalSlides - 1].insertAdjacentElement("afterend", firstElement);
369
+ for (const key in slides) {
370
+ if (containerWidth >= key) {
371
+ visibleSlides = slides[key];
372
+ }
373
+ }
360
374
 
361
- slides[0].insertAdjacentElement("beforebegin", lastElement);
375
+ const {originSlides} = getSlidesAndTotal.call(this);
376
+ if (visibleSlides > originSlides.length) {
377
+ visibleSlides = originSlides.length - 1;
378
+ }
362
379
 
363
- moveTo.call(this, 1);
364
- }
380
+
381
+ return visibleSlides;
382
+ }
383
+
384
+ /**
385
+ * @private
386
+ */
387
+ function initShadows() {
388
+ const {slides, totalSlides} = getSlidesAndTotal.call(this);
389
+ const slidesVisible = getVisibleSlidesFromContainerWidth.call(this);
390
+
391
+ if (totalSlides > slidesVisible) {
392
+
393
+ let current = slides[0];
394
+ let last = slides[totalSlides - 1];
395
+ for (let i = 0; i < slidesVisible; i++) {
396
+ const clone = current.cloneNode(true);
397
+ clone.setAttribute('data-monster-clone-from', i);
398
+ last.insertAdjacentElement('afterend', clone);
399
+ current = current.nextElementSibling;
400
+ last = clone;
401
+ }
402
+
403
+ current = slides[totalSlides - 1];
404
+ let first = slides[0];
405
+ for (let i = 0; i < slidesVisible; i++) {
406
+ const clone = current.cloneNode(true);
407
+ clone.setAttribute('data-monster-clone-from', totalSlides - i);
408
+ first.insertAdjacentElement('beforebegin', clone);
409
+ current = current.previousElementSibling;
410
+ first = clone;
411
+ }
412
+
413
+ moveTo.call(this, 0);
414
+
415
+ }
365
416
  }
366
417
 
367
418
  /**
@@ -369,9 +420,13 @@ function initCarousel() {
369
420
  * @return {{slides: unknown[], totalSlides: number}}
370
421
  */
371
422
  function getSlidesAndTotal() {
372
- const slides = Array.from(getSlottedElements.call(this, ":scope", null));
373
- const totalSlides = slides.length;
374
- return { slides, totalSlides };
423
+ const originSlides = Array.from(getSlottedElements.call(this, ":scope:not([data-monster-clone-from])", null));
424
+ const totalOriginSlides = originSlides.length;
425
+
426
+ const slides = Array.from(getSlottedElements.call(this, ":scope", null));
427
+ const totalSlides = slides.length;
428
+
429
+ return {originSlides, totalOriginSlides, slides, totalSlides};
375
430
  }
376
431
 
377
432
  /**
@@ -379,22 +434,17 @@ function getSlidesAndTotal() {
379
434
  * @return {number}
380
435
  */
381
436
  function next() {
382
- const { slides, totalSlides } = getSlidesAndTotal.call(this);
383
- const nextIndex = this[configSymbol].currentIndex + 1;
384
-
385
- if (nextIndex >= totalSlides) {
386
- return -1;
387
- }
388
-
389
- queueMicrotask(() => {
390
- getWindow().requestAnimationFrame(() => {
391
- getWindow().requestAnimationFrame(() => {
392
- moveTo.call(this, nextIndex);
393
- });
394
- });
395
- });
396
-
397
- return 0;
437
+ const nextIndex = this[configSymbol].currentIndex + 1;
438
+
439
+ queueMicrotask(() => {
440
+ getWindow().requestAnimationFrame(() => {
441
+ getWindow().requestAnimationFrame(() => {
442
+ moveTo.call(this, nextIndex);
443
+ });
444
+ });
445
+ });
446
+
447
+ return 0;
398
448
  }
399
449
 
400
450
  /**
@@ -402,14 +452,17 @@ function next() {
402
452
  * @return {number}
403
453
  */
404
454
  function prev() {
405
- const prevIndex = this[configSymbol].currentIndex - 1;
455
+ const prevIndex = this[configSymbol].currentIndex - 1;
406
456
 
407
- if (prevIndex < 0) {
408
- return -1;
409
- }
457
+ queueMicrotask(() => {
458
+ getWindow().requestAnimationFrame(() => {
459
+ getWindow().requestAnimationFrame(() => {
460
+ moveTo.call(this, prevIndex);
461
+ });
462
+ });
463
+ });
410
464
 
411
- moveTo.call(this, prevIndex);
412
- return 0;
465
+ return 0;
413
466
  }
414
467
 
415
468
  /**
@@ -418,83 +471,98 @@ function prev() {
418
471
  * @param index
419
472
  */
420
473
  function setMoveProperties(slides, index) {
421
- this[configSymbol].currentIndex = index;
474
+ slides.forEach((slide) => {
475
+ slide.classList.remove("current");
476
+ });
477
+
478
+ let offset = -(index * 100);
479
+ const slidesVisible = getVisibleSlidesFromContainerWidth.call(this);
480
+
481
+ offset = offset / slidesVisible;
422
482
 
423
- slides.forEach((slide) => {
424
- slide.classList.remove("current");
425
- });
483
+ if (offset !== 0) {
484
+ offset += "%";
485
+ }
426
486
 
427
- let offset = -(index * 100);
428
- if (offset !== 0) {
429
- offset += "%";
430
- }
487
+ this[sliderElementSymbol].style.transform =
488
+ `translateX(calc(${offset} + ${this[configSymbol].draggingPos}px))`;
489
+
490
+ slides[index].classList.add("current");
491
+ this[configSymbol].lastOffset = offset;
431
492
 
432
- this[sliderElementSymbol].style.transform =
433
- `translateX(calc(${offset} + ${this[configSymbol].draggingPos}px))`;
434
- slides[index].classList.add("current");
435
493
  }
436
494
 
437
495
  /**
438
496
  * @private
439
- * @param index
497
+ * @param {number} index
498
+ * @param {boolean} animation
440
499
  * @fires monster-slider-moved
441
500
  */
442
- function moveTo(index) {
443
- const { slides, totalSlides } = getSlidesAndTotal.call(this);
444
-
445
- if (index < 0) {
446
- index = totalSlides - 1;
447
- } else if (index >= totalSlides) {
448
- index = 0;
449
- }
450
-
451
- const slider = this[sliderElementSymbol];
452
-
453
- setMoveProperties.call(this, slides, index);
454
-
455
- const style = getComputedStyle(this[sliderElementSymbol]);
456
- const duration = style.transitionDuration;
457
- const durationMilis = parseFloat(duration) * 1000;
458
-
459
- let slideIndex = index;
460
- let eventFired = false;
461
-
462
- if (this.getOption("features.carousel")) {
463
- slideIndex = index - 1;
464
-
465
- if (slides[index].hasAttribute(ATTRIBUTE_CLONE_FROM)) {
466
- const from = parseInt(slides[index].getAttribute(ATTRIBUTE_CLONE_FROM));
467
-
468
- getWindow().requestAnimationFrame(() => {
469
- getWindow().requestAnimationFrame(() => {
470
- setTimeout(() => {
471
- slider.style.transitionProperty = "none";
472
-
473
- setMoveProperties.call(this, slides, from);
474
- slideIndex = from - 1;
475
-
476
- getWindow().requestAnimationFrame(() => {
477
- getWindow().requestAnimationFrame(() => {
478
- slider.style.transitionProperty = "";
479
-
480
- fireCustomEvent(this, "monster-slider-moved", {
481
- index: slideIndex,
482
- });
483
-
484
- eventFired = true;
485
- });
486
- });
487
- }, durationMilis);
488
- });
489
- });
490
- }
491
- }
492
-
493
- if (!eventFired) {
494
- fireCustomEvent(this, "monster-slider-moved", {
495
- index: slideIndex,
496
- });
497
- }
501
+ function moveTo(index, animation) {
502
+
503
+ const {slides, totalSlides, originSlides, totalOriginSlides} = getSlidesAndTotal.call(this);
504
+
505
+ if (animation === false) {
506
+ this[sliderElementSymbol].classList.remove("animate");
507
+ } else {
508
+ this[sliderElementSymbol].classList.add("animate");
509
+ }
510
+
511
+ if (this.getOption("features.carousel") === true) {
512
+
513
+ if (index < 0) {
514
+ index = -1;
515
+ }
516
+
517
+ if (index > totalOriginSlides) {
518
+ index = totalOriginSlides;
519
+ }
520
+
521
+ } else {
522
+
523
+ if (index < 0) {
524
+ index = 0;
525
+ }
526
+
527
+ if (index >= totalOriginSlides) {
528
+ index = totalOriginSlides - 1;
529
+ }
530
+ }
531
+
532
+ if (!isInteger(index)) {
533
+ return;
534
+ }
535
+
536
+ this[configSymbol].currentIndex = index;
537
+ let slidesIndex = index + getVisibleSlidesFromContainerWidth.call(this);
538
+
539
+ if (slidesIndex < 0) {
540
+ slidesIndex = totalSlides - 1 - getVisibleSlidesFromContainerWidth.call(this);
541
+ this[configSymbol].currentIndex = totalOriginSlides - 1;
542
+ } else if (index > totalOriginSlides) {
543
+ slidesIndex = 0;
544
+ this[configSymbol].currentIndex = 0;
545
+ }
546
+
547
+ setMoveProperties.call(this, slides, slidesIndex);
548
+
549
+ if (index === totalOriginSlides) {
550
+ setTimeout(() => {
551
+ getWindow().requestAnimationFrame(() => {
552
+ moveTo.call(this, 0, false);
553
+ });
554
+ }, this.getOption("carousel.transition"));
555
+ } else if (index === -1) {
556
+ setTimeout(() => {
557
+ getWindow().requestAnimationFrame(() => {
558
+ moveTo.call(this, totalOriginSlides - 1, false);
559
+ });
560
+ }, this.getOption("carousel.transition"));
561
+ }
562
+
563
+ fireCustomEvent(this, "monster-slider-moved", {
564
+ index: index,
565
+ });
498
566
  }
499
567
 
500
568
  /**
@@ -502,35 +570,35 @@ function moveTo(index) {
502
570
  * @return {initEventHandler}
503
571
  */
504
572
  function initEventHandler() {
505
- const self = this;
573
+ const self = this;
506
574
 
507
- const nextElements = this[nextElementSymbol];
575
+ const nextElements = this[nextElementSymbol];
508
576
 
509
- if (nextElements) {
510
- nextElements.addEventListener("click", () => {
511
- self.next();
512
- });
513
- }
577
+ if (nextElements) {
578
+ nextElements.addEventListener("click", () => {
579
+ self.next();
580
+ });
581
+ }
514
582
 
515
- const prevElements = this[prevElementSymbol];
583
+ const prevElements = this[prevElementSymbol];
516
584
 
517
- if (prevElements) {
518
- prevElements.addEventListener("click", () => {
519
- self.previous();
520
- });
521
- }
585
+ if (prevElements) {
586
+ prevElements.addEventListener("click", () => {
587
+ self.previous();
588
+ });
589
+ }
522
590
 
523
- if (this.getOption("features.drag")) {
524
- this[sliderElementSymbol].addEventListener("mousedown", (e) =>
525
- startDragging.call(this, e, "mouse"),
526
- );
591
+ if (this.getOption("features.drag")) {
592
+ this[sliderElementSymbol].addEventListener("mousedown", (e) =>
593
+ startDragging.call(this, e, "mouse"),
594
+ );
527
595
 
528
- this[sliderElementSymbol].addEventListener("touchstart", (e) =>
529
- startDragging.call(this, e, "touch"),
530
- );
531
- }
596
+ this[sliderElementSymbol].addEventListener("touchstart", (e) =>
597
+ startDragging.call(this, e, "touch"),
598
+ );
599
+ }
532
600
 
533
- return this;
601
+ return this;
534
602
  }
535
603
 
536
604
  /**
@@ -539,45 +607,45 @@ function initEventHandler() {
539
607
  * @param type
540
608
  */
541
609
  function startDragging(e, type) {
542
- this[configSymbol].isDragging = true;
543
- this[configSymbol].startPos = getPositionX(e, type);
544
- this[sliderElementSymbol].classList.add("grabbing");
545
- this[sliderElementSymbol].style.transitionProperty = "none";
546
610
 
547
- const callbackMousemove = (x) => {
548
- dragging.call(this, x, type);
549
- };
611
+ const {slides} = getSlidesAndTotal.call(this);
550
612
 
551
- const callbackMouseUp = () => {
552
- const endEvent = type === "mouse" ? "mouseup" : "touchend";
553
- const moveEvent = type === "mouse" ? "mousemove" : "touchmove";
613
+ const widthOfSlider = slides[this[configSymbol].currentIndex]?.offsetWidth
554
614
 
555
- document.body.removeEventListener(endEvent, callbackMouseUp);
556
- document.body.removeEventListener(moveEvent, callbackMousemove);
615
+ this[configSymbol].isDragging = true;
616
+ this[configSymbol].startPos = getPositionX(e, type);
617
+ this[sliderElementSymbol].classList.add("grabbing");
618
+ this[sliderElementSymbol].style.transitionProperty = "none";
557
619
 
558
- this[configSymbol].isDragging = false;
559
- this[configSymbol].startPos = 0;
560
- this[sliderElementSymbol].classList.remove("grabbing");
561
- this[sliderElementSymbol].style.transitionProperty = "";
620
+ const callbackMousemove = (x) => {
621
+ dragging.call(this, x, type);
622
+ };
562
623
 
563
- const lastPos = this[configSymbol].draggingPos;
564
- const widthOfSlider = this[sliderElementSymbol].offsetWidth;
565
- this[configSymbol].draggingPos = 0;
624
+ const callbackMouseUp = () => {
625
+ const endEvent = type === "mouse" ? "mouseup" : "touchend";
626
+ const moveEvent = type === "mouse" ? "mousemove" : "touchmove";
566
627
 
567
- let newIndex = this[configSymbol].currentIndex;
628
+ document.body.removeEventListener(endEvent, callbackMouseUp);
629
+ document.body.removeEventListener(moveEvent, callbackMousemove);
568
630
 
569
- const x = lastPos / widthOfSlider;
570
- if (x > 0.5) {
571
- newIndex--;
572
- } else if (x < -0.5) {
573
- newIndex++;
574
- }
631
+ this[configSymbol].isDragging = false;
632
+ this[configSymbol].startPos = 0;
633
+ this[sliderElementSymbol].classList.remove("grabbing");
634
+ this[sliderElementSymbol].style.transitionProperty = "";
575
635
 
576
- this.moveTo(newIndex);
577
- };
636
+ const lastPos = this[configSymbol].draggingPos;
637
+ this[configSymbol].draggingPos = 0;
578
638
 
579
- document.body.addEventListener("mouseup", callbackMouseUp);
580
- document.body.addEventListener("mousemove", callbackMousemove);
639
+ let newIndex = this[configSymbol].currentIndex;
640
+ const shift = lastPos / widthOfSlider;
641
+ const shiftIndex = Math.round(shift);
642
+
643
+ newIndex += (shiftIndex * -1);
644
+ this.moveTo(newIndex);
645
+ };
646
+
647
+ document.body.addEventListener("mouseup", callbackMouseUp);
648
+ document.body.addEventListener("mousemove", callbackMousemove);
581
649
  }
582
650
 
583
651
  /**
@@ -587,7 +655,7 @@ function startDragging(e, type) {
587
655
  * @return {*|number|number}
588
656
  */
589
657
  function getPositionX(e, type) {
590
- return type === "mouse" ? e.pageX : e.touches[0].clientX;
658
+ return type === "mouse" ? e.pageX : e.touches[0].clientX;
591
659
  }
592
660
 
593
661
  /**
@@ -596,11 +664,13 @@ function getPositionX(e, type) {
596
664
  * @param type
597
665
  */
598
666
  function dragging(e, type) {
599
- if (!this[configSymbol].isDragging) return;
600
- this[configSymbol].draggingPos =
601
- getPositionX(e, type) - this[configSymbol].startPos;
602
- const { slides, totalSlides } = getSlidesAndTotal.call(this);
603
- setMoveProperties.call(this, slides, this[configSymbol].currentIndex);
667
+ if (!this[configSymbol].isDragging) return;
668
+ this[configSymbol].draggingPos =
669
+ getPositionX(e, type) - this[configSymbol].startPos;
670
+
671
+ this[sliderElementSymbol].style.transform =
672
+ `translateX(calc(${this[configSymbol].lastOffset} + ${this[configSymbol].draggingPos}px))`;
673
+
604
674
  }
605
675
 
606
676
  /**
@@ -608,21 +678,21 @@ function dragging(e, type) {
608
678
  * @return {void}
609
679
  */
610
680
  function initControlReferences() {
611
- this[controlElementSymbol] = this.shadowRoot.querySelector(
612
- `[${ATTRIBUTE_ROLE}="control"]`,
613
- );
681
+ this[controlElementSymbol] = this.shadowRoot.querySelector(
682
+ `[${ATTRIBUTE_ROLE}="control"]`,
683
+ );
614
684
 
615
- this[sliderElementSymbol] = this.shadowRoot.querySelector(
616
- `[${ATTRIBUTE_ROLE}="slider"]`,
617
- );
685
+ this[sliderElementSymbol] = this.shadowRoot.querySelector(
686
+ `[${ATTRIBUTE_ROLE}="slider"]`,
687
+ );
618
688
 
619
- this[prevElementSymbol] = this.shadowRoot.querySelector(
620
- `[${ATTRIBUTE_ROLE}="prev"]`,
621
- );
689
+ this[prevElementSymbol] = this.shadowRoot.querySelector(
690
+ `[${ATTRIBUTE_ROLE}="prev"]`,
691
+ );
622
692
 
623
- this[nextElementSymbol] = this.shadowRoot.querySelector(
624
- `[${ATTRIBUTE_ROLE}="next"]`,
625
- );
693
+ this[nextElementSymbol] = this.shadowRoot.querySelector(
694
+ `[${ATTRIBUTE_ROLE}="next"]`,
695
+ );
626
696
  }
627
697
 
628
698
  /**
@@ -630,8 +700,8 @@ function initControlReferences() {
630
700
  * @return {string}
631
701
  */
632
702
  function getTemplate() {
633
- // language=HTML
634
- return `
703
+ // language=HTML
704
+ return `
635
705
  <div data-monster-role="control" part="control">
636
706
  <div class="prev" data-monster-role="prev" part="prev" part="prev">
637
707
  <slot name="prev"></slot>