@schukai/monster 4.136.6 → 4.136.8
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 +1 -1
- package/source/components/form/select.mjs +82 -22
- package/source/components/form/style/select.pcss +1 -1
- package/source/components/form/stylesheet/select.mjs +1 -1
- package/source/components/form/util/floating-ui.mjs +19 -11
- package/source/components/form/util/popper.mjs +4 -0
- package/source/components/navigation/site-navigation.mjs +79 -58
- package/source/types/version.mjs +1 -1
- package/test/cases/components/form/message-state-button.mjs +36 -60
- package/test/cases/components/form/select.mjs +109 -57
- package/test/cases/monster.mjs +1 -1
- package/test/web/import.js +4 -0
- package/test/web/test.html +2 -2
- package/test/web/tests.js +6841 -2575
|
@@ -73,8 +73,9 @@ describe("MessageStateButton", function () {
|
|
|
73
73
|
|
|
74
74
|
describe("document.createElement", function () {
|
|
75
75
|
it("should instance of message-state-button", function () {
|
|
76
|
-
expect(
|
|
77
|
-
.
|
|
76
|
+
expect(
|
|
77
|
+
document.createElement("monster-message-state-button"),
|
|
78
|
+
).is.instanceof(MessageStateButton);
|
|
78
79
|
});
|
|
79
80
|
});
|
|
80
81
|
});
|
|
@@ -93,9 +94,7 @@ describe("MessageStateButton", function () {
|
|
|
93
94
|
|
|
94
95
|
setTimeout(() => {
|
|
95
96
|
try {
|
|
96
|
-
const inner = button.shadowRoot.querySelector(
|
|
97
|
-
"monster-state-button",
|
|
98
|
-
);
|
|
97
|
+
const inner = button.shadowRoot.querySelector("monster-state-button");
|
|
99
98
|
expect(inner).to.exist;
|
|
100
99
|
|
|
101
100
|
button.setAttribute("disabled", "");
|
|
@@ -231,19 +230,22 @@ describe("MessageStateButton", function () {
|
|
|
231
230
|
|
|
232
231
|
setTimeout(() => {
|
|
233
232
|
try {
|
|
234
|
-
button.setMessage(
|
|
233
|
+
button.setMessage(
|
|
234
|
+
"<div><strong>Saved</strong><p>plain html</p></div>",
|
|
235
|
+
);
|
|
235
236
|
button.showMessage();
|
|
236
237
|
|
|
237
238
|
setTimeout(() => {
|
|
238
239
|
try {
|
|
239
|
-
const content =
|
|
240
|
+
const content =
|
|
241
|
+
button.shadowRoot.querySelector('[part="content"]');
|
|
240
242
|
const message = button.shadowRoot.querySelector(
|
|
241
243
|
'[data-monster-role="message"]',
|
|
242
244
|
);
|
|
243
245
|
expect(content).to.exist;
|
|
244
|
-
expect(
|
|
245
|
-
"
|
|
246
|
-
);
|
|
246
|
+
expect(
|
|
247
|
+
content.getAttribute("data-monster-overflow-mode"),
|
|
248
|
+
).to.equal("both");
|
|
247
249
|
expect(
|
|
248
250
|
content.getAttribute("data-monster-message-layout"),
|
|
249
251
|
).to.equal("prose");
|
|
@@ -306,10 +308,7 @@ describe("MessageStateButton", function () {
|
|
|
306
308
|
try {
|
|
307
309
|
const wrapper = document.createElement("div");
|
|
308
310
|
const line = document.createElement("div");
|
|
309
|
-
line.setAttribute(
|
|
310
|
-
"style",
|
|
311
|
-
"white-space: nowrap; overflow-x: auto;",
|
|
312
|
-
);
|
|
311
|
+
line.setAttribute("style", "white-space: nowrap; overflow-x: auto;");
|
|
313
312
|
line.textContent =
|
|
314
313
|
"this is intentionally a single long line to trigger wide layout";
|
|
315
314
|
wrapper.appendChild(line);
|
|
@@ -319,14 +318,15 @@ describe("MessageStateButton", function () {
|
|
|
319
318
|
|
|
320
319
|
setTimeout(() => {
|
|
321
320
|
try {
|
|
322
|
-
const content =
|
|
321
|
+
const content =
|
|
322
|
+
button.shadowRoot.querySelector('[part="content"]');
|
|
323
323
|
const message = button.shadowRoot.querySelector(
|
|
324
324
|
'[data-monster-role="message"]',
|
|
325
325
|
);
|
|
326
326
|
expect(content).to.exist;
|
|
327
|
-
expect(
|
|
328
|
-
"
|
|
329
|
-
);
|
|
327
|
+
expect(
|
|
328
|
+
content.getAttribute("data-monster-overflow-mode"),
|
|
329
|
+
).to.equal("both");
|
|
330
330
|
expect(
|
|
331
331
|
content.getAttribute("data-monster-message-layout"),
|
|
332
332
|
).to.equal("wide");
|
|
@@ -351,7 +351,8 @@ describe("MessageStateButton", function () {
|
|
|
351
351
|
|
|
352
352
|
beforeEach(() => {
|
|
353
353
|
originalInnerWidth = window.innerWidth;
|
|
354
|
-
originalGetBoundingClientRect =
|
|
354
|
+
originalGetBoundingClientRect =
|
|
355
|
+
HTMLElement.prototype.getBoundingClientRect;
|
|
355
356
|
});
|
|
356
357
|
|
|
357
358
|
afterEach(() => {
|
|
@@ -360,7 +361,8 @@ describe("MessageStateButton", function () {
|
|
|
360
361
|
writable: true,
|
|
361
362
|
value: originalInnerWidth,
|
|
362
363
|
});
|
|
363
|
-
HTMLElement.prototype.getBoundingClientRect =
|
|
364
|
+
HTMLElement.prototype.getBoundingClientRect =
|
|
365
|
+
originalGetBoundingClientRect;
|
|
364
366
|
let mocks = document.getElementById("mocks");
|
|
365
367
|
mocks.innerHTML = "";
|
|
366
368
|
});
|
|
@@ -388,14 +390,7 @@ describe("MessageStateButton", function () {
|
|
|
388
390
|
};
|
|
389
391
|
}
|
|
390
392
|
|
|
391
|
-
return
|
|
392
|
-
width: 100,
|
|
393
|
-
height: 40,
|
|
394
|
-
top: 0,
|
|
395
|
-
left: 0,
|
|
396
|
-
right: 100,
|
|
397
|
-
bottom: 40,
|
|
398
|
-
};
|
|
393
|
+
return originalGetBoundingClientRect.call(this);
|
|
399
394
|
};
|
|
400
395
|
|
|
401
396
|
setTimeout(() => {
|
|
@@ -405,18 +400,12 @@ describe("MessageStateButton", function () {
|
|
|
405
400
|
);
|
|
406
401
|
button.showMessage();
|
|
407
402
|
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
expect(popper.style.maxWidth).to.equal("512px");
|
|
415
|
-
done();
|
|
416
|
-
} catch (e) {
|
|
417
|
-
done(e);
|
|
418
|
-
}
|
|
419
|
-
}, 0);
|
|
403
|
+
const popper = button.shadowRoot.querySelector(
|
|
404
|
+
'[data-monster-role="popper"]',
|
|
405
|
+
);
|
|
406
|
+
expect(popper.style.width).to.equal("512px");
|
|
407
|
+
expect(popper.style.maxWidth).to.equal("512px");
|
|
408
|
+
done();
|
|
420
409
|
} catch (e) {
|
|
421
410
|
done(e);
|
|
422
411
|
}
|
|
@@ -446,14 +435,7 @@ describe("MessageStateButton", function () {
|
|
|
446
435
|
};
|
|
447
436
|
}
|
|
448
437
|
|
|
449
|
-
return
|
|
450
|
-
width: 100,
|
|
451
|
-
height: 40,
|
|
452
|
-
top: 0,
|
|
453
|
-
left: 0,
|
|
454
|
-
right: 100,
|
|
455
|
-
bottom: 40,
|
|
456
|
-
};
|
|
438
|
+
return originalGetBoundingClientRect.call(this);
|
|
457
439
|
};
|
|
458
440
|
|
|
459
441
|
setTimeout(() => {
|
|
@@ -465,18 +447,12 @@ describe("MessageStateButton", function () {
|
|
|
465
447
|
button.setMessage(wrapper);
|
|
466
448
|
button.showMessage();
|
|
467
449
|
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
expect(popper.style.maxWidth).to.equal("768px");
|
|
475
|
-
done();
|
|
476
|
-
} catch (e) {
|
|
477
|
-
done(e);
|
|
478
|
-
}
|
|
479
|
-
}, 0);
|
|
450
|
+
const popper = button.shadowRoot.querySelector(
|
|
451
|
+
'[data-monster-role="popper"]',
|
|
452
|
+
);
|
|
453
|
+
expect(popper.style.width).to.equal("768px");
|
|
454
|
+
expect(popper.style.maxWidth).to.equal("768px");
|
|
455
|
+
done();
|
|
480
456
|
} catch (e) {
|
|
481
457
|
done(e);
|
|
482
458
|
}
|
|
@@ -47,7 +47,35 @@ function createJsonResponse(data, status = 200) {
|
|
|
47
47
|
});
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
function waitForCondition(check, {timeout = 4000, interval = 25} = {}) {
|
|
51
|
+
return new Promise((resolve, reject) => {
|
|
52
|
+
const start = Date.now();
|
|
53
|
+
|
|
54
|
+
const poll = () => {
|
|
55
|
+
try {
|
|
56
|
+
if (check()) {
|
|
57
|
+
resolve();
|
|
58
|
+
return;
|
|
59
|
+
}
|
|
60
|
+
} catch (e) {
|
|
61
|
+
reject(e);
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
if (Date.now() - start >= timeout) {
|
|
66
|
+
reject(new Error('Timed out while waiting for test condition.'));
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
setTimeout(poll, interval);
|
|
71
|
+
};
|
|
72
|
+
|
|
73
|
+
poll();
|
|
74
|
+
});
|
|
75
|
+
}
|
|
76
|
+
|
|
50
77
|
let Select,
|
|
78
|
+
SelectStyleSheet,
|
|
51
79
|
getDefaultSelectPopperPositionProfile,
|
|
52
80
|
resolveSelectListDimension,
|
|
53
81
|
resolveSelectPopperWidthConstraints,
|
|
@@ -75,6 +103,9 @@ describe('Select', function () {
|
|
|
75
103
|
resolveSelectPopperWidthConstraints = m['resolveSelectPopperWidthConstraints'];
|
|
76
104
|
resolveSelectVisibleRect = m['resolveSelectVisibleRect'];
|
|
77
105
|
resolveSelectViewportMetrics = m['resolveSelectViewportMetrics'];
|
|
106
|
+
return import("../../../../source/components/form/stylesheet/select.mjs");
|
|
107
|
+
}).then((m) => {
|
|
108
|
+
SelectStyleSheet = m['SelectStyleSheet'];
|
|
78
109
|
done()
|
|
79
110
|
}).catch(e => done(e))
|
|
80
111
|
|
|
@@ -276,6 +307,16 @@ describe('Select', function () {
|
|
|
276
307
|
expect(result.overflowY).to.equal('hidden');
|
|
277
308
|
});
|
|
278
309
|
|
|
310
|
+
it('should keep option list scroll layout stable while overflow toggles', function () {
|
|
311
|
+
const cssText = Array.from(SelectStyleSheet.cssRules)
|
|
312
|
+
.map((rule) => rule.cssText)
|
|
313
|
+
.join('\n')
|
|
314
|
+
.replace(/\s+/g, '');
|
|
315
|
+
|
|
316
|
+
expect(cssText).to.contain('scrollbar-gutter:stable');
|
|
317
|
+
expect(cssText).to.not.contain('transition:height');
|
|
318
|
+
});
|
|
319
|
+
|
|
279
320
|
it('should refresh the content max height when the available popper height grows again', function (done) {
|
|
280
321
|
const mocks = document.getElementById('mocks');
|
|
281
322
|
const select = document.createElement('monster-select');
|
|
@@ -810,7 +851,7 @@ describe('Select', function () {
|
|
|
810
851
|
}, 50);
|
|
811
852
|
});
|
|
812
853
|
|
|
813
|
-
it('should reuse defaultOptionsUrl after clearing the filter and reopening', function (
|
|
854
|
+
it('should reuse defaultOptionsUrl after clearing the filter and reopening', async function () {
|
|
814
855
|
this.timeout(5000);
|
|
815
856
|
|
|
816
857
|
let mocks = document.getElementById('mocks');
|
|
@@ -867,68 +908,33 @@ describe('Select', function () {
|
|
|
867
908
|
}));
|
|
868
909
|
};
|
|
869
910
|
|
|
870
|
-
|
|
871
|
-
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
try {
|
|
875
|
-
container = select.shadowRoot.querySelector('[data-monster-role=container]');
|
|
876
|
-
filterInput = select.shadowRoot.querySelector('[data-monster-role=filter][name="popper-filter"]');
|
|
877
|
-
container.click();
|
|
878
|
-
} catch (e) {
|
|
879
|
-
return done(e);
|
|
880
|
-
}
|
|
881
|
-
|
|
882
|
-
setTimeout(() => {
|
|
883
|
-
try {
|
|
884
|
-
expect(requests[0]).to.equal('https://example.com/defaults?page=1');
|
|
885
|
-
|
|
886
|
-
filterInput.value = 'alpha';
|
|
887
|
-
dispatchFilterKey(filterInput, 'KeyA', 'a');
|
|
888
|
-
} catch (e) {
|
|
889
|
-
return done(e);
|
|
890
|
-
}
|
|
911
|
+
await waitForCondition(() => {
|
|
912
|
+
return select.shadowRoot.querySelector('[data-monster-role=container]') instanceof HTMLElement;
|
|
913
|
+
});
|
|
891
914
|
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
expect(requests[1]).to.equal('https://example.com/items?filter=alpha&page=1');
|
|
915
|
+
const container = select.shadowRoot.querySelector('[data-monster-role=container]');
|
|
916
|
+
const filterInput = select.shadowRoot.querySelector('[data-monster-role=filter][name="popper-filter"]');
|
|
895
917
|
|
|
896
|
-
|
|
897
|
-
|
|
898
|
-
|
|
899
|
-
return done(e);
|
|
900
|
-
}
|
|
918
|
+
container.click();
|
|
919
|
+
await waitForCondition(() => requests.length >= 1);
|
|
920
|
+
expect(requests[0]).to.equal('https://example.com/defaults?page=1');
|
|
901
921
|
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
922
|
+
filterInput.value = 'alpha';
|
|
923
|
+
dispatchFilterKey(filterInput, 'KeyA', 'a');
|
|
924
|
+
await waitForCondition(() => requests.length >= 2);
|
|
925
|
+
expect(requests[1]).to.equal('https://example.com/items?filter=alpha&page=1');
|
|
905
926
|
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
927
|
+
filterInput.value = '';
|
|
928
|
+
dispatchFilterKey(filterInput, 'Backspace', 'Backspace');
|
|
929
|
+
await waitForCondition(() => requests.length >= 3);
|
|
930
|
+
expect(requests[2]).to.equal('https://example.com/defaults?page=1');
|
|
910
931
|
|
|
911
|
-
|
|
912
|
-
|
|
913
|
-
container.click();
|
|
914
|
-
} catch (e) {
|
|
915
|
-
return done(e);
|
|
916
|
-
}
|
|
932
|
+
container.click();
|
|
933
|
+
await waitForCondition(() => select.shadowRoot.querySelector('[data-monster-role=popper]').style.display === 'none');
|
|
917
934
|
|
|
918
|
-
|
|
919
|
-
|
|
920
|
-
|
|
921
|
-
} catch (e) {
|
|
922
|
-
return done(e);
|
|
923
|
-
}
|
|
924
|
-
|
|
925
|
-
done();
|
|
926
|
-
}, 250);
|
|
927
|
-
}, 50);
|
|
928
|
-
}, 300);
|
|
929
|
-
}, 300);
|
|
930
|
-
}, 250);
|
|
931
|
-
}, 50);
|
|
935
|
+
container.click();
|
|
936
|
+
await waitForCondition(() => requests.length >= 4);
|
|
937
|
+
expect(requests[3]).to.equal('https://example.com/defaults?page=1');
|
|
932
938
|
});
|
|
933
939
|
|
|
934
940
|
it('should keep unresolved lookup values visible and mark their badge', function (done) {
|
|
@@ -974,6 +980,52 @@ describe('Select', function () {
|
|
|
974
980
|
}, 250);
|
|
975
981
|
});
|
|
976
982
|
|
|
983
|
+
it('should keep unresolved object lookup values visible by key and mark their badge', function (done) {
|
|
984
|
+
this.timeout(3000);
|
|
985
|
+
|
|
986
|
+
let mocks = document.getElementById('mocks');
|
|
987
|
+
const requests = [];
|
|
988
|
+
global['fetch'] = function (url) {
|
|
989
|
+
requests.push(url.toString());
|
|
990
|
+
return createJsonResponse({
|
|
991
|
+
items: [],
|
|
992
|
+
pagination: {
|
|
993
|
+
total: 0,
|
|
994
|
+
page: 1,
|
|
995
|
+
perPage: 1
|
|
996
|
+
}
|
|
997
|
+
});
|
|
998
|
+
};
|
|
999
|
+
|
|
1000
|
+
const select = document.createElement('monster-select');
|
|
1001
|
+
select.setOption('lookup.url', 'https://example.com/items?filter={filter}');
|
|
1002
|
+
select.setOption('mapping.selector', 'items.*');
|
|
1003
|
+
select.setOption('mapping.labelTemplate', '${name}');
|
|
1004
|
+
select.setOption('mapping.valueTemplate', '${id}');
|
|
1005
|
+
select.setOption('selection', [{value: {id: 'missing-key'}}]);
|
|
1006
|
+
mocks.appendChild(select);
|
|
1007
|
+
|
|
1008
|
+
setTimeout(() => {
|
|
1009
|
+
try {
|
|
1010
|
+
const badge = select.shadowRoot.querySelector('[data-monster-role=badge]');
|
|
1011
|
+
const badgeLabel = select.shadowRoot.querySelector('[data-monster-role=badge-label]');
|
|
1012
|
+
|
|
1013
|
+
expect(requests).to.include('https://example.com/items?filter=missing-key');
|
|
1014
|
+
expect(badge).to.be.instanceof(HTMLDivElement);
|
|
1015
|
+
expect(badgeLabel).to.be.instanceof(HTMLDivElement);
|
|
1016
|
+
expect(badgeLabel.textContent.trim()).to.equal('missing-key');
|
|
1017
|
+
expect(badge.className).to.contain('monster-badge-warning');
|
|
1018
|
+
expect(badge.className).to.not.contain('monster-badge-primary');
|
|
1019
|
+
expect(badge.getAttribute('data-monster-unresolved')).to.equal('true');
|
|
1020
|
+
expect(badgeLabel.textContent).to.not.contain(select.getOption('labels.cannot-be-loaded'));
|
|
1021
|
+
} catch (e) {
|
|
1022
|
+
return done(e);
|
|
1023
|
+
}
|
|
1024
|
+
|
|
1025
|
+
done();
|
|
1026
|
+
}, 250);
|
|
1027
|
+
});
|
|
1028
|
+
|
|
977
1029
|
it('should clear the unresolved badge state once a local option can resolve the value', function (done) {
|
|
978
1030
|
this.timeout(4000);
|
|
979
1031
|
|
package/test/cases/monster.mjs
CHANGED
package/test/web/import.js
CHANGED
|
@@ -9,14 +9,18 @@ import "../cases/components/form/buy-box.mjs";
|
|
|
9
9
|
import "../cases/components/form/message-state-button.mjs";
|
|
10
10
|
import "../cases/components/form/button-bar.mjs";
|
|
11
11
|
import "../cases/components/form/reload.mjs";
|
|
12
|
+
import "../cases/components/form/context-help.mjs";
|
|
12
13
|
import "../cases/components/form/state-button.mjs";
|
|
13
14
|
import "../cases/components/form/select.mjs";
|
|
14
15
|
import "../cases/components/form/login.mjs";
|
|
15
16
|
import "../cases/components/form/confirm-button.mjs";
|
|
17
|
+
import "../cases/components/form/context-error.mjs";
|
|
16
18
|
import "../cases/components/form/form.mjs";
|
|
17
19
|
import "../cases/components/form/tree-select.mjs";
|
|
20
|
+
import "../cases/components/form/popper-button.mjs";
|
|
18
21
|
import "../cases/components/form/wizard.mjs";
|
|
19
22
|
import "../cases/components/form/button.mjs";
|
|
23
|
+
import "../cases/components/form/floating-ui.mjs";
|
|
20
24
|
import "../cases/components/form/toggle-switch.mjs";
|
|
21
25
|
import "../cases/components/form/template.mjs";
|
|
22
26
|
import "../cases/components/notify/message.mjs";
|
package/test/web/test.html
CHANGED
|
@@ -9,8 +9,8 @@
|
|
|
9
9
|
</head>
|
|
10
10
|
<body>
|
|
11
11
|
<div id="headline" style="display: flex;align-items: center;justify-content: center;flex-direction: column;">
|
|
12
|
-
<h1 style='margin-bottom: 0.1em;'>Monster 4.
|
|
13
|
-
<div id="lastupdate" style='font-size:0.7em'>last update
|
|
12
|
+
<h1 style='margin-bottom: 0.1em;'>Monster 4.136.7</h1>
|
|
13
|
+
<div id="lastupdate" style='font-size:0.7em'>last update Wed Apr 22 21:49:31 CEST 2026</div>
|
|
14
14
|
</div>
|
|
15
15
|
<div id="mocha-errors"
|
|
16
16
|
style="color: red;font-weight: bold;display: flex;align-items: center;justify-content: center;flex-direction: column;margin:20px;"></div>
|