@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.
@@ -194,8 +194,9 @@ describe("ButtonBar", function () {
194
194
  return originalSetAttribute(name, value);
195
195
  };
196
196
 
197
- resizeObserver.triggerResize([]);
198
- resizeObserver.triggerResize([]);
197
+ const wrapperResizeEntry = { target: wrapper };
198
+ resizeObserver.triggerResize([wrapperResizeEntry]);
199
+ resizeObserver.triggerResize([wrapperResizeEntry]);
199
200
 
200
201
  expect(scheduledCallbacks.length).to.equal(1);
201
202
  await flushFrames();
@@ -162,6 +162,7 @@ describe("ControlBar", function () {
162
162
  stacked: false,
163
163
  stackedAlignment: undefined,
164
164
  stackedBreakpoint: undefined,
165
+ stackedBreakpointContainer: undefined,
165
166
  });
166
167
  });
167
168
 
@@ -843,4 +844,458 @@ describe("ControlBar", function () {
843
844
  globalThis.requestAnimationFrame = originalGlobalRequestAnimationFrame;
844
845
  }
845
846
  });
847
+
848
+ it("should keep the configured alignment when the reference container is above the stacked breakpoint", async function () {
849
+ const originalRequestAnimationFrame = window.requestAnimationFrame;
850
+ const originalGlobalRequestAnimationFrame = globalThis.requestAnimationFrame;
851
+
852
+ const scheduledCallbacks = [];
853
+ const flushFrames = async () => {
854
+ while (scheduledCallbacks.length > 0) {
855
+ scheduledCallbacks.shift()();
856
+ await new Promise((resolve) => setTimeout(resolve, 0));
857
+ }
858
+ };
859
+
860
+ try {
861
+ window.requestAnimationFrame = (callback) => {
862
+ scheduledCallbacks.push(callback);
863
+ return scheduledCallbacks.length;
864
+ };
865
+ globalThis.requestAnimationFrame = window.requestAnimationFrame;
866
+
867
+ const mocks = document.getElementById("mocks");
868
+ mocks.innerHTML = `
869
+ <div id="headline-wide" class="page-headline-bar">
870
+ <div id="headline-wide-control-column">
871
+ <monster-control-bar
872
+ id="headline-wide-bar"
873
+ data-monster-option-layout-alignment="right"
874
+ data-monster-option-layout-stacked-alignment="left"
875
+ data-monster-option-layout-stacked-breakpoint="480px"
876
+ data-monster-option-layout-stacked-breakpoint-container=".page-headline-bar"
877
+ >
878
+ <button id="headline-wide-button">Run</button>
879
+ </monster-control-bar>
880
+ </div>
881
+ </div>
882
+ `;
883
+
884
+ const headline = document.getElementById("headline-wide");
885
+ const column = document.getElementById("headline-wide-control-column");
886
+ const button = document.getElementById("headline-wide-button");
887
+ const bar = document.getElementById("headline-wide-bar");
888
+ const controlBar = bar.shadowRoot.querySelector(
889
+ '[data-monster-role="control-bar"]',
890
+ );
891
+
892
+ headline.style.boxSizing = "border-box";
893
+ Object.defineProperty(headline, "clientWidth", {
894
+ configurable: true,
895
+ value: 640,
896
+ });
897
+ column.style.boxSizing = "border-box";
898
+ Object.defineProperty(column, "clientWidth", {
899
+ configurable: true,
900
+ value: 459.469,
901
+ });
902
+ Object.defineProperty(button, "offsetWidth", {
903
+ configurable: true,
904
+ value: 40,
905
+ });
906
+ Object.defineProperty(button, "offsetHeight", {
907
+ configurable: true,
908
+ value: 30,
909
+ });
910
+ button.getBoundingClientRect = () => ({
911
+ width: 40,
912
+ height: 30,
913
+ top: 0,
914
+ right: 40,
915
+ bottom: 30,
916
+ left: 0,
917
+ x: 0,
918
+ y: 0,
919
+ toJSON: () => {},
920
+ });
921
+
922
+ await flushFrames();
923
+ await new Promise((resolve) => setTimeout(resolve, 0));
924
+ await new Promise((resolve) => setTimeout(resolve, 0));
925
+
926
+ expect(controlBar.getAttribute("data-monster-layout-stacked")).to.equal(
927
+ "false",
928
+ );
929
+ expect(controlBar.getAttribute("data-monster-layout-alignment")).to.equal(
930
+ "right",
931
+ );
932
+ } finally {
933
+ window.requestAnimationFrame = originalRequestAnimationFrame;
934
+ globalThis.requestAnimationFrame = originalGlobalRequestAnimationFrame;
935
+ }
936
+ });
937
+
938
+ it("should apply stacked alignment when the reference container is below the stacked breakpoint", async function () {
939
+ const originalRequestAnimationFrame = window.requestAnimationFrame;
940
+ const originalGlobalRequestAnimationFrame = globalThis.requestAnimationFrame;
941
+
942
+ const scheduledCallbacks = [];
943
+ const flushFrames = async () => {
944
+ while (scheduledCallbacks.length > 0) {
945
+ scheduledCallbacks.shift()();
946
+ await new Promise((resolve) => setTimeout(resolve, 0));
947
+ }
948
+ };
949
+
950
+ try {
951
+ window.requestAnimationFrame = (callback) => {
952
+ scheduledCallbacks.push(callback);
953
+ return scheduledCallbacks.length;
954
+ };
955
+ globalThis.requestAnimationFrame = window.requestAnimationFrame;
956
+
957
+ const mocks = document.getElementById("mocks");
958
+ mocks.innerHTML = `
959
+ <div id="headline-narrow" class="page-headline-bar">
960
+ <div id="headline-narrow-control-column">
961
+ <monster-control-bar
962
+ id="headline-narrow-bar"
963
+ data-monster-option-layout-alignment="right"
964
+ data-monster-option-layout-stacked-alignment="left"
965
+ data-monster-option-layout-stacked-breakpoint="480px"
966
+ data-monster-option-layout-stacked-breakpoint-container=".page-headline-bar"
967
+ >
968
+ <button id="headline-narrow-button">Run</button>
969
+ </monster-control-bar>
970
+ </div>
971
+ </div>
972
+ `;
973
+
974
+ const headline = document.getElementById("headline-narrow");
975
+ const column = document.getElementById("headline-narrow-control-column");
976
+ const button = document.getElementById("headline-narrow-button");
977
+ const bar = document.getElementById("headline-narrow-bar");
978
+ const controlBar = bar.shadowRoot.querySelector(
979
+ '[data-monster-role="control-bar"]',
980
+ );
981
+
982
+ headline.style.boxSizing = "border-box";
983
+ Object.defineProperty(headline, "clientWidth", {
984
+ configurable: true,
985
+ value: 350,
986
+ });
987
+ column.style.boxSizing = "border-box";
988
+ Object.defineProperty(column, "clientWidth", {
989
+ configurable: true,
990
+ value: 459.469,
991
+ });
992
+ Object.defineProperty(button, "offsetWidth", {
993
+ configurable: true,
994
+ value: 40,
995
+ });
996
+ Object.defineProperty(button, "offsetHeight", {
997
+ configurable: true,
998
+ value: 30,
999
+ });
1000
+ button.getBoundingClientRect = () => ({
1001
+ width: 40,
1002
+ height: 30,
1003
+ top: 0,
1004
+ right: 40,
1005
+ bottom: 30,
1006
+ left: 0,
1007
+ x: 0,
1008
+ y: 0,
1009
+ toJSON: () => {},
1010
+ });
1011
+
1012
+ await flushFrames();
1013
+ await new Promise((resolve) => setTimeout(resolve, 0));
1014
+ await new Promise((resolve) => setTimeout(resolve, 0));
1015
+
1016
+ expect(controlBar.getAttribute("data-monster-layout-stacked")).to.equal(
1017
+ "true",
1018
+ );
1019
+ expect(controlBar.getAttribute("data-monster-layout-alignment")).to.equal(
1020
+ "left",
1021
+ );
1022
+ } finally {
1023
+ window.requestAnimationFrame = originalRequestAnimationFrame;
1024
+ globalThis.requestAnimationFrame = originalGlobalRequestAnimationFrame;
1025
+ }
1026
+ });
1027
+
1028
+ it("should fall back to the control bar width when the breakpoint container selector cannot resolve", async function () {
1029
+ const originalRequestAnimationFrame = window.requestAnimationFrame;
1030
+ const originalGlobalRequestAnimationFrame = globalThis.requestAnimationFrame;
1031
+
1032
+ const scheduledCallbacks = [];
1033
+ const flushFrames = async () => {
1034
+ while (scheduledCallbacks.length > 0) {
1035
+ scheduledCallbacks.shift()();
1036
+ await new Promise((resolve) => setTimeout(resolve, 0));
1037
+ }
1038
+ };
1039
+
1040
+ try {
1041
+ window.requestAnimationFrame = (callback) => {
1042
+ scheduledCallbacks.push(callback);
1043
+ return scheduledCallbacks.length;
1044
+ };
1045
+ globalThis.requestAnimationFrame = window.requestAnimationFrame;
1046
+
1047
+ const mocks = document.getElementById("mocks");
1048
+ mocks.innerHTML = `
1049
+ <div id="missing-reference-wrapper">
1050
+ <monster-control-bar
1051
+ id="missing-reference-bar"
1052
+ data-monster-option-layout-alignment="right"
1053
+ data-monster-option-layout-stacked-alignment="left"
1054
+ data-monster-option-layout-stacked-breakpoint="480px"
1055
+ data-monster-option-layout-stacked-breakpoint-container=".missing-reference"
1056
+ >
1057
+ <button id="missing-reference-button">Run</button>
1058
+ </monster-control-bar>
1059
+ </div>
1060
+ `;
1061
+
1062
+ const wrapper = document.getElementById("missing-reference-wrapper");
1063
+ const button = document.getElementById("missing-reference-button");
1064
+ const bar = document.getElementById("missing-reference-bar");
1065
+ const controlBar = bar.shadowRoot.querySelector(
1066
+ '[data-monster-role="control-bar"]',
1067
+ );
1068
+
1069
+ wrapper.style.boxSizing = "border-box";
1070
+ Object.defineProperty(wrapper, "clientWidth", {
1071
+ configurable: true,
1072
+ value: 350,
1073
+ });
1074
+ Object.defineProperty(button, "offsetWidth", {
1075
+ configurable: true,
1076
+ value: 40,
1077
+ });
1078
+ Object.defineProperty(button, "offsetHeight", {
1079
+ configurable: true,
1080
+ value: 30,
1081
+ });
1082
+ button.getBoundingClientRect = () => ({
1083
+ width: 40,
1084
+ height: 30,
1085
+ top: 0,
1086
+ right: 40,
1087
+ bottom: 30,
1088
+ left: 0,
1089
+ x: 0,
1090
+ y: 0,
1091
+ toJSON: () => {},
1092
+ });
1093
+
1094
+ await flushFrames();
1095
+ await new Promise((resolve) => setTimeout(resolve, 0));
1096
+ await new Promise((resolve) => setTimeout(resolve, 0));
1097
+
1098
+ expect(controlBar.getAttribute("data-monster-layout-stacked")).to.equal(
1099
+ "true",
1100
+ );
1101
+ expect(controlBar.getAttribute("data-monster-layout-alignment")).to.equal(
1102
+ "left",
1103
+ );
1104
+ } finally {
1105
+ window.requestAnimationFrame = originalRequestAnimationFrame;
1106
+ globalThis.requestAnimationFrame = originalGlobalRequestAnimationFrame;
1107
+ }
1108
+ });
1109
+
1110
+ it("should fall back without throwing when the breakpoint container selector is invalid", async function () {
1111
+ const originalRequestAnimationFrame = window.requestAnimationFrame;
1112
+ const originalGlobalRequestAnimationFrame = globalThis.requestAnimationFrame;
1113
+
1114
+ const scheduledCallbacks = [];
1115
+ const flushFrames = async () => {
1116
+ while (scheduledCallbacks.length > 0) {
1117
+ scheduledCallbacks.shift()();
1118
+ await new Promise((resolve) => setTimeout(resolve, 0));
1119
+ }
1120
+ };
1121
+
1122
+ try {
1123
+ window.requestAnimationFrame = (callback) => {
1124
+ scheduledCallbacks.push(callback);
1125
+ return scheduledCallbacks.length;
1126
+ };
1127
+ globalThis.requestAnimationFrame = window.requestAnimationFrame;
1128
+
1129
+ const mocks = document.getElementById("mocks");
1130
+ mocks.innerHTML = `
1131
+ <div id="invalid-reference-wrapper">
1132
+ <monster-control-bar
1133
+ id="invalid-reference-bar"
1134
+ data-monster-option-layout-alignment="right"
1135
+ data-monster-option-layout-stacked-alignment="left"
1136
+ data-monster-option-layout-stacked-breakpoint="480px"
1137
+ >
1138
+ <button id="invalid-reference-button">Run</button>
1139
+ </monster-control-bar>
1140
+ </div>
1141
+ `;
1142
+
1143
+ const wrapper = document.getElementById("invalid-reference-wrapper");
1144
+ const button = document.getElementById("invalid-reference-button");
1145
+ const bar = document.getElementById("invalid-reference-bar");
1146
+ const controlBar = bar.shadowRoot.querySelector(
1147
+ '[data-monster-role="control-bar"]',
1148
+ );
1149
+
1150
+ bar.setOption("layout.stackedBreakpointContainer", "[");
1151
+ wrapper.style.boxSizing = "border-box";
1152
+ Object.defineProperty(wrapper, "clientWidth", {
1153
+ configurable: true,
1154
+ value: 350,
1155
+ });
1156
+ Object.defineProperty(button, "offsetWidth", {
1157
+ configurable: true,
1158
+ value: 40,
1159
+ });
1160
+ Object.defineProperty(button, "offsetHeight", {
1161
+ configurable: true,
1162
+ value: 30,
1163
+ });
1164
+ button.getBoundingClientRect = () => ({
1165
+ width: 40,
1166
+ height: 30,
1167
+ top: 0,
1168
+ right: 40,
1169
+ bottom: 30,
1170
+ left: 0,
1171
+ x: 0,
1172
+ y: 0,
1173
+ toJSON: () => {},
1174
+ });
1175
+
1176
+ await flushFrames();
1177
+ await new Promise((resolve) => setTimeout(resolve, 0));
1178
+ await new Promise((resolve) => setTimeout(resolve, 0));
1179
+
1180
+ expect(controlBar.getAttribute("data-monster-layout-stacked")).to.equal(
1181
+ "true",
1182
+ );
1183
+ expect(controlBar.getAttribute("data-monster-layout-alignment")).to.equal(
1184
+ "left",
1185
+ );
1186
+ } finally {
1187
+ window.requestAnimationFrame = originalRequestAnimationFrame;
1188
+ globalThis.requestAnimationFrame = originalGlobalRequestAnimationFrame;
1189
+ }
1190
+ });
1191
+
1192
+ it("should observe the resolved breakpoint container and update observation when it changes", async function () {
1193
+ const OriginalResizeObserver = window.ResizeObserver;
1194
+ const originalGlobalResizeObserver = globalThis.ResizeObserver;
1195
+ const originalRequestAnimationFrame = window.requestAnimationFrame;
1196
+ const originalGlobalRequestAnimationFrame = globalThis.requestAnimationFrame;
1197
+
1198
+ class TrackingResizeObserver extends ResizeObserverMock {
1199
+ static instances = [];
1200
+
1201
+ constructor(callback) {
1202
+ super(callback);
1203
+ TrackingResizeObserver.instances.push(this);
1204
+ }
1205
+ }
1206
+
1207
+ const scheduledCallbacks = [];
1208
+ const flushFrames = async () => {
1209
+ while (scheduledCallbacks.length > 0) {
1210
+ scheduledCallbacks.shift()();
1211
+ await new Promise((resolve) => setTimeout(resolve, 0));
1212
+ }
1213
+ };
1214
+
1215
+ try {
1216
+ window.ResizeObserver = TrackingResizeObserver;
1217
+ globalThis.ResizeObserver = TrackingResizeObserver;
1218
+ window.requestAnimationFrame = (callback) => {
1219
+ scheduledCallbacks.push(callback);
1220
+ return scheduledCallbacks.length;
1221
+ };
1222
+ globalThis.requestAnimationFrame = window.requestAnimationFrame;
1223
+
1224
+ const mocks = document.getElementById("mocks");
1225
+ mocks.innerHTML = `
1226
+ <div id="observed-reference-wrapper">
1227
+ <monster-control-bar
1228
+ id="observed-reference-bar"
1229
+ data-monster-option-layout-stacked-breakpoint="480px"
1230
+ data-monster-option-layout-stacked-breakpoint-container="#reference-a"
1231
+ >
1232
+ <button id="observed-reference-button">Run</button>
1233
+ </monster-control-bar>
1234
+ </div>
1235
+ <div id="reference-a"></div>
1236
+ <div id="reference-b"></div>
1237
+ `;
1238
+
1239
+ const wrapper = document.getElementById("observed-reference-wrapper");
1240
+ const referenceA = document.getElementById("reference-a");
1241
+ const referenceB = document.getElementById("reference-b");
1242
+ const button = document.getElementById("observed-reference-button");
1243
+ const bar = document.getElementById("observed-reference-bar");
1244
+
1245
+ wrapper.style.boxSizing = "border-box";
1246
+ referenceA.style.boxSizing = "border-box";
1247
+ referenceB.style.boxSizing = "border-box";
1248
+ Object.defineProperty(wrapper, "clientWidth", {
1249
+ configurable: true,
1250
+ value: 459,
1251
+ });
1252
+ Object.defineProperty(referenceA, "clientWidth", {
1253
+ configurable: true,
1254
+ value: 640,
1255
+ });
1256
+ Object.defineProperty(referenceB, "clientWidth", {
1257
+ configurable: true,
1258
+ value: 350,
1259
+ });
1260
+ Object.defineProperty(button, "offsetWidth", {
1261
+ configurable: true,
1262
+ value: 40,
1263
+ });
1264
+ Object.defineProperty(button, "offsetHeight", {
1265
+ configurable: true,
1266
+ value: 30,
1267
+ });
1268
+ button.getBoundingClientRect = () => ({
1269
+ width: 40,
1270
+ height: 30,
1271
+ top: 0,
1272
+ right: 40,
1273
+ bottom: 30,
1274
+ left: 0,
1275
+ x: 0,
1276
+ y: 0,
1277
+ toJSON: () => {},
1278
+ });
1279
+
1280
+ await flushFrames();
1281
+ await new Promise((resolve) => setTimeout(resolve, 0));
1282
+ await new Promise((resolve) => setTimeout(resolve, 0));
1283
+
1284
+ const observer = TrackingResizeObserver.instances[0];
1285
+ expect(observer.elements).to.include(referenceA);
1286
+
1287
+ bar.setOption("layout.stackedBreakpointContainer", "#reference-b");
1288
+ await flushFrames();
1289
+ await new Promise((resolve) => setTimeout(resolve, 0));
1290
+ await new Promise((resolve) => setTimeout(resolve, 0));
1291
+
1292
+ expect(observer.elements).to.not.include(referenceA);
1293
+ expect(observer.elements).to.include(referenceB);
1294
+ } finally {
1295
+ window.ResizeObserver = OriginalResizeObserver;
1296
+ globalThis.ResizeObserver = originalGlobalResizeObserver;
1297
+ window.requestAnimationFrame = originalRequestAnimationFrame;
1298
+ globalThis.requestAnimationFrame = originalGlobalRequestAnimationFrame;
1299
+ }
1300
+ });
846
1301
  });