@schukai/monster 4.129.0 → 4.129.2

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 (35) hide show
  1. package/CHANGELOG.md +3 -0
  2. package/package.json +1 -1
  3. package/source/components/content/stylesheet/camera-capture.mjs +1 -1
  4. package/source/components/content/stylesheet/copy.mjs +1 -1
  5. package/source/components/content/viewer/stylesheet/message.mjs +1 -1
  6. package/source/components/datatable/stylesheet/filter-controls-defaults.mjs +1 -1
  7. package/source/components/form/message-state-button.mjs +234 -18
  8. package/source/components/form/popper-button.mjs +51 -9
  9. package/source/components/form/select.mjs +76 -14
  10. package/source/components/form/style/context-error.pcss +15 -0
  11. package/source/components/form/style/context-help.pcss +13 -1
  12. package/source/components/form/style/message-state-button.pcss +46 -3
  13. package/source/components/form/stylesheet/button-bar.mjs +1 -1
  14. package/source/components/form/stylesheet/confirm-button.mjs +1 -1
  15. package/source/components/form/stylesheet/context-error.mjs +1 -1
  16. package/source/components/form/stylesheet/context-help.mjs +1 -1
  17. package/source/components/form/stylesheet/digits.mjs +1 -1
  18. package/source/components/form/stylesheet/field-set.mjs +1 -1
  19. package/source/components/form/stylesheet/login.mjs +1 -1
  20. package/source/components/form/stylesheet/message-state-button.mjs +1 -1
  21. package/source/components/form/stylesheet/popper-button.mjs +1 -1
  22. package/source/components/form/stylesheet/select.mjs +1 -1
  23. package/source/components/form/util/floating-ui.mjs +808 -168
  24. package/source/components/layout/popper.mjs +139 -15
  25. package/source/components/layout/stylesheet/popper.mjs +1 -1
  26. package/source/components/style/floating-ui.css +8 -0
  27. package/source/components/style/floating-ui.pcss +10 -0
  28. package/source/components/stylesheet/floating-ui.mjs +1 -1
  29. package/source/dom/util/extract-keys.mjs +46 -10
  30. package/source/dom/util/init-options-from-attributes.mjs +4 -2
  31. package/source/dom/util/set-option-from-attribute.mjs +4 -2
  32. package/test/cases/components/form/message-state-button.mjs +272 -0
  33. package/test/cases/components/form/popper-button.mjs +89 -0
  34. package/test/cases/dom/util/extract-keys.mjs +34 -23
  35. package/test/cases/dom/util/init-options-from-attributes.mjs +21 -0
@@ -21,6 +21,7 @@ import {
21
21
  import { ATTRIBUTE_ROLE } from "../../dom/constants.mjs";
22
22
  import {
23
23
  assembleMethodSymbol,
24
+ attributeObserverSymbol,
24
25
  CustomElement,
25
26
  registerCustomElement,
26
27
  } from "../../dom/customelement.mjs";
@@ -30,8 +31,12 @@ import {
30
31
  getDocument,
31
32
  } from "../../dom/util.mjs";
32
33
  import { DeadMansSwitch } from "../../util/deadmansswitch.mjs";
33
- import { STYLE_DISPLAY_MODE_BLOCK } from "../form/constants.mjs";
34
- import { positionPopper } from "../form/util/floating-ui.mjs";
34
+ import {
35
+ closePositionedPopper,
36
+ isPositionedPopperOpen,
37
+ openPositionedPopper,
38
+ positionPopper,
39
+ } from "../form/util/floating-ui.mjs";
35
40
  import { PopperStyleSheet } from "./stylesheet/popper.mjs";
36
41
  import { isArray } from "../../types/is.mjs";
37
42
 
@@ -79,6 +84,13 @@ const buttonElementSymbol = Symbol("buttonElement");
79
84
  */
80
85
  const popperElementSymbol = Symbol("popperElement");
81
86
 
87
+ /**
88
+ * Symbol for content element reference
89
+ * @private
90
+ * @type {symbol}
91
+ */
92
+ const contentElementSymbol = Symbol("contentElement");
93
+
82
94
  /**
83
95
  * Symbol for arrow element reference
84
96
  * @private
@@ -143,6 +155,7 @@ class Popper extends CustomElement {
143
155
  * @property {Object} popper - Positioning options
144
156
  * @property {string} popper.placement - Placement: top|bottom|left|right
145
157
  * @property {Array} popper.middleware - Positioning middleware functions
158
+ * @property {string} popper.contentOverflow - Content clipping mode: both|horizontal
146
159
  * @property {Object} features - Feature flags
147
160
  * @property {boolean} features.preventOpenEventSent - Prevent open event
148
161
  * @returns {Object} Default options merged with parent defaults
@@ -156,7 +169,9 @@ class Popper extends CustomElement {
156
169
  content: "<slot></slot>",
157
170
  popper: {
158
171
  placement: "top",
172
+ engine: "native",
159
173
  middleware: ["autoPlacement", "shift", "offset:15", "arrow"],
174
+ contentOverflow: "both",
160
175
  },
161
176
  features: {
162
177
  preventOpenEventSent: false,
@@ -172,9 +187,24 @@ class Popper extends CustomElement {
172
187
  [assembleMethodSymbol]() {
173
188
  super[assembleMethodSymbol]();
174
189
  initControlReferences.call(this);
190
+ initOverflowObserver.call(this);
191
+ applyContentOverflowMode.call(this);
175
192
  initEventHandler.call(this);
176
193
  }
177
194
 
195
+ /**
196
+ * @inheritdoc
197
+ */
198
+ setOption(path, value) {
199
+ super.setOption(path, value);
200
+
201
+ if (path === "popper.contentOverflow") {
202
+ applyContentOverflowMode.call(this);
203
+ }
204
+
205
+ return this;
206
+ }
207
+
178
208
  /**
179
209
  * Gets the custom element tag name
180
210
  * @return {string} The tag name
@@ -245,6 +275,16 @@ class Popper extends CustomElement {
245
275
  return this;
246
276
  }
247
277
 
278
+ /**
279
+ * Resolves the effective content overflow mode for the rendered wrapper.
280
+ * Subclasses can override this when the configured option is only an intermediate mode.
281
+ *
282
+ * @return {string}
283
+ */
284
+ resolveContentOverflowMode() {
285
+ return this.getOption("popper.contentOverflow", "both");
286
+ }
287
+
248
288
  /**
249
289
  * Hides the popper element
250
290
  * @return {Popper} The popper instance
@@ -259,7 +299,7 @@ class Popper extends CustomElement {
259
299
  * @return {Popper} The popper instance
260
300
  */
261
301
  toggleDialog() {
262
- if (this[popperElementSymbol].style.display === STYLE_DISPLAY_MODE_BLOCK) {
302
+ if (isPositionedPopperOpen(this[popperElementSymbol])) {
263
303
  this.hideDialog();
264
304
  } else {
265
305
  this.showDialog();
@@ -275,16 +315,20 @@ class Popper extends CustomElement {
275
315
  */
276
316
  function initEventHandler() {
277
317
  this[closeEventHandler] = (event) => {
278
- const path = event.composedPath();
279
-
280
- for (const [, element] of Object.entries(path)) {
281
- if (element === this) {
282
- return;
283
- }
318
+ if (
319
+ isEventInsidePopperOwner(
320
+ this,
321
+ event,
322
+ this[controlElementSymbol],
323
+ this[buttonElementSymbol],
324
+ this[popperElementSymbol],
325
+ )
326
+ ) {
327
+ return;
284
328
  }
285
329
 
286
330
  if (
287
- this[popperElementSymbol].style.display === "none" &&
331
+ !isPositionedPopperOpen(this[popperElementSymbol]) &&
288
332
  !containsAttributeToken(this[controlElementSymbol], "class", "open")
289
333
  ) {
290
334
  return;
@@ -316,6 +360,45 @@ function initEventHandler() {
316
360
  return this;
317
361
  }
318
362
 
363
+ function isEventInsidePopperOwner(
364
+ owner,
365
+ event,
366
+ controlElement,
367
+ buttonElement,
368
+ popperElement,
369
+ ) {
370
+ const path = event.composedPath?.() || [];
371
+
372
+ for (const element of path) {
373
+ if (
374
+ element === owner ||
375
+ element === controlElement ||
376
+ element === buttonElement ||
377
+ element === popperElement
378
+ ) {
379
+ return true;
380
+ }
381
+ }
382
+
383
+ const target = path[0] || event.target;
384
+ if (!(target instanceof Node)) {
385
+ return false;
386
+ }
387
+
388
+ if (owner instanceof HTMLElement && owner.contains(target)) {
389
+ return true;
390
+ }
391
+
392
+ if (
393
+ owner?.shadowRoot instanceof ShadowRoot &&
394
+ owner.shadowRoot.contains(target)
395
+ ) {
396
+ return true;
397
+ }
398
+
399
+ return false;
400
+ }
401
+
319
402
  /**
320
403
  * Sets up event handlers for specific interaction mode
321
404
  * @private
@@ -440,7 +523,7 @@ function hide() {
440
523
  });
441
524
 
442
525
  if (popperElement instanceof HTMLElement) {
443
- popperElement.style.display = "none";
526
+ closePositionedPopper(popperElement);
444
527
  }
445
528
 
446
529
  if (controlElement instanceof HTMLElement) {
@@ -477,7 +560,7 @@ function show() {
477
560
  return;
478
561
  }
479
562
 
480
- if (popperElement.style.display === STYLE_DISPLAY_MODE_BLOCK) {
563
+ if (isPositionedPopperOpen(popperElement)) {
481
564
  return;
482
565
  }
483
566
 
@@ -485,8 +568,14 @@ function show() {
485
568
  self,
486
569
  });
487
570
 
571
+ applyContentOverflowMode.call(self);
572
+
488
573
  popperElement.style.visibility = "hidden";
489
- popperElement.style.display = STYLE_DISPLAY_MODE_BLOCK;
574
+ openPositionedPopper(
575
+ self[controlElementSymbol],
576
+ popperElement,
577
+ self.getOption("popper", {}),
578
+ );
490
579
 
491
580
  addAttributeToken(controlElement, "class", "open");
492
581
  registerWithHost.call(self);
@@ -512,7 +601,7 @@ function updatePopper() {
512
601
  return;
513
602
  }
514
603
 
515
- if (this[popperElementSymbol].style.display !== STYLE_DISPLAY_MODE_BLOCK) {
604
+ if (!isPositionedPopperOpen(this[popperElementSymbol])) {
516
605
  return;
517
606
  }
518
607
 
@@ -520,6 +609,8 @@ function updatePopper() {
520
609
  return;
521
610
  }
522
611
 
612
+ applyContentOverflowMode.call(this);
613
+
523
614
  positionPopper.call(
524
615
  this,
525
616
  this[controlElementSymbol],
@@ -596,9 +687,40 @@ function initControlReferences() {
596
687
  this[arrowElementSymbol] = this.shadowRoot.querySelector(
597
688
  `[${ATTRIBUTE_ROLE}=arrow]`,
598
689
  );
690
+ this[contentElementSymbol] =
691
+ this.shadowRoot.querySelector(`[part="content"]`);
599
692
  return this;
600
693
  }
601
694
 
695
+ /**
696
+ * Keeps the rendered content wrapper in sync with the configured overflow mode
697
+ * @private
698
+ * @return {void}
699
+ */
700
+ function initOverflowObserver() {
701
+ this[attributeObserverSymbol]["data-monster-option-popper-content-overflow"] =
702
+ () => {
703
+ applyContentOverflowMode.call(this);
704
+ };
705
+ }
706
+
707
+ /**
708
+ * Applies the current content overflow mode to the rendered wrapper element
709
+ * @private
710
+ * @return {void}
711
+ */
712
+ function applyContentOverflowMode() {
713
+ const contentElement = this[contentElementSymbol];
714
+ if (!(contentElement instanceof HTMLElement)) {
715
+ return;
716
+ }
717
+
718
+ contentElement.setAttribute(
719
+ "data-monster-overflow-mode",
720
+ this.resolveContentOverflowMode(),
721
+ );
722
+ }
723
+
602
724
  /**
603
725
  * Gets the main template HTML
604
726
  * @private
@@ -612,7 +734,9 @@ function getTemplate() {
612
734
 
613
735
  <div data-monster-role="popper" part="popper" tabindex="-1" class="monster-color-primary-1">
614
736
  <div data-monster-role="arrow"></div>
615
- <div part="content" class="flex" data-monster-replace="path:content">
737
+ <div part="content"
738
+ class="flex"
739
+ data-monster-replace="path:content">
616
740
  </div>
617
741
  </div>
618
742
  </div>
@@ -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] 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: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}
29
29
  }`,
30
30
  0,
31
31
  );
@@ -26,6 +26,14 @@ div[data-monster-role="popper"] > [part="content"] {
26
26
  max-width: 100%;
27
27
  overflow: auto;
28
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
+ }
29
37
  div[data-monster-role="popper"] div[data-monster-role="arrow"] {
30
38
  background: var(--monster-bg-color-primary-1);
31
39
  height: calc(
@@ -29,6 +29,16 @@ div[data-monster-role=popper] {
29
29
  max-height: var(--monster-popper-content-max-height, calc(100vh - 4.2rem));
30
30
  }
31
31
 
32
+ & > [part=content][data-monster-overflow-mode=horizontal] {
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
+ );
40
+ }
41
+
32
42
  & div[data-monster-role=arrow] {
33
43
  position: absolute;
34
44
  width: calc(2 * max(var(--monster-popper-witharrrow-distance), -1 * var(--monster-popper-witharrrow-distance)));
@@ -25,7 +25,7 @@ try {
25
25
  FloatingUiStyleSheet.insertRule(
26
26
  `
27
27
  @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] 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
+ 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
29
  }`,
30
30
  0,
31
31
  );
@@ -32,32 +32,68 @@ function extractKeys(
32
32
  ) {
33
33
  const resultMap = new Map();
34
34
 
35
- function helper(currentObj, currentKeyPrefix, currentValuePrefix) {
35
+ function normalizeKeySegment(value) {
36
+ return String(value).toLowerCase();
37
+ }
38
+
39
+ function toKebabCase(value) {
40
+ return String(value)
41
+ .replace(/([a-z0-9])([A-Z])/g, "$1-$2")
42
+ .toLowerCase();
43
+ }
44
+
45
+ function appendKeys(compactKey, kebabKey, valuePath) {
46
+ resultMap.set(compactKey, valuePath);
47
+ if (kebabKey !== compactKey) {
48
+ resultMap.set(kebabKey, valuePath);
49
+ }
50
+ }
51
+
52
+ function helper(
53
+ currentObj,
54
+ currentCompactKeyPrefix,
55
+ currentKebabKeyPrefix,
56
+ currentValuePrefix,
57
+ ) {
36
58
  for (const key in currentObj) {
59
+ const compactSegment = normalizeKeySegment(key);
60
+ const kebabSegment = toKebabCase(key);
61
+
37
62
  if (
38
63
  currentObj[key] !== null &&
39
64
  typeof currentObj[key] === "object" &&
40
65
  !Array.isArray(currentObj[key])
41
66
  ) {
42
- const newKeyPrefix = currentKeyPrefix
43
- ? currentKeyPrefix + keySeparator + key.toLowerCase()
44
- : key.toLowerCase();
67
+ const newCompactKeyPrefix = currentCompactKeyPrefix
68
+ ? currentCompactKeyPrefix + keySeparator + compactSegment
69
+ : compactSegment;
70
+ const newKebabKeyPrefix = currentKebabKeyPrefix
71
+ ? currentKebabKeyPrefix + keySeparator + kebabSegment
72
+ : kebabSegment;
45
73
  const newValuePrefix = currentValuePrefix
46
74
  ? currentValuePrefix + valueSeparator + key
47
75
  : key;
48
- helper(currentObj[key], newKeyPrefix, newValuePrefix);
76
+ helper(
77
+ currentObj[key],
78
+ newCompactKeyPrefix,
79
+ newKebabKeyPrefix,
80
+ newValuePrefix,
81
+ );
49
82
  } else {
50
- const finalKey = currentKeyPrefix
51
- ? currentKeyPrefix + keySeparator + key.toLowerCase()
52
- : key.toLowerCase();
83
+ const finalCompactKey = currentCompactKeyPrefix
84
+ ? currentCompactKeyPrefix + keySeparator + compactSegment
85
+ : compactSegment;
86
+ const finalKebabKey = currentKebabKeyPrefix
87
+ ? currentKebabKeyPrefix + keySeparator + kebabSegment
88
+ : kebabSegment;
53
89
  const finalValue = currentValuePrefix
54
90
  ? currentValuePrefix + valueSeparator + key
55
91
  : key;
56
- resultMap.set(finalKey, finalValue);
92
+ appendKeys(finalCompactKey, finalKebabKey, finalValue);
57
93
  }
58
94
  }
59
95
  }
60
96
 
61
- helper(obj, keyPrefix, keyPrefix);
97
+ helper(obj, keyPrefix, keyPrefix, keyPrefix);
62
98
  return resultMap;
63
99
  }
@@ -29,8 +29,10 @@ export { initOptionsFromAttributes };
29
29
  /**
30
30
  * Initializes the given options object based on the attributes of the current DOM element.
31
31
  * The function looks for attributes with the prefix 'data-monster-option-', and maps them to
32
- * properties in the options object. It replaces the dashes with dots to form the property path.
33
- * For example, the attribute 'data-monster-option-url' maps to the 'url' property in the options object.
32
+ * properties in the options object. It supports both the historic compact form and kebab-case aliases
33
+ * for camelCase option names.
34
+ * For example, the attributes 'data-monster-option-url' and
35
+ * 'data-monster-option-popper-content-overflow' map to 'url' and 'popper.contentOverflow'.
34
36
  *
35
37
  * With the mapping parameter, the attribute value can be mapped to a different value.
36
38
  * For example, the attribute 'data-monster-option-foo' maps to the 'bar' property in the options object.
@@ -30,8 +30,10 @@ export { setOptionFromAttribute };
30
30
  /**
31
31
  * Set the given options object based on the attributes of the current DOM element.
32
32
  * The function looks for attributes with the prefix 'data-monster-option-', and maps them to
33
- * properties in the options object. It replaces the dashes with dots to form the property path.
34
- * For example, the attribute 'data-monster-option-url' maps to the 'url' property in the options object.
33
+ * properties in the options object. It supports both the historic compact form and kebab-case aliases
34
+ * for camelCase option names.
35
+ * For example, the attributes 'data-monster-option-url' and
36
+ * 'data-monster-option-popper-content-overflow' map to 'url' and 'popper.contentOverflow'.
35
37
  *
36
38
  * With the mapping parameter, the attribute value can be mapped to a different value.
37
39
  * For example, the attribute 'data-monster-option-foo' maps to the 'bar' property in the options object.