@schukai/monster 4.140.3 → 4.141.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/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.
|
|
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.1"}
|
|
@@ -179,6 +179,13 @@ const ATTRIBUTE_OPTION_LAYOUT_ALIGNMENT =
|
|
|
179
179
|
const ATTRIBUTE_OPTION_LAYOUT_STACKED_ALIGNMENT =
|
|
180
180
|
"data-monster-option-layout-stacked-alignment";
|
|
181
181
|
|
|
182
|
+
/**
|
|
183
|
+
* @private
|
|
184
|
+
* @type {string}
|
|
185
|
+
*/
|
|
186
|
+
const ATTRIBUTE_OPTION_LAYOUT_STACKED_BREAKPOINT =
|
|
187
|
+
"data-monster-option-layout-stacked-breakpoint";
|
|
188
|
+
|
|
182
189
|
/**
|
|
183
190
|
* @private
|
|
184
191
|
* @type {string}
|
|
@@ -233,6 +240,7 @@ class ControlBar extends CustomElement {
|
|
|
233
240
|
layout: {
|
|
234
241
|
alignment: "left",
|
|
235
242
|
stackedAlignment: undefined,
|
|
243
|
+
stackedBreakpoint: undefined,
|
|
236
244
|
},
|
|
237
245
|
popper: {
|
|
238
246
|
placement: "left",
|
|
@@ -287,7 +295,11 @@ class ControlBar extends CustomElement {
|
|
|
287
295
|
*/
|
|
288
296
|
setOption(path, value) {
|
|
289
297
|
super.setOption(path, value);
|
|
290
|
-
if (
|
|
298
|
+
if (
|
|
299
|
+
path === "layout.alignment" ||
|
|
300
|
+
path === "layout.stackedAlignment" ||
|
|
301
|
+
path === "layout.stackedBreakpoint"
|
|
302
|
+
) {
|
|
291
303
|
syncLayoutState.call(this);
|
|
292
304
|
}
|
|
293
305
|
return this;
|
|
@@ -339,6 +351,7 @@ class ControlBar extends CustomElement {
|
|
|
339
351
|
attributes.push(ATTRIBUTE_POPPER_POSITION);
|
|
340
352
|
attributes.push(ATTRIBUTE_OPTION_LAYOUT_ALIGNMENT);
|
|
341
353
|
attributes.push(ATTRIBUTE_OPTION_LAYOUT_STACKED_ALIGNMENT);
|
|
354
|
+
attributes.push(ATTRIBUTE_OPTION_LAYOUT_STACKED_BREAKPOINT);
|
|
342
355
|
return attributes;
|
|
343
356
|
}
|
|
344
357
|
|
|
@@ -531,6 +544,11 @@ function initEventHandler() {
|
|
|
531
544
|
syncLayoutState.call(self);
|
|
532
545
|
};
|
|
533
546
|
|
|
547
|
+
self[attributeObserverSymbol][ATTRIBUTE_OPTION_LAYOUT_STACKED_BREAKPOINT] =
|
|
548
|
+
() => {
|
|
549
|
+
syncLayoutState.call(self);
|
|
550
|
+
};
|
|
551
|
+
|
|
534
552
|
self[resizeObserverSymbol] = new ResizeObserver(() => {
|
|
535
553
|
scheduleLayout.call(self, { measure: true, layout: true });
|
|
536
554
|
});
|
|
@@ -743,9 +761,11 @@ function rearrangeItems() {
|
|
|
743
761
|
|
|
744
762
|
const shouldShowSwitch =
|
|
745
763
|
layout.itemsToMoveToPopper.length > 0 && hasItems;
|
|
764
|
+
const shouldUseStackedLayout =
|
|
765
|
+
shouldShowSwitch || isStackedBreakpointMatched.call(this);
|
|
746
766
|
|
|
747
767
|
suppressLayoutFeedback.call(this);
|
|
748
|
-
setLayoutStackedState.call(this,
|
|
768
|
+
setLayoutStackedState.call(this, shouldUseStackedLayout);
|
|
749
769
|
|
|
750
770
|
for (const item of layout.itemsToMoveToPopper) {
|
|
751
771
|
if (item.getAttribute("slot") !== "popper") {
|
|
@@ -1183,10 +1203,12 @@ function calculateControlBarDimensions() {
|
|
|
1183
1203
|
}
|
|
1184
1204
|
|
|
1185
1205
|
let width = this.parentElement.clientWidth;
|
|
1206
|
+
let containerWidth = width;
|
|
1186
1207
|
if (computedStyle.getPropertyValue("box-sizing") !== "border-box") {
|
|
1187
1208
|
width = computedStyle.getPropertyValue("width");
|
|
1188
1209
|
|
|
1189
1210
|
const pixel = getComputedCssPixels(width);
|
|
1211
|
+
containerWidth = pixel;
|
|
1190
1212
|
|
|
1191
1213
|
this[dimensionsSymbol].setVia("data.space", pixel);
|
|
1192
1214
|
} else {
|
|
@@ -1206,7 +1228,8 @@ function calculateControlBarDimensions() {
|
|
|
1206
1228
|
);
|
|
1207
1229
|
}
|
|
1208
1230
|
|
|
1209
|
-
this[dimensionsSymbol].setVia("data.visible", !(
|
|
1231
|
+
this[dimensionsSymbol].setVia("data.visible", !(containerWidth === 0));
|
|
1232
|
+
this[dimensionsSymbol].setVia("data.containerWidth", containerWidth);
|
|
1210
1233
|
|
|
1211
1234
|
const itemReferences = [];
|
|
1212
1235
|
|
|
@@ -1509,6 +1532,41 @@ function syncLayoutState() {
|
|
|
1509
1532
|
scheduleLayout.call(this, { measure: true, layout: true });
|
|
1510
1533
|
}
|
|
1511
1534
|
|
|
1535
|
+
/**
|
|
1536
|
+
* @private
|
|
1537
|
+
* @return {boolean}
|
|
1538
|
+
*/
|
|
1539
|
+
function isStackedBreakpointMatched() {
|
|
1540
|
+
const breakpoint = this.getOption("layout.stackedBreakpoint");
|
|
1541
|
+
if (typeof breakpoint !== "string" || breakpoint.trim() === "") {
|
|
1542
|
+
return false;
|
|
1543
|
+
}
|
|
1544
|
+
|
|
1545
|
+
let width = 0;
|
|
1546
|
+
try {
|
|
1547
|
+
width = this[dimensionsSymbol].getVia("data.containerWidth");
|
|
1548
|
+
} catch {
|
|
1549
|
+
try {
|
|
1550
|
+
width = this[dimensionsSymbol].getVia("data.space");
|
|
1551
|
+
} catch {}
|
|
1552
|
+
}
|
|
1553
|
+
|
|
1554
|
+
if (!(width > 0)) {
|
|
1555
|
+
width = getComputedCssPixels(width);
|
|
1556
|
+
}
|
|
1557
|
+
|
|
1558
|
+
if (!(width > 0)) {
|
|
1559
|
+
return false;
|
|
1560
|
+
}
|
|
1561
|
+
|
|
1562
|
+
const breakpointWidth = getComputedCssPixels(breakpoint);
|
|
1563
|
+
if (!(breakpointWidth > 0)) {
|
|
1564
|
+
return false;
|
|
1565
|
+
}
|
|
1566
|
+
|
|
1567
|
+
return width <= breakpointWidth;
|
|
1568
|
+
}
|
|
1569
|
+
|
|
1512
1570
|
/**
|
|
1513
1571
|
* @private
|
|
1514
1572
|
* @param {boolean} stacked
|
|
@@ -1531,6 +1589,7 @@ function setLayoutStackedState(stacked) {
|
|
|
1531
1589
|
)) {
|
|
1532
1590
|
queueLayoutChangedEvent.call(this);
|
|
1533
1591
|
}
|
|
1592
|
+
applyLayoutAlignment.call(this);
|
|
1534
1593
|
}
|
|
1535
1594
|
|
|
1536
1595
|
/**
|
|
@@ -1618,6 +1677,7 @@ function getLayoutChangedEventDetail() {
|
|
|
1618
1677
|
configuredAlignment: this.getOption("layout.alignment", "left"),
|
|
1619
1678
|
stacked,
|
|
1620
1679
|
stackedAlignment: this.getOption("layout.stackedAlignment"),
|
|
1680
|
+
stackedBreakpoint: this.getOption("layout.stackedBreakpoint"),
|
|
1621
1681
|
};
|
|
1622
1682
|
}
|
|
1623
1683
|
|
|
@@ -161,6 +161,7 @@ describe("ControlBar", function () {
|
|
|
161
161
|
configuredAlignment: "left",
|
|
162
162
|
stacked: false,
|
|
163
163
|
stackedAlignment: undefined,
|
|
164
|
+
stackedBreakpoint: undefined,
|
|
164
165
|
});
|
|
165
166
|
});
|
|
166
167
|
|
|
@@ -660,4 +661,183 @@ describe("ControlBar", function () {
|
|
|
660
661
|
globalThis.requestAnimationFrame = originalGlobalRequestAnimationFrame;
|
|
661
662
|
}
|
|
662
663
|
});
|
|
664
|
+
|
|
665
|
+
it("should apply stacked alignment below the configured container breakpoint without overflow", async function () {
|
|
666
|
+
const originalRequestAnimationFrame = window.requestAnimationFrame;
|
|
667
|
+
const originalGlobalRequestAnimationFrame = globalThis.requestAnimationFrame;
|
|
668
|
+
|
|
669
|
+
const scheduledCallbacks = [];
|
|
670
|
+
const flushFrames = async () => {
|
|
671
|
+
while (scheduledCallbacks.length > 0) {
|
|
672
|
+
scheduledCallbacks.shift()();
|
|
673
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
674
|
+
}
|
|
675
|
+
};
|
|
676
|
+
|
|
677
|
+
try {
|
|
678
|
+
window.requestAnimationFrame = (callback) => {
|
|
679
|
+
scheduledCallbacks.push(callback);
|
|
680
|
+
return scheduledCallbacks.length;
|
|
681
|
+
};
|
|
682
|
+
globalThis.requestAnimationFrame = window.requestAnimationFrame;
|
|
683
|
+
|
|
684
|
+
const mocks = document.getElementById("mocks");
|
|
685
|
+
mocks.innerHTML = `
|
|
686
|
+
<div id="breakpoint-bar-wrapper">
|
|
687
|
+
<monster-control-bar
|
|
688
|
+
id="breakpoint-bar"
|
|
689
|
+
data-monster-option-layout-alignment="right"
|
|
690
|
+
data-monster-option-layout-stacked-alignment="left"
|
|
691
|
+
data-monster-option-layout-stacked-breakpoint="100px"
|
|
692
|
+
>
|
|
693
|
+
<button id="breakpoint-button">Run</button>
|
|
694
|
+
</monster-control-bar>
|
|
695
|
+
</div>
|
|
696
|
+
`;
|
|
697
|
+
|
|
698
|
+
const wrapper = document.getElementById("breakpoint-bar-wrapper");
|
|
699
|
+
const button = document.getElementById("breakpoint-button");
|
|
700
|
+
const bar = document.getElementById("breakpoint-bar");
|
|
701
|
+
const controlBar = bar.shadowRoot.querySelector(
|
|
702
|
+
'[data-monster-role="control-bar"]',
|
|
703
|
+
);
|
|
704
|
+
const switchButton = bar.shadowRoot.querySelector(
|
|
705
|
+
'[data-monster-role="switch"]',
|
|
706
|
+
);
|
|
707
|
+
|
|
708
|
+
wrapper.style.boxSizing = "border-box";
|
|
709
|
+
Object.defineProperty(wrapper, "clientWidth", {
|
|
710
|
+
configurable: true,
|
|
711
|
+
value: 90,
|
|
712
|
+
});
|
|
713
|
+
Object.defineProperty(button, "offsetWidth", {
|
|
714
|
+
configurable: true,
|
|
715
|
+
value: 40,
|
|
716
|
+
});
|
|
717
|
+
Object.defineProperty(button, "offsetHeight", {
|
|
718
|
+
configurable: true,
|
|
719
|
+
value: 30,
|
|
720
|
+
});
|
|
721
|
+
button.getBoundingClientRect = () => ({
|
|
722
|
+
width: 40,
|
|
723
|
+
height: 30,
|
|
724
|
+
top: 0,
|
|
725
|
+
right: 40,
|
|
726
|
+
bottom: 30,
|
|
727
|
+
left: 0,
|
|
728
|
+
x: 0,
|
|
729
|
+
y: 0,
|
|
730
|
+
toJSON: () => {},
|
|
731
|
+
});
|
|
732
|
+
Object.defineProperty(switchButton, "offsetWidth", {
|
|
733
|
+
configurable: true,
|
|
734
|
+
value: 20,
|
|
735
|
+
});
|
|
736
|
+
|
|
737
|
+
await flushFrames();
|
|
738
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
739
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
740
|
+
|
|
741
|
+
expect(switchButton.hasAttribute("hidden")).to.be.true;
|
|
742
|
+
expect(button.hasAttribute("slot")).to.be.false;
|
|
743
|
+
expect(controlBar.getAttribute("data-monster-layout-stacked")).to.equal(
|
|
744
|
+
"true",
|
|
745
|
+
);
|
|
746
|
+
expect(controlBar.getAttribute("data-monster-layout-alignment")).to.equal(
|
|
747
|
+
"left",
|
|
748
|
+
);
|
|
749
|
+
} finally {
|
|
750
|
+
window.requestAnimationFrame = originalRequestAnimationFrame;
|
|
751
|
+
globalThis.requestAnimationFrame = originalGlobalRequestAnimationFrame;
|
|
752
|
+
}
|
|
753
|
+
});
|
|
754
|
+
|
|
755
|
+
it("should match the stacked breakpoint when the content-box container width is a css string", async function () {
|
|
756
|
+
const originalRequestAnimationFrame = window.requestAnimationFrame;
|
|
757
|
+
const originalGlobalRequestAnimationFrame = globalThis.requestAnimationFrame;
|
|
758
|
+
|
|
759
|
+
const scheduledCallbacks = [];
|
|
760
|
+
const flushFrames = async () => {
|
|
761
|
+
while (scheduledCallbacks.length > 0) {
|
|
762
|
+
scheduledCallbacks.shift()();
|
|
763
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
764
|
+
}
|
|
765
|
+
};
|
|
766
|
+
|
|
767
|
+
try {
|
|
768
|
+
window.requestAnimationFrame = (callback) => {
|
|
769
|
+
scheduledCallbacks.push(callback);
|
|
770
|
+
return scheduledCallbacks.length;
|
|
771
|
+
};
|
|
772
|
+
globalThis.requestAnimationFrame = window.requestAnimationFrame;
|
|
773
|
+
|
|
774
|
+
const mocks = document.getElementById("mocks");
|
|
775
|
+
mocks.innerHTML = `
|
|
776
|
+
<div id="content-box-breakpoint-wrapper">
|
|
777
|
+
<monster-control-bar
|
|
778
|
+
id="content-box-breakpoint-bar"
|
|
779
|
+
data-monster-option-layout-alignment="right"
|
|
780
|
+
data-monster-option-layout-stacked-alignment="left"
|
|
781
|
+
data-monster-option-layout-stacked-breakpoint="480px"
|
|
782
|
+
>
|
|
783
|
+
<button id="content-box-breakpoint-button">Run</button>
|
|
784
|
+
</monster-control-bar>
|
|
785
|
+
</div>
|
|
786
|
+
`;
|
|
787
|
+
|
|
788
|
+
const wrapper = document.getElementById(
|
|
789
|
+
"content-box-breakpoint-wrapper",
|
|
790
|
+
);
|
|
791
|
+
const button = document.getElementById("content-box-breakpoint-button");
|
|
792
|
+
const bar = document.getElementById("content-box-breakpoint-bar");
|
|
793
|
+
const controlBar = bar.shadowRoot.querySelector(
|
|
794
|
+
'[data-monster-role="control-bar"]',
|
|
795
|
+
);
|
|
796
|
+
const switchButton = bar.shadowRoot.querySelector(
|
|
797
|
+
'[data-monster-role="switch"]',
|
|
798
|
+
);
|
|
799
|
+
|
|
800
|
+
wrapper.style.boxSizing = "content-box";
|
|
801
|
+
wrapper.style.width = "350.156px";
|
|
802
|
+
Object.defineProperty(button, "offsetWidth", {
|
|
803
|
+
configurable: true,
|
|
804
|
+
value: 40,
|
|
805
|
+
});
|
|
806
|
+
Object.defineProperty(button, "offsetHeight", {
|
|
807
|
+
configurable: true,
|
|
808
|
+
value: 30,
|
|
809
|
+
});
|
|
810
|
+
button.getBoundingClientRect = () => ({
|
|
811
|
+
width: 40,
|
|
812
|
+
height: 30,
|
|
813
|
+
top: 0,
|
|
814
|
+
right: 40,
|
|
815
|
+
bottom: 30,
|
|
816
|
+
left: 0,
|
|
817
|
+
x: 0,
|
|
818
|
+
y: 0,
|
|
819
|
+
toJSON: () => {},
|
|
820
|
+
});
|
|
821
|
+
Object.defineProperty(switchButton, "offsetWidth", {
|
|
822
|
+
configurable: true,
|
|
823
|
+
value: 20,
|
|
824
|
+
});
|
|
825
|
+
|
|
826
|
+
await flushFrames();
|
|
827
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
828
|
+
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
829
|
+
|
|
830
|
+
expect(switchButton.hasAttribute("hidden")).to.be.true;
|
|
831
|
+
expect(button.hasAttribute("slot")).to.be.false;
|
|
832
|
+
expect(controlBar.getAttribute("data-monster-layout-stacked")).to.equal(
|
|
833
|
+
"true",
|
|
834
|
+
);
|
|
835
|
+
expect(controlBar.getAttribute("data-monster-layout-alignment")).to.equal(
|
|
836
|
+
"left",
|
|
837
|
+
);
|
|
838
|
+
} finally {
|
|
839
|
+
window.requestAnimationFrame = originalRequestAnimationFrame;
|
|
840
|
+
globalThis.requestAnimationFrame = originalGlobalRequestAnimationFrame;
|
|
841
|
+
}
|
|
842
|
+
});
|
|
663
843
|
});
|