@schukai/monster 4.136.2 → 4.136.4
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/context-base.mjs +41 -6
- package/source/components/form/select.mjs +52 -44
- package/source/components/form/style/context-error.pcss +0 -2
- package/source/components/form/style/context-help.pcss +0 -2
- package/source/components/form/stylesheet/context-error.mjs +7 -14
- package/source/components/form/stylesheet/context-help.mjs +7 -14
- package/source/components/form/util/floating-ui.mjs +165 -11
- package/test/cases/components/form/context-help.mjs +47 -0
- package/test/cases/components/form/floating-ui.mjs +102 -0
- package/test/cases/components/form/message-state-button.mjs +54 -32
- package/test/cases/components/form/select.mjs +40 -0
- package/test/util/intersection-mock.mjs +3 -1
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.136.
|
|
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.136.4"}
|
|
@@ -13,7 +13,10 @@
|
|
|
13
13
|
*/
|
|
14
14
|
|
|
15
15
|
import { assembleMethodSymbol } from "../../dom/customelement.mjs";
|
|
16
|
-
import {
|
|
16
|
+
import {
|
|
17
|
+
resolveClippingBoundaryElement,
|
|
18
|
+
resolveParentPopperContentBoundary,
|
|
19
|
+
} from "./util/floating-ui.mjs";
|
|
17
20
|
import { Popper } from "../layout/popper.mjs";
|
|
18
21
|
|
|
19
22
|
export { ContextBase };
|
|
@@ -85,17 +88,40 @@ class ContextBase extends Popper {
|
|
|
85
88
|
*/
|
|
86
89
|
resolvePopperOptions() {
|
|
87
90
|
const options = super.resolvePopperOptions();
|
|
88
|
-
const controlElement =
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
91
|
+
const { controlElement, popperElement } = getPopperElements.call(this);
|
|
92
|
+
const parentPopperBoundary = resolveParentPopperContentBoundary(
|
|
93
|
+
controlElement,
|
|
94
|
+
popperElement,
|
|
95
|
+
);
|
|
92
96
|
|
|
93
|
-
if (
|
|
97
|
+
if (
|
|
98
|
+
resolveClippingBoundaryElement(controlElement, popperElement) ||
|
|
99
|
+
parentPopperBoundary
|
|
100
|
+
) {
|
|
94
101
|
options.strategy = "fixed";
|
|
95
102
|
}
|
|
96
103
|
|
|
97
104
|
return options;
|
|
98
105
|
}
|
|
106
|
+
|
|
107
|
+
/**
|
|
108
|
+
* Nested context poppers inside another popper need bounded height.
|
|
109
|
+
*
|
|
110
|
+
* @return {string}
|
|
111
|
+
*/
|
|
112
|
+
resolveContentOverflowMode() {
|
|
113
|
+
const configuredMode = super.resolveContentOverflowMode();
|
|
114
|
+
if (configuredMode !== "visible") {
|
|
115
|
+
return configuredMode;
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
const { controlElement, popperElement } = getPopperElements.call(this);
|
|
119
|
+
if (resolveParentPopperContentBoundary(controlElement, popperElement)) {
|
|
120
|
+
return "both";
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
return configuredMode;
|
|
124
|
+
}
|
|
99
125
|
}
|
|
100
126
|
|
|
101
127
|
/**
|
|
@@ -126,6 +152,15 @@ function initContentObserver() {
|
|
|
126
152
|
});
|
|
127
153
|
}
|
|
128
154
|
|
|
155
|
+
function getPopperElements() {
|
|
156
|
+
return {
|
|
157
|
+
controlElement:
|
|
158
|
+
this.shadowRoot?.querySelector('[data-monster-role="control"]') || null,
|
|
159
|
+
popperElement:
|
|
160
|
+
this.shadowRoot?.querySelector('[data-monster-role="popper"]') || null,
|
|
161
|
+
};
|
|
162
|
+
}
|
|
163
|
+
|
|
129
164
|
/**
|
|
130
165
|
* @private
|
|
131
166
|
* @return {void}
|
|
@@ -1765,55 +1765,20 @@ function getTranslations() {
|
|
|
1765
1765
|
*/
|
|
1766
1766
|
function lookupSelection() {
|
|
1767
1767
|
const self = this;
|
|
1768
|
+
const IntersectionObserverImplementation =
|
|
1769
|
+
getGlobal().IntersectionObserver;
|
|
1768
1770
|
|
|
1769
|
-
|
|
1771
|
+
if (!(IntersectionObserverImplementation instanceof Function)) {
|
|
1772
|
+
runSelectionLookupWhenVisible(self);
|
|
1773
|
+
return;
|
|
1774
|
+
}
|
|
1775
|
+
|
|
1776
|
+
const observer = new IntersectionObserverImplementation(
|
|
1770
1777
|
(entries, obs) => {
|
|
1771
1778
|
for (const entry of entries) {
|
|
1772
1779
|
if (entry.isIntersecting) {
|
|
1773
1780
|
obs.disconnect();
|
|
1774
|
-
|
|
1775
|
-
setTimeout(() => {
|
|
1776
|
-
const selection = self.getOption("selection");
|
|
1777
|
-
if (
|
|
1778
|
-
selection.length === 0 ||
|
|
1779
|
-
self[isLoadingSymbol] ||
|
|
1780
|
-
self[lazyLoadDoneSymbol]
|
|
1781
|
-
) {
|
|
1782
|
-
return;
|
|
1783
|
-
}
|
|
1784
|
-
|
|
1785
|
-
let url = self.getOption("lookup.url") || self.getOption("url");
|
|
1786
|
-
self[cleanupOptionsListSymbol] = false;
|
|
1787
|
-
|
|
1788
|
-
if (self.getOption("lookup.grouping") === true) {
|
|
1789
|
-
const values = selection
|
|
1790
|
-
.map((s) => s?.["value"])
|
|
1791
|
-
.filter(
|
|
1792
|
-
(value) => isEmptyLookupValue.call(self, value) === false,
|
|
1793
|
-
);
|
|
1794
|
-
if (values.length === 0) {
|
|
1795
|
-
return;
|
|
1796
|
-
}
|
|
1797
|
-
filterFromRemoteByValue
|
|
1798
|
-
.call(self, url, { filter: values.join(",") })
|
|
1799
|
-
.catch((e) => {
|
|
1800
|
-
addErrorAttribute(self, e);
|
|
1801
|
-
});
|
|
1802
|
-
return;
|
|
1803
|
-
}
|
|
1804
|
-
|
|
1805
|
-
for (const s of selection) {
|
|
1806
|
-
const value = s?.["value"];
|
|
1807
|
-
if (isEmptyLookupValue.call(self, value)) {
|
|
1808
|
-
continue;
|
|
1809
|
-
}
|
|
1810
|
-
filterFromRemoteByValue
|
|
1811
|
-
.call(self, url, { filter: value })
|
|
1812
|
-
.catch((e) => {
|
|
1813
|
-
addErrorAttribute(self, e);
|
|
1814
|
-
});
|
|
1815
|
-
}
|
|
1816
|
-
}, 100);
|
|
1781
|
+
runSelectionLookupWhenVisible(self);
|
|
1817
1782
|
}
|
|
1818
1783
|
}
|
|
1819
1784
|
},
|
|
@@ -1823,6 +1788,49 @@ function lookupSelection() {
|
|
|
1823
1788
|
observer.observe(self);
|
|
1824
1789
|
}
|
|
1825
1790
|
|
|
1791
|
+
function runSelectionLookupWhenVisible(self) {
|
|
1792
|
+
setTimeout(() => {
|
|
1793
|
+
const selection = self.getOption("selection");
|
|
1794
|
+
if (
|
|
1795
|
+
selection.length === 0 ||
|
|
1796
|
+
self[isLoadingSymbol] ||
|
|
1797
|
+
self[lazyLoadDoneSymbol]
|
|
1798
|
+
) {
|
|
1799
|
+
return;
|
|
1800
|
+
}
|
|
1801
|
+
|
|
1802
|
+
let url = self.getOption("lookup.url") || self.getOption("url");
|
|
1803
|
+
self[cleanupOptionsListSymbol] = false;
|
|
1804
|
+
|
|
1805
|
+
if (self.getOption("lookup.grouping") === true) {
|
|
1806
|
+
const values = selection
|
|
1807
|
+
.map((s) => s?.["value"])
|
|
1808
|
+
.filter((value) => isEmptyLookupValue.call(self, value) === false);
|
|
1809
|
+
if (values.length === 0) {
|
|
1810
|
+
return;
|
|
1811
|
+
}
|
|
1812
|
+
filterFromRemoteByValue
|
|
1813
|
+
.call(self, url, { filter: values.join(",") })
|
|
1814
|
+
.catch((e) => {
|
|
1815
|
+
addErrorAttribute(self, e);
|
|
1816
|
+
});
|
|
1817
|
+
return;
|
|
1818
|
+
}
|
|
1819
|
+
|
|
1820
|
+
for (const s of selection) {
|
|
1821
|
+
const value = s?.["value"];
|
|
1822
|
+
if (isEmptyLookupValue.call(self, value)) {
|
|
1823
|
+
continue;
|
|
1824
|
+
}
|
|
1825
|
+
filterFromRemoteByValue
|
|
1826
|
+
.call(self, url, { filter: value })
|
|
1827
|
+
.catch((e) => {
|
|
1828
|
+
addErrorAttribute(self, e);
|
|
1829
|
+
});
|
|
1830
|
+
}
|
|
1831
|
+
}, 100);
|
|
1832
|
+
}
|
|
1833
|
+
|
|
1826
1834
|
/**
|
|
1827
1835
|
* @private
|
|
1828
1836
|
* @param {*} value
|
|
@@ -10,10 +10,10 @@
|
|
|
10
10
|
* For more information about purchasing a commercial license, please contact Volker Schukai.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
13
|
+
import {addAttributeToken} from "../../../dom/attributes.mjs";
|
|
14
|
+
import {ATTRIBUTE_ERRORMESSAGE} from "../../../dom/constants.mjs";
|
|
15
15
|
|
|
16
|
-
export {
|
|
16
|
+
export {ContextErrorStyleSheet}
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* @private
|
|
@@ -22,17 +22,10 @@ export { ContextErrorStyleSheet };
|
|
|
22
22
|
const ContextErrorStyleSheet = new CSSStyleSheet();
|
|
23
23
|
|
|
24
24
|
try {
|
|
25
|
-
|
|
26
|
-
`
|
|
25
|
+
ContextErrorStyleSheet.insertRule(`
|
|
27
26
|
@layer contexterror {
|
|
28
|
-
[data-monster-role=control]{box-sizing:border-box;outline:none;width:100%}[data-monster-role=control].flex{align-items:center;display:flex;flex-direction:row}:host{box-sizing:border-box;display:block}div[data-monster-role=popper]{align-content:center;background:var(--monster-bg-color-primary-1);border-color:var(--monster-bg-color-primary-4);border-radius:var(--monster-border-radius);border-style:var(--monster-border-style);border-width:var(--monster-border-width);box-shadow:var(--monster-box-shadow-1);box-sizing:border-box;color:var(--monster-color-primary-1);display:none;justify-content:space-between;left:0;max-height:var(--monster-popper-max-height,calc(100vh - 2rem));max-width:var(--monster-popper-max-width,calc(100vw - 2rem));padding:1.1em;position:absolute;top:0;width:-moz-max-content;width:max-content;z-index:var(--monster-z-index-modal)}div[data-monster-role=popper]>[part=content]{max-height:var(--monster-popper-content-max-height,calc(100vh - 4.2rem));overflow:auto}div[data-monster-role=popper]>[part=content][data-monster-overflow-mode=horizontal]{clip-path:none;overflow:visible}div[data-monster-role=popper]>[part=content][data-monster-overflow-mode=visible]{clip-path:none;max-height:none;max-width:none;overflow:visible}div[data-monster-role=popper] div[data-monster-role=arrow]{background:var(--monster-bg-color-primary-1);height:calc(max(var(--monster-popper-witharrrow-distance), -1 * var(--monster-popper-witharrrow-distance))*2);pointer-events:none;position:absolute;width:calc(max(var(--monster-popper-witharrrow-distance), -1 * var(--monster-popper-witharrrow-distance))*2);z-index:-1}[data-monster-role=control]{line-height:1em;margin:0;padding:0;position:relative}[data-monster-role=control] [data-monster-role=button]{display:inline-block;position:relative}:is([data-monster-role=control] [data-monster-role=button]) svg{cursor:pointer}:is([data-monster-role=control] [data-monster-role=button]) svg.hidden{cursor:default;pointer-events:none;visibility:hidden}:host{display:inline-block;margin:0 .2em;padding:0;position:relative;vertical-align:bottom}div[data-monster-role=popper]{max-width:min(var(--monster-popper-max-width,calc(100vw - 2rem)),32rem)}div[data-monster-role=popper]>[part=content]{display:block;max-
|
|
29
|
-
}`,
|
|
30
|
-
0,
|
|
31
|
-
);
|
|
27
|
+
[data-monster-role=control]{box-sizing:border-box;outline:none;width:100%}[data-monster-role=control].flex{align-items:center;display:flex;flex-direction:row}:host{box-sizing:border-box;display:block}div[data-monster-role=popper]{align-content:center;background:var(--monster-bg-color-primary-1);border-color:var(--monster-bg-color-primary-4);border-radius:var(--monster-border-radius);border-style:var(--monster-border-style);border-width:var(--monster-border-width);box-shadow:var(--monster-box-shadow-1);box-sizing:border-box;color:var(--monster-color-primary-1);display:none;justify-content:space-between;left:0;max-height:var(--monster-popper-max-height,calc(100vh - 2rem));max-width:var(--monster-popper-max-width,calc(100vw - 2rem));padding:1.1em;position:absolute;top:0;width:-moz-max-content;width:max-content;z-index:var(--monster-z-index-modal)}div[data-monster-role=popper]>[part=content]{max-height:var(--monster-popper-content-max-height,calc(100vh - 4.2rem));overflow:auto}div[data-monster-role=popper]>[part=content][data-monster-overflow-mode=horizontal]{clip-path:none;overflow:visible}div[data-monster-role=popper]>[part=content][data-monster-overflow-mode=visible]{clip-path:none;max-height:none;max-width:none;overflow:visible}div[data-monster-role=popper] div[data-monster-role=arrow]{background:var(--monster-bg-color-primary-1);height:calc(max(var(--monster-popper-witharrrow-distance), -1 * var(--monster-popper-witharrrow-distance))*2);pointer-events:none;position:absolute;width:calc(max(var(--monster-popper-witharrrow-distance), -1 * var(--monster-popper-witharrrow-distance))*2);z-index:-1}[data-monster-role=control]{line-height:1em;margin:0;padding:0;position:relative}[data-monster-role=control] [data-monster-role=button]{display:inline-block;position:relative}:is([data-monster-role=control] [data-monster-role=button]) svg{cursor:pointer}:is([data-monster-role=control] [data-monster-role=button]) svg.hidden{cursor:default;pointer-events:none;visibility:hidden}:host{display:inline-block;margin:0 .2em;padding:0;position:relative;vertical-align:bottom}div[data-monster-role=popper]{max-width:min(var(--monster-popper-max-width,calc(100vw - 2rem)),32rem)}div[data-monster-role=popper]>[part=content]{display:block;max-width:100%;overflow-wrap:anywhere;text-wrap:pretty;white-space:normal;word-break:break-word}:host([disabled]) [data-monster-role=button] svg{cursor:default;pointer-events:none}
|
|
28
|
+
}`, 0);
|
|
32
29
|
} catch (e) {
|
|
33
|
-
|
|
34
|
-
document.getRootNode().querySelector("html"),
|
|
35
|
-
ATTRIBUTE_ERRORMESSAGE,
|
|
36
|
-
e + "",
|
|
37
|
-
);
|
|
30
|
+
addAttributeToken(document.getRootNode().querySelector('html'), ATTRIBUTE_ERRORMESSAGE, e + "");
|
|
38
31
|
}
|
|
@@ -10,10 +10,10 @@
|
|
|
10
10
|
* For more information about purchasing a commercial license, please contact Volker Schukai.
|
|
11
11
|
*/
|
|
12
12
|
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
13
|
+
import {addAttributeToken} from "../../../dom/attributes.mjs";
|
|
14
|
+
import {ATTRIBUTE_ERRORMESSAGE} from "../../../dom/constants.mjs";
|
|
15
15
|
|
|
16
|
-
export {
|
|
16
|
+
export {ContextHelpStyleSheet}
|
|
17
17
|
|
|
18
18
|
/**
|
|
19
19
|
* @private
|
|
@@ -22,17 +22,10 @@ export { ContextHelpStyleSheet };
|
|
|
22
22
|
const ContextHelpStyleSheet = new CSSStyleSheet();
|
|
23
23
|
|
|
24
24
|
try {
|
|
25
|
-
|
|
26
|
-
`
|
|
25
|
+
ContextHelpStyleSheet.insertRule(`
|
|
27
26
|
@layer contexthelp {
|
|
28
|
-
[data-monster-role=control]{box-sizing:border-box;outline:none;width:100%}[data-monster-role=control].flex{align-items:center;display:flex;flex-direction:row}:host{box-sizing:border-box;display:block}div[data-monster-role=popper]{align-content:center;background:var(--monster-bg-color-primary-1);border-color:var(--monster-bg-color-primary-4);border-radius:var(--monster-border-radius);border-style:var(--monster-border-style);border-width:var(--monster-border-width);box-shadow:var(--monster-box-shadow-1);box-sizing:border-box;color:var(--monster-color-primary-1);display:none;justify-content:space-between;left:0;max-height:var(--monster-popper-max-height,calc(100vh - 2rem));max-width:var(--monster-popper-max-width,calc(100vw - 2rem));padding:1.1em;position:absolute;top:0;width:-moz-max-content;width:max-content;z-index:var(--monster-z-index-modal)}div[data-monster-role=popper]>[part=content]{max-height:var(--monster-popper-content-max-height,calc(100vh - 4.2rem));overflow:auto}div[data-monster-role=popper]>[part=content][data-monster-overflow-mode=horizontal]{clip-path:none;overflow:visible}div[data-monster-role=popper]>[part=content][data-monster-overflow-mode=visible]{clip-path:none;max-height:none;max-width:none;overflow:visible}div[data-monster-role=popper] div[data-monster-role=arrow]{background:var(--monster-bg-color-primary-1);height:calc(max(var(--monster-popper-witharrrow-distance), -1 * var(--monster-popper-witharrrow-distance))*2);pointer-events:none;position:absolute;width:calc(max(var(--monster-popper-witharrrow-distance), -1 * var(--monster-popper-witharrrow-distance))*2);z-index:-1}[data-monster-role=control]{line-height:1em;margin:0;padding:0;position:relative}[data-monster-role=control] [data-monster-role=button]{display:inline-block;position:relative}:is([data-monster-role=control] [data-monster-role=button]) svg{cursor:pointer}:is([data-monster-role=control] [data-monster-role=button]) svg.hidden{cursor:default;pointer-events:none;visibility:hidden}div[data-monster-role=popper]{max-width:min(var(--monster-popper-max-width,calc(100vw - 2rem)),32rem);z-index:var(--monster-z-index-tooltip-overlay)}div[data-monster-role=popper]>[part=content]{display:block;max-
|
|
29
|
-
}`,
|
|
30
|
-
0,
|
|
31
|
-
);
|
|
27
|
+
[data-monster-role=control]{box-sizing:border-box;outline:none;width:100%}[data-monster-role=control].flex{align-items:center;display:flex;flex-direction:row}:host{box-sizing:border-box;display:block}div[data-monster-role=popper]{align-content:center;background:var(--monster-bg-color-primary-1);border-color:var(--monster-bg-color-primary-4);border-radius:var(--monster-border-radius);border-style:var(--monster-border-style);border-width:var(--monster-border-width);box-shadow:var(--monster-box-shadow-1);box-sizing:border-box;color:var(--monster-color-primary-1);display:none;justify-content:space-between;left:0;max-height:var(--monster-popper-max-height,calc(100vh - 2rem));max-width:var(--monster-popper-max-width,calc(100vw - 2rem));padding:1.1em;position:absolute;top:0;width:-moz-max-content;width:max-content;z-index:var(--monster-z-index-modal)}div[data-monster-role=popper]>[part=content]{max-height:var(--monster-popper-content-max-height,calc(100vh - 4.2rem));overflow:auto}div[data-monster-role=popper]>[part=content][data-monster-overflow-mode=horizontal]{clip-path:none;overflow:visible}div[data-monster-role=popper]>[part=content][data-monster-overflow-mode=visible]{clip-path:none;max-height:none;max-width:none;overflow:visible}div[data-monster-role=popper] div[data-monster-role=arrow]{background:var(--monster-bg-color-primary-1);height:calc(max(var(--monster-popper-witharrrow-distance), -1 * var(--monster-popper-witharrrow-distance))*2);pointer-events:none;position:absolute;width:calc(max(var(--monster-popper-witharrrow-distance), -1 * var(--monster-popper-witharrrow-distance))*2);z-index:-1}[data-monster-role=control]{line-height:1em;margin:0;padding:0;position:relative}[data-monster-role=control] [data-monster-role=button]{display:inline-block;position:relative}:is([data-monster-role=control] [data-monster-role=button]) svg{cursor:pointer}:is([data-monster-role=control] [data-monster-role=button]) svg.hidden{cursor:default;pointer-events:none;visibility:hidden}div[data-monster-role=popper]{max-width:min(var(--monster-popper-max-width,calc(100vw - 2rem)),32rem);z-index:var(--monster-z-index-tooltip-overlay)}div[data-monster-role=popper]>[part=content]{display:block;max-width:100%;overflow-wrap:anywhere;text-wrap:pretty;white-space:normal;word-break:break-word}:host{display:inline-block;margin:0 .2em;padding:0;position:relative;vertical-align:bottom}:host([disabled]) [data-monster-role=button] svg{cursor:default;pointer-events:none}
|
|
28
|
+
}`, 0);
|
|
32
29
|
} catch (e) {
|
|
33
|
-
|
|
34
|
-
document.getRootNode().querySelector("html"),
|
|
35
|
-
ATTRIBUTE_ERRORMESSAGE,
|
|
36
|
-
e + "",
|
|
37
|
-
);
|
|
30
|
+
addAttributeToken(document.getRootNode().querySelector('html'), ATTRIBUTE_ERRORMESSAGE, e + "");
|
|
38
31
|
}
|
|
@@ -30,6 +30,7 @@ export {
|
|
|
30
30
|
applyAdaptiveFloatingElementSize,
|
|
31
31
|
closePositionedPopper,
|
|
32
32
|
resolveClippingBoundaryElement,
|
|
33
|
+
resolveParentPopperContentBoundary,
|
|
33
34
|
isPositionedPopperOpen,
|
|
34
35
|
openPositionedPopper,
|
|
35
36
|
positionPopper,
|
|
@@ -144,10 +145,12 @@ function normalizePopperConfig(options, controlElement, popperElement) {
|
|
|
144
145
|
options,
|
|
145
146
|
);
|
|
146
147
|
|
|
147
|
-
config.boundaryElement
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
148
|
+
if (!(config.boundaryElement instanceof HTMLElement)) {
|
|
149
|
+
config.boundaryElement = resolveClippingBoundaryElement(
|
|
150
|
+
controlElement,
|
|
151
|
+
popperElement,
|
|
152
|
+
);
|
|
153
|
+
}
|
|
151
154
|
config.detectOverflowOptions = buildDetectOverflowOptions(
|
|
152
155
|
config.boundaryElement,
|
|
153
156
|
);
|
|
@@ -283,6 +286,10 @@ function applyAdaptiveFloatingElementSize(
|
|
|
283
286
|
floatingElement,
|
|
284
287
|
{ availableWidth, availableHeight },
|
|
285
288
|
) {
|
|
289
|
+
const contentElement = getFloatingContentElement(floatingElement);
|
|
290
|
+
const usesVisibleOverflow =
|
|
291
|
+
contentElement instanceof HTMLElement &&
|
|
292
|
+
contentElement.dataset.monsterOverflowMode === "visible";
|
|
286
293
|
const maxWidth = clampAvailableDimension(
|
|
287
294
|
availableWidth,
|
|
288
295
|
readMaxDimension(floatingElement, "maxWidth"),
|
|
@@ -301,7 +308,7 @@ function applyAdaptiveFloatingElementSize(
|
|
|
301
308
|
nextStyle.maxWidth = "";
|
|
302
309
|
}
|
|
303
310
|
|
|
304
|
-
if (Number.isFinite(maxHeight) && maxHeight > 0) {
|
|
311
|
+
if (!usesVisibleOverflow && Number.isFinite(maxHeight) && maxHeight > 0) {
|
|
305
312
|
nextStyle.maxHeight = `${maxHeight}px`;
|
|
306
313
|
} else {
|
|
307
314
|
nextStyle.maxHeight = "";
|
|
@@ -332,14 +339,19 @@ function applyAdaptiveFloatingContentSize(floatingElement, maxHeight) {
|
|
|
332
339
|
Number.isFinite(maxHeight) ? maxHeight - reservedHeight : null,
|
|
333
340
|
readMaxDimension(contentElement, "maxHeight"),
|
|
334
341
|
);
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
342
|
+
const minimumReadableHeight = getMinimumReadableContentHeight(contentElement);
|
|
343
|
+
const nextContentMaxHeight =
|
|
344
|
+
Number.isFinite(contentMaxHeight) && contentMaxHeight > 0
|
|
345
|
+
? Math.max(contentMaxHeight, minimumReadableHeight)
|
|
346
|
+
: contentMaxHeight;
|
|
347
|
+
|
|
348
|
+
if (Number.isFinite(nextContentMaxHeight) && nextContentMaxHeight > 0) {
|
|
349
|
+
contentElement.style.maxHeight = `${nextContentMaxHeight}px`;
|
|
338
350
|
} else {
|
|
339
351
|
contentElement.style.maxHeight = "";
|
|
340
352
|
}
|
|
341
353
|
|
|
342
|
-
syncNestedScrollContainerHeight(contentElement,
|
|
354
|
+
syncNestedScrollContainerHeight(contentElement, nextContentMaxHeight);
|
|
343
355
|
}
|
|
344
356
|
|
|
345
357
|
function getFloatingContentElement(floatingElement) {
|
|
@@ -391,6 +403,63 @@ function readBoxDimension(rawValue) {
|
|
|
391
403
|
return Number.isFinite(value) ? value : 0;
|
|
392
404
|
}
|
|
393
405
|
|
|
406
|
+
function getMinimumReadableContentHeight(contentElement) {
|
|
407
|
+
if (!(contentElement instanceof HTMLElement)) {
|
|
408
|
+
return 0;
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
const measurementTarget =
|
|
412
|
+
getPrimaryReadableContentElement(contentElement) || contentElement;
|
|
413
|
+
const style = getComputedStyle(measurementTarget);
|
|
414
|
+
const lineHeight = readLineHeight(style);
|
|
415
|
+
const paddingHeight =
|
|
416
|
+
readBoxDimension(getComputedStyle(contentElement).paddingTop) +
|
|
417
|
+
readBoxDimension(getComputedStyle(contentElement).paddingBottom);
|
|
418
|
+
|
|
419
|
+
return Math.max(0, lineHeight + paddingHeight);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
function readLineHeight(style) {
|
|
423
|
+
if (!style) {
|
|
424
|
+
return 0;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
const lineHeight = Number.parseFloat(style.lineHeight);
|
|
428
|
+
if (Number.isFinite(lineHeight) && lineHeight > 0) {
|
|
429
|
+
return lineHeight;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
const fontSize = Number.parseFloat(style.fontSize);
|
|
433
|
+
if (Number.isFinite(fontSize) && fontSize > 0) {
|
|
434
|
+
return fontSize * 1.4;
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
return 0;
|
|
438
|
+
}
|
|
439
|
+
|
|
440
|
+
function getPrimaryReadableContentElement(contentElement) {
|
|
441
|
+
if (!(contentElement instanceof HTMLElement)) {
|
|
442
|
+
return null;
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
const slotElement = contentElement.querySelector("slot");
|
|
446
|
+
if (slotElement?.assignedElements instanceof Function) {
|
|
447
|
+
for (const element of slotElement.assignedElements({ flatten: true })) {
|
|
448
|
+
if (element instanceof HTMLElement) {
|
|
449
|
+
return element;
|
|
450
|
+
}
|
|
451
|
+
}
|
|
452
|
+
}
|
|
453
|
+
|
|
454
|
+
for (const child of contentElement.children) {
|
|
455
|
+
if (child instanceof HTMLElement) {
|
|
456
|
+
return child;
|
|
457
|
+
}
|
|
458
|
+
}
|
|
459
|
+
|
|
460
|
+
return null;
|
|
461
|
+
}
|
|
462
|
+
|
|
394
463
|
function syncNestedScrollContainerHeight(contentElement, contentMaxHeight) {
|
|
395
464
|
const nestedScrollableElement = getNestedScrollableElement(contentElement);
|
|
396
465
|
if (!(nestedScrollableElement instanceof HTMLElement)) {
|
|
@@ -398,8 +467,12 @@ function syncNestedScrollContainerHeight(contentElement, contentMaxHeight) {
|
|
|
398
467
|
}
|
|
399
468
|
|
|
400
469
|
if (Number.isFinite(contentMaxHeight) && contentMaxHeight > 0) {
|
|
401
|
-
|
|
402
|
-
|
|
470
|
+
const nextNestedHeight = resolveNestedScrollContainerHeight(
|
|
471
|
+
nestedScrollableElement,
|
|
472
|
+
contentMaxHeight,
|
|
473
|
+
);
|
|
474
|
+
nestedScrollableElement.style.height = `${nextNestedHeight}px`;
|
|
475
|
+
nestedScrollableElement.style.maxHeight = `${nextNestedHeight}px`;
|
|
403
476
|
return;
|
|
404
477
|
}
|
|
405
478
|
|
|
@@ -407,6 +480,41 @@ function syncNestedScrollContainerHeight(contentElement, contentMaxHeight) {
|
|
|
407
480
|
nestedScrollableElement.style.maxHeight = "";
|
|
408
481
|
}
|
|
409
482
|
|
|
483
|
+
function resolveNestedScrollContainerHeight(
|
|
484
|
+
nestedScrollableElement,
|
|
485
|
+
contentMaxHeight,
|
|
486
|
+
) {
|
|
487
|
+
const declaredHeight = readDeclaredDimension(nestedScrollableElement, "height");
|
|
488
|
+
const declaredMaxHeight = readDeclaredDimension(
|
|
489
|
+
nestedScrollableElement,
|
|
490
|
+
"maxHeight",
|
|
491
|
+
);
|
|
492
|
+
const scrollHeight = nestedScrollableElement.scrollHeight;
|
|
493
|
+
const preferredHeightCandidates = [
|
|
494
|
+
declaredHeight,
|
|
495
|
+
declaredMaxHeight,
|
|
496
|
+
scrollHeight,
|
|
497
|
+
];
|
|
498
|
+
const preferredHeight = preferredHeightCandidates.find((value) => {
|
|
499
|
+
return Number.isFinite(value) && value > 0;
|
|
500
|
+
});
|
|
501
|
+
|
|
502
|
+
if (Number.isFinite(preferredHeight) && preferredHeight > 0) {
|
|
503
|
+
return Math.min(contentMaxHeight, preferredHeight);
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
return contentMaxHeight;
|
|
507
|
+
}
|
|
508
|
+
|
|
509
|
+
function readDeclaredDimension(element, property) {
|
|
510
|
+
if (!(element instanceof HTMLElement)) {
|
|
511
|
+
return NaN;
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
const value = Number.parseFloat(element.style?.[property] || "");
|
|
515
|
+
return Number.isFinite(value) ? value : NaN;
|
|
516
|
+
}
|
|
517
|
+
|
|
410
518
|
function syncPreferredFloatingWidth(floatingElement, maxWidth) {
|
|
411
519
|
const preferredWidth = Number.parseFloat(
|
|
412
520
|
floatingElement.dataset.monsterPreferredWidth || "",
|
|
@@ -539,6 +647,17 @@ function resolveClippingBoundaryElement(...elements) {
|
|
|
539
647
|
return null;
|
|
540
648
|
}
|
|
541
649
|
|
|
650
|
+
function resolveParentPopperContentBoundary(...elements) {
|
|
651
|
+
for (const element of elements) {
|
|
652
|
+
const clippingBoundary = findNearestIgnoredClippingContainer(element);
|
|
653
|
+
if (clippingBoundary instanceof HTMLElement) {
|
|
654
|
+
return clippingBoundary;
|
|
655
|
+
}
|
|
656
|
+
}
|
|
657
|
+
|
|
658
|
+
return null;
|
|
659
|
+
}
|
|
660
|
+
|
|
542
661
|
function findNearestClippingContainer(element) {
|
|
543
662
|
let current = getComposedParent(element);
|
|
544
663
|
|
|
@@ -557,11 +676,46 @@ function findNearestClippingContainer(element) {
|
|
|
557
676
|
return null;
|
|
558
677
|
}
|
|
559
678
|
|
|
679
|
+
function findNearestIgnoredClippingContainer(element) {
|
|
680
|
+
let current = getComposedParent(element);
|
|
681
|
+
|
|
682
|
+
while (current) {
|
|
683
|
+
if (
|
|
684
|
+
current instanceof HTMLElement &&
|
|
685
|
+
shouldIgnoreClippingContainer(current) &&
|
|
686
|
+
shouldEscapeParentPopperContentWrapper(current)
|
|
687
|
+
) {
|
|
688
|
+
return current;
|
|
689
|
+
}
|
|
690
|
+
|
|
691
|
+
current = getComposedParent(current);
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
return null;
|
|
695
|
+
}
|
|
696
|
+
|
|
697
|
+
function shouldEscapeParentPopperContentWrapper(element) {
|
|
698
|
+
if (!(element instanceof HTMLElement) || !isPopperContentWrapper(element)) {
|
|
699
|
+
return false;
|
|
700
|
+
}
|
|
701
|
+
|
|
702
|
+
const overflowMode = element.getAttribute("data-monster-overflow-mode");
|
|
703
|
+
if (overflowMode === "both") {
|
|
704
|
+
return true;
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
return isClippingContainer(getComputedStyle(element));
|
|
708
|
+
}
|
|
709
|
+
|
|
560
710
|
function getComposedParent(node) {
|
|
561
711
|
if (!node) {
|
|
562
712
|
return null;
|
|
563
713
|
}
|
|
564
714
|
|
|
715
|
+
if (node instanceof Element && node.assignedSlot) {
|
|
716
|
+
return node.assignedSlot;
|
|
717
|
+
}
|
|
718
|
+
|
|
565
719
|
if (node instanceof ShadowRoot) {
|
|
566
720
|
return node.host || null;
|
|
567
721
|
}
|
|
@@ -11,6 +11,7 @@ const global = getGlobal();
|
|
|
11
11
|
|
|
12
12
|
let ContextHelp;
|
|
13
13
|
let resolveClippingBoundaryElement;
|
|
14
|
+
let resolveParentPopperContentBoundary;
|
|
14
15
|
|
|
15
16
|
describe("ContextHelp", function () {
|
|
16
17
|
before(function (done) {
|
|
@@ -29,6 +30,8 @@ describe("ContextHelp", function () {
|
|
|
29
30
|
ContextHelp = contextHelpModule.ContextHelp;
|
|
30
31
|
resolveClippingBoundaryElement =
|
|
31
32
|
floatingUiModule.resolveClippingBoundaryElement;
|
|
33
|
+
resolveParentPopperContentBoundary =
|
|
34
|
+
floatingUiModule.resolveParentPopperContentBoundary;
|
|
32
35
|
done();
|
|
33
36
|
})
|
|
34
37
|
.catch((e) => done(e));
|
|
@@ -114,4 +117,48 @@ describe("ContextHelp", function () {
|
|
|
114
117
|
}
|
|
115
118
|
}, 0);
|
|
116
119
|
});
|
|
120
|
+
|
|
121
|
+
it("should switch to fixed positioning inside a parent popper content wrapper with overflow both", function (done) {
|
|
122
|
+
let mocks = document.getElementById("mocks");
|
|
123
|
+
const host = document.createElement("div");
|
|
124
|
+
const help = document.createElement("monster-context-help");
|
|
125
|
+
|
|
126
|
+
mocks.appendChild(host);
|
|
127
|
+
const shadowRoot = host.attachShadow({ mode: "open" });
|
|
128
|
+
shadowRoot.innerHTML = `
|
|
129
|
+
<div data-monster-role="popper">
|
|
130
|
+
<div part="content"
|
|
131
|
+
data-monster-overflow-mode="both">
|
|
132
|
+
</div>
|
|
133
|
+
</div>
|
|
134
|
+
`;
|
|
135
|
+
shadowRoot.querySelector('[part="content"]').appendChild(help);
|
|
136
|
+
help.innerHTML = "<p>Nested help</p>";
|
|
137
|
+
|
|
138
|
+
setTimeout(() => {
|
|
139
|
+
try {
|
|
140
|
+
const control = help.shadowRoot.querySelector(
|
|
141
|
+
'[data-monster-role="control"]',
|
|
142
|
+
);
|
|
143
|
+
const popper = help.shadowRoot.querySelector(
|
|
144
|
+
'[data-monster-role="popper"]',
|
|
145
|
+
);
|
|
146
|
+
|
|
147
|
+
expect(
|
|
148
|
+
resolveParentPopperContentBoundary(control, popper),
|
|
149
|
+
).to.equal(shadowRoot.querySelector('[part="content"]'));
|
|
150
|
+
|
|
151
|
+
const content = help.shadowRoot.querySelector('[part="content"]');
|
|
152
|
+
expect(content.getAttribute("data-monster-overflow-mode")).to.equal(
|
|
153
|
+
"both",
|
|
154
|
+
);
|
|
155
|
+
|
|
156
|
+
help.showDialog();
|
|
157
|
+
expect(popper.style.position).to.equal("fixed");
|
|
158
|
+
done();
|
|
159
|
+
} catch (e) {
|
|
160
|
+
done(e);
|
|
161
|
+
}
|
|
162
|
+
}, 0);
|
|
163
|
+
});
|
|
117
164
|
});
|
|
@@ -135,4 +135,106 @@ describe("form floating-ui boundary resolution", function () {
|
|
|
135
135
|
expect(content.style.maxWidth).to.equal("");
|
|
136
136
|
expect(content.style.maxHeight).to.equal("100px");
|
|
137
137
|
});
|
|
138
|
+
|
|
139
|
+
it("should not clamp the floating element height when content overflow is visible", function () {
|
|
140
|
+
const mocks = document.getElementById("mocks");
|
|
141
|
+
const popper = document.createElement("div");
|
|
142
|
+
const content = document.createElement("div");
|
|
143
|
+
|
|
144
|
+
popper.style.maxHeight = "300px";
|
|
145
|
+
content.style.maxHeight = "240px";
|
|
146
|
+
content.setAttribute("part", "content");
|
|
147
|
+
content.setAttribute("data-monster-overflow-mode", "visible");
|
|
148
|
+
|
|
149
|
+
popper.appendChild(content);
|
|
150
|
+
mocks.appendChild(popper);
|
|
151
|
+
|
|
152
|
+
applyAdaptiveFloatingElementSize(popper, {
|
|
153
|
+
availableWidth: 220,
|
|
154
|
+
availableHeight: 160,
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
expect(popper.style.maxHeight).to.equal("");
|
|
158
|
+
expect(content.style.maxHeight).to.equal("240px");
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
it("should keep at least one readable line for scrollable content", function () {
|
|
162
|
+
const mocks = document.getElementById("mocks");
|
|
163
|
+
const popper = document.createElement("div");
|
|
164
|
+
const content = document.createElement("div");
|
|
165
|
+
|
|
166
|
+
popper.style.maxHeight = "300px";
|
|
167
|
+
content.setAttribute("part", "content");
|
|
168
|
+
content.textContent = "A long help text that still needs one readable line.";
|
|
169
|
+
content.style.fontSize = "16px";
|
|
170
|
+
content.style.lineHeight = "24px";
|
|
171
|
+
popper.appendChild(content);
|
|
172
|
+
mocks.appendChild(popper);
|
|
173
|
+
|
|
174
|
+
applyAdaptiveFloatingElementSize(popper, {
|
|
175
|
+
availableWidth: 220,
|
|
176
|
+
availableHeight: 10,
|
|
177
|
+
});
|
|
178
|
+
|
|
179
|
+
expect(content.style.maxHeight).to.equal("24px");
|
|
180
|
+
});
|
|
181
|
+
|
|
182
|
+
it("should use the first slotted element line height for the minimum readable size", function () {
|
|
183
|
+
const mocks = document.getElementById("mocks");
|
|
184
|
+
const popperHost = document.createElement("div");
|
|
185
|
+
const slottedParagraph = document.createElement("p");
|
|
186
|
+
slottedParagraph.textContent = "Readable help line";
|
|
187
|
+
slottedParagraph.style.lineHeight = "26px";
|
|
188
|
+
|
|
189
|
+
mocks.appendChild(popperHost);
|
|
190
|
+
const shadowRoot = popperHost.attachShadow({ mode: "open" });
|
|
191
|
+
shadowRoot.innerHTML = `
|
|
192
|
+
<div data-monster-role="popper">
|
|
193
|
+
<div part="content">
|
|
194
|
+
<slot></slot>
|
|
195
|
+
</div>
|
|
196
|
+
</div>
|
|
197
|
+
`;
|
|
198
|
+
|
|
199
|
+
const popper = shadowRoot.querySelector('[data-monster-role="popper"]');
|
|
200
|
+
const content = shadowRoot.querySelector('[part="content"]');
|
|
201
|
+
popperHost.appendChild(slottedParagraph);
|
|
202
|
+
|
|
203
|
+
applyAdaptiveFloatingElementSize(popper, {
|
|
204
|
+
availableWidth: 220,
|
|
205
|
+
availableHeight: 10,
|
|
206
|
+
});
|
|
207
|
+
|
|
208
|
+
expect(content.style.maxHeight).to.equal("26px");
|
|
209
|
+
});
|
|
210
|
+
|
|
211
|
+
it("should respect a smaller nested scroll container height", function () {
|
|
212
|
+
const mocks = document.getElementById("mocks");
|
|
213
|
+
const popper = document.createElement("div");
|
|
214
|
+
const content = document.createElement("div");
|
|
215
|
+
const options = document.createElement("div");
|
|
216
|
+
|
|
217
|
+
content.setAttribute("part", "content");
|
|
218
|
+
content.style.overflowY = "hidden";
|
|
219
|
+
options.style.overflowY = "auto";
|
|
220
|
+
options.style.height = "72px";
|
|
221
|
+
options.style.maxHeight = "72px";
|
|
222
|
+
Object.defineProperty(options, "scrollHeight", {
|
|
223
|
+
configurable: true,
|
|
224
|
+
value: 72,
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
content.appendChild(options);
|
|
228
|
+
popper.appendChild(content);
|
|
229
|
+
mocks.appendChild(popper);
|
|
230
|
+
|
|
231
|
+
applyAdaptiveFloatingElementSize(popper, {
|
|
232
|
+
availableWidth: 220,
|
|
233
|
+
availableHeight: 180,
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
expect(content.style.maxHeight).to.equal("180px");
|
|
237
|
+
expect(options.style.height).to.equal("72px");
|
|
238
|
+
expect(options.style.maxHeight).to.equal("72px");
|
|
239
|
+
});
|
|
138
240
|
});
|
|
@@ -261,44 +261,39 @@ describe("MessageStateButton", function () {
|
|
|
261
261
|
}, 0);
|
|
262
262
|
});
|
|
263
263
|
|
|
264
|
-
it("should resolve nested select message content to horizontal clipping only", function (
|
|
264
|
+
it("should resolve nested select message content to horizontal clipping only", async function () {
|
|
265
265
|
let mocks = document.getElementById("mocks");
|
|
266
266
|
const button = document.createElement("monster-message-state-button");
|
|
267
267
|
button.innerHTML = "Save";
|
|
268
268
|
mocks.appendChild(button);
|
|
269
269
|
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
270
|
+
const wrapper = document.createElement("div");
|
|
271
|
+
wrapper.appendChild(document.createElement("monster-select"));
|
|
272
|
+
button.setMessage(wrapper);
|
|
273
|
+
button.showMessage();
|
|
274
|
+
|
|
275
|
+
await waitForCondition(() => {
|
|
276
|
+
const content = button.shadowRoot?.querySelector('[part="content"]');
|
|
277
|
+
return (
|
|
278
|
+
content?.getAttribute("data-monster-overflow-mode") === "horizontal"
|
|
279
|
+
);
|
|
280
|
+
});
|
|
276
281
|
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
).to.equal("overlay");
|
|
293
|
-
done();
|
|
294
|
-
} catch (e) {
|
|
295
|
-
done(e);
|
|
296
|
-
}
|
|
297
|
-
}, 0);
|
|
298
|
-
} catch (e) {
|
|
299
|
-
done(e);
|
|
300
|
-
}
|
|
301
|
-
}, 0);
|
|
282
|
+
const content = button.shadowRoot.querySelector('[part="content"]');
|
|
283
|
+
const message = button.shadowRoot.querySelector(
|
|
284
|
+
'[data-monster-role="message"]',
|
|
285
|
+
);
|
|
286
|
+
|
|
287
|
+
expect(content).to.exist;
|
|
288
|
+
expect(content.getAttribute("data-monster-overflow-mode")).to.equal(
|
|
289
|
+
"horizontal",
|
|
290
|
+
);
|
|
291
|
+
expect(content.getAttribute("data-monster-message-layout")).to.equal(
|
|
292
|
+
"overlay",
|
|
293
|
+
);
|
|
294
|
+
expect(message.getAttribute("data-monster-message-layout")).to.equal(
|
|
295
|
+
"overlay",
|
|
296
|
+
);
|
|
302
297
|
});
|
|
303
298
|
|
|
304
299
|
it("should resolve wide plain content to the wide layout", function (done) {
|
|
@@ -489,3 +484,30 @@ describe("MessageStateButton", function () {
|
|
|
489
484
|
});
|
|
490
485
|
});
|
|
491
486
|
});
|
|
487
|
+
|
|
488
|
+
function waitForCondition(check, { timeout = 4000, interval = 25 } = {}) {
|
|
489
|
+
return new Promise((resolve, reject) => {
|
|
490
|
+
const start = Date.now();
|
|
491
|
+
|
|
492
|
+
const poll = () => {
|
|
493
|
+
try {
|
|
494
|
+
if (check()) {
|
|
495
|
+
resolve();
|
|
496
|
+
return;
|
|
497
|
+
}
|
|
498
|
+
} catch (error) {
|
|
499
|
+
reject(error);
|
|
500
|
+
return;
|
|
501
|
+
}
|
|
502
|
+
|
|
503
|
+
if (Date.now() - start >= timeout) {
|
|
504
|
+
reject(new Error("Timed out while waiting for test condition."));
|
|
505
|
+
return;
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
setTimeout(poll, interval);
|
|
509
|
+
};
|
|
510
|
+
|
|
511
|
+
poll();
|
|
512
|
+
});
|
|
513
|
+
}
|
|
@@ -549,6 +549,46 @@ describe('Select', function () {
|
|
|
549
549
|
}, 50);
|
|
550
550
|
});
|
|
551
551
|
|
|
552
|
+
it('should not throw when IntersectionObserver is unavailable', function (done) {
|
|
553
|
+
this.timeout(2000);
|
|
554
|
+
|
|
555
|
+
let mocks = document.getElementById('mocks');
|
|
556
|
+
const savedIntersectionObserver = global.IntersectionObserver;
|
|
557
|
+
global.IntersectionObserver = undefined;
|
|
558
|
+
window.IntersectionObserver = undefined;
|
|
559
|
+
const failures = [];
|
|
560
|
+
const onError = (event) => {
|
|
561
|
+
failures.push(event?.error || event);
|
|
562
|
+
};
|
|
563
|
+
window.addEventListener('error', onError);
|
|
564
|
+
|
|
565
|
+
const select = document.createElement('monster-select');
|
|
566
|
+
select.setOption('url', 'https://example.com/items?filter={filter}&page={page}');
|
|
567
|
+
select.setOption('filter.mode', 'remote');
|
|
568
|
+
select.setOption('mapping.selector', 'items.*');
|
|
569
|
+
select.setOption('mapping.labelTemplate', '${name}');
|
|
570
|
+
select.setOption('mapping.valueTemplate', '${id}');
|
|
571
|
+
select.setOption('mapping.total', 'pagination.total');
|
|
572
|
+
select.setOption('mapping.currentPage', 'pagination.page');
|
|
573
|
+
select.setOption('mapping.objectsPerPage', 'pagination.perPage');
|
|
574
|
+
select.setOption('selection', [{value: 'alpha'}]);
|
|
575
|
+
mocks.appendChild(select);
|
|
576
|
+
|
|
577
|
+
setTimeout(() => {
|
|
578
|
+
try {
|
|
579
|
+
expect(failures).to.have.length(0);
|
|
580
|
+
} catch (e) {
|
|
581
|
+
return done(e);
|
|
582
|
+
} finally {
|
|
583
|
+
window.removeEventListener('error', onError);
|
|
584
|
+
global.IntersectionObserver = savedIntersectionObserver;
|
|
585
|
+
window.IntersectionObserver = savedIntersectionObserver;
|
|
586
|
+
}
|
|
587
|
+
|
|
588
|
+
done();
|
|
589
|
+
}, 250);
|
|
590
|
+
});
|
|
591
|
+
|
|
552
592
|
});
|
|
553
593
|
|
|
554
594
|
|
|
@@ -14,6 +14,7 @@ export function setupIntersectionObserverMock(
|
|
|
14
14
|
} = {}) {
|
|
15
15
|
|
|
16
16
|
const savedImplementation = window.IntersectionObserver;
|
|
17
|
+
const savedGlobalImplementation = global.IntersectionObserver;
|
|
17
18
|
|
|
18
19
|
let lastObject;
|
|
19
20
|
|
|
@@ -61,9 +62,10 @@ export function setupIntersectionObserverMock(
|
|
|
61
62
|
return {
|
|
62
63
|
restore: function () {
|
|
63
64
|
window.IntersectionObserver = savedImplementation;
|
|
65
|
+
global.IntersectionObserver = savedGlobalImplementation;
|
|
64
66
|
},
|
|
65
67
|
getInstance: function () {
|
|
66
68
|
return lastObject;
|
|
67
69
|
}
|
|
68
70
|
}
|
|
69
|
-
}
|
|
71
|
+
}
|