@lion/ui 0.0.9 → 0.0.11

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 (158) hide show
  1. package/components/accordion/src/LionAccordion.js +2 -2
  2. package/components/core/src/SlotMixin.js +2 -1
  3. package/components/dialog/src/LionDialog.js +0 -28
  4. package/components/dialog/test/lion-dialog.test.js +11 -10
  5. package/components/form-integrations/test/form-group-methods.test.js +6 -4
  6. package/components/form-integrations/test/form-integrations.test.js +10 -5
  7. package/components/form-integrations/test/helpers/umbrella-form.js +10 -0
  8. package/components/form-integrations/test/model-value-consistency.test.js +29 -20
  9. package/components/input-datepicker/src/LionInputDatepicker.js +66 -104
  10. package/components/input-datepicker/src/localizeNamespaceLoader.js +188 -0
  11. package/components/input-datepicker/test/lion-input-datepicker.test.js +15 -20
  12. package/components/input-datepicker/test-helpers/DatepickerInputObject.js +3 -3
  13. package/components/input-tel/src/parsers.js +1 -1
  14. package/components/listbox/test-suites/ListboxMixin.suite.js +3 -3
  15. package/components/localize/src/singleton.js +1 -1
  16. package/components/localize/test/number/formatNumber.test.js +2 -6
  17. package/components/overlays/src/OverlayController.js +292 -291
  18. package/components/overlays/src/OverlayMixin.js +17 -18
  19. package/components/overlays/src/OverlaysManager.js +28 -53
  20. package/components/overlays/src/configurations/visibility-trigger-partials/withClickInteraction.js +32 -0
  21. package/components/overlays/src/configurations/visibility-trigger-partials/withHoverInteraction.js +76 -0
  22. package/components/overlays/src/configurations/withBottomSheetConfig.js +3 -0
  23. package/components/overlays/src/configurations/withDropdownConfig.js +3 -0
  24. package/components/overlays/src/configurations/withModalDialogConfig.js +3 -0
  25. package/components/overlays/src/configurations/withTooltipConfig.js +29 -0
  26. package/components/overlays/src/overlayDocumentStyle.js +24 -0
  27. package/components/overlays/src/overlayShadowDomStyle.js +138 -0
  28. package/components/overlays/src/singleton.js +3 -1
  29. package/components/overlays/test/ArrowMixin.test.js +0 -1
  30. package/components/overlays/test/OverlayController.test.js +372 -274
  31. package/components/overlays/test/OverlaysManager.test.js +23 -32
  32. package/components/overlays/test/global-positioning.test.js +4 -15
  33. package/components/overlays/test/local-positioning.test.js +65 -38
  34. package/components/overlays/test-suites/OverlayMixin.suite.js +18 -26
  35. package/components/overlays/types/OverlayConfig.ts +38 -11
  36. package/components/overlays/types/OverlayMixinTypes.ts +2 -2
  37. package/components/select-rich/src/LionSelectInvoker.js +2 -3
  38. package/components/select-rich/src/LionSelectRich.js +22 -20
  39. package/components/select-rich/test/lion-select-rich.test.js +5 -7
  40. package/components/tooltip/src/LionTooltip.js +3 -90
  41. package/components/tooltip/test/lion-tooltip.test.js +52 -20
  42. package/custom-elements.json +535 -503
  43. package/dist-types/components/core/src/SlotMixin.d.ts.map +1 -1
  44. package/dist-types/components/dialog/src/LionDialog.d.ts +0 -2
  45. package/dist-types/components/dialog/src/LionDialog.d.ts.map +1 -1
  46. package/dist-types/components/form-integrations/test/helpers/umbrella-form.d.ts +4 -0
  47. package/dist-types/components/form-integrations/test/helpers/umbrella-form.d.ts.map +1 -1
  48. package/dist-types/components/form-integrations/test/model-value-consistency.test.d.ts.map +1 -1
  49. package/dist-types/components/input-datepicker/src/LionInputDatepicker.d.ts +3 -3
  50. package/dist-types/components/input-datepicker/src/LionInputDatepicker.d.ts.map +1 -1
  51. package/dist-types/components/input-datepicker/src/localizeNamespaceLoader.d.ts +4 -0
  52. package/dist-types/components/input-datepicker/src/localizeNamespaceLoader.d.ts.map +1 -0
  53. package/dist-types/components/overlays/src/OverlayController.d.ts +56 -101
  54. package/dist-types/components/overlays/src/OverlayController.d.ts.map +1 -1
  55. package/dist-types/components/overlays/src/OverlayMixin.d.ts.map +1 -1
  56. package/dist-types/components/overlays/src/OverlaysManager.d.ts +0 -7
  57. package/dist-types/components/overlays/src/OverlaysManager.d.ts.map +1 -1
  58. package/dist-types/components/overlays/src/configurations/visibility-trigger-partials/withClickInteraction.d.ts +12 -0
  59. package/dist-types/components/overlays/src/configurations/visibility-trigger-partials/withClickInteraction.d.ts.map +1 -0
  60. package/dist-types/components/overlays/src/configurations/visibility-trigger-partials/withHoverInteraction.d.ts +18 -0
  61. package/dist-types/components/overlays/src/configurations/visibility-trigger-partials/withHoverInteraction.d.ts.map +1 -0
  62. package/dist-types/components/overlays/src/configurations/withBottomSheetConfig.d.ts.map +1 -1
  63. package/dist-types/components/overlays/src/configurations/withDropdownConfig.d.ts.map +1 -1
  64. package/dist-types/components/overlays/src/configurations/withModalDialogConfig.d.ts.map +1 -1
  65. package/dist-types/components/overlays/src/configurations/withTooltipConfig.d.ts +8 -0
  66. package/dist-types/components/overlays/src/configurations/withTooltipConfig.d.ts.map +1 -0
  67. package/dist-types/components/overlays/src/overlayDocumentStyle.d.ts +2 -0
  68. package/dist-types/components/overlays/src/overlayDocumentStyle.d.ts.map +1 -0
  69. package/dist-types/components/overlays/src/overlayShadowDomStyle.d.ts +2 -0
  70. package/dist-types/components/overlays/src/overlayShadowDomStyle.d.ts.map +1 -0
  71. package/dist-types/components/overlays/src/singleton.d.ts +2 -1
  72. package/dist-types/components/overlays/src/singleton.d.ts.map +1 -1
  73. package/dist-types/components/overlays/test-suites/OverlayMixin.suite.d.ts.map +1 -1
  74. package/dist-types/components/overlays/types/OverlayConfig.d.ts +19 -10
  75. package/dist-types/components/overlays/types/OverlayConfig.d.ts.map +1 -1
  76. package/dist-types/components/overlays/types/OverlayMixinTypes.d.ts +2 -2
  77. package/dist-types/components/overlays/types/OverlayMixinTypes.d.ts.map +1 -1
  78. package/dist-types/components/select-rich/src/LionSelectInvoker.d.ts +3 -27
  79. package/dist-types/components/select-rich/src/LionSelectInvoker.d.ts.map +1 -1
  80. package/dist-types/components/select-rich/src/LionSelectRich.d.ts.map +1 -1
  81. package/dist-types/components/select-rich/test/lion-select-rich.test.d.ts.map +1 -1
  82. package/dist-types/components/tooltip/src/LionTooltip.d.ts +4 -20
  83. package/dist-types/components/tooltip/src/LionTooltip.d.ts.map +1 -1
  84. package/dist-types/components/tooltip/test/lion-tooltip.test.d.ts.map +1 -1
  85. package/dist-types/exports/input-datepicker.d.ts +0 -1
  86. package/dist-types/exports/overlays.d.ts +1 -1
  87. package/dist-types/exports/types/overlays.d.ts +1 -0
  88. package/dist-types/exports/types/overlays.d.ts.map +1 -1
  89. package/dist-types/tsconfig.tsbuildinfo +1 -1
  90. package/docs/components/checkbox-group/overview.md +2 -2
  91. package/docs/components/collapsible/overview.md +1 -1
  92. package/docs/components/combobox/overview.md +1 -1
  93. package/docs/components/combobox/use-cases.md +1 -1
  94. package/docs/components/dialog/overview.md +5 -9
  95. package/docs/components/dialog/use-cases.md +43 -87
  96. package/docs/components/fieldset/overview.md +5 -5
  97. package/docs/components/form/overview.md +3 -3
  98. package/docs/components/icon/use-cases.md +1 -1
  99. package/docs/components/input/overview.md +1 -1
  100. package/docs/components/input-amount/overview.md +3 -3
  101. package/docs/components/input-date/overview.md +3 -3
  102. package/docs/components/input-datepicker/overview.md +5 -5
  103. package/docs/components/input-email/overview.md +2 -2
  104. package/docs/components/input-iban/overview.md +2 -2
  105. package/docs/components/input-range/overview.md +2 -2
  106. package/docs/components/input-stepper/overview.md +1 -1
  107. package/docs/components/input-tel/overview.md +1 -1
  108. package/docs/components/input-tel/use-cases.md +6 -6
  109. package/docs/components/input-tel-dropdown/overview.md +1 -1
  110. package/docs/components/radio-group/overview.md +3 -3
  111. package/docs/components/select-rich/use-cases.md +1 -1
  112. package/docs/components/tabs/examples.md +1 -1
  113. package/docs/fundamentals/index.md +4 -4
  114. package/docs/fundamentals/node-tools/providence-analytics/LocalConfiguration.md +1 -1
  115. package/docs/fundamentals/node-tools/providence-analytics/QueryResult.md +1 -1
  116. package/docs/fundamentals/node-tools/providence-analytics/analyzer.md +1 -1
  117. package/docs/fundamentals/node-tools/providence-analytics/dashboard.md +1 -1
  118. package/docs/fundamentals/node-tools/providence-analytics/overview.md +3 -3
  119. package/docs/fundamentals/node-tools/publish-docs/overview.md +3 -3
  120. package/docs/fundamentals/node-tools/rocket-preset-extend-lion-docs/overview.md +2 -2
  121. package/docs/fundamentals/systems/core/overview.md +1 -1
  122. package/docs/fundamentals/systems/form/formatting-and-parsing.md +4 -4
  123. package/docs/fundamentals/systems/form/model-value.md +1 -1
  124. package/docs/fundamentals/systems/form/overview.md +28 -28
  125. package/docs/fundamentals/systems/form/use-cases.md +4 -0
  126. package/docs/fundamentals/systems/form/validate.md +1 -1
  127. package/docs/fundamentals/systems/localize/overview.md +4 -4
  128. package/docs/fundamentals/systems/overlays/assets/{applyDemoOverlayStyles.js → applyDemoOverlayStyles.mjs} +2 -1
  129. package/docs/fundamentals/systems/overlays/assets/demo-el-using-overlaymixin.mjs +119 -0
  130. package/docs/fundamentals/systems/overlays/assets/{demo-overlay-backdrop.js → demo-overlay-backdrop.mjs} +3 -4
  131. package/docs/fundamentals/systems/overlays/assets/demo-overlay-positioning.mjs +537 -0
  132. package/docs/fundamentals/systems/overlays/assets/umbrella-form.js +9 -2
  133. package/docs/fundamentals/systems/overlays/configuration.md +56 -54
  134. package/docs/fundamentals/systems/overlays/overview.md +5 -5
  135. package/docs/fundamentals/systems/overlays/use-cases.md +83 -77
  136. package/docs/fundamentals/tools/helpers/overview.md +1 -1
  137. package/docs/fundamentals/tools/singleton-manager/overview.md +4 -4
  138. package/docs/guides/how-to/create-a-custom-field.md +6 -6
  139. package/docs/guides/how-to/extend-a-native-input.md +3 -3
  140. package/docs/guides/index.md +8 -8
  141. package/docs/guides/principles/index.md +5 -5
  142. package/docs/guides/principles/styling.md +1 -1
  143. package/exports/input-datepicker.js +0 -1
  144. package/exports/overlays.js +1 -1
  145. package/exports/types/overlays.ts +1 -0
  146. package/package.json +2 -1
  147. package/components/input-datepicker/src/LionCalendarOverlayFrame.js +0 -125
  148. package/components/overlays/src/globalOverlaysStyle.js +0 -139
  149. package/dist-types/components/input-datepicker/src/LionCalendarOverlayFrame.d.ts +0 -10
  150. package/dist-types/components/input-datepicker/src/LionCalendarOverlayFrame.d.ts.map +0 -1
  151. package/dist-types/components/overlays/src/globalOverlaysStyle.d.ts +0 -2
  152. package/dist-types/components/overlays/src/globalOverlaysStyle.d.ts.map +0 -1
  153. package/dist-types/exports/define/lion-calendar-overlay-frame.d.ts +0 -2
  154. package/dist-types/exports/define/lion-calendar-overlay-frame.d.ts.map +0 -1
  155. package/docs/fundamentals/systems/overlays/assets/demo-overlay-system.js +0 -42
  156. package/docs/fundamentals/systems/overlays/form-integration.md +0 -65
  157. package/docs/fundamentals/systems/overlays/scope.md +0 -176
  158. package/exports/define/lion-calendar-overlay-frame.js +0 -3
@@ -1,89 +1,133 @@
1
1
  import { EventTargetShim } from '@lion/ui/core.js';
2
+ import { adoptStyles } from 'lit';
2
3
  import { overlays } from './singleton.js';
3
4
  import { containFocus } from './utils/contain-focus.js';
5
+ import { overlayShadowDomStyle } from './overlayShadowDomStyle.js';
4
6
 
5
7
  /**
6
- * @typedef {import('../types/OverlayConfig.js').OverlayConfig} OverlayConfig
7
- * @typedef {import('../types/OverlayConfig.js').ViewportConfig} ViewportConfig
8
- * @typedef {import('@popperjs/core/lib/popper.js').createPopper} Popper
9
- * @typedef {import('@popperjs/core/lib/popper.js').Options} PopperOptions
10
- * @typedef {import('@popperjs/core/lib/enums.js').Placement} Placement
8
+ * @typedef {import('@lion/ui/types/overlays.js').OverlayConfig} OverlayConfig
9
+ * @typedef {import('@lion/ui/types/overlays.js').ViewportConfig} ViewportConfig
10
+ * @typedef {import('@popperjs/core').createPopper} Popper
11
+ * @typedef {import('@popperjs/core').Options} PopperOptions
12
+ * @typedef {import('@popperjs/core').Placement} Placement
11
13
  * @typedef {{ createPopper: Popper }} PopperModule
12
14
  * @typedef {'setup'|'init'|'teardown'|'before-show'|'show'|'hide'|'add'|'remove'} OverlayPhase
13
15
  */
14
16
 
17
+ const rootNodeStylesMap = new WeakSet();
18
+
19
+ /**
20
+ * Returns element that adopts stylesheet
21
+ * @param {Element} shadowOrBodyEl
22
+ * @returns {ShadowRoot}
23
+ */
24
+ function getRootNodeOrBodyElThatAdoptsStylesheet(shadowOrBodyEl) {
25
+ const rootNode = /** @type {* & DocumentOrShadowRoot} */ (shadowOrBodyEl.getRootNode());
26
+ if (rootNode === document) {
27
+ // @ts-ignore
28
+ return document.body;
29
+ }
30
+ return rootNode;
31
+ }
32
+
33
+ /**
34
+ * From:
35
+ * - wrappingDialogNodeL1: `<dialog role="none"/>`
36
+ * - contentWrapperNodeL2: `<div id="content-wrapper-node"/>`
37
+ * - contentNodeL3: `<div slot="my-content"/>`
38
+ * To:
39
+ * ```html
40
+ * <dialog role="none">
41
+ * <div id="content-wrapper-node">
42
+ * <!-- this was the (slot for) original content node -->
43
+ * <slot name="my-content"></slot>
44
+ * </div>
45
+ * </dialog>
46
+ * ```
47
+ *
48
+ * `<slot name="my-content">` belonging to `<div slot="content"/>` will be wrapped with wrappingDialogNodeL1 and contentWrapperNodeL2
49
+ * inside shadow dom. With the help of temp markers, `<slot name="my-content">`'s original position will be respected.
50
+ *
51
+ * @param {{ wrappingDialogNodeL1:HTMLDialogElement|HTMLDivElement; contentWrapperNodeL2:Element; contentNodeL3: Element }} opts
52
+ */
53
+ function rearrangeNodes({ wrappingDialogNodeL1, contentWrapperNodeL2, contentNodeL3 }) {
54
+ if (!(contentWrapperNodeL2.isConnected || contentNodeL3.isConnected)) {
55
+ throw new Error(
56
+ '[OverlayController] Could not find a render target, since the provided contentNode is not connected to the DOM. Make sure that it is connected, e.g. by doing "document.body.appendChild(contentNode)", before passing it on.',
57
+ );
58
+ }
59
+
60
+ let parentElement;
61
+ const tempMarker = document.createComment('tempMarker');
62
+
63
+ if (contentWrapperNodeL2.isConnected) {
64
+ // This is the case when contentWrapperNode (living in shadow dom, wrapping <slot name="my-content-outlet">) is already provided via controller.
65
+ parentElement = contentWrapperNodeL2.parentElement || contentWrapperNodeL2.getRootNode();
66
+ parentElement.insertBefore(tempMarker, contentWrapperNodeL2);
67
+ // Wrap...
68
+ wrappingDialogNodeL1.appendChild(contentWrapperNodeL2);
69
+ }
70
+ // if contentNodeL3.isConnected
71
+ else {
72
+ const contentIsProjected = contentNodeL3.assignedSlot;
73
+ if (contentIsProjected) {
74
+ parentElement =
75
+ contentNodeL3.assignedSlot.parentElement || contentNodeL3.assignedSlot.getRootNode();
76
+ parentElement.insertBefore(tempMarker, contentNodeL3.assignedSlot);
77
+ wrappingDialogNodeL1.appendChild(contentWrapperNodeL2);
78
+ // Important: we do not move around contentNodeL3, but the assigned slot
79
+ contentWrapperNodeL2.appendChild(contentNodeL3.assignedSlot);
80
+ } else {
81
+ parentElement = contentNodeL3.parentElement || contentNodeL3.getRootNode();
82
+ parentElement.insertBefore(tempMarker, contentNodeL3);
83
+ wrappingDialogNodeL1.appendChild(contentWrapperNodeL2);
84
+ contentWrapperNodeL2.appendChild(contentNodeL3);
85
+ }
86
+ }
87
+
88
+ /**
89
+ * From:
90
+ * ```html
91
+ * #shadow-root:
92
+ * <div>
93
+ * <!-- tempMarker -->
94
+ * <slot name="x"/>
95
+ * </div>
96
+ * ```
97
+ *
98
+ * To:
99
+ * ```html
100
+ * #shadow-root:
101
+ * <div>
102
+ * <!-- tempMarker -->
103
+ * <dialog role="none">
104
+ * <div id="content-wrapper-node">
105
+ * <slot name="x"/>
106
+ * </div>
107
+ * </dialog>
108
+ * </div>
109
+ * ```
110
+ */
111
+ parentElement.insertBefore(wrappingDialogNodeL1, tempMarker);
112
+ parentElement?.removeChild(tempMarker);
113
+ }
114
+
15
115
  /**
16
116
  * @returns {Promise<PopperModule>}
17
117
  */
18
118
  async function preloadPopper() {
19
- /* eslint-disable import/no-extraneous-dependencies */ // -- [external]: import complains about untyped module, but we typecast it ourselves
20
- // @ts-ignore
119
+ // @ts-ignore [external]: import complains about untyped module, but we typecast it ourselves
21
120
  return /** @type {* & Promise<PopperModule>} */ (import('@popperjs/core/dist/esm/popper.js'));
22
- /* eslint-enable import/no-extraneous-dependencies */
23
121
  }
24
122
 
25
- const GLOBAL_OVERLAYS_CONTAINER_CLASS = 'global-overlays__overlay-container';
26
- const GLOBAL_OVERLAYS_CLASS = 'global-overlays__overlay';
27
123
  // @ts-expect-error [external]: CSS not yet typed
28
124
  const supportsCSSTypedObject = window.CSS?.number && document.body.attributeStyleMap?.set;
29
125
 
30
126
  /**
31
- * @desc OverlayController is the fundament for every single type of overlay. With the right
127
+ * OverlayController is the fundament for every single type of overlay. With the right
32
128
  * configuration, it can be used to build (modal) dialogs, tooltips, dropdowns, popovers,
33
129
  * bottom/top/left/right sheets etc.
34
130
  *
35
- * ### About contentNode, contentWrapperNode and renderTarget.
36
- *
37
- * #### contentNode
38
- * Node containing actual overlay contents.
39
- * It will not be touched by the OverlayController, it will only set attributes needed
40
- * for accessibility.
41
- *
42
- * #### contentWrapperNode
43
- * The 'positioning' element.
44
- * For local overlays, this node will be provided to Popper and all
45
- * inline positioning styles will be added here. It will also act as the container of an arrow
46
- * element (the arrow needs to be a sibling of contentNode for Popper to work correctly).
47
- * When projecting a contentNode from a shadowRoot, it is essential to have the wrapper in
48
- * shadow dom, so that contentNode can be styled via `::slotted` from the shadow root.
49
- * The Popper arrow can then be styled from that same shadow root as well.
50
- * For global overlays, the contentWrapperNode will be appended to the globalRootNode structure.
51
- *
52
- * #### renderTarget
53
- * Usually the parent node of contentWrapperNode that either exists locally or globally.
54
- * When a responsive scenario is created (in which we switch from global to local or vice versa)
55
- * we need to know where we should reappend contentWrapperNode (or contentNode in case it's projected)
56
- *
57
- * So a regular flow can be summarized as follows:
58
- * 1. Application Developer spawns an OverlayController with a contentNode reference
59
- * 2. OverlayController will create a contentWrapperNode around contentNode (or consumes when provided)
60
- * 3. contentWrapperNode will be appended to the right renderTarget
61
- *
62
- * There are subtle differences depending on the following factors:
63
- * - whether in global/local placement mode
64
- * - whether contentNode projected
65
- * - whether an arrow is provided
66
- *
67
- * This leads to the following possible combinations:
68
- * - [l1]. local + no content projection + no arrow
69
- * - [l2]. local + content projection + no arrow
70
- * - [l3]. local + no content projection + arrow
71
- * - [l4]. local + content projection + arrow
72
- * - [g1]. global
73
- *
74
- * #### html structure for a content projected node
75
- * <div id="contentWrapperNode">
76
- * <slot name="contentNode"></slot>
77
- * <div x-arrow></div>
78
- * </div>
79
- *
80
- * Structure above depicts [l4]
81
- * So in case of [l1] and [l3], the <slot> element would be a regular element
82
- * In case of [l1] and [l2], there would be no arrow.
83
- * Note that a contentWrapperNode should be provided for [l2], [l3] and [l4]
84
- * In case of a global overlay ([g1]), it's enough to provide just the contentNode.
85
- * In case of a local overlay or a responsive overlay switching from placementMode, one should
86
- * always configure as if it were a local overlay.
87
131
  */
88
132
  export class OverlayController extends EventTargetShim {
89
133
  /**
@@ -97,6 +141,9 @@ export class OverlayController extends EventTargetShim {
97
141
  /** @private */
98
142
  this.__sharedConfig = config;
99
143
 
144
+ /** @type {OverlayConfig} */
145
+ this.config = {};
146
+
100
147
  /**
101
148
  * @type {OverlayConfig}
102
149
  * @protected
@@ -119,11 +166,11 @@ export class OverlayController extends EventTargetShim {
119
166
  hidesOnOutsideClick: false,
120
167
  isTooltip: false,
121
168
  invokerRelation: 'description',
122
- // handlesUserInteraction: false,
169
+ visibilityTriggerFunction: undefined,
123
170
  handlesAccessibility: false,
124
171
  popperConfig: {
125
172
  placement: 'top',
126
- strategy: 'absolute',
173
+ strategy: 'fixed',
127
174
  modifiers: [
128
175
  {
129
176
  name: 'preventOverflow',
@@ -156,6 +203,7 @@ export class OverlayController extends EventTargetShim {
156
203
  viewportConfig: {
157
204
  placement: 'center',
158
205
  },
206
+ zIndex: 9999,
159
207
  };
160
208
 
161
209
  this.manager.add(this);
@@ -163,25 +211,11 @@ export class OverlayController extends EventTargetShim {
163
211
  this._contentId = `overlay-content--${Math.random().toString(36).substr(2, 10)}`;
164
212
  /** @private */
165
213
  this.__originalAttrs = new Map();
166
- if (this._defaultConfig.contentNode) {
167
- if (!this._defaultConfig.contentNode.isConnected) {
168
- throw new Error(
169
- '[OverlayController] Could not find a render target, since the provided contentNode is not connected to the DOM. Make sure that it is connected, e.g. by doing "document.body.appendChild(contentNode)", before passing it on.',
170
- );
171
- }
172
- this.__isContentNodeProjected = Boolean(this._defaultConfig.contentNode.assignedSlot);
173
- }
174
214
  this.updateConfig(config);
175
215
  /** @private */
176
216
  this.__hasActiveTrapsKeyboardFocus = false;
177
217
  /** @private */
178
218
  this.__hasActiveBackdrop = true;
179
- /**
180
- * @type {HTMLElement | undefined}
181
- * @private
182
- */
183
- this.__backdropNodeToBeTornDown = undefined;
184
-
185
219
  /** @private */
186
220
  this.__escKeyHandler = this.__escKeyHandler.bind(this);
187
221
  }
@@ -196,10 +230,10 @@ export class OverlayController extends EventTargetShim {
196
230
 
197
231
  /**
198
232
  * The contentWrapperNode
199
- * @type {HTMLElement}
233
+ * @type {HTMLDialogElement | HTMLDivElement}
200
234
  */
201
235
  get content() {
202
- return /** @type {HTMLElement} */ (this.contentWrapperNode);
236
+ return /** @type {HTMLDialogElement | HTMLDivElement} */ (this.__wrappingDialogNode);
203
237
  }
204
238
 
205
239
  /**
@@ -385,26 +419,8 @@ export class OverlayController extends EventTargetShim {
385
419
  return /** @type {ViewportConfig} */ (this.config?.viewportConfig);
386
420
  }
387
421
 
388
- /**
389
- * Usually the parent node of contentWrapperNode that either exists locally or globally.
390
- * When a responsive scenario is created (in which we switch from global to local or vice versa)
391
- * we need to know where we should reappend contentWrapperNode (or contentNode in case it's
392
- * projected).
393
- * @type {HTMLElement}
394
- * @protected
395
- */
396
- get _renderTarget() {
397
- /** config [g1] */
398
- if (this.placementMode === 'global') {
399
- return this.manager.globalRootNode;
400
- }
401
- /** config [l2] or [l4] */
402
- if (this.__isContentNodeProjected) {
403
- // @ts-expect-error [external]: fix Node types
404
- return this.__originalContentParent?.getRootNode().host;
405
- }
406
- /** config [l1] or [l3] */
407
- return /** @type {HTMLElement} */ (this.__originalContentParent);
422
+ get visibilityTriggerFunction() {
423
+ return /** @type {function} */ (this.config?.visibilityTriggerFunction);
408
424
  }
409
425
 
410
426
  /**
@@ -420,12 +436,8 @@ export class OverlayController extends EventTargetShim {
420
436
  * @param {number} value
421
437
  */
422
438
  set elevation(value) {
423
- if (this.contentWrapperNode) {
424
- this.contentWrapperNode.style.zIndex = `${value}`;
425
- }
426
- if (this.backdropNode) {
427
- this.backdropNode.style.zIndex = `${value}`;
428
- }
439
+ // @ts-expect-error find out why config would/could be undfined
440
+ this.__wrappingDialogNode.style.zIndex = `${this.config.zIndex + value}`;
429
441
  }
430
442
 
431
443
  /**
@@ -450,7 +462,7 @@ export class OverlayController extends EventTargetShim {
450
462
  * @type {OverlayConfig}
451
463
  * @private
452
464
  */
453
- this.__prevConfig = this.config || {};
465
+ this.__prevConfig = this.config;
454
466
 
455
467
  /** @type {OverlayConfig} */
456
468
  this.config = {
@@ -462,19 +474,17 @@ export class OverlayController extends EventTargetShim {
462
474
  ...(this.__sharedConfig.popperConfig || {}),
463
475
  ...(cfgToAdd.popperConfig || {}),
464
476
  modifiers: [
465
- ...((this._defaultConfig.popperConfig && this._defaultConfig.popperConfig.modifiers) ||
466
- []),
467
- ...((this.__sharedConfig.popperConfig && this.__sharedConfig.popperConfig.modifiers) ||
468
- []),
469
- ...((cfgToAdd.popperConfig && cfgToAdd.popperConfig.modifiers) || []),
477
+ ...(this._defaultConfig.popperConfig?.modifiers || []),
478
+ ...(this.__sharedConfig.popperConfig?.modifiers || []),
479
+ ...(cfgToAdd.popperConfig?.modifiers || []),
470
480
  ],
471
481
  },
472
482
  };
473
483
 
474
484
  /** @private */
475
- this.__validateConfiguration(/** @type {OverlayConfig} */ (this.config));
485
+ this.__validateConfiguration(this.config);
476
486
  /** @protected */
477
- this._init({ cfgToAdd });
487
+ this._init();
478
488
  /** @private */
479
489
  this.__elementToFocusAfterHide = undefined;
480
490
  }
@@ -498,16 +508,6 @@ export class OverlayController extends EventTargetShim {
498
508
  if (!newConfig.contentNode) {
499
509
  throw new Error('[OverlayController] You need to provide a .contentNode');
500
510
  }
501
- if (this.__isContentNodeProjected && !newConfig.contentWrapperNode) {
502
- throw new Error(
503
- '[OverlayController] You need to provide a .contentWrapperNode when .contentNode is projected',
504
- );
505
- }
506
- if (newConfig.isTooltip && newConfig.placementMode !== 'local') {
507
- throw new Error(
508
- '[OverlayController] .isTooltip should be configured with .placementMode "local"',
509
- );
510
- }
511
511
  if (newConfig.isTooltip && !newConfig.handlesAccessibility) {
512
512
  throw new Error(
513
513
  '[OverlayController] .isTooltip only takes effect when .handlesAccessibility is enabled',
@@ -519,85 +519,103 @@ export class OverlayController extends EventTargetShim {
519
519
  }
520
520
 
521
521
  /**
522
- * @param {{ cfgToAdd: OverlayConfig }} options
523
522
  * @protected
524
523
  */
525
- _init({ cfgToAdd }) {
526
- this.__initContentWrapperNode({ cfgToAdd });
527
- this.__initConnectionTarget();
524
+ _init() {
525
+ if (!this.__contentHasBeenInitialized) {
526
+ this.__initContentDomStructure();
527
+ this.__contentHasBeenInitialized = true;
528
+ }
529
+
530
+ // Reset all positioning styles (local, c.q. Popper) and classes (global)
531
+ this.contentWrapperNode.removeAttribute('style');
532
+ this.contentWrapperNode.removeAttribute('class');
528
533
 
529
534
  if (this.placementMode === 'local') {
530
- // Lazily load Popper if not done yet
535
+ // Lazily load Popper as soon as the first local overlay is used...
531
536
  if (!OverlayController.popperModule) {
532
- // a@ts-expect-error FIXME: for some reason createPopper is missing here
533
537
  OverlayController.popperModule = preloadPopper();
534
538
  }
535
539
  }
540
+ this.__initOverlayStyles();
536
541
  this._handleFeatures({ phase: 'init' });
537
542
  }
538
543
 
539
- /** @private */
540
- __initConnectionTarget() {
541
- // Now, add our node to the right place in dom (renderTarget)
542
- if (this.contentWrapperNode !== this.__prevConfig?.contentWrapperNode) {
543
- if (this.config?.placementMode === 'global' || !this.__isContentNodeProjected) {
544
- /** @type {HTMLElement} */
545
- (this.contentWrapperNode).appendChild(this.contentNode);
546
- }
547
- }
548
-
549
- if (!this._renderTarget) {
550
- return;
551
- }
552
-
553
- if (this.__isContentNodeProjected && this.placementMode === 'local') {
554
- // We add the contentNode in its slot, so that it will be projected by contentWrapperNode
555
- this._renderTarget.appendChild(this.contentNode);
556
- } else {
557
- const isInsideRenderTarget = this._renderTarget === this.contentWrapperNode.parentNode;
558
- const nodeContainsTarget = this.contentWrapperNode.contains(this._renderTarget);
559
- if (!isInsideRenderTarget && !nodeContainsTarget) {
560
- // contentWrapperNode becomes the direct (non projected) parent of contentNode
561
- this._renderTarget.appendChild(this.contentWrapperNode);
562
- }
544
+ __initOverlayStyles() {
545
+ const rootNode = getRootNodeOrBodyElThatAdoptsStylesheet(this.contentWrapperNode);
546
+ if (!rootNodeStylesMap.has(rootNode)) {
547
+ // TODO: ideally we should also support a teardown
548
+ adoptStyles(rootNode, [...(rootNode.adoptedStyleSheets || []), overlayShadowDomStyle]);
549
+ rootNodeStylesMap.add(rootNode);
563
550
  }
564
551
  }
565
552
 
566
553
  /**
567
- * Cleanup ._contentWrapperNode. We do this, because creating a fresh wrapper
568
- * can lead to problems with event listeners...
569
- * @param {{ cfgToAdd: OverlayConfig }} options
554
+ * Here we arrange our content node via:
555
+ * 1. HTMLDialogElement: the content will always be painted to the browser's top layer
556
+ * - no matter what context the contentNode lives in, the overlay will be painted correctly via the <dialog> element,
557
+ * even if 'overflow:hidden' or a css transform is applied in its parent hierarchy.
558
+ * - the dialog element will be unstyled, but will span the whole screen
559
+ * - a backdrop element will be a child of the dialog element, so it leverages the capabilities of the parent
560
+ * (filling the whole screen if wanted an always painted to top layer)
561
+ * 2. ContentWrapper: the content receives the right positioning styles in a clean/non conflicting way:
562
+ * - local positioning: receive inline (position) styling that can never conflict with the already existing computed styles
563
+ * - global positioning: receive flex (child) classes that position the content correctly relative to the viewport
564
+ *
565
+ * The resulting structure that will be created looks like this:
566
+ *
567
+ * ...
568
+ * <dialog role="none">
569
+ * <div id="optional-backdrop"></div>
570
+ * <div id="content-wrapper-node">
571
+ * <!-- this was the (slot for) original content node -->
572
+ * <slot name="content"></slot>
573
+ * </div>
574
+ * </dialog>
575
+ * ...
576
+ *
570
577
  * @private
571
578
  */
572
- __initContentWrapperNode({ cfgToAdd }) {
573
- if (this.config?.contentWrapperNode && this.placementMode === 'local') {
574
- /** config [l2],[l3],[l4] */
575
- this.__contentWrapperNode = this.config.contentWrapperNode;
576
- } else {
577
- /** config [l1],[g1] */
579
+ __initContentDomStructure() {
580
+ const wrappingDialogElement = document.createElement(
581
+ this.config?._noDialogEl ? 'div' : 'dialog',
582
+ );
583
+ // We use a dialog for its visual capabilities: it renders to the top layer.
584
+ // A11y will depend on the type of overlay and is arranged on contentNode level.
585
+ // Also see: https://www.scottohara.me/blog/2019/03/05/open-dialog.html
586
+ wrappingDialogElement.setAttribute('role', 'none');
587
+ wrappingDialogElement.setAttribute('data-overlay-outer-wrapper', '');
588
+ // N.B. position: fixed is needed to escape out of 'overflow: hidden'
589
+ // We give a high z-index for non-modal dialogs, so that we at least win from all siblings of our
590
+ // parent stacking context
591
+ wrappingDialogElement.style.cssText = `display:none; z-index: ${this.config.zIndex};`;
592
+ this.__wrappingDialogNode = wrappingDialogElement;
593
+
594
+ /**
595
+ * Based on the configuration of the developer, multiple scenarios are accounted for
596
+ * A. We already have a contentWrapperNode ()
597
+ */
598
+ if (!this.config?.contentWrapperNode) {
578
599
  this.__contentWrapperNode = document.createElement('div');
579
600
  }
601
+ this.contentWrapperNode.setAttribute('data-id', 'content-wrapper');
602
+
603
+ rearrangeNodes({
604
+ wrappingDialogNodeL1: wrappingDialogElement,
605
+ contentWrapperNodeL2: this.contentWrapperNode,
606
+ contentNodeL3: this.contentNode,
607
+ });
608
+ // @ts-ignore
609
+ wrappingDialogElement.open = true;
580
610
 
581
- this.contentWrapperNode.style.cssText = '';
582
- this.contentWrapperNode.style.display = 'none';
611
+ this.__wrappingDialogNode.style.display = 'none';
612
+ this.contentWrapperNode.style.zIndex = '1';
583
613
 
584
614
  if (getComputedStyle(this.contentNode).position === 'absolute') {
585
615
  // Having a _contWrapperNode and a contentNode with 'position:absolute' results in
586
616
  // computed height of 0...
587
617
  this.contentNode.style.position = 'static';
588
618
  }
589
-
590
- if (this.__isContentNodeProjected && this.contentWrapperNode.isConnected) {
591
- // We need to keep track of the original local context.
592
- /** config [l2], [l4] */
593
- this.__originalContentParent = /** @type {HTMLElement} */ (
594
- this.contentWrapperNode.parentNode
595
- );
596
- } else if (cfgToAdd.contentNode && cfgToAdd.contentNode.isConnected) {
597
- // We need to keep track of the original local context.
598
- /** config [l1], [l3], [g1] */
599
- this.__originalContentParent = /** @type {HTMLElement} */ (this.contentNode?.parentNode);
600
- }
601
619
  }
602
620
 
603
621
  /**
@@ -613,7 +631,7 @@ export class OverlayController extends EventTargetShim {
613
631
  if (phase === 'setup') {
614
632
  const zIndexNumber = Number(getComputedStyle(this.contentNode).zIndex);
615
633
  if (zIndexNumber < 1 || Number.isNaN(zIndexNumber)) {
616
- this.contentWrapperNode.style.zIndex = '1';
634
+ this.contentNode.style.zIndex = '1';
617
635
  }
618
636
  }
619
637
  }
@@ -686,7 +704,7 @@ export class OverlayController extends EventTargetShim {
686
704
  }
687
705
 
688
706
  get isShown() {
689
- return Boolean(this.contentWrapperNode.style.display !== 'none');
707
+ return Boolean(this.__wrappingDialogNode?.style.display !== 'none');
690
708
  }
691
709
 
692
710
  /**
@@ -717,7 +735,11 @@ export class OverlayController extends EventTargetShim {
717
735
  const event = new CustomEvent('before-show', { cancelable: true });
718
736
  this.dispatchEvent(event);
719
737
  if (!event.defaultPrevented) {
720
- this.contentWrapperNode.style.display = '';
738
+ if (this.__wrappingDialogNode instanceof HTMLDialogElement) {
739
+ this.__wrappingDialogNode.open = true;
740
+ }
741
+ // @ts-ignore
742
+ this.__wrappingDialogNode.style.display = '';
721
743
  this._keepBodySize({ phase: 'before-show' });
722
744
  await this._handleFeatures({ phase: 'show' });
723
745
  this._keepBodySize({ phase: 'show' });
@@ -739,11 +761,17 @@ export class OverlayController extends EventTargetShim {
739
761
  */
740
762
  async _handlePosition({ phase }) {
741
763
  if (this.placementMode === 'global') {
742
- const addOrRemove = phase === 'show' ? 'add' : 'remove';
743
- const placementClass = `${GLOBAL_OVERLAYS_CONTAINER_CLASS}--${this.viewportConfig.placement}`;
744
- this.contentWrapperNode.classList[addOrRemove](GLOBAL_OVERLAYS_CONTAINER_CLASS);
745
- this.contentWrapperNode.classList[addOrRemove](placementClass);
746
- this.contentNode.classList[addOrRemove](GLOBAL_OVERLAYS_CLASS);
764
+ const placementClass = `overlays__overlay-container--${this.viewportConfig.placement}`;
765
+
766
+ if (phase === 'show') {
767
+ this.contentWrapperNode.classList.add('overlays__overlay-container');
768
+ this.contentWrapperNode.classList.add(placementClass);
769
+ this.contentNode.classList.add('overlays__overlay');
770
+ } else if (phase === 'hide') {
771
+ this.contentWrapperNode.classList.remove('overlays__overlay-container');
772
+ this.contentWrapperNode.classList.remove(placementClass);
773
+ this.contentNode.classList.remove('overlays__overlay');
774
+ }
747
775
  } else if (this.placementMode === 'local' && phase === 'show') {
748
776
  /**
749
777
  * Popper is weird about properly positioning the popper element when it is recreated so
@@ -753,7 +781,7 @@ export class OverlayController extends EventTargetShim {
753
781
  * This is however necessary for initial placement.
754
782
  */
755
783
  await this.__createPopperInstance();
756
- /** @type {Popper} */ (this._popper).forceUpdate();
784
+ this._popper.forceUpdate();
757
785
  }
758
786
  }
759
787
 
@@ -829,7 +857,11 @@ export class OverlayController extends EventTargetShim {
829
857
  contentNode: this.contentNode,
830
858
  });
831
859
 
832
- this.contentWrapperNode.style.display = 'none';
860
+ if (this.__wrappingDialogNode instanceof HTMLDialogElement) {
861
+ this.__wrappingDialogNode.close();
862
+ }
863
+ // @ts-ignore
864
+ this.__wrappingDialogNode.style.display = 'none';
833
865
  this._handleFeatures({ phase: 'hide' });
834
866
  this._keepBodySize({ phase: 'hide' });
835
867
  this.dispatchEvent(new Event('hide'));
@@ -843,6 +875,7 @@ export class OverlayController extends EventTargetShim {
843
875
  *
844
876
  * @param {{backdropNode:HTMLElement, contentNode:HTMLElement}} hideConfig
845
877
  */
878
+ // @ts-ignore
846
879
  // eslint-disable-next-line class-methods-use-this, no-empty-function, no-unused-vars
847
880
  async transitionHide(hideConfig) {}
848
881
 
@@ -851,48 +884,27 @@ export class OverlayController extends EventTargetShim {
851
884
  * @protected
852
885
  */
853
886
  // eslint-disable-next-line class-methods-use-this, no-empty-function, no-unused-vars
854
- async _transitionHide(hideConfig) {
887
+ async _transitionHide({ backdropNode, contentNode }) {
855
888
  // `this.transitionHide` is a hook for our users
856
- await this.transitionHide({ backdropNode: this.backdropNode, contentNode: this.contentNode });
857
-
858
- if (hideConfig.backdropNode) {
859
- hideConfig.backdropNode.classList.remove(
860
- `${this.placementMode}-overlays__backdrop--animation-in`,
861
- );
862
- /** @type {() => void} */
863
- let afterFadeOut = () => {};
864
- hideConfig.backdropNode.classList.add(
865
- `${this.placementMode}-overlays__backdrop--animation-out`,
866
- );
867
- this.__backdropAnimation = new Promise(resolve => {
868
- afterFadeOut = () => {
869
- if (hideConfig.backdropNode) {
870
- hideConfig.backdropNode.classList.remove(
871
- `${this.placementMode}-overlays__backdrop--animation-out`,
872
- );
873
- hideConfig.backdropNode.classList.remove(
874
- `${this.placementMode}-overlays__backdrop--visible`,
875
- );
876
- hideConfig.backdropNode.removeEventListener('animationend', afterFadeOut);
877
- }
878
- resolve(undefined);
879
- };
880
- });
881
-
882
- hideConfig.backdropNode.addEventListener('animationend', afterFadeOut);
889
+ await this.transitionHide({ backdropNode, contentNode });
890
+ this._handlePosition({ phase: 'hide' });
891
+ if (!backdropNode) {
892
+ return;
883
893
  }
894
+ backdropNode.classList.remove(`overlays__backdrop--animation-in`);
884
895
  }
885
896
 
886
897
  /**
887
898
  * To be overridden by subclassers
888
899
  *
889
- * @param {{backdropNode:HTMLElement, contentNode:HTMLElement}} showConfig
900
+ * @param {{backdropNode:HTMLElement; contentNode:HTMLElement}} showConfig
890
901
  */
902
+ // @ts-ignore
891
903
  // eslint-disable-next-line class-methods-use-this, no-empty-function, no-unused-vars
892
904
  async transitionShow(showConfig) {}
893
905
 
894
906
  /**
895
- * @param {{backdropNode:HTMLElement, contentNode:HTMLElement}} showConfig
907
+ * @param {{backdropNode:HTMLElement; contentNode:HTMLElement}} showConfig
896
908
  */
897
909
  // eslint-disable-next-line class-methods-use-this, no-empty-function, no-unused-vars
898
910
  async _transitionShow(showConfig) {
@@ -900,28 +912,25 @@ export class OverlayController extends EventTargetShim {
900
912
  await this.transitionShow({ backdropNode: this.backdropNode, contentNode: this.contentNode });
901
913
 
902
914
  if (showConfig.backdropNode) {
903
- showConfig.backdropNode.classList.add(
904
- `${this.placementMode}-overlays__backdrop--animation-in`,
905
- );
915
+ showConfig.backdropNode.classList.add(`overlays__backdrop--animation-in`);
906
916
  }
907
917
  }
908
918
 
909
919
  /** @protected */
910
920
  _restoreFocus() {
911
- const { activeElement } = /** @type {* & ShadowRoot} */ (
912
- this.__contentWrapperNode
913
- ).getRootNode();
914
- // We only are allowed to move focus if we (still) 'own' it.
915
- // Otherwise we assume the 'outside world' has, purposefully, taken over
916
- if (
917
- activeElement &&
918
- /** @type {HTMLElement} */ (this.__contentWrapperNode).contains(activeElement)
919
- ) {
920
- if (this.elementToFocusAfterHide) {
921
- this.elementToFocusAfterHide.focus();
922
- } else {
923
- activeElement.blur();
924
- }
921
+ // We only are allowed to move focus if we (still) 'own' the active element.
922
+ // Otherwise we assume the 'outside world' has purposefully taken over
923
+ const { activeElement } = /** @type {ShadowRoot} */ (this.contentNode.getRootNode());
924
+ const weStillOwnActiveElement =
925
+ activeElement instanceof HTMLElement && this.contentNode.contains(activeElement);
926
+ if (!weStillOwnActiveElement) {
927
+ return;
928
+ }
929
+
930
+ if (this.elementToFocusAfterHide) {
931
+ this.elementToFocusAfterHide.focus();
932
+ } else {
933
+ activeElement.blur();
925
934
  }
926
935
  }
927
936
 
@@ -964,6 +973,24 @@ export class OverlayController extends EventTargetShim {
964
973
  if (this.inheritsReferenceWidth) {
965
974
  this._handleInheritsReferenceWidth();
966
975
  }
976
+
977
+ if (this.visibilityTriggerFunction) {
978
+ this._handleUserInteraction({ phase });
979
+ }
980
+ }
981
+
982
+ /**
983
+ * @param {{ phase: OverlayPhase }} config
984
+ */
985
+ _handleUserInteraction({ phase }) {
986
+ if (typeof this.visibilityTriggerFunction === 'function') {
987
+ if (phase === 'init') {
988
+ this.__userInteractionHandler = this.visibilityTriggerFunction({ phase, controller: this });
989
+ }
990
+ if (this.__userInteractionHandler[phase]) {
991
+ this.__userInteractionHandler[phase]();
992
+ }
993
+ }
967
994
  }
968
995
 
969
996
  /**
@@ -1010,55 +1037,28 @@ export class OverlayController extends EventTargetShim {
1010
1037
  * @protected
1011
1038
  */
1012
1039
  _handleBackdrop({ phase }) {
1040
+ // eslint-disable-next-line default-case
1013
1041
  switch (phase) {
1014
1042
  case 'init': {
1015
- if (!this.backdropNode) {
1016
- this.__backdropNode = document.createElement('div');
1017
- /** @type {HTMLElement} */
1018
- (this.backdropNode).slot = 'backdrop';
1019
- /** @type {HTMLElement} */
1020
- (this.backdropNode).classList.add(`${this.placementMode}-overlays__backdrop`);
1021
- }
1022
-
1023
- let insertionAnchor = /** @type {HTMLElement} */ (this.contentNode.parentNode);
1024
- let insertionBefore = this.contentNode;
1025
- if (this.placementMode === 'global') {
1026
- insertionAnchor = /** @type {HTMLElement} */ (this.contentWrapperNode.parentElement);
1027
- insertionBefore = this.contentWrapperNode;
1043
+ if (!this.__backdropInitialized) {
1044
+ if (!this.config?.backdropNode) {
1045
+ this.__backdropNode = document.createElement('div');
1046
+ // If backdropNode existed in config, styles are applied by implementing party
1047
+ this.__backdropNode.classList.add(`overlays__backdrop`);
1048
+ }
1049
+ // @ts-ignore
1050
+ this.__wrappingDialogNode.prepend(this.backdropNode);
1051
+ this.__backdropInitialized = true;
1028
1052
  }
1029
- insertionAnchor.insertBefore(this.backdropNode, insertionBefore);
1030
1053
  break;
1031
1054
  }
1032
1055
  case 'show':
1033
- this.backdropNode.classList.add(`${this.placementMode}-overlays__backdrop--visible`);
1056
+ this.backdropNode.classList.add(`overlays__backdrop--visible`);
1034
1057
  this.__hasActiveBackdrop = true;
1035
1058
  break;
1036
1059
  case 'hide':
1037
- if (!this.backdropNode) {
1038
- return;
1039
- }
1040
1060
  this.__hasActiveBackdrop = false;
1041
1061
  break;
1042
- case 'teardown':
1043
- if (!this.backdropNode || !this.backdropNode.parentNode) {
1044
- return;
1045
- }
1046
- if (this.__backdropAnimation) {
1047
- this.__backdropNodeToBeTornDown = this.backdropNode;
1048
-
1049
- this.__backdropAnimation.then(() => {
1050
- if (this.__backdropNodeToBeTornDown && this.__backdropNodeToBeTornDown.parentNode) {
1051
- this.__backdropNodeToBeTornDown.parentNode.removeChild(
1052
- this.__backdropNodeToBeTornDown,
1053
- );
1054
- }
1055
- });
1056
- } else {
1057
- this.backdropNode.parentNode.removeChild(this.backdropNode);
1058
- }
1059
- this.__backdropNode = undefined;
1060
- break;
1061
- /* no default */
1062
1062
  }
1063
1063
  }
1064
1064
 
@@ -1072,7 +1072,16 @@ export class OverlayController extends EventTargetShim {
1072
1072
  */
1073
1073
  _handleTrapsKeyboardFocus({ phase }) {
1074
1074
  if (phase === 'show') {
1075
+ // @ts-ignore
1076
+ if ('showModal' in this.__wrappingDialogNode) {
1077
+ // @ts-ignore
1078
+ this.__wrappingDialogNode.close();
1079
+ // @ts-ignore
1080
+ this.__wrappingDialogNode.showModal();
1081
+ }
1082
+ // else {
1075
1083
  this.enableTrapsKeyboardFocus();
1084
+ // }
1076
1085
  } else if (phase === 'hide' || phase === 'teardown') {
1077
1086
  this.disableTrapsKeyboardFocus();
1078
1087
  }
@@ -1271,24 +1280,6 @@ export class OverlayController extends EventTargetShim {
1271
1280
 
1272
1281
  teardown() {
1273
1282
  this._handleFeatures({ phase: 'teardown' });
1274
-
1275
- if (this.placementMode === 'global' && this.__isContentNodeProjected) {
1276
- /** @type {HTMLElement} */ (this.__originalContentParent).appendChild(this.contentNode);
1277
- }
1278
-
1279
- // Remove the content node wrapper from the global rootnode
1280
- this._teardownContentWrapperNode();
1281
- }
1282
-
1283
- /** @protected */
1284
- _teardownContentWrapperNode() {
1285
- if (
1286
- this.placementMode === 'global' &&
1287
- this.contentWrapperNode &&
1288
- this.contentWrapperNode.parentNode
1289
- ) {
1290
- this.contentWrapperNode.parentNode.removeChild(this.contentWrapperNode);
1291
- }
1292
1283
  }
1293
1284
 
1294
1285
  /** @private */
@@ -1305,6 +1296,16 @@ export class OverlayController extends EventTargetShim {
1305
1296
  });
1306
1297
  }
1307
1298
  }
1299
+
1300
+ _hasDisabledInvoker() {
1301
+ if (this.invokerNode) {
1302
+ return (
1303
+ /** @type {HTMLElement & { disabled: boolean }} */ (this.invokerNode).disabled ||
1304
+ this.invokerNode.getAttribute('aria-disabled') === 'true'
1305
+ );
1306
+ }
1307
+ return false;
1308
+ }
1308
1309
  }
1309
1310
  /** @type {Promise<PopperModule> | undefined} */
1310
1311
  OverlayController.popperModule = undefined;