@schukai/monster 4.129.8 → 4.129.10

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.129.8"}
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.129.10"}
@@ -50,6 +50,9 @@ class ContextBase extends Popper {
50
50
  */
51
51
  get defaults() {
52
52
  return Object.assign({}, super.defaults, {
53
+ popper: Object.assign({}, super.defaults.popper, {
54
+ contentOverflow: "visible",
55
+ }),
53
56
  features: Object.assign({}, super.defaults.features, {
54
57
  showIconWithoutContent: false,
55
58
  }),
@@ -114,6 +114,10 @@ class ContextError extends Popper {
114
114
 
115
115
  content: "<slot></slot>",
116
116
 
117
+ popper: Object.assign({}, super.defaults.popper, {
118
+ contentOverflow: "visible",
119
+ }),
120
+
117
121
  classes: {
118
122
  button: "monster-theme-error-2",
119
123
  },
@@ -160,6 +160,9 @@ class PopperButton extends Popper {
160
160
  },
161
161
  mode: "click",
162
162
  value: null,
163
+ popper: Object.assign({}, super.defaults.popper, {
164
+ contentOverflow: "smart",
165
+ }),
163
166
 
164
167
  aria: {
165
168
  role: null,
@@ -309,7 +309,8 @@ function findNearestClippingContainer(element) {
309
309
  while (current) {
310
310
  if (
311
311
  current instanceof HTMLElement &&
312
- isClippingContainer(getComputedStyle(current))
312
+ isClippingContainer(getComputedStyle(current)) &&
313
+ !shouldIgnoreClippingContainer(current)
313
314
  ) {
314
315
  return current;
315
316
  }
@@ -341,6 +342,41 @@ function getComposedParent(node) {
341
342
  return node.parentNode || null;
342
343
  }
343
344
 
345
+ function shouldIgnoreClippingContainer(element) {
346
+ if (!(element instanceof HTMLElement)) {
347
+ return false;
348
+ }
349
+
350
+ if (!isPopperContentWrapper(element)) {
351
+ return false;
352
+ }
353
+
354
+ const parent = getComposedParent(element);
355
+ return (
356
+ parent instanceof HTMLElement &&
357
+ parent.getAttribute("data-monster-role") === "popper"
358
+ );
359
+ }
360
+
361
+ function isPopperContentWrapper(element) {
362
+ if (!(element instanceof HTMLElement)) {
363
+ return false;
364
+ }
365
+
366
+ if (!element.hasAttribute("data-monster-overflow-mode")) {
367
+ return false;
368
+ }
369
+
370
+ const part = element.getAttribute("part");
371
+ return (
372
+ isString(part) &&
373
+ part
374
+ .split(/\s+/)
375
+ .filter((token) => token.length > 0)
376
+ .includes("content")
377
+ );
378
+ }
379
+
344
380
  function isClippingContainer(style) {
345
381
  if (!style) {
346
382
  return false;
@@ -155,7 +155,7 @@ class Popper extends CustomElement {
155
155
  * @property {Object} popper - Positioning options
156
156
  * @property {string} popper.placement - Placement: top|bottom|left|right
157
157
  * @property {Array} popper.middleware - Positioning middleware functions
158
- * @property {string} popper.contentOverflow - Content clipping mode: both|horizontal
158
+ * @property {string} popper.contentOverflow - Content clipping mode: both|horizontal|visible|smart
159
159
  * @property {Object} features - Feature flags
160
160
  * @property {boolean} features.preventOpenEventSent - Prevent open event
161
161
  * @returns {Object} Default options merged with parent defaults
@@ -200,6 +200,10 @@ class Popper extends CustomElement {
200
200
 
201
201
  if (path === "popper.contentOverflow") {
202
202
  applyContentOverflowMode.call(this);
203
+ } else if (path === "content") {
204
+ queueMicrotask(() => {
205
+ applyContentOverflowMode.call(this);
206
+ });
203
207
  }
204
208
 
205
209
  return this;
@@ -282,7 +286,16 @@ class Popper extends CustomElement {
282
286
  * @return {string}
283
287
  */
284
288
  resolveContentOverflowMode() {
285
- return this.getOption("popper.contentOverflow", "both");
289
+ const configuredMode = this.getOption("popper.contentOverflow", "both");
290
+ if (configuredMode !== "smart") {
291
+ return configuredMode;
292
+ }
293
+
294
+ if (containsNestedOverlayContent(this.getOption("content"))) {
295
+ return "horizontal";
296
+ }
297
+
298
+ return "both";
286
299
  }
287
300
 
288
301
  /**
@@ -702,6 +715,9 @@ function initOverflowObserver() {
702
715
  () => {
703
716
  applyContentOverflowMode.call(this);
704
717
  };
718
+ this[attributeObserverSymbol]["data-monster-option-content"] = () => {
719
+ applyContentOverflowMode.call(this);
720
+ };
705
721
  }
706
722
 
707
723
  /**
@@ -743,4 +759,31 @@ function getTemplate() {
743
759
  `;
744
760
  }
745
761
 
762
+ function containsNestedOverlayContent(content) {
763
+ const selector = [
764
+ "monster-details",
765
+ "monster-message-state-button",
766
+ "monster-popper",
767
+ "monster-popper-button",
768
+ "monster-select",
769
+ "details",
770
+ ].join(",");
771
+
772
+ if (typeof content === "string") {
773
+ const container = document.createElement("div");
774
+ container.innerHTML = content;
775
+ return container.querySelector(selector) instanceof HTMLElement;
776
+ }
777
+
778
+ if (!(content instanceof HTMLElement)) {
779
+ return false;
780
+ }
781
+
782
+ if (content.matches(selector)) {
783
+ return true;
784
+ }
785
+
786
+ return content.querySelector(selector) instanceof HTMLElement;
787
+ }
788
+
746
789
  registerCustomElement(Popper);
@@ -25,7 +25,7 @@ try {
25
25
  PopperStyleSheet.insertRule(
26
26
  `
27
27
  @layer popper {
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));max-width:100%;overflow:auto}div[data-monster-role=popper]>[part=content][data-monster-overflow-mode=horizontal]{clip-path:inset(calc(var(--monster-popper-content-block-overflow, 100vh)*-1) 0 calc(var(--monster-popper-content-block-overflow, 100vh)*-1) 0);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]{display:flex;position:relative}
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));max-width:100%;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]{display:flex;position:relative}
29
29
  }`,
30
30
  0,
31
31
  );
@@ -1,58 +1,2 @@
1
1
  /** generated from floating-ui.pcss **/
2
- div[data-monster-role="popper"] {
3
- align-content: center;
4
- background: var(--monster-bg-color-primary-1);
5
- border-color: var(--monster-bg-color-primary-4);
6
- border-radius: var(--monster-border-radius);
7
- border-style: var(--monster-border-style);
8
- border-width: var(--monster-border-width);
9
- box-shadow: var(--monster-box-shadow-1);
10
- box-sizing: border-box;
11
- color: var(--monster-color-primary-1);
12
- display: none;
13
- justify-content: space-between;
14
- left: 0;
15
- max-height: var(--monster-popper-max-height, calc(100vh - 2rem));
16
- max-width: var(--monster-popper-max-width, calc(100vw - 2rem));
17
- padding: 1.1em;
18
- position: absolute;
19
- top: 0;
20
- width: -moz-max-content;
21
- width: max-content;
22
- z-index: var(--monster-z-index-modal);
23
- }
24
- div[data-monster-role="popper"] > [part="content"] {
25
- max-height: var(--monster-popper-content-max-height, calc(100vh - 4.2rem));
26
- max-width: 100%;
27
- overflow: auto;
28
- }
29
- div[data-monster-role="popper"]
30
- > [part="content"][data-monster-overflow-mode="horizontal"] {
31
- clip-path: inset(
32
- calc(var(--monster-popper-content-block-overflow, 100vh) * -1) 0
33
- calc(var(--monster-popper-content-block-overflow, 100vh) * -1) 0
34
- );
35
- overflow: visible;
36
- }
37
- div[data-monster-role="popper"] div[data-monster-role="arrow"] {
38
- background: var(--monster-bg-color-primary-1);
39
- height: calc(
40
- max(
41
- var(--monster-popper-witharrrow-distance),
42
- -1 *
43
- var(--monster-popper-witharrrow-distance)
44
- ) *
45
- 2
46
- );
47
- pointer-events: none;
48
- position: absolute;
49
- width: calc(
50
- max(
51
- var(--monster-popper-witharrrow-distance),
52
- -1 *
53
- var(--monster-popper-witharrrow-distance)
54
- ) *
55
- 2
56
- );
57
- z-index: -1;
58
- }
2
+ 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));max-width:100%;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}
@@ -31,12 +31,14 @@ div[data-monster-role=popper] {
31
31
 
32
32
  & > [part=content][data-monster-overflow-mode=horizontal] {
33
33
  overflow: visible;
34
- clip-path: inset(
35
- calc(-1 * var(--monster-popper-content-block-overflow, 100vh))
36
- 0
37
- calc(-1 * var(--monster-popper-content-block-overflow, 100vh))
38
- 0
39
- );
34
+ clip-path: none;
35
+ }
36
+
37
+ & > [part=content][data-monster-overflow-mode=visible] {
38
+ overflow: visible;
39
+ clip-path: none;
40
+ max-width: none;
41
+ max-height: none;
40
42
  }
41
43
 
42
44
  & div[data-monster-role=arrow] {
@@ -10,10 +10,10 @@
10
10
  * For more information about purchasing a commercial license, please contact Volker Schukai.
11
11
  */
12
12
 
13
- import { addAttributeToken } from "../../dom/attributes.mjs";
14
- import { ATTRIBUTE_ERRORMESSAGE } from "../../dom/constants.mjs";
13
+ import {addAttributeToken} from "../../dom/attributes.mjs";
14
+ import {ATTRIBUTE_ERRORMESSAGE} from "../../dom/constants.mjs";
15
15
 
16
- export { FloatingUiStyleSheet };
16
+ export {FloatingUiStyleSheet}
17
17
 
18
18
  /**
19
19
  * @private
@@ -22,17 +22,10 @@ export { FloatingUiStyleSheet };
22
22
  const FloatingUiStyleSheet = new CSSStyleSheet();
23
23
 
24
24
  try {
25
- FloatingUiStyleSheet.insertRule(
26
- `
25
+ FloatingUiStyleSheet.insertRule(`
27
26
  @layer floatingui {
28
- 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));max-width:100%;overflow:auto}div[data-monster-role=popper]>[part=content][data-monster-overflow-mode=horizontal]{clip-path:inset(calc(var(--monster-popper-content-block-overflow, 100vh)*-1) 0 calc(var(--monster-popper-content-block-overflow, 100vh)*-1) 0);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}
29
- }`,
30
- 0,
31
- );
27
+ 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));max-width:100%;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}
28
+ }`, 0);
32
29
  } catch (e) {
33
- addAttributeToken(
34
- document.getRootNode().querySelector("html"),
35
- ATTRIBUTE_ERRORMESSAGE,
36
- e + "",
37
- );
30
+ addAttributeToken(document.getRootNode().querySelector('html'), ATTRIBUTE_ERRORMESSAGE, e + "");
38
31
  }
@@ -0,0 +1,48 @@
1
+ import * as chai from "chai";
2
+ import { chaiDom } from "../../../util/chai-dom.mjs";
3
+ import { initJSDOM } from "../../../util/jsdom.mjs";
4
+
5
+ let expect = chai.expect;
6
+ chai.use(chaiDom);
7
+
8
+ let ContextError;
9
+
10
+ describe("ContextError", function () {
11
+ before(function (done) {
12
+ initJSDOM()
13
+ .then(() => {
14
+ return import("../../../../source/components/form/context-error.mjs");
15
+ })
16
+ .then((m) => {
17
+ ContextError = m["ContextError"];
18
+ done();
19
+ })
20
+ .catch((e) => done(e));
21
+ });
22
+
23
+ afterEach(() => {
24
+ let mocks = document.getElementById("mocks");
25
+ mocks.innerHTML = "";
26
+ });
27
+
28
+ it("should default to visible content overflow", function (done) {
29
+ let mocks = document.getElementById("mocks");
30
+ const error = document.createElement("monster-context-error");
31
+ error.innerHTML = "<p>Error message</p>";
32
+ mocks.appendChild(error);
33
+
34
+ setTimeout(() => {
35
+ try {
36
+ expect(error).to.be.instanceof(ContextError);
37
+ const content = error.shadowRoot.querySelector('[part="content"]');
38
+ expect(error.getOption("popper.contentOverflow")).to.equal("visible");
39
+ expect(content.getAttribute("data-monster-overflow-mode")).to.equal(
40
+ "visible",
41
+ );
42
+ done();
43
+ } catch (e) {
44
+ done(e);
45
+ }
46
+ }, 0);
47
+ });
48
+ });
@@ -68,4 +68,24 @@ describe("ContextHelp", function () {
68
68
  }
69
69
  }, 0);
70
70
  });
71
+
72
+ it("should default to visible content overflow", function (done) {
73
+ let mocks = document.getElementById("mocks");
74
+ const help = document.createElement("monster-context-help");
75
+ help.innerHTML = "<p>Inline help</p>";
76
+ mocks.appendChild(help);
77
+
78
+ setTimeout(() => {
79
+ try {
80
+ const content = help.shadowRoot.querySelector('[part="content"]');
81
+ expect(help.getOption("popper.contentOverflow")).to.equal("visible");
82
+ expect(content.getAttribute("data-monster-overflow-mode")).to.equal(
83
+ "visible",
84
+ );
85
+ done();
86
+ } catch (e) {
87
+ done(e);
88
+ }
89
+ }, 0);
90
+ });
71
91
  });
@@ -0,0 +1,61 @@
1
+ import * as chai from "chai";
2
+ import { initJSDOM } from "../../../util/jsdom.mjs";
3
+
4
+ let expect = chai.expect;
5
+
6
+ let resolveClippingBoundaryElement;
7
+
8
+ describe("form floating-ui boundary resolution", function () {
9
+ before(function (done) {
10
+ initJSDOM()
11
+ .then(() => {
12
+ return import(
13
+ "../../../../source/components/form/util/floating-ui.mjs"
14
+ );
15
+ })
16
+ .then((m) => {
17
+ resolveClippingBoundaryElement = m.resolveClippingBoundaryElement;
18
+ done();
19
+ })
20
+ .catch((e) => done(e));
21
+ });
22
+
23
+ afterEach(() => {
24
+ const mocks = document.getElementById("mocks");
25
+ mocks.innerHTML = "";
26
+ });
27
+
28
+ it("should ignore parent popper content wrappers as clipping boundaries for nested controls", function () {
29
+ const mocks = document.getElementById("mocks");
30
+ const wrapper = document.createElement("div");
31
+ const popperHost = document.createElement("div");
32
+ const selectHost = document.createElement("div");
33
+
34
+ wrapper.style.overflow = "hidden";
35
+ mocks.appendChild(wrapper);
36
+ wrapper.appendChild(popperHost);
37
+
38
+ const popperShadow = popperHost.attachShadow({ mode: "open" });
39
+ popperShadow.innerHTML = `
40
+ <div data-monster-role="popper">
41
+ <div part="content"
42
+ data-monster-overflow-mode="both"
43
+ style="overflow: auto;">
44
+ </div>
45
+ </div>
46
+ `;
47
+
48
+ popperShadow.querySelector('[part="content"]').appendChild(selectHost);
49
+
50
+ const selectShadow = selectHost.attachShadow({ mode: "open" });
51
+ selectShadow.innerHTML = `
52
+ <div data-monster-role="control"></div>
53
+ <div data-monster-role="popper"></div>
54
+ `;
55
+
56
+ const control = selectShadow.querySelector('[data-monster-role="control"]');
57
+ const popper = selectShadow.querySelector('[data-monster-role="popper"]');
58
+
59
+ expect(resolveClippingBoundaryElement(control, popper)).to.equal(wrapper);
60
+ });
61
+ });
@@ -62,6 +62,68 @@ describe("PopperButton", function () {
62
62
  }, 0);
63
63
  });
64
64
 
65
+ it("should resolve nested overlay content to horizontal overflow by default", function (done) {
66
+ let mocks = document.getElementById("mocks");
67
+ const button = document.createElement("monster-popper-button");
68
+ mocks.appendChild(button);
69
+
70
+ setTimeout(() => {
71
+ try {
72
+ const content = button.shadowRoot.querySelector('[part="content"]');
73
+ expect(content).to.exist;
74
+
75
+ button.setOption(
76
+ "content",
77
+ "<div><monster-select></monster-select></div>",
78
+ );
79
+
80
+ setTimeout(() => {
81
+ try {
82
+ expect(
83
+ content.getAttribute("data-monster-overflow-mode"),
84
+ ).to.equal("horizontal");
85
+ done();
86
+ } catch (e) {
87
+ done(e);
88
+ }
89
+ }, 0);
90
+ } catch (e) {
91
+ done(e);
92
+ }
93
+ }, 0);
94
+ });
95
+
96
+ it("should apply visible content overflow mode to the rendered content wrapper", function (done) {
97
+ let mocks = document.getElementById("mocks");
98
+ const button = document.createElement("monster-popper-button");
99
+ mocks.appendChild(button);
100
+
101
+ setTimeout(() => {
102
+ try {
103
+ const content = button.shadowRoot.querySelector('[part="content"]');
104
+ expect(content).to.exist;
105
+
106
+ button.setOption("popper.contentOverflow", "visible");
107
+
108
+ setTimeout(() => {
109
+ try {
110
+ expect(
111
+ button.getOption("popper.contentOverflow"),
112
+ ).to.equal("visible");
113
+ expect(
114
+ content.getAttribute("data-monster-overflow-mode"),
115
+ ).to.equal("visible");
116
+ done();
117
+ } catch (e) {
118
+ done(e);
119
+ }
120
+ }, 0);
121
+ } catch (e) {
122
+ done(e);
123
+ }
124
+ }, 0);
125
+ });
126
+
65
127
  it("should apply content overflow mode from the HTML attribute", function (done) {
66
128
  let mocks = document.getElementById("mocks");
67
129
  mocks.innerHTML = `
@@ -87,6 +149,31 @@ describe("PopperButton", function () {
87
149
  }, 0);
88
150
  });
89
151
 
152
+ it("should apply visible content overflow mode from the HTML attribute", function (done) {
153
+ let mocks = document.getElementById("mocks");
154
+ mocks.innerHTML = `
155
+ <monster-popper-button
156
+ data-monster-option-popper-content-overflow="visible"
157
+ ></monster-popper-button>
158
+ `;
159
+
160
+ setTimeout(() => {
161
+ try {
162
+ const button = mocks.querySelector("monster-popper-button");
163
+ const content = button.shadowRoot.querySelector('[part="content"]');
164
+ expect(button.getOption("popper.contentOverflow")).to.equal(
165
+ "visible",
166
+ );
167
+ expect(content.getAttribute("data-monster-overflow-mode")).to.equal(
168
+ "visible",
169
+ );
170
+ done();
171
+ } catch (e) {
172
+ done(e);
173
+ }
174
+ }, 0);
175
+ });
176
+
90
177
  it("should use absolute positioning by default", function (done) {
91
178
  let mocks = document.getElementById("mocks");
92
179
  const button = document.createElement("monster-popper-button");
@@ -185,4 +185,18 @@ describe('initOptionsFromAttributes', () => {
185
185
  expect(result.message.width.viewportRatio).to.equal(0.9);
186
186
  });
187
187
 
188
+ it('should preserve visible for popper content overflow attributes', () => {
189
+ options = {
190
+ popper: {
191
+ contentOverflow: 'both',
192
+ },
193
+ };
194
+
195
+ element.setAttribute('data-monster-option-popper-content-overflow', 'visible');
196
+
197
+ const result = initOptionsFromAttributes(element, options);
198
+
199
+ expect(result.popper.contentOverflow).to.equal('visible');
200
+ });
201
+
188
202
  });