@schukai/monster 4.137.2 → 4.137.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.
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"author":"Volker Schukai","dependencies":{"@floating-ui/dom":"^1.7.6"},"description":"Monster is a simple library for creating fast, robust and lightweight websites.","homepage":"https://monsterjs.org/","keywords":["framework","web","dom","css","sass","mobile-first","app","front-end","templates","schukai","core","shopcloud","alvine","monster","buildmap","stack","observer","observable","uuid","node","nodelist","css-in-js","logger","log","theme"],"license":"AGPL 3.0","main":"source/monster.mjs","module":"source/monster.mjs","name":"@schukai/monster","repository":{"type":"git","url":"https://gitlab.schukai.com/oss/libraries/javascript/monster.git"},"type":"module","version":"4.137.
|
|
1
|
+
{"author":"Volker Schukai","dependencies":{"@floating-ui/dom":"^1.7.6"},"description":"Monster is a simple library for creating fast, robust and lightweight websites.","homepage":"https://monsterjs.org/","keywords":["framework","web","dom","css","sass","mobile-first","app","front-end","templates","schukai","core","shopcloud","alvine","monster","buildmap","stack","observer","observable","uuid","node","nodelist","css-in-js","logger","log","theme"],"license":"AGPL 3.0","main":"source/monster.mjs","module":"source/monster.mjs","name":"@schukai/monster","repository":{"type":"git","url":"https://gitlab.schukai.com/oss/libraries/javascript/monster.git"},"type":"module","version":"4.137.4"}
|
|
@@ -25,6 +25,7 @@ import { getLocaleOfDocument } from "../../dom/locale.mjs";
|
|
|
25
25
|
import { hasObjectLink } from "../../dom/attributes.mjs";
|
|
26
26
|
import { customElementUpdaterLinkSymbol } from "../../dom/constants.mjs";
|
|
27
27
|
import { getGlobalObject } from "../../types/global.mjs";
|
|
28
|
+
import { UniqueQueue } from "../../types/uniquequeue.mjs";
|
|
28
29
|
import {
|
|
29
30
|
createFloatingPopper,
|
|
30
31
|
popperInstanceSymbol,
|
|
@@ -83,6 +84,23 @@ const dotsUpdateInProgressSymbol = Symbol("dotsUpdateInProgress");
|
|
|
83
84
|
* @type {symbol}
|
|
84
85
|
*/
|
|
85
86
|
const dotsFrameRequestSymbol = Symbol("dotsFrameRequest");
|
|
87
|
+
/**
|
|
88
|
+
* @private
|
|
89
|
+
* @type {symbol}
|
|
90
|
+
*/
|
|
91
|
+
const dotsLayoutCacheSymbol = Symbol("dotsLayoutCache");
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* @private
|
|
95
|
+
* @type {UniqueQueue}
|
|
96
|
+
*/
|
|
97
|
+
const scheduledDotsUpdates = new UniqueQueue();
|
|
98
|
+
|
|
99
|
+
/**
|
|
100
|
+
* @private
|
|
101
|
+
* @type {number|null}
|
|
102
|
+
*/
|
|
103
|
+
let scheduledDotsFrameRequest = null;
|
|
86
104
|
|
|
87
105
|
/**
|
|
88
106
|
* @private
|
|
@@ -222,14 +240,8 @@ class ColumnBar extends CustomElement {
|
|
|
222
240
|
this[dotsMutationObserverSymbol] = null;
|
|
223
241
|
}
|
|
224
242
|
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
typeof globalThis.cancelAnimationFrame === "function"
|
|
228
|
-
? globalThis.cancelAnimationFrame.bind(globalThis)
|
|
229
|
-
: globalThis.clearTimeout.bind(globalThis);
|
|
230
|
-
cancelFrame(this[dotsFrameRequestSymbol]);
|
|
231
|
-
this[dotsFrameRequestSymbol] = null;
|
|
232
|
-
}
|
|
243
|
+
removeScheduledDotsUpdate(this);
|
|
244
|
+
this[dotsFrameRequestSymbol] = null;
|
|
233
245
|
|
|
234
246
|
if (this[closeEventHandlerSymbol]) {
|
|
235
247
|
getGlobalObject("document").removeEventListener(
|
|
@@ -455,7 +467,11 @@ function initDotsObservers() {
|
|
|
455
467
|
const parentElement = this.parentElement;
|
|
456
468
|
|
|
457
469
|
if (controlElement && !this[resizeObserverSymbol]) {
|
|
458
|
-
this[resizeObserverSymbol] = new ResizeObserver(() => {
|
|
470
|
+
this[resizeObserverSymbol] = new ResizeObserver((entries) => {
|
|
471
|
+
updateDotsLayoutResizeCache.call(this, entries, {
|
|
472
|
+
controlElement,
|
|
473
|
+
parentElement,
|
|
474
|
+
});
|
|
459
475
|
scheduleDotsVisibilityUpdate.call(this);
|
|
460
476
|
});
|
|
461
477
|
this[resizeObserverSymbol].observe(controlElement);
|
|
@@ -465,10 +481,17 @@ function initDotsObservers() {
|
|
|
465
481
|
}
|
|
466
482
|
|
|
467
483
|
if (this[dotsContainerElementSymbol] && !this[dotsMutationObserverSymbol]) {
|
|
468
|
-
this[dotsMutationObserverSymbol] = new MutationObserver(() => {
|
|
469
|
-
if (
|
|
484
|
+
this[dotsMutationObserverSymbol] = new MutationObserver((mutations) => {
|
|
485
|
+
if (
|
|
486
|
+
this[dotsUpdateInProgressSymbol] ||
|
|
487
|
+
mutations.every(isOverflowIndicatorMutation)
|
|
488
|
+
) {
|
|
470
489
|
return;
|
|
471
490
|
}
|
|
491
|
+
invalidateDotsLayoutCache.call(this, {
|
|
492
|
+
dots: true,
|
|
493
|
+
visibility: true,
|
|
494
|
+
});
|
|
472
495
|
scheduleDotsVisibilityUpdate.call(this);
|
|
473
496
|
});
|
|
474
497
|
this[dotsMutationObserverSymbol].observe(this[dotsContainerElementSymbol], {
|
|
@@ -481,29 +504,43 @@ function initDotsObservers() {
|
|
|
481
504
|
* @private
|
|
482
505
|
*/
|
|
483
506
|
function scheduleDotsVisibilityUpdate() {
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
this[dotsFrameRequestSymbol] !== undefined
|
|
487
|
-
) {
|
|
488
|
-
return;
|
|
489
|
-
}
|
|
507
|
+
scheduledDotsUpdates.add(this);
|
|
508
|
+
this[dotsFrameRequestSymbol] = true;
|
|
490
509
|
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
510
|
+
if (scheduledDotsFrameRequest !== null) return;
|
|
511
|
+
|
|
512
|
+
scheduledDotsFrameRequest = requestAnimationFrame(() => {
|
|
513
|
+
const pending = [];
|
|
514
|
+
while (!scheduledDotsUpdates.isEmpty()) {
|
|
515
|
+
pending.push(scheduledDotsUpdates.poll());
|
|
516
|
+
}
|
|
517
|
+
scheduledDotsFrameRequest = null;
|
|
518
|
+
|
|
519
|
+
const layouts = [];
|
|
520
|
+
for (const element of pending) {
|
|
521
|
+
element[dotsFrameRequestSymbol] = null;
|
|
522
|
+
const layout = measureDotsLayout.call(element);
|
|
523
|
+
if (layout) {
|
|
524
|
+
layouts.push(layout);
|
|
525
|
+
}
|
|
526
|
+
}
|
|
527
|
+
|
|
528
|
+
for (const layout of layouts) {
|
|
529
|
+
applyDotsLayout(layout);
|
|
530
|
+
}
|
|
494
531
|
});
|
|
495
532
|
}
|
|
496
533
|
|
|
497
534
|
/**
|
|
498
535
|
* @private
|
|
499
536
|
*/
|
|
500
|
-
function
|
|
537
|
+
function measureDotsLayout() {
|
|
501
538
|
if (this[dotsUpdateInProgressSymbol]) {
|
|
502
|
-
return;
|
|
539
|
+
return null;
|
|
503
540
|
}
|
|
504
541
|
|
|
505
542
|
if (!this.shadowRoot || !this[dotsContainerElementSymbol]) {
|
|
506
|
-
return;
|
|
543
|
+
return null;
|
|
507
544
|
}
|
|
508
545
|
|
|
509
546
|
const controlElement = this.shadowRoot.querySelector(
|
|
@@ -513,81 +550,318 @@ function updateDotsVisibility() {
|
|
|
513
550
|
const parentElement = this.parentElement;
|
|
514
551
|
|
|
515
552
|
if (!controlElement || !settingsButton) {
|
|
516
|
-
return;
|
|
553
|
+
return null;
|
|
517
554
|
}
|
|
518
555
|
|
|
519
556
|
const dotsContainer = this[dotsContainerElementSymbol];
|
|
520
|
-
|
|
557
|
+
const cache = getDotsLayoutCache.call(this);
|
|
558
|
+
const dots = Array.from(
|
|
559
|
+
dotsContainer.querySelectorAll("li:not(.dots-overflow-indicator)"),
|
|
560
|
+
);
|
|
521
561
|
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
562
|
+
if (dots.length === 0) {
|
|
563
|
+
return {
|
|
564
|
+
hostElement: this,
|
|
565
|
+
dots,
|
|
566
|
+
dotsContainer,
|
|
567
|
+
hiddenCount: 0,
|
|
568
|
+
hideContainer: true,
|
|
569
|
+
visibleDots: 0,
|
|
570
|
+
};
|
|
571
|
+
}
|
|
528
572
|
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
573
|
+
if (cache.dotsCount !== dots.length) {
|
|
574
|
+
cache.dotsCount = dots.length;
|
|
575
|
+
cache.dotSlotWidth = null;
|
|
576
|
+
cache.lastVisibleDots = null;
|
|
577
|
+
cache.lastHiddenCount = null;
|
|
578
|
+
}
|
|
532
579
|
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
580
|
+
if (cache.controlWidth === null || cache.controlWidth <= 0) {
|
|
581
|
+
cache.controlWidth = controlElement.getBoundingClientRect().width;
|
|
582
|
+
}
|
|
583
|
+
if (cache.settingsWidth === null || cache.settingsWidth <= 0) {
|
|
584
|
+
cache.settingsWidth = settingsButton.getBoundingClientRect().width;
|
|
585
|
+
}
|
|
537
586
|
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
controlWidth - settingsWidth - 12,
|
|
544
|
-
);
|
|
587
|
+
const availableWidth = Math.max(
|
|
588
|
+
0,
|
|
589
|
+
getAvailableWidth(parentElement, cache.settingsWidth, this, cache) ??
|
|
590
|
+
cache.controlWidth - cache.settingsWidth - 12,
|
|
591
|
+
);
|
|
545
592
|
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
593
|
+
if (cache.dotSlotWidth === null || cache.dotSlotWidth <= 0) {
|
|
594
|
+
cache.dotSlotWidth = getDotSlotWidth(dots[0]);
|
|
595
|
+
}
|
|
596
|
+
|
|
597
|
+
const maxDots =
|
|
598
|
+
cache.dotSlotWidth > 0
|
|
599
|
+
? Math.floor(availableWidth / cache.dotSlotWidth)
|
|
600
|
+
: dots.length;
|
|
601
|
+
const configuredMaxVisible = parseInt(this.getOption("dots.maxVisible"), 10);
|
|
602
|
+
const enforceMaxVisible =
|
|
603
|
+
Number.isFinite(configuredMaxVisible) && configuredMaxVisible > 0;
|
|
604
|
+
|
|
605
|
+
if (maxDots <= 1) {
|
|
606
|
+
return {
|
|
607
|
+
hostElement: this,
|
|
608
|
+
dots,
|
|
609
|
+
dotsContainer,
|
|
610
|
+
hiddenCount: 0,
|
|
611
|
+
hideContainer: true,
|
|
612
|
+
visibleDots: 0,
|
|
613
|
+
};
|
|
614
|
+
}
|
|
615
|
+
|
|
616
|
+
const configLimit = enforceMaxVisible
|
|
617
|
+
? configuredMaxVisible
|
|
618
|
+
: Number.POSITIVE_INFINITY;
|
|
619
|
+
const baseLimit = Math.min(maxDots, configLimit, dots.length);
|
|
620
|
+
const needsIndicator = baseLimit < dots.length;
|
|
621
|
+
|
|
622
|
+
let visibleDots = baseLimit;
|
|
623
|
+
if (needsIndicator) {
|
|
624
|
+
visibleDots = Math.min(
|
|
625
|
+
Math.max(1, maxDots - 1),
|
|
626
|
+
configLimit,
|
|
627
|
+
dots.length,
|
|
554
628
|
);
|
|
555
|
-
|
|
556
|
-
Number.isFinite(configuredMaxVisible) && configuredMaxVisible > 0;
|
|
629
|
+
}
|
|
557
630
|
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
631
|
+
return {
|
|
632
|
+
hostElement: this,
|
|
633
|
+
dots,
|
|
634
|
+
dotsContainer,
|
|
635
|
+
hiddenCount: dots.length - visibleDots,
|
|
636
|
+
hideContainer: false,
|
|
637
|
+
visibleDots,
|
|
638
|
+
};
|
|
639
|
+
}
|
|
640
|
+
|
|
641
|
+
/**
|
|
642
|
+
* @private
|
|
643
|
+
* @param {object} layout
|
|
644
|
+
* @return {void}
|
|
645
|
+
*/
|
|
646
|
+
function applyDotsLayout(layout) {
|
|
647
|
+
const cache = getDotsLayoutCache.call(layout.hostElement);
|
|
562
648
|
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
let visibleDots = baseLimit;
|
|
570
|
-
if (needsIndicator) {
|
|
571
|
-
visibleDots = Math.min(
|
|
572
|
-
Math.max(1, maxDots - 1),
|
|
573
|
-
configLimit,
|
|
574
|
-
dots.length,
|
|
649
|
+
layout.hostElement[dotsUpdateInProgressSymbol] = true;
|
|
650
|
+
try {
|
|
651
|
+
if (cache.lastContainerHidden !== layout.hideContainer) {
|
|
652
|
+
layout.dotsContainer.classList.toggle(
|
|
653
|
+
"dots-hidden",
|
|
654
|
+
layout.hideContainer,
|
|
575
655
|
);
|
|
656
|
+
cache.lastContainerHidden = layout.hideContainer;
|
|
576
657
|
}
|
|
577
|
-
|
|
578
|
-
|
|
658
|
+
|
|
659
|
+
if (
|
|
660
|
+
cache.lastVisibleDots !== layout.visibleDots ||
|
|
661
|
+
cache.lastDotsCount !== layout.dots.length
|
|
662
|
+
) {
|
|
663
|
+
for (let i = 0; i < layout.dots.length; i++) {
|
|
664
|
+
const shouldHide = i >= layout.visibleDots;
|
|
665
|
+
if (
|
|
666
|
+
layout.dots[i].classList.contains("dots-overflow-hidden") !==
|
|
667
|
+
shouldHide
|
|
668
|
+
) {
|
|
669
|
+
layout.dots[i].classList.toggle("dots-overflow-hidden", shouldHide);
|
|
670
|
+
}
|
|
671
|
+
}
|
|
672
|
+
cache.lastVisibleDots = layout.visibleDots;
|
|
673
|
+
cache.lastDotsCount = layout.dots.length;
|
|
579
674
|
}
|
|
580
675
|
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
overflowIndicator.className = "dots-overflow-indicator";
|
|
585
|
-
overflowIndicator.textContent = `+${hiddenCount}`;
|
|
586
|
-
dotsContainer.appendChild(overflowIndicator);
|
|
676
|
+
if (cache.lastHiddenCount !== layout.hiddenCount) {
|
|
677
|
+
updateOverflowIndicator(layout.dotsContainer, layout.hiddenCount);
|
|
678
|
+
cache.lastHiddenCount = layout.hiddenCount;
|
|
587
679
|
}
|
|
588
680
|
} finally {
|
|
589
|
-
|
|
681
|
+
layout.hostElement[dotsUpdateInProgressSymbol] = false;
|
|
682
|
+
}
|
|
683
|
+
}
|
|
684
|
+
|
|
685
|
+
/**
|
|
686
|
+
* @private
|
|
687
|
+
* @param {MutationRecord} mutation
|
|
688
|
+
* @return {boolean}
|
|
689
|
+
*/
|
|
690
|
+
function isOverflowIndicatorMutation(mutation) {
|
|
691
|
+
const changedNodes = Array.from(mutation.addedNodes).concat(
|
|
692
|
+
Array.from(mutation.removedNodes),
|
|
693
|
+
);
|
|
694
|
+
|
|
695
|
+
return (
|
|
696
|
+
changedNodes.length > 0 &&
|
|
697
|
+
changedNodes.every((node) => {
|
|
698
|
+
return (
|
|
699
|
+
node instanceof HTMLElement &&
|
|
700
|
+
node.classList.contains("dots-overflow-indicator")
|
|
701
|
+
);
|
|
702
|
+
})
|
|
703
|
+
);
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
/**
|
|
707
|
+
* @private
|
|
708
|
+
* @param {HTMLElement} dotsContainer
|
|
709
|
+
* @param {number} hiddenCount
|
|
710
|
+
* @return {void}
|
|
711
|
+
*/
|
|
712
|
+
function updateOverflowIndicator(dotsContainer, hiddenCount) {
|
|
713
|
+
let overflowIndicator = dotsContainer.querySelector(
|
|
714
|
+
".dots-overflow-indicator",
|
|
715
|
+
);
|
|
716
|
+
|
|
717
|
+
if (hiddenCount <= 0) {
|
|
718
|
+
overflowIndicator?.remove();
|
|
719
|
+
return;
|
|
720
|
+
}
|
|
721
|
+
|
|
722
|
+
const label = `+${hiddenCount}`;
|
|
723
|
+
if (!overflowIndicator) {
|
|
724
|
+
overflowIndicator = document.createElement("li");
|
|
725
|
+
overflowIndicator.className = "dots-overflow-indicator";
|
|
726
|
+
dotsContainer.appendChild(overflowIndicator);
|
|
727
|
+
}
|
|
728
|
+
|
|
729
|
+
if (overflowIndicator.textContent !== label) {
|
|
730
|
+
overflowIndicator.textContent = label;
|
|
731
|
+
}
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
/**
|
|
735
|
+
* @private
|
|
736
|
+
* @param {ColumnBar} element
|
|
737
|
+
* @return {void}
|
|
738
|
+
*/
|
|
739
|
+
function removeScheduledDotsUpdate(element) {
|
|
740
|
+
const pending = [];
|
|
741
|
+
while (!scheduledDotsUpdates.isEmpty()) {
|
|
742
|
+
const item = scheduledDotsUpdates.poll();
|
|
743
|
+
if (item !== element) {
|
|
744
|
+
pending.push(item);
|
|
745
|
+
}
|
|
746
|
+
}
|
|
747
|
+
for (const item of pending) {
|
|
748
|
+
scheduledDotsUpdates.add(item);
|
|
749
|
+
}
|
|
750
|
+
}
|
|
751
|
+
|
|
752
|
+
/**
|
|
753
|
+
* @private
|
|
754
|
+
* @return {object}
|
|
755
|
+
*/
|
|
756
|
+
function getDotsLayoutCache() {
|
|
757
|
+
if (!this[dotsLayoutCacheSymbol]) {
|
|
758
|
+
this[dotsLayoutCacheSymbol] = {
|
|
759
|
+
controlWidth: null,
|
|
760
|
+
dotSlotWidth: null,
|
|
761
|
+
dotsCount: null,
|
|
762
|
+
lastContainerHidden: null,
|
|
763
|
+
lastDotsCount: null,
|
|
764
|
+
lastHiddenCount: null,
|
|
765
|
+
lastVisibleDots: null,
|
|
766
|
+
parentGap: null,
|
|
767
|
+
parentWidth: null,
|
|
768
|
+
settingsWidth: null,
|
|
769
|
+
siblingsSignature: null,
|
|
770
|
+
siblingsWidth: null,
|
|
771
|
+
};
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
return this[dotsLayoutCacheSymbol];
|
|
775
|
+
}
|
|
776
|
+
|
|
777
|
+
/**
|
|
778
|
+
* @private
|
|
779
|
+
* @param {object} options
|
|
780
|
+
* @return {void}
|
|
781
|
+
*/
|
|
782
|
+
function invalidateDotsLayoutCache(options = {}) {
|
|
783
|
+
const cache = getDotsLayoutCache.call(this);
|
|
784
|
+
|
|
785
|
+
if (options.dots === true) {
|
|
786
|
+
cache.dotSlotWidth = null;
|
|
787
|
+
cache.dotsCount = null;
|
|
788
|
+
}
|
|
789
|
+
|
|
790
|
+
if (options.visibility === true) {
|
|
791
|
+
cache.lastContainerHidden = null;
|
|
792
|
+
cache.lastDotsCount = null;
|
|
793
|
+
cache.lastHiddenCount = null;
|
|
794
|
+
cache.lastVisibleDots = null;
|
|
795
|
+
}
|
|
796
|
+
|
|
797
|
+
if (options.control === true) {
|
|
798
|
+
cache.controlWidth = null;
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
if (options.parent === true) {
|
|
802
|
+
cache.parentWidth = null;
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
if (options.settings === true) {
|
|
806
|
+
cache.settingsWidth = null;
|
|
807
|
+
}
|
|
808
|
+
|
|
809
|
+
if (options.siblings === true) {
|
|
810
|
+
cache.parentGap = null;
|
|
811
|
+
cache.siblingsSignature = null;
|
|
812
|
+
cache.siblingsWidth = null;
|
|
813
|
+
}
|
|
814
|
+
}
|
|
815
|
+
|
|
816
|
+
/**
|
|
817
|
+
* @private
|
|
818
|
+
* @param {ResizeObserverEntry[]} entries
|
|
819
|
+
* @param {object} elements
|
|
820
|
+
* @return {void}
|
|
821
|
+
*/
|
|
822
|
+
function updateDotsLayoutResizeCache(entries, { controlElement, parentElement }) {
|
|
823
|
+
const cache = getDotsLayoutCache.call(this);
|
|
824
|
+
|
|
825
|
+
if (!Array.isArray(entries) || entries.length === 0) {
|
|
826
|
+
invalidateDotsLayoutCache.call(this, {
|
|
827
|
+
control: true,
|
|
828
|
+
parent: true,
|
|
829
|
+
siblings: true,
|
|
830
|
+
});
|
|
831
|
+
return;
|
|
590
832
|
}
|
|
833
|
+
|
|
834
|
+
for (const entry of entries) {
|
|
835
|
+
const width = getResizeEntryWidth(entry);
|
|
836
|
+
if (width === null) continue;
|
|
837
|
+
|
|
838
|
+
if (entry.target === controlElement) {
|
|
839
|
+
cache.controlWidth = width;
|
|
840
|
+
}
|
|
841
|
+
if (entry.target === parentElement) {
|
|
842
|
+
cache.parentWidth = width;
|
|
843
|
+
cache.siblingsSignature = null;
|
|
844
|
+
cache.siblingsWidth = null;
|
|
845
|
+
}
|
|
846
|
+
}
|
|
847
|
+
}
|
|
848
|
+
|
|
849
|
+
/**
|
|
850
|
+
* @private
|
|
851
|
+
* @param {ResizeObserverEntry} entry
|
|
852
|
+
* @return {number|null}
|
|
853
|
+
*/
|
|
854
|
+
function getResizeEntryWidth(entry) {
|
|
855
|
+
const borderSize = Array.isArray(entry.borderBoxSize)
|
|
856
|
+
? entry.borderBoxSize[0]
|
|
857
|
+
: entry.borderBoxSize;
|
|
858
|
+
const contentSize = Array.isArray(entry.contentBoxSize)
|
|
859
|
+
? entry.contentBoxSize[0]
|
|
860
|
+
: entry.contentBoxSize;
|
|
861
|
+
const width =
|
|
862
|
+
borderSize?.inlineSize ?? contentSize?.inlineSize ?? entry.contentRect?.width;
|
|
863
|
+
|
|
864
|
+
return Number.isFinite(width) ? width : null;
|
|
591
865
|
}
|
|
592
866
|
|
|
593
867
|
/**
|
|
@@ -607,32 +881,50 @@ function getDotSlotWidth(dot) {
|
|
|
607
881
|
* @private
|
|
608
882
|
* @param {HTMLElement|null} parent
|
|
609
883
|
* @param {number} settingsWidth
|
|
884
|
+
* @param {ColumnBar} hostElement
|
|
885
|
+
* @param {object} cache
|
|
610
886
|
* @return {number|null}
|
|
611
887
|
*/
|
|
612
|
-
function getAvailableWidth(parent, settingsWidth, hostElement) {
|
|
888
|
+
function getAvailableWidth(parent, settingsWidth, hostElement, cache) {
|
|
613
889
|
if (!parent) return null;
|
|
614
890
|
|
|
615
|
-
const parentWidth =
|
|
891
|
+
const parentWidth =
|
|
892
|
+
cache.parentWidth ?? parent.getBoundingClientRect().width ?? null;
|
|
616
893
|
if (!parentWidth) return null;
|
|
617
|
-
|
|
618
|
-
const styles = getComputedStyle(parent);
|
|
619
|
-
const gapValue = styles.columnGap || styles.gap || "0";
|
|
620
|
-
const gap = parseFloat(gapValue) || 0;
|
|
894
|
+
cache.parentWidth = parentWidth;
|
|
621
895
|
|
|
622
896
|
const siblings = Array.from(parent.children).filter(
|
|
623
897
|
(el) => el !== hostElement,
|
|
624
898
|
);
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
899
|
+
const siblingsSignature = siblings
|
|
900
|
+
.map((sibling) => sibling.getAttribute("data-monster-role") || sibling.tagName)
|
|
901
|
+
.join("|");
|
|
902
|
+
|
|
903
|
+
if (
|
|
904
|
+
cache.siblingsSignature !== siblingsSignature ||
|
|
905
|
+
cache.siblingsWidth === null ||
|
|
906
|
+
cache.parentGap === null
|
|
907
|
+
) {
|
|
908
|
+
const styles = getComputedStyle(parent);
|
|
909
|
+
const gapValue = styles.columnGap || styles.gap || "0";
|
|
910
|
+
cache.parentGap = parseFloat(gapValue) || 0;
|
|
911
|
+
cache.siblingsSignature = siblingsSignature;
|
|
912
|
+
cache.siblingsWidth = 0;
|
|
913
|
+
|
|
914
|
+
for (const sibling of siblings) {
|
|
915
|
+
const siblingStyles = getComputedStyle(sibling);
|
|
916
|
+
if (siblingStyles.display === "none") {
|
|
917
|
+
continue;
|
|
918
|
+
}
|
|
919
|
+
cache.siblingsWidth += sibling.getBoundingClientRect().width;
|
|
630
920
|
}
|
|
631
|
-
siblingsWidth += sibling.getBoundingClientRect().width;
|
|
632
921
|
}
|
|
633
922
|
|
|
634
923
|
const gaps = siblings.length > 0 ? siblings.length : 0;
|
|
635
|
-
return Math.max(
|
|
924
|
+
return Math.max(
|
|
925
|
+
0,
|
|
926
|
+
parentWidth - cache.siblingsWidth - cache.parentGap * gaps - settingsWidth,
|
|
927
|
+
);
|
|
636
928
|
}
|
|
637
929
|
|
|
638
930
|
/**
|
|
@@ -580,6 +580,7 @@ function initPopperSwitch() {
|
|
|
580
580
|
}
|
|
581
581
|
|
|
582
582
|
this[switchElementSymbol] = switchButton;
|
|
583
|
+
updatePopperSwitchVisibility.call(this);
|
|
583
584
|
}
|
|
584
585
|
|
|
585
586
|
/**
|
|
@@ -1180,25 +1181,36 @@ function adjustButtonVisibility() {
|
|
|
1180
1181
|
const self = this;
|
|
1181
1182
|
|
|
1182
1183
|
return new Promise((resolve) => {
|
|
1183
|
-
|
|
1184
|
+
let resolved = false;
|
|
1185
|
+
let observer;
|
|
1186
|
+
const runIfRendered = () => {
|
|
1187
|
+
if (resolved === true) return;
|
|
1188
|
+
|
|
1184
1189
|
const defCount = self.getOption("buttons.standard").length;
|
|
1185
1190
|
const domCount = self[navElementSymbol].querySelectorAll(
|
|
1186
|
-
'button[data-monster-role="button"]',
|
|
1191
|
+
'button[data-monster-role="button"][data-monster-tab-reference]',
|
|
1187
1192
|
).length;
|
|
1188
1193
|
|
|
1189
|
-
// in drawing
|
|
1190
1194
|
if (defCount !== domCount) return;
|
|
1191
1195
|
|
|
1192
|
-
|
|
1193
|
-
|
|
1196
|
+
resolved = true;
|
|
1197
|
+
observer?.disconnect();
|
|
1194
1198
|
checkAndRearrangeButtons.call(self);
|
|
1195
|
-
|
|
1196
1199
|
resolve();
|
|
1200
|
+
};
|
|
1201
|
+
|
|
1202
|
+
observer = new MutationObserver(function () {
|
|
1203
|
+
runIfRendered();
|
|
1197
1204
|
});
|
|
1198
1205
|
|
|
1199
1206
|
observer.observe(self[navElementSymbol], {
|
|
1200
1207
|
attributes: true,
|
|
1208
|
+
childList: true,
|
|
1209
|
+
subtree: true,
|
|
1201
1210
|
});
|
|
1211
|
+
|
|
1212
|
+
runIfRendered();
|
|
1213
|
+
getWindow().requestAnimationFrame(runIfRendered);
|
|
1202
1214
|
});
|
|
1203
1215
|
}
|
|
1204
1216
|
|
|
@@ -1273,16 +1285,25 @@ function rearrangeButtons() {
|
|
|
1273
1285
|
|
|
1274
1286
|
setButtonCollections.call(this, standardButtons, popperButtons);
|
|
1275
1287
|
|
|
1276
|
-
|
|
1277
|
-
if (popperButtons.length > 0) {
|
|
1278
|
-
this[switchElementSymbol].classList.remove("hidden");
|
|
1279
|
-
} else {
|
|
1280
|
-
this[switchElementSymbol].classList.add("hidden");
|
|
1281
|
-
}
|
|
1282
|
-
}
|
|
1288
|
+
updatePopperSwitchVisibility.call(this);
|
|
1283
1289
|
});
|
|
1284
1290
|
}
|
|
1285
1291
|
|
|
1292
|
+
/**
|
|
1293
|
+
* @private
|
|
1294
|
+
*/
|
|
1295
|
+
function updatePopperSwitchVisibility() {
|
|
1296
|
+
if (!this[switchElementSymbol]) {
|
|
1297
|
+
return;
|
|
1298
|
+
}
|
|
1299
|
+
|
|
1300
|
+
if (this.getOption("buttons.popper").length > 0) {
|
|
1301
|
+
this[switchElementSymbol].classList.remove("hidden");
|
|
1302
|
+
} else {
|
|
1303
|
+
this[switchElementSymbol].classList.add("hidden");
|
|
1304
|
+
}
|
|
1305
|
+
}
|
|
1306
|
+
|
|
1286
1307
|
/**
|
|
1287
1308
|
* @private
|
|
1288
1309
|
* @param {string} ref
|
|
@@ -557,4 +557,122 @@ describe("Datatable drag scroll", function () {
|
|
|
557
557
|
globalThis.requestAnimationFrame = originalGlobalRequestAnimationFrame;
|
|
558
558
|
}
|
|
559
559
|
});
|
|
560
|
+
|
|
561
|
+
it("coalesces column bar dot updates and ignores overflow indicator mutations", async function () {
|
|
562
|
+
const OriginalResizeObserver = window.ResizeObserver;
|
|
563
|
+
const originalGlobalResizeObserver = globalThis.ResizeObserver;
|
|
564
|
+
const originalRequestAnimationFrame = window.requestAnimationFrame;
|
|
565
|
+
const originalGlobalRequestAnimationFrame = globalThis.requestAnimationFrame;
|
|
566
|
+
|
|
567
|
+
class TrackingResizeObserver extends ResizeObserverMock {
|
|
568
|
+
static instances = [];
|
|
569
|
+
|
|
570
|
+
constructor(callback) {
|
|
571
|
+
super(callback);
|
|
572
|
+
TrackingResizeObserver.instances.push(this);
|
|
573
|
+
}
|
|
574
|
+
}
|
|
575
|
+
|
|
576
|
+
try {
|
|
577
|
+
window.ResizeObserver = TrackingResizeObserver;
|
|
578
|
+
globalThis.ResizeObserver = TrackingResizeObserver;
|
|
579
|
+
|
|
580
|
+
const mocks = document.getElementById("mocks");
|
|
581
|
+
const wrapper = document.createElement("div");
|
|
582
|
+
let parentWidth = 80;
|
|
583
|
+
|
|
584
|
+
Object.defineProperty(wrapper, "getBoundingClientRect", {
|
|
585
|
+
configurable: true,
|
|
586
|
+
value: () => ({ width: parentWidth }),
|
|
587
|
+
});
|
|
588
|
+
|
|
589
|
+
mocks.appendChild(wrapper);
|
|
590
|
+
|
|
591
|
+
const createColumnBar = async () => {
|
|
592
|
+
const columnBar = document.createElement("monster-column-bar");
|
|
593
|
+
columnBar.setOption("columns", [
|
|
594
|
+
{ index: 0, name: "One", visible: true },
|
|
595
|
+
{ index: 1, name: "Two", visible: true },
|
|
596
|
+
{ index: 2, name: "Three", visible: true },
|
|
597
|
+
{ index: 3, name: "Four", visible: true },
|
|
598
|
+
{ index: 4, name: "Five", visible: true },
|
|
599
|
+
{ index: 5, name: "Six", visible: true },
|
|
600
|
+
]);
|
|
601
|
+
wrapper.appendChild(columnBar);
|
|
602
|
+
|
|
603
|
+
await new Promise((resolve) => setTimeout(resolve, 30));
|
|
604
|
+
|
|
605
|
+
const control = columnBar.shadowRoot.querySelector(
|
|
606
|
+
"[data-monster-role=control]",
|
|
607
|
+
);
|
|
608
|
+
const settingsButton = columnBar.shadowRoot.querySelector(
|
|
609
|
+
"[data-monster-role=settings-button]",
|
|
610
|
+
);
|
|
611
|
+
const dotsContainer = columnBar.shadowRoot.querySelector(
|
|
612
|
+
"[data-monster-role=dots]",
|
|
613
|
+
);
|
|
614
|
+
const dots = Array.from(dotsContainer.querySelectorAll("li"));
|
|
615
|
+
|
|
616
|
+
Object.defineProperty(control, "getBoundingClientRect", {
|
|
617
|
+
configurable: true,
|
|
618
|
+
value: () => ({ width: parentWidth }),
|
|
619
|
+
});
|
|
620
|
+
Object.defineProperty(settingsButton, "getBoundingClientRect", {
|
|
621
|
+
configurable: true,
|
|
622
|
+
value: () => ({ width: 20 }),
|
|
623
|
+
});
|
|
624
|
+
dots.forEach((dot) => {
|
|
625
|
+
Object.defineProperty(dot, "getBoundingClientRect", {
|
|
626
|
+
configurable: true,
|
|
627
|
+
value: () => ({ width: 20 }),
|
|
628
|
+
});
|
|
629
|
+
});
|
|
630
|
+
|
|
631
|
+
return { columnBar, control, dotsContainer };
|
|
632
|
+
};
|
|
633
|
+
|
|
634
|
+
const first = await createColumnBar();
|
|
635
|
+
const second = await createColumnBar();
|
|
636
|
+
|
|
637
|
+
const firstResizeObserver = TrackingResizeObserver.instances.find(
|
|
638
|
+
(observer) => observer.elements.includes(first.control),
|
|
639
|
+
);
|
|
640
|
+
const secondResizeObserver = TrackingResizeObserver.instances.find(
|
|
641
|
+
(observer) => observer.elements.includes(second.control),
|
|
642
|
+
);
|
|
643
|
+
|
|
644
|
+
expect(firstResizeObserver).to.exist;
|
|
645
|
+
expect(secondResizeObserver).to.exist;
|
|
646
|
+
|
|
647
|
+
const scheduledCallbacks = [];
|
|
648
|
+
window.requestAnimationFrame = (callback) => {
|
|
649
|
+
scheduledCallbacks.push(callback);
|
|
650
|
+
return scheduledCallbacks.length;
|
|
651
|
+
};
|
|
652
|
+
globalThis.requestAnimationFrame = window.requestAnimationFrame;
|
|
653
|
+
|
|
654
|
+
firstResizeObserver.triggerResize([]);
|
|
655
|
+
secondResizeObserver.triggerResize([]);
|
|
656
|
+
|
|
657
|
+
expect(scheduledCallbacks.length).to.equal(1);
|
|
658
|
+
|
|
659
|
+
scheduledCallbacks.shift()();
|
|
660
|
+
|
|
661
|
+
expect(
|
|
662
|
+
first.dotsContainer.querySelector(".dots-overflow-indicator"),
|
|
663
|
+
).to.exist;
|
|
664
|
+
expect(
|
|
665
|
+
second.dotsContainer.querySelector(".dots-overflow-indicator"),
|
|
666
|
+
).to.exist;
|
|
667
|
+
|
|
668
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
669
|
+
|
|
670
|
+
expect(scheduledCallbacks.length).to.equal(0);
|
|
671
|
+
} finally {
|
|
672
|
+
window.ResizeObserver = OriginalResizeObserver;
|
|
673
|
+
globalThis.ResizeObserver = originalGlobalResizeObserver;
|
|
674
|
+
window.requestAnimationFrame = originalRequestAnimationFrame;
|
|
675
|
+
globalThis.requestAnimationFrame = originalGlobalRequestAnimationFrame;
|
|
676
|
+
}
|
|
677
|
+
});
|
|
560
678
|
});
|