@schukai/monster 4.141.2 → 4.142.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.
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.141.2"}
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.142.0"}
@@ -319,6 +319,12 @@ class Pagination extends CustomElement {
319
319
 
320
320
  setTimeout(() => {
321
321
  const parentParentNode = parentNode?.parentNode || parentNode;
322
+ const sizeContainer =
323
+ parentParentNode instanceof HTMLElement
324
+ ? parentParentNode
325
+ : parentNode instanceof HTMLElement
326
+ ? parentNode
327
+ : this;
322
328
 
323
329
  this[resizeObserverSymbol] = new ResizeObserver(() => {
324
330
  if (this[layoutApplySymbol]) {
@@ -340,7 +346,7 @@ class Pagination extends CustomElement {
340
346
  return;
341
347
  }
342
348
 
343
- const parentWidth = parentParentNode.offsetWidth;
349
+ const parentWidth = sizeContainer.offsetWidth;
344
350
  const ownWidth = this.clientWidth;
345
351
 
346
352
  if (this[sizeDataSymbol]?.last?.parentWidth === parentWidth) {
@@ -366,7 +372,7 @@ class Pagination extends CustomElement {
366
372
  };
367
373
  schedulePaginationLayoutUpdate.call(this);
368
374
  } else {
369
- const parentWidth = parentParentNode.offsetWidth;
375
+ const parentWidth = sizeContainer.offsetWidth;
370
376
  const ownWidth = this.offsetWidth;
371
377
 
372
378
  this[sizeDataSymbol] = {
@@ -381,7 +387,7 @@ class Pagination extends CustomElement {
381
387
  }
382
388
  }
383
389
 
384
- this[resizeObserverSymbol].observe(parentParentNode);
390
+ this[resizeObserverSymbol].observe(sizeContainer);
385
391
  }, 0);
386
392
  }
387
393
 
@@ -186,6 +186,13 @@ const ATTRIBUTE_OPTION_LAYOUT_STACKED_ALIGNMENT =
186
186
  const ATTRIBUTE_OPTION_LAYOUT_STACKED_BREAKPOINT =
187
187
  "data-monster-option-layout-stacked-breakpoint";
188
188
 
189
+ /**
190
+ * @private
191
+ * @type {string}
192
+ */
193
+ const ATTRIBUTE_OPTION_LAYOUT_STACKED_BREAKPOINT_CONTAINER =
194
+ "data-monster-option-layout-stacked-breakpoint-container";
195
+
189
196
  /**
190
197
  * @private
191
198
  * @type {string}
@@ -241,6 +248,7 @@ class ControlBar extends CustomElement {
241
248
  alignment: "left",
242
249
  stackedAlignment: undefined,
243
250
  stackedBreakpoint: undefined,
251
+ stackedBreakpointContainer: undefined,
244
252
  },
245
253
  popper: {
246
254
  placement: "left",
@@ -270,6 +278,7 @@ class ControlBar extends CustomElement {
270
278
  initialLayoutOpacity: undefined,
271
279
  suppressSlotChange: false,
272
280
  suppressMutation: false,
281
+ suppressResize: false,
273
282
  };
274
283
 
275
284
  initControlReferences.call(this);
@@ -301,9 +310,12 @@ class ControlBar extends CustomElement {
301
310
  if (
302
311
  path === "layout.alignment" ||
303
312
  path === "layout.stackedAlignment" ||
304
- path === "layout.stackedBreakpoint"
313
+ path === "layout.stackedBreakpoint" ||
314
+ path === "layout.stackedBreakpointContainer"
305
315
  ) {
306
- syncLayoutState.call(this);
316
+ syncLayoutState.call(this, {
317
+ observe: path === "layout.stackedBreakpointContainer",
318
+ });
307
319
  }
308
320
  return this;
309
321
  }
@@ -355,6 +367,7 @@ class ControlBar extends CustomElement {
355
367
  attributes.push(ATTRIBUTE_OPTION_LAYOUT_ALIGNMENT);
356
368
  attributes.push(ATTRIBUTE_OPTION_LAYOUT_STACKED_ALIGNMENT);
357
369
  attributes.push(ATTRIBUTE_OPTION_LAYOUT_STACKED_BREAKPOINT);
370
+ attributes.push(ATTRIBUTE_OPTION_LAYOUT_STACKED_BREAKPOINT_CONTAINER);
358
371
  return attributes;
359
372
  }
360
373
 
@@ -590,7 +603,16 @@ function initEventHandler() {
590
603
  syncLayoutState.call(self);
591
604
  };
592
605
 
593
- self[resizeObserverSymbol] = new ResizeObserver(() => {
606
+ self[attributeObserverSymbol][
607
+ ATTRIBUTE_OPTION_LAYOUT_STACKED_BREAKPOINT_CONTAINER
608
+ ] = () => {
609
+ syncLayoutState.call(self, { observe: true });
610
+ };
611
+
612
+ self[resizeObserverSymbol] = new ResizeObserver((entries) => {
613
+ if (!hasContainerResizeEntry.call(self, entries)) {
614
+ return;
615
+ }
594
616
  scheduleLayout.call(self, { measure: true, layout: true });
595
617
  });
596
618
  self[mutationObserverSymbol] = new MutationObserver(mutationCallback);
@@ -801,8 +823,7 @@ function rearrangeItems() {
801
823
  layout = layoutItems(space - switchWidth);
802
824
  }
803
825
 
804
- const shouldShowSwitch =
805
- layout.itemsToMoveToPopper.length > 0 && hasItems;
826
+ const shouldShowSwitch = layout.itemsToMoveToPopper.length > 0 && hasItems;
806
827
  const shouldUseStackedLayout =
807
828
  shouldShowSwitch || isStackedBreakpointMatched.call(this);
808
829
 
@@ -883,17 +904,11 @@ function getComputedCssPixels(value) {
883
904
  */
884
905
  function updateControlSizing(layout, shouldShowSwitch) {
885
906
  const mainItems = [...layout.visibleItemsInMainSlot];
886
- if (
887
- shouldShowSwitch &&
888
- this[popperNavElementSymbol] instanceof HTMLElement
889
- ) {
907
+ if (shouldShowSwitch && this[popperNavElementSymbol] instanceof HTMLElement) {
890
908
  mainItems.push(this[popperNavElementSymbol]);
891
909
  }
892
910
 
893
- const controlItems = [
894
- ...mainItems,
895
- ...layout.itemsToMoveToPopper,
896
- ];
911
+ const controlItems = [...mainItems, ...layout.itemsToMoveToPopper];
897
912
  for (const element of controlItems) {
898
913
  applyControlSizing.call(this, element);
899
914
  }
@@ -992,13 +1007,7 @@ function updateJoinedBorders(layout, shouldShowSwitch) {
992
1007
  layout.itemsToMoveToPopper,
993
1008
  marginTopByElement,
994
1009
  );
995
- updateSpacerLineWidths.call(
996
- this,
997
- mainItems,
998
- "inline",
999
- "right",
1000
- "left",
1001
- );
1010
+ updateSpacerLineWidths.call(this, mainItems, "inline", "right", "left");
1002
1011
  updateSpacerLineWidths.call(
1003
1012
  this,
1004
1013
  layout.itemsToMoveToPopper,
@@ -1272,6 +1281,10 @@ function calculateControlBarDimensions() {
1272
1281
 
1273
1282
  this[dimensionsSymbol].setVia("data.visible", !(containerWidth === 0));
1274
1283
  this[dimensionsSymbol].setVia("data.containerWidth", containerWidth);
1284
+ this[dimensionsSymbol].setVia(
1285
+ "data.stackedBreakpointContainerWidth",
1286
+ getStackedBreakpointContainerWidth.call(this),
1287
+ );
1275
1288
 
1276
1289
  const itemReferences = [];
1277
1290
 
@@ -1336,6 +1349,65 @@ function calculateControlBarDimensions() {
1336
1349
  this[dimensionsSymbol].setVia("data.itemReferences", itemReferences);
1337
1350
  }
1338
1351
 
1352
+ /**
1353
+ * @private
1354
+ * @return {number}
1355
+ */
1356
+ function getStackedBreakpointContainerWidth() {
1357
+ const container = resolveStackedBreakpointContainer.call(this);
1358
+ if (!(container instanceof HTMLElement)) {
1359
+ return 0;
1360
+ }
1361
+
1362
+ return getElementLayoutWidth(container);
1363
+ }
1364
+
1365
+ /**
1366
+ * @private
1367
+ * @return {HTMLElement|undefined}
1368
+ */
1369
+ function resolveStackedBreakpointContainer() {
1370
+ const selector = this.getOption("layout.stackedBreakpointContainer");
1371
+ if (typeof selector !== "string" || selector.trim() === "") {
1372
+ return undefined;
1373
+ }
1374
+
1375
+ try {
1376
+ const closest = this.closest(selector);
1377
+ if (closest instanceof HTMLElement) {
1378
+ return closest;
1379
+ }
1380
+
1381
+ const root = this.getRootNode();
1382
+ if (root && typeof root.querySelector === "function") {
1383
+ const found = root.querySelector(selector);
1384
+ if (found instanceof HTMLElement) {
1385
+ return found;
1386
+ }
1387
+ }
1388
+ } catch {}
1389
+
1390
+ return undefined;
1391
+ }
1392
+
1393
+ /**
1394
+ * @private
1395
+ * @param {HTMLElement} element
1396
+ * @return {number}
1397
+ */
1398
+ function getElementLayoutWidth(element) {
1399
+ const computedStyle = getComputedStyle(element);
1400
+ if (computedStyle === null) {
1401
+ return 0;
1402
+ }
1403
+
1404
+ if (computedStyle.getPropertyValue("box-sizing") !== "border-box") {
1405
+ return getComputedCssPixels(computedStyle.getPropertyValue("width"));
1406
+ }
1407
+
1408
+ return element.clientWidth;
1409
+ }
1410
+
1339
1411
  /**
1340
1412
  * @private
1341
1413
  */
@@ -1369,20 +1441,21 @@ function updateResizeObserverObservation() {
1369
1441
  */
1370
1442
  function getLayoutObservedNodes() {
1371
1443
  const observedNodes = [];
1372
- Array.from(this.children).forEach((node) => {
1373
- if (node instanceof HTMLElement) {
1444
+ const addObservedNode = (node) => {
1445
+ if (node instanceof HTMLElement && !observedNodes.includes(node)) {
1374
1446
  observedNodes.push(node);
1375
1447
  }
1376
- });
1448
+ };
1449
+
1450
+ Array.from(this.children).forEach(addObservedNode);
1377
1451
 
1378
1452
  let parent = this.parentNode;
1379
1453
  while (!(parent instanceof HTMLElement) && parent !== null) {
1380
1454
  parent = parent.parentNode;
1381
1455
  }
1382
1456
 
1383
- if (parent instanceof HTMLElement) {
1384
- observedNodes.push(parent);
1385
- }
1457
+ addObservedNode(parent);
1458
+ addObservedNode(resolveStackedBreakpointContainer.call(this));
1386
1459
 
1387
1460
  return observedNodes;
1388
1461
  }
@@ -1422,9 +1495,27 @@ function suppressLayoutFeedback() {
1422
1495
 
1423
1496
  state.suppressSlotChange = true;
1424
1497
  state.suppressMutation = true;
1425
- queueMicrotask(() => {
1498
+ state.suppressResize = true;
1499
+ requestAnimationFrame(() => {
1426
1500
  state.suppressSlotChange = false;
1427
1501
  state.suppressMutation = false;
1502
+ state.suppressResize = false;
1503
+ });
1504
+ }
1505
+
1506
+ /**
1507
+ * @private
1508
+ * @param {ResizeObserverEntry[]} entries
1509
+ * @return {boolean}
1510
+ */
1511
+ function hasContainerResizeEntry(entries) {
1512
+ const stackedBreakpointContainer =
1513
+ resolveStackedBreakpointContainer.call(this);
1514
+ return entries.some((entry) => {
1515
+ return (
1516
+ entry.target === this.parentElement ||
1517
+ entry.target === stackedBreakpointContainer
1518
+ );
1428
1519
  });
1429
1520
  }
1430
1521
 
@@ -1546,32 +1637,41 @@ function applyLayoutAlignment() {
1546
1637
  }
1547
1638
 
1548
1639
  if (alignment === "right") {
1549
- if (setAttributeIfChanged(
1550
- this[controlBarElementSymbol],
1551
- ATTRIBUTE_LAYOUT_ALIGNMENT,
1552
- "right",
1553
- )) {
1640
+ if (
1641
+ setAttributeIfChanged(
1642
+ this[controlBarElementSymbol],
1643
+ ATTRIBUTE_LAYOUT_ALIGNMENT,
1644
+ "right",
1645
+ )
1646
+ ) {
1554
1647
  queueLayoutChangedEvent.call(this);
1555
1648
  }
1556
1649
  return;
1557
1650
  }
1558
1651
 
1559
- if (setAttributeIfChanged(
1560
- this[controlBarElementSymbol],
1561
- ATTRIBUTE_LAYOUT_ALIGNMENT,
1562
- "left",
1563
- )) {
1652
+ if (
1653
+ setAttributeIfChanged(
1654
+ this[controlBarElementSymbol],
1655
+ ATTRIBUTE_LAYOUT_ALIGNMENT,
1656
+ "left",
1657
+ )
1658
+ ) {
1564
1659
  queueLayoutChangedEvent.call(this);
1565
1660
  }
1566
1661
  }
1567
1662
 
1568
1663
  /**
1569
1664
  * @private
1665
+ * @param {{observe?: boolean}} options
1570
1666
  * @return {void}
1571
1667
  */
1572
- function syncLayoutState() {
1668
+ function syncLayoutState(options = {}) {
1573
1669
  applyLayoutAlignment.call(this);
1574
- scheduleLayout.call(this, { measure: true, layout: true });
1670
+ scheduleLayout.call(this, {
1671
+ measure: true,
1672
+ layout: true,
1673
+ observe: options.observe === true,
1674
+ });
1575
1675
  }
1576
1676
 
1577
1677
  /**
@@ -1586,11 +1686,19 @@ function isStackedBreakpointMatched() {
1586
1686
 
1587
1687
  let width = 0;
1588
1688
  try {
1589
- width = this[dimensionsSymbol].getVia("data.containerWidth");
1590
- } catch {
1689
+ width = this[dimensionsSymbol].getVia(
1690
+ "data.stackedBreakpointContainerWidth",
1691
+ );
1692
+ } catch {}
1693
+
1694
+ if (!(width > 0)) {
1591
1695
  try {
1592
- width = this[dimensionsSymbol].getVia("data.space");
1593
- } catch {}
1696
+ width = this[dimensionsSymbol].getVia("data.containerWidth");
1697
+ } catch {
1698
+ try {
1699
+ width = this[dimensionsSymbol].getVia("data.space");
1700
+ } catch {}
1701
+ }
1594
1702
  }
1595
1703
 
1596
1704
  if (!(width > 0)) {
@@ -1624,11 +1732,13 @@ function setLayoutStackedState(stacked) {
1624
1732
  return;
1625
1733
  }
1626
1734
 
1627
- if (setAttributeIfChanged(
1628
- this[controlBarElementSymbol],
1629
- ATTRIBUTE_LAYOUT_STACKED,
1630
- this[layoutStateSymbol].stacked ? "true" : "false",
1631
- )) {
1735
+ if (
1736
+ setAttributeIfChanged(
1737
+ this[controlBarElementSymbol],
1738
+ ATTRIBUTE_LAYOUT_STACKED,
1739
+ this[layoutStateSymbol].stacked ? "true" : "false",
1740
+ )
1741
+ ) {
1632
1742
  queueLayoutChangedEvent.call(this);
1633
1743
  }
1634
1744
  applyLayoutAlignment.call(this);
@@ -1643,7 +1753,9 @@ function queueLayoutChangedEvent() {
1643
1753
  return;
1644
1754
  }
1645
1755
 
1646
- this[layoutChangedEventQueueSymbol].add(getLayoutChangedEventDetail.call(this));
1756
+ this[layoutChangedEventQueueSymbol].add(
1757
+ getLayoutChangedEventDetail.call(this),
1758
+ );
1647
1759
 
1648
1760
  if (this[layoutChangedEventSwitchSymbol] instanceof DeadMansSwitch) {
1649
1761
  this[layoutChangedEventSwitchSymbol].touch();
@@ -1720,6 +1832,9 @@ function getLayoutChangedEventDetail() {
1720
1832
  stacked,
1721
1833
  stackedAlignment: this.getOption("layout.stackedAlignment"),
1722
1834
  stackedBreakpoint: this.getOption("layout.stackedBreakpoint"),
1835
+ stackedBreakpointContainer: this.getOption(
1836
+ "layout.stackedBreakpointContainer",
1837
+ ),
1723
1838
  };
1724
1839
  }
1725
1840