@schukai/monster 4.53.0 → 4.54.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/CHANGELOG.md +22 -0
- package/package.json +1 -1
- package/source/components/form/button-bar.mjs +112 -50
- package/source/dom/customelement.mjs +963 -959
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,28 @@
|
|
|
2
2
|
|
|
3
3
|
|
|
4
4
|
|
|
5
|
+
## [4.54.1] - 2025-12-28
|
|
6
|
+
|
|
7
|
+
### Bug Fixes
|
|
8
|
+
|
|
9
|
+
- Reorganize imports and improve code structure in CustomElement
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
## [4.54.0] - 2025-12-28
|
|
14
|
+
|
|
15
|
+
### Add Features
|
|
16
|
+
|
|
17
|
+
- Update project references and add issue handling for button bar
|
|
18
|
+
### Bug Fixes
|
|
19
|
+
|
|
20
|
+
- revert to jsdom 26.1
|
|
21
|
+
### Changes
|
|
22
|
+
|
|
23
|
+
- close issue [#347](https://gitlab.schukai.com/oss/libraries/javascript/monster/issues/347)
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
|
|
5
27
|
## [4.53.0] - 2025-12-28
|
|
6
28
|
|
|
7
29
|
### Add Features
|
package/package.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"author":"schukai GmbH","dependencies":{"@floating-ui/dom":"^1.7.4","@popperjs/core":"^2.11.8"},"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.
|
|
1
|
+
{"author":"schukai GmbH","dependencies":{"@floating-ui/dom":"^1.7.4","@popperjs/core":"^2.11.8"},"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.54.1"}
|
|
@@ -112,6 +112,12 @@ const popperSwitchEventHandler = Symbol("popperSwitchEventHandler");
|
|
|
112
112
|
*/
|
|
113
113
|
const popperNavElementSymbol = Symbol("popperNavElement");
|
|
114
114
|
|
|
115
|
+
/**
|
|
116
|
+
* @private
|
|
117
|
+
* @type {symbol}
|
|
118
|
+
*/
|
|
119
|
+
const mutationObserverSymbol = Symbol("mutationObserver");
|
|
120
|
+
|
|
115
121
|
/**
|
|
116
122
|
* @private
|
|
117
123
|
* @type {symbol}
|
|
@@ -257,6 +263,9 @@ class ButtonBar extends CustomElement {
|
|
|
257
263
|
}
|
|
258
264
|
|
|
259
265
|
disconnectResizeObserver.call(this);
|
|
266
|
+
if (this[mutationObserverSymbol]) {
|
|
267
|
+
this[mutationObserverSymbol].disconnect();
|
|
268
|
+
}
|
|
260
269
|
}
|
|
261
270
|
|
|
262
271
|
/**
|
|
@@ -318,67 +327,82 @@ function isElementTrulyVisible(element) {
|
|
|
318
327
|
*/
|
|
319
328
|
function initEventHandler() {
|
|
320
329
|
const self = this;
|
|
330
|
+
|
|
331
|
+
const triggerRecalculation = () => {
|
|
332
|
+
if (self[timerCallbackSymbol] instanceof DeadMansSwitch) {
|
|
333
|
+
try {
|
|
334
|
+
self[timerCallbackSymbol].touch();
|
|
335
|
+
return;
|
|
336
|
+
} catch (e) {
|
|
337
|
+
if (e.message !== "has already run") throw e;
|
|
338
|
+
delete self[timerCallbackSymbol];
|
|
339
|
+
}
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
self[timerCallbackSymbol] = new DeadMansSwitch(50, () => {
|
|
343
|
+
requestAnimationFrame(() => {
|
|
344
|
+
updatePopper.call(self);
|
|
345
|
+
self[dimensionsSymbol].setVia("data.calculated", false);
|
|
346
|
+
try {
|
|
347
|
+
checkAndRearrangeButtons.call(self);
|
|
348
|
+
} catch (error) {
|
|
349
|
+
addErrorAttribute(
|
|
350
|
+
self,
|
|
351
|
+
error?.message || "An error occurred while rearranging the buttons",
|
|
352
|
+
);
|
|
353
|
+
}
|
|
354
|
+
});
|
|
355
|
+
});
|
|
356
|
+
};
|
|
357
|
+
|
|
358
|
+
const mutationCallback = (mutationList) => {
|
|
359
|
+
let needsRecalc = false;
|
|
360
|
+
for (const mutation of mutationList) {
|
|
361
|
+
if (mutation.type === "attributes") {
|
|
362
|
+
const target = mutation.target;
|
|
363
|
+
if (target instanceof HTMLElement) {
|
|
364
|
+
const ref = target.getAttribute("data-monster-reference");
|
|
365
|
+
if (ref && !isElementTrulyVisible(target)) {
|
|
366
|
+
self[dimensionsSymbol].setVia(`data.button.${ref}`, 0);
|
|
367
|
+
needsRecalc = true;
|
|
368
|
+
}
|
|
369
|
+
}
|
|
370
|
+
}
|
|
371
|
+
}
|
|
372
|
+
if (needsRecalc) {
|
|
373
|
+
triggerRecalculation();
|
|
374
|
+
}
|
|
375
|
+
};
|
|
376
|
+
|
|
321
377
|
/**
|
|
322
378
|
* @param {Event} event
|
|
323
379
|
*/
|
|
324
380
|
self[closeEventHandler] = (event) => {
|
|
325
381
|
const path = event.composedPath();
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
if (element === self) {
|
|
329
|
-
return;
|
|
330
|
-
}
|
|
382
|
+
for (const element of path) {
|
|
383
|
+
if (element === self) return;
|
|
331
384
|
}
|
|
332
|
-
|
|
333
385
|
hide.call(self);
|
|
334
386
|
};
|
|
335
387
|
|
|
336
388
|
if (self[buttonBarSlotElementSymbol]) {
|
|
337
|
-
self[buttonBarSlotElementSymbol].addEventListener("slotchange", (
|
|
389
|
+
self[buttonBarSlotElementSymbol].addEventListener("slotchange", () => {
|
|
338
390
|
checkAndRearrangeButtons.call(self);
|
|
339
391
|
});
|
|
340
392
|
}
|
|
341
393
|
|
|
342
394
|
if (self[popperElementSymbol]) {
|
|
343
|
-
self[popperElementSymbol].addEventListener("slotchange", (
|
|
395
|
+
self[popperElementSymbol].addEventListener("slotchange", () => {
|
|
344
396
|
checkAndRearrangeButtons.call(self);
|
|
345
397
|
});
|
|
346
398
|
}
|
|
347
399
|
|
|
348
|
-
// data-monster-options
|
|
349
400
|
self[attributeObserverSymbol][ATTRIBUTE_POPPER_POSITION] = function (value) {
|
|
350
401
|
self.setOption("classes.button", value);
|
|
351
402
|
};
|
|
352
403
|
|
|
353
|
-
self[resizeObserverSymbol] = new ResizeObserver(
|
|
354
|
-
|
|
355
|
-
try {
|
|
356
|
-
self[timerCallbackSymbol].touch();
|
|
357
|
-
return;
|
|
358
|
-
} catch (e) {
|
|
359
|
-
// catch Error("has already run");
|
|
360
|
-
if (e.message !== "has already run") {
|
|
361
|
-
throw e;
|
|
362
|
-
}
|
|
363
|
-
delete self[timerCallbackSymbol];
|
|
364
|
-
}
|
|
365
|
-
}
|
|
366
|
-
|
|
367
|
-
self[timerCallbackSymbol] = new DeadMansSwitch(200, () => {
|
|
368
|
-
requestAnimationFrame(() => {
|
|
369
|
-
updatePopper.call(self);
|
|
370
|
-
self[dimensionsSymbol].setVia("data.calculated", false);
|
|
371
|
-
try {
|
|
372
|
-
checkAndRearrangeButtons.call(self);
|
|
373
|
-
} catch (error) {
|
|
374
|
-
addErrorAttribute(
|
|
375
|
-
this,
|
|
376
|
-
error?.message || "An error occurred while rearranging the buttons",
|
|
377
|
-
);
|
|
378
|
-
}
|
|
379
|
-
});
|
|
380
|
-
});
|
|
381
|
-
});
|
|
404
|
+
self[resizeObserverSymbol] = new ResizeObserver(triggerRecalculation);
|
|
405
|
+
self[mutationObserverSymbol] = new MutationObserver(mutationCallback);
|
|
382
406
|
|
|
383
407
|
initSlotChangedHandler.call(self);
|
|
384
408
|
}
|
|
@@ -440,17 +464,39 @@ function rearrangeButtons() {
|
|
|
440
464
|
continue;
|
|
441
465
|
}
|
|
442
466
|
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
467
|
+
let buttonWidth = 0;
|
|
468
|
+
try {
|
|
469
|
+
buttonWidth = this[dimensionsSymbol].getVia(`data.button.${ref}`);
|
|
470
|
+
} catch (e) {
|
|
471
|
+
// If the path does not exist, pathfinder throws an error.
|
|
472
|
+
// In this case, we assume the width is 0.
|
|
473
|
+
// This can happen for buttons that have never been visible.
|
|
474
|
+
}
|
|
475
|
+
const style = getComputedStyle(element);
|
|
476
|
+
|
|
477
|
+
// A user-hidden button should not participate in layout calculations.
|
|
478
|
+
// We will assign it to the popper to keep it out of the flow.
|
|
479
|
+
if (style.display === "none") {
|
|
480
|
+
// This button is not visible. It could be user-hidden, or it could be
|
|
481
|
+
// in the popper which is currently hidden.
|
|
482
|
+
// We should only count it towards the popper if it has a non-zero width,
|
|
483
|
+
// which implies it's a genuinely overflowing button, not one that is
|
|
484
|
+
// user-hidden from the start.
|
|
485
|
+
if (buttonWidth > 0) {
|
|
446
486
|
buttonsToMoveToPopper.push(element);
|
|
447
487
|
} else {
|
|
448
|
-
|
|
488
|
+
// It has 0 width. Treat it as a truly hidden element.
|
|
489
|
+
// Put it in the main slot, where it will be invisible and take no space.
|
|
449
490
|
visibleButtonsInMainSlot.push(element);
|
|
450
491
|
}
|
|
492
|
+
continue;
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
const switchWidth = this[dimensionsSymbol].getVia("data.switchWidth") || 2;
|
|
496
|
+
if (sum + buttonWidth > space - switchWidth) { buttonsToMoveToPopper.push(element);
|
|
451
497
|
} else {
|
|
452
|
-
|
|
453
|
-
|
|
498
|
+
sum += buttonWidth;
|
|
499
|
+
visibleButtonsInMainSlot.push(element);
|
|
454
500
|
}
|
|
455
501
|
}
|
|
456
502
|
|
|
@@ -462,11 +508,9 @@ function rearrangeButtons() {
|
|
|
462
508
|
button.removeAttribute("slot");
|
|
463
509
|
}
|
|
464
510
|
|
|
465
|
-
const
|
|
466
|
-
getSlottedElements.call(this, ":scope", "popper"),
|
|
467
|
-
).filter(isElementTrulyVisible);
|
|
511
|
+
const buttonsInPopper = getSlottedElements.call(this, ":scope", "popper");
|
|
468
512
|
|
|
469
|
-
if (
|
|
513
|
+
if (buttonsInPopper.size > 0) {
|
|
470
514
|
this[switchElementSymbol].classList.remove("hidden");
|
|
471
515
|
} else {
|
|
472
516
|
this[switchElementSymbol].classList.add("hidden");
|
|
@@ -576,9 +620,11 @@ function calculateButtonBarDimensions() {
|
|
|
576
620
|
const ref = button.getAttribute("data-monster-reference");
|
|
577
621
|
if (ref === null) continue;
|
|
578
622
|
|
|
579
|
-
|
|
623
|
+
buttonReferences.push(ref);
|
|
624
|
+
|
|
625
|
+
// Only calculate width for visible buttons. Assume invisible ones
|
|
626
|
+
// (e.g. in popper) have their width calculated previously and stored.
|
|
580
627
|
if (isElementTrulyVisible(button)) {
|
|
581
|
-
buttonReferences.push(ref);
|
|
582
628
|
this[dimensionsSymbol].setVia(
|
|
583
629
|
`data.button.${ref}`,
|
|
584
630
|
calcBoxWidth.call(this, button),
|
|
@@ -586,6 +632,13 @@ function calculateButtonBarDimensions() {
|
|
|
586
632
|
}
|
|
587
633
|
}
|
|
588
634
|
|
|
635
|
+
if (this[switchElementSymbol]) {
|
|
636
|
+
this[dimensionsSymbol].setVia(
|
|
637
|
+
"data.switchWidth",
|
|
638
|
+
this[switchElementSymbol].offsetWidth,
|
|
639
|
+
);
|
|
640
|
+
}
|
|
641
|
+
|
|
589
642
|
this[dimensionsSymbol].setVia("data.calculated", true);
|
|
590
643
|
this[dimensionsSymbol].setVia("data.buttonReferences", buttonReferences);
|
|
591
644
|
}
|
|
@@ -595,10 +648,19 @@ function calculateButtonBarDimensions() {
|
|
|
595
648
|
*/
|
|
596
649
|
function updateResizeObserverObservation() {
|
|
597
650
|
this[resizeObserverSymbol].disconnect();
|
|
651
|
+
if (this[mutationObserverSymbol]) {
|
|
652
|
+
this[mutationObserverSymbol].disconnect();
|
|
653
|
+
}
|
|
598
654
|
|
|
599
655
|
const slottedNodes = getSlottedElements.call(this);
|
|
600
656
|
slottedNodes.forEach((node) => {
|
|
601
657
|
this[resizeObserverSymbol].observe(node);
|
|
658
|
+
if (this[mutationObserverSymbol]) {
|
|
659
|
+
this[mutationObserverSymbol].observe(node, {
|
|
660
|
+
attributes: true,
|
|
661
|
+
attributeFilter: ["style", "class"],
|
|
662
|
+
});
|
|
663
|
+
}
|
|
602
664
|
});
|
|
603
665
|
|
|
604
666
|
requestAnimationFrame(() => {
|