@schukai/monster 4.129.9 → 4.130.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.
Files changed (27) hide show
  1. package/package.json +1 -1
  2. package/source/components/content/image-editor.mjs +1 -0
  3. package/source/components/datatable/change-button.mjs +1 -1
  4. package/source/components/datatable/pagination.mjs +2 -1
  5. package/source/components/datatable/save-button.mjs +1 -0
  6. package/source/components/files/file-manager.mjs +1 -0
  7. package/source/components/form/api-button.mjs +2 -1
  8. package/source/components/form/context-error.mjs +1 -0
  9. package/source/components/form/context-help.mjs +1 -0
  10. package/source/components/form/credential-button.mjs +1 -0
  11. package/source/components/form/field-set.mjs +2 -1
  12. package/source/components/form/popper-button.mjs +3 -0
  13. package/source/components/form/quantity.mjs +2 -1
  14. package/source/components/form/repeat-field-set.mjs +1 -0
  15. package/source/components/form/toggle-switch.mjs +1 -0
  16. package/source/components/form/util/floating-ui.mjs +37 -1
  17. package/source/components/layout/popper.mjs +45 -2
  18. package/source/components/layout/stylesheet/popper.mjs +1 -1
  19. package/source/components/notify/monitor-attribute-errors.mjs +1 -1
  20. package/source/components/state/log.mjs +1 -0
  21. package/source/components/state/state.mjs +1 -0
  22. package/source/components/state/thread.mjs +1 -0
  23. package/source/components/style/floating-ui.css +1 -1
  24. package/source/components/style/floating-ui.pcss +1 -6
  25. package/source/components/stylesheet/floating-ui.mjs +1 -1
  26. package/test/cases/components/form/floating-ui.mjs +61 -0
  27. package/test/cases/components/form/popper-button.mjs +31 -0
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.9"}
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.130.0"}
@@ -274,6 +274,7 @@ const rotateResetButtonElementSymbol = Symbol("rotateResetButtonElement");
274
274
  * An Image Editor Component
275
275
  *
276
276
  * @fragments /fragments/components/content/image-editor/
277
+ * @example /examples/components/content/image-editor-basic Basic editor workflow
277
278
  *
278
279
  * @since 4.68.0
279
280
  * @copyright Volker Schukai
@@ -187,7 +187,7 @@ function initControlReferences() {
187
187
  const selector2 = this.getOption("overlay.selector");
188
188
 
189
189
  if (isString(selector2)) {
190
- const element = findElementWithSelectorUpwards(this, selector);
190
+ const element = findElementWithSelectorUpwards(this, selector2);
191
191
  if (element === null) {
192
192
  throw new Error("the selector must match exactly one element");
193
193
  }
@@ -102,7 +102,8 @@ const compactNextIcon = `<svg xmlns="http://www.w3.org/2000/svg" width="16" heig
102
102
  *
103
103
  * @fragments /fragments/components/datatable/pagination
104
104
  *
105
- * @example /examples/components/datatable/pagination-simple Pagination
105
+ * @example /examples/components/datatable/pagination-simple Datasource pagination
106
+ * @example /examples/components/datatable/pagination-programmatic Programmatic pagination state
106
107
  *
107
108
  * @copyright Volker Schukai
108
109
  * @summary The Pagination component is used to show the current page and the total number of pages.
@@ -84,6 +84,7 @@ const internalDisableVersionSymbol = Symbol("internalDisableVersion");
84
84
  * @fragments /fragments/components/datatable/save-button
85
85
  *
86
86
  * @example /examples/components/datatable/save-button-simple Simple example
87
+ * @example /examples/components/datatable/save-button-workflow Draft changes workflow
87
88
  *
88
89
  * @issue https://localhost.alvine.dev:8440/development/issues/closed/274.html
89
90
  *
@@ -137,6 +137,7 @@ const saveAllButtonSymbol = Symbol("saveAllButton");
137
137
  * A file manager for navigating and editing files.
138
138
  *
139
139
  * @fragments /fragments/components/files/file-manager/
140
+ * @example /examples/components/files/file-manager-basic Basic file manager workflow
140
141
  *
141
142
  * @since 4.44.0
142
143
  * @summary A file manager control that builds a tree navigation from an API and opens files in tabs.
@@ -57,10 +57,11 @@ const containerElementSymbol = Symbol("containerElement");
57
57
  * @fragments /fragments/components/form/api-button/
58
58
  *
59
59
  * @example /examples/components/form/api-button-simple API Button
60
+ * @example /examples/components/form/api-button-workflow API workflow with events
60
61
  *
61
62
  * @since 3.32.0
62
63
  * @copyright Volker Schukai
63
- * @summary A api button control
64
+ * @summary An API button that loads actions dynamically and executes follow-up requests
64
65
  * @fires monster-button-set
65
66
  * @fires monster-api-button-click
66
67
  * @fires monster-api-button-successful
@@ -60,6 +60,7 @@ const iconElementSymbol = Symbol("iconElement");
60
60
  * @fragments /fragments/components/form/context-error
61
61
  *
62
62
  * @example /examples/components/form/context-error-simple
63
+ * @example /examples/components/form/context-error-live-validation
63
64
  *
64
65
  * @since 3.55.0
65
66
  * @copyright Volker Schukai
@@ -25,6 +25,7 @@ export { ContextHelp };
25
25
  * @fragments /fragments/components/form/context-help
26
26
  *
27
27
  * @example /examples/components/form/context-help-simple
28
+ * @example /examples/components/form/context-help-inline-guidance
28
29
  *
29
30
  * @since 3.29.0
30
31
  * @copyright Volker Schukai
@@ -53,6 +53,7 @@ const passwordWiredSymbol = Symbol("passwordWired");
53
53
  * @fragments /fragments/components/form/credential-button/
54
54
  *
55
55
  * @example /examples/components/form/credential-button-simple
56
+ * @example /examples/components/form/credential-button-retry
56
57
  *
57
58
  * @since 3.91.0
58
59
  * @copyright Volker Schukai
@@ -75,7 +75,8 @@ const extendedSwitchElementSymbol = Symbol("extendedSwitchElement");
75
75
  *
76
76
  * @fragments /fragments/components/form/field-set/
77
77
  *
78
- * @example /examples/components/form/field-set-simple
78
+ * @example /examples/components/form/field-set-simple Shipping field set
79
+ * @example /examples/components/form/field-set-preferences Compact settings field set
79
80
  *
80
81
  * @since 3.65.0
81
82
  * @copyright Volker Schukai
@@ -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,
@@ -53,7 +53,8 @@ const holdIntervalSymbol = Symbol("holdInterval");
53
53
  *
54
54
  * @fragments /fragments/components/form/quantity/
55
55
  *
56
- * @example /examples/components/form/quantity-simple
56
+ * @example /examples/components/form/quantity-simple Basic quantity control
57
+ * @example /examples/components/form/quantity-decimal Decimal pricing stepper
57
58
  *
58
59
  * @since 4.41.0
59
60
  * @copyright Volker Schukai
@@ -70,6 +70,7 @@ const itemDefaultsSymbol = Symbol("itemDefaults");
70
70
  * A repeatable field-set control that manages array data.
71
71
  *
72
72
  * @fragments /fragments/components/form/repeat-field-set/
73
+ * @example /examples/components/form/repeat-field-set-simple Repeatable contacts
73
74
  *
74
75
  * @since 3.78.0
75
76
  * @summary A repeatable field-set control
@@ -58,6 +58,7 @@ export const STATE_OFF = "off";
58
58
  * @fragments /fragments/components/form/toggle-switch
59
59
  *
60
60
  * @example /examples/components/form/toggle-switch-simple Simple example
61
+ * @example /examples/components/form/toggle-switch-custom-values Custom values and labels
61
62
  *
62
63
  * @since 3.57.0
63
64
  * @copyright Volker Schukai
@@ -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|visible
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]>[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}
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
  );
@@ -47,7 +47,7 @@ const mutationObserversSymbol = Symbol("mutationObservers");
47
47
  *
48
48
  * @since 3.98.0
49
49
  * @copyright Volker Schukai
50
- * @summary A beautiful MonitorAttributeErrors that can make your life easier and also looks good.
50
+ * @summary Watches the DOM for `data-monster-error` attributes and can forward them to `monster-notify`.
51
51
  */
52
52
  class MonitorAttributeErrors extends CustomElement {
53
53
  /**
@@ -58,6 +58,7 @@ const timeAgoIntervalSymbol = Symbol("timeAgoInterval");
58
58
  * @fragments /fragments/components/state/log
59
59
  *
60
60
  * @example /examples/components/state/log-simple Log
61
+ * @example /examples/components/state/log-live-feed Live deployment feed
61
62
  *
62
63
  * @issue https://localhost.alvine.dev:8444/development/issues/closed/270.html
63
64
  *
@@ -28,6 +28,7 @@ export { State };
28
28
  * @fragments /fragments/components/state/state
29
29
  *
30
30
  * @example /examples/components/state/state-simple State
31
+ * @example /examples/components/state/state-actionable Actionable empty state
31
32
  *
32
33
  * @since 1.5.0
33
34
  * @copyright Volker Schukai
@@ -54,6 +54,7 @@ const timeAgoIntervalSymbol = Symbol("timeAgoInterval");
54
54
  * @fragments /fragments/components/state/thread
55
55
  *
56
56
  * @example /examples/components/state/thread-simple Thread
57
+ * @example /examples/components/state/thread-review Review thread with nested replies
57
58
  *
58
59
  * @issue https://localhost.alvine.dev:8444/development/issues/open/374.html
59
60
  *
@@ -1,2 +1,2 @@
1
1
  /** generated from floating-ui.pcss **/
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: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]>[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}
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,7 @@ 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;
40
35
  }
41
36
 
42
37
  & > [part=content][data-monster-overflow-mode=visible] {
@@ -24,7 +24,7 @@ const FloatingUiStyleSheet = new CSSStyleSheet();
24
24
  try {
25
25
  FloatingUiStyleSheet.insertRule(`
26
26
  @layer floatingui {
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: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]>[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}
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
28
  }`, 0);
29
29
  } catch (e) {
30
30
  addAttributeToken(document.getRootNode().querySelector('html'), ATTRIBUTE_ERRORMESSAGE, e + "");
@@ -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,37 @@ 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
+
65
96
  it("should apply visible content overflow mode to the rendered content wrapper", function (done) {
66
97
  let mocks = document.getElementById("mocks");
67
98
  const button = document.createElement("monster-popper-button");