@schukai/monster 3.73.9 → 3.75.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (35) hide show
  1. package/CHANGELOG.md +27 -0
  2. package/package.json +1 -1
  3. package/source/components/datatable/change-button.mjs +4 -4
  4. package/source/components/datatable/columnbar.mjs +2 -2
  5. package/source/components/datatable/dataset.mjs +2 -2
  6. package/source/components/datatable/datasource/rest.mjs +8 -8
  7. package/source/components/datatable/datatable.mjs +6 -6
  8. package/source/components/datatable/filter/date-range.mjs +6 -6
  9. package/source/components/datatable/filter/range.mjs +4 -4
  10. package/source/components/datatable/filter.mjs +4 -4
  11. package/source/components/datatable/save-button.mjs +4 -4
  12. package/source/components/datatable/util.mjs +2 -2
  13. package/source/components/form/api-button.mjs +0 -1
  14. package/source/components/form/context-error.mjs +0 -1
  15. package/source/components/form/context-help.mjs +0 -1
  16. package/source/components/form/message-state-button.mjs +0 -1
  17. package/source/components/form/popper-button.mjs +0 -1
  18. package/source/components/form/select.mjs +16 -5
  19. package/source/components/form/toggle-switch.mjs +0 -3
  20. package/source/components/form/tree-select.mjs +0 -1
  21. package/source/components/layout/slider.mjs +649 -0
  22. package/source/components/layout/style/slider.pcss +114 -0
  23. package/source/components/layout/stylesheet/slider.mjs +38 -0
  24. package/source/components/navigation/table-of-content.mjs +0 -1
  25. package/source/components/tree-menu/dragable-tree-menu.mjs +4 -4
  26. package/source/components/tree-menu/tree-menu.mjs +6 -6
  27. package/source/data/datasource/server/restapi.mjs +0 -1
  28. package/source/dom/events.mjs +1 -1
  29. package/source/dom/updater.mjs +767 -772
  30. package/source/monster.mjs +11 -3
  31. package/source/types/observer.mjs +7 -8
  32. package/source/types/version.mjs +1 -1
  33. package/test/cases/monster.mjs +1 -1
  34. package/test/web/test.html +2 -2
  35. package/test/web/tests.js +243 -202
@@ -0,0 +1,649 @@
1
+ /**
2
+ * Copyright © schukai GmbH and all contributing authors, {{copyRightYear}}. All rights reserved.
3
+ * Node module: @schukai/monster
4
+ *
5
+ * This source code is licensed under the GNU Affero General Public License version 3 (AGPLv3).
6
+ * The full text of the license can be found at: https://www.gnu.org/licenses/agpl-3.0.en.html
7
+ *
8
+ * For those who do not wish to adhere to the AGPLv3, a commercial license is available.
9
+ * Acquiring a commercial license allows you to use this software without complying with the AGPLv3 terms.
10
+ * For more information about purchasing a commercial license, please contact schukai GmbH.
11
+ */
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";
16
+ import {
17
+ assembleMethodSymbol,
18
+ registerCustomElement,
19
+ } from "../../dom/customelement.mjs";
20
+ import { SliderStyleSheet } from "./stylesheet/slider.mjs";
21
+ import { fireCustomEvent } from "../../dom/events.mjs";
22
+
23
+ import { getWindow } from "../../dom/util.mjs";
24
+
25
+ export { Slider };
26
+
27
+ /**
28
+ * @private
29
+ * @type {symbol}
30
+ */
31
+ const sliderElementSymbol = Symbol("sliderElement");
32
+
33
+ /**
34
+ * @private
35
+ * @type {symbol}
36
+ */
37
+ const controlElementSymbol = Symbol("controlElement");
38
+
39
+ /**
40
+ * @private
41
+ * @type {symbol}
42
+ */
43
+ const prevElementSymbol = Symbol("prevElement");
44
+
45
+ /**
46
+ * @private
47
+ * @type {symbol}
48
+ */
49
+ const nextElementSymbol = Symbol("nextElement");
50
+
51
+ /**
52
+ * @private
53
+ * @type {symbol}
54
+ */
55
+ const configSymbol = Symbol("config");
56
+
57
+ /**
58
+ * @private
59
+ * @type {string}
60
+ */
61
+ const ATTRIBUTE_CLON_FROM = ATTRIBUTE_PREFIX + "clone-from";
62
+
63
+ /**
64
+ * A Slider
65
+ *
66
+ * @fragments /fragments/components/form/slider/
67
+ *
68
+ * @example /examples/components/form/slider-simple
69
+ *
70
+ * @since 3.74.0
71
+ * @copyright schukai GmbH
72
+ * @summary A beautiful Slider that can make your life easier and also looks good.
73
+ */
74
+ class Slider extends CustomElement {
75
+ /**
76
+ * This method is called by the `instanceof` operator.
77
+ * @returns {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 auto play
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
+ * @returns {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
+ }
216
+ }
217
+
218
+ /**
219
+ * @private
220
+ * @param name
221
+ */
222
+ function initNavigation(name) {
223
+ const element = this.shadowRoot.querySelector("." + name + "");
224
+ const elementHeight = element.offsetHeight;
225
+ element.style.top = `calc(50% - ${elementHeight / 2}px)`;
226
+ }
227
+
228
+ /**
229
+ * @private
230
+ */
231
+ function initStructure() {
232
+ initNavigation.call(this, "next");
233
+ initNavigation.call(this, "prev");
234
+
235
+ if (this.getOption("features.thumbnails")) {
236
+ initThumbnails.call(this);
237
+ }
238
+
239
+ if (this.getOption("features.carousel")) {
240
+ initCarousel.call(this);
241
+ }
242
+
243
+ if (this.getOption("features.autoPlay")) {
244
+ initAutoPlay.call(this);
245
+ }
246
+ }
247
+
248
+ /**
249
+ * @private
250
+ */
251
+ 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
+ });
286
+ }
287
+
288
+ /**
289
+ * @private
290
+ */
291
+ 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
+ }
346
+ }
347
+
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_CLON_FROM, 1);
356
+
357
+ const lastElement = slides[totalSlides - 1].cloneNode(true);
358
+ lastElement.setAttribute(ATTRIBUTE_CLON_FROM, totalSlides);
359
+ slides[totalSlides - 1].insertAdjacentElement("afterend", firstElement);
360
+
361
+ slides[0].insertAdjacentElement("beforebegin", lastElement);
362
+
363
+ moveTo.call(this, 1);
364
+ }
365
+ }
366
+
367
+ /**
368
+ * @private
369
+ * @returns {{slides: unknown[], totalSlides: number}}
370
+ */
371
+ function getSlidesAndTotal() {
372
+ const slides = Array.from(getSlottedElements.call(this, ":scope", null));
373
+ const totalSlides = slides.length;
374
+ return { slides, totalSlides };
375
+ }
376
+
377
+ /**
378
+ * @private
379
+ * @returns {number}
380
+ */
381
+ 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;
398
+ }
399
+
400
+ /**
401
+ * @private
402
+ * @returns {number}
403
+ */
404
+ function prev() {
405
+ const prevIndex = this[configSymbol].currentIndex - 1;
406
+
407
+ if (prevIndex < 0) {
408
+ return -1;
409
+ }
410
+
411
+ moveTo.call(this, prevIndex);
412
+ return 0;
413
+ }
414
+
415
+ /**
416
+ * @private
417
+ * @param slides
418
+ * @param index
419
+ */
420
+ function setMoveProperties(slides, index) {
421
+ this[configSymbol].currentIndex = index;
422
+
423
+ slides.forEach((slide) => {
424
+ slide.classList.remove("current");
425
+ });
426
+
427
+ let offset = -(index * 100);
428
+ if (offset !== 0) {
429
+ offset += "%";
430
+ }
431
+
432
+ this[sliderElementSymbol].style.transform =
433
+ `translateX(calc(${offset} + ${this[configSymbol].draggingPos}px))`;
434
+ slides[index].classList.add("current");
435
+ }
436
+
437
+ /**
438
+ * @private
439
+ * @param index
440
+ * @fires monster-slider-moved
441
+ */
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_CLON_FROM)) {
466
+ const from = parseInt(slides[index].getAttribute(ATTRIBUTE_CLON_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
+ }
498
+ }
499
+
500
+ /**
501
+ * @private
502
+ * @return {initEventHandler}
503
+ */
504
+ function initEventHandler() {
505
+ const self = this;
506
+
507
+ const nextElements = this[nextElementSymbol];
508
+
509
+ if (nextElements) {
510
+ nextElements.addEventListener("click", () => {
511
+ self.next();
512
+ });
513
+ }
514
+
515
+ const prevElements = this[prevElementSymbol];
516
+
517
+ if (prevElements) {
518
+ prevElements.addEventListener("click", () => {
519
+ self.previous();
520
+ });
521
+ }
522
+
523
+ if (this.getOption("features.drag")) {
524
+ this[sliderElementSymbol].addEventListener("mousedown", (e) =>
525
+ startDragging.call(this, e, "mouse"),
526
+ );
527
+
528
+ this[sliderElementSymbol].addEventListener("touchstart", (e) =>
529
+ startDragging.call(this, e, "touch"),
530
+ );
531
+ }
532
+
533
+ return this;
534
+ }
535
+
536
+ /**
537
+ * @private
538
+ * @param e
539
+ * @param type
540
+ */
541
+ 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
+
547
+ const callbackMousemove = (x) => {
548
+ dragging.call(this, x, type);
549
+ };
550
+
551
+ const callbackMouseUp = () => {
552
+ const endEvent = type === "mouse" ? "mouseup" : "touchend";
553
+ const moveEvent = type === "mouse" ? "mousemove" : "touchmove";
554
+
555
+ document.body.removeEventListener(endEvent, callbackMouseUp);
556
+ document.body.removeEventListener(moveEvent, callbackMousemove);
557
+
558
+ this[configSymbol].isDragging = false;
559
+ this[configSymbol].startPos = 0;
560
+ this[sliderElementSymbol].classList.remove("grabbing");
561
+ this[sliderElementSymbol].style.transitionProperty = "";
562
+
563
+ const lastPos = this[configSymbol].draggingPos;
564
+ const widthOfSlider = this[sliderElementSymbol].offsetWidth;
565
+ this[configSymbol].draggingPos = 0;
566
+
567
+ let newIndex = this[configSymbol].currentIndex;
568
+
569
+ const x = lastPos / widthOfSlider;
570
+ if (x > 0.5) {
571
+ newIndex--;
572
+ } else if (x < -0.5) {
573
+ newIndex++;
574
+ }
575
+
576
+ this.moveTo(newIndex);
577
+ };
578
+
579
+ document.body.addEventListener("mouseup", callbackMouseUp);
580
+ document.body.addEventListener("mousemove", callbackMousemove);
581
+ }
582
+
583
+ /**
584
+ * @private
585
+ * @param e
586
+ * @param type
587
+ * @returns {*|number|number}
588
+ */
589
+ function getPositionX(e, type) {
590
+ return type === "mouse" ? e.pageX : e.touches[0].clientX;
591
+ }
592
+
593
+ /**
594
+ * @private
595
+ * @param e
596
+ * @param type
597
+ */
598
+ 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);
604
+ }
605
+
606
+ /**
607
+ * @private
608
+ * @return {void}
609
+ */
610
+ function initControlReferences() {
611
+ this[controlElementSymbol] = this.shadowRoot.querySelector(
612
+ `[${ATTRIBUTE_ROLE}="control"]`,
613
+ );
614
+
615
+ this[sliderElementSymbol] = this.shadowRoot.querySelector(
616
+ `[${ATTRIBUTE_ROLE}="slider"]`,
617
+ );
618
+
619
+ this[prevElementSymbol] = this.shadowRoot.querySelector(
620
+ `[${ATTRIBUTE_ROLE}="prev"]`,
621
+ );
622
+
623
+ this[nextElementSymbol] = this.shadowRoot.querySelector(
624
+ `[${ATTRIBUTE_ROLE}="next"]`,
625
+ );
626
+ }
627
+
628
+ /**
629
+ * @private
630
+ * @return {string}
631
+ */
632
+ function getTemplate() {
633
+ // language=HTML
634
+ return `
635
+ <div data-monster-role="control" part="control">
636
+ <div class="prev" data-monster-role="prev" part="prev">
637
+ <slot name="prev"></slot>
638
+ </div>
639
+ <div data-monster-role="slider">
640
+ <slot></slot>
641
+ </div>
642
+ <div data-monster-role="thumbnails"></div>
643
+ <div class="next" data-monster-role="next" part="next">
644
+ <slot name="next"></slot>
645
+ </div>
646
+ </div>`;
647
+ }
648
+
649
+ registerCustomElement(Slider);