@lion/ui 0.21.1-menu-system.0 → 0.22.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 (185) hide show
  1. package/components/button/src/LionButton.js +0 -4
  2. package/components/form/test/lion-form.test.js +4 -3
  3. package/components/form-core/src/form-group/FormGroupMixin.js +37 -0
  4. package/components/form-core/test-suites/form-group/FormGroupMixin.suite.js +25 -0
  5. package/components/input-amount-dropdown/src/LionInputAmountDropdown.js +2 -2
  6. package/components/input-amount-dropdown/test/lion-input-amount-dropdown-integrations.test.js +12 -3
  7. package/components/input-amount-dropdown/test-suites/LionInputAmountDropdown.suite.js +10 -3
  8. package/components/overlays/src/OverlayController.js +111 -296
  9. package/components/overlays/src/OverlayMixin.js +17 -76
  10. package/components/overlays/src/utils/adopt-styles.js +1 -1
  11. package/components/overlays/src/utils/is-equal-config.js +6 -15
  12. package/components/overlays/test/OverlayController.test.js +24 -144
  13. package/components/overlays/test-suites/OverlayMixin.suite.js +8 -8
  14. package/components/overlays/types/ArrowMixinTypes.ts +3 -1
  15. package/components/overlays/types/OverlayConfig.ts +5 -20
  16. package/components/overlays/types/OverlayMixinTypes.ts +0 -2
  17. package/custom-elements.json +6260 -13587
  18. package/dist-types/components/button/src/LionButton.d.ts +0 -1
  19. package/dist-types/components/button/src/LionButton.d.ts.map +1 -1
  20. package/dist-types/components/combobox/src/LionCombobox.d.ts +1 -1
  21. package/dist-types/components/dialog/src/LionDialog.d.ts +2 -6
  22. package/dist-types/components/dialog/src/LionDialog.d.ts.map +1 -1
  23. package/dist-types/components/form-core/src/form-group/FormGroupMixin.d.ts +1 -0
  24. package/dist-types/components/form-core/src/form-group/FormGroupMixin.d.ts.map +1 -1
  25. package/dist-types/components/form-core/test-suites/form-group/FormGroupMixin.suite.d.ts.map +1 -1
  26. package/dist-types/components/input-amount-dropdown/test-suites/LionInputAmountDropdown.suite.d.ts.map +1 -1
  27. package/dist-types/components/input-datepicker/src/LionInputDatepicker.d.ts +1 -1
  28. package/dist-types/components/overlays/src/OverlayController.d.ts +5 -22
  29. package/dist-types/components/overlays/src/OverlayController.d.ts.map +1 -1
  30. package/dist-types/components/overlays/src/OverlayMixin.d.ts.map +1 -1
  31. package/dist-types/components/overlays/src/utils/is-equal-config.d.ts.map +1 -1
  32. package/dist-types/components/overlays/types/ArrowMixinTypes.d.ts.map +1 -1
  33. package/dist-types/components/overlays/types/OverlayConfig.d.ts +2 -12
  34. package/dist-types/components/overlays/types/OverlayConfig.d.ts.map +1 -1
  35. package/dist-types/components/overlays/types/OverlayMixinTypes.d.ts +0 -1
  36. package/dist-types/components/overlays/types/OverlayMixinTypes.d.ts.map +1 -1
  37. package/dist-types/components/select-rich/src/LionSelectRich.d.ts +2 -6
  38. package/dist-types/components/select-rich/src/LionSelectRich.d.ts.map +1 -1
  39. package/dist-types/components/tooltip/src/LionTooltip.d.ts +1 -1
  40. package/dist-types/exports/overlays.d.ts +0 -6
  41. package/dist-types/exports/overlays.d.ts.map +1 -1
  42. package/dist-types/tsconfig.tsbuildinfo +1 -1
  43. package/docs/components/checkbox-group/overview.md +2 -2
  44. package/docs/components/collapsible/overview.md +1 -1
  45. package/docs/components/combobox/api-table.md +39 -53
  46. package/docs/components/combobox/overview.md +1 -1
  47. package/docs/components/combobox/use-cases.md +1 -1
  48. package/docs/components/dialog/api-table.md +6 -32
  49. package/docs/components/dialog/overview.md +1 -1
  50. package/docs/components/fieldset/overview.md +5 -5
  51. package/docs/components/form/overview.md +3 -3
  52. package/docs/components/form/use-cases.md +2 -2
  53. package/docs/components/icon/use-cases.md +1 -1
  54. package/docs/components/input/overview.md +1 -1
  55. package/docs/components/input-amount/overview.md +3 -3
  56. package/docs/components/input-date/overview.md +3 -3
  57. package/docs/components/input-datepicker/api-table.md +45 -63
  58. package/docs/components/input-datepicker/overview.md +5 -5
  59. package/docs/components/input-email/overview.md +2 -2
  60. package/docs/components/input-file/overview.md +1 -1
  61. package/docs/components/input-iban/overview.md +2 -2
  62. package/docs/components/input-range/overview.md +2 -2
  63. package/docs/components/input-stepper/overview.md +1 -1
  64. package/docs/components/input-tel/overview.md +1 -1
  65. package/docs/components/input-tel/use-cases.md +6 -6
  66. package/docs/components/input-tel-dropdown/overview.md +1 -1
  67. package/docs/components/listbox/use-cases.md +1 -1
  68. package/docs/components/radio-group/overview.md +3 -3
  69. package/docs/components/select/use-cases.md +1 -1
  70. package/docs/components/select-rich/api-table.md +33 -50
  71. package/docs/components/select-rich/use-cases.md +2 -2
  72. package/docs/components/tabs/examples.md +1 -1
  73. package/docs/components/tooltip/api-table.md +7 -33
  74. package/docs/fundamentals/index.md +4 -4
  75. package/docs/fundamentals/node-tools/publish-docs/overview.md +3 -3
  76. package/docs/fundamentals/node-tools/rocket-preset-extend-lion-docs/overview.md +2 -2
  77. package/docs/fundamentals/rationales/accessibility.md +1 -1
  78. package/docs/fundamentals/systems/core/SlotMixin.md +1 -1
  79. package/docs/fundamentals/systems/core/overview.md +1 -1
  80. package/docs/fundamentals/systems/form/formatting-and-parsing.md +4 -4
  81. package/docs/fundamentals/systems/form/model-value.md +1 -1
  82. package/docs/fundamentals/systems/form/overview.md +28 -28
  83. package/docs/fundamentals/systems/form/validate.md +2 -2
  84. package/docs/fundamentals/systems/localize/overview.md +4 -4
  85. package/docs/fundamentals/systems/overlays/api-table.md +43 -46
  86. package/docs/fundamentals/systems/overlays/configuration.md +2 -2
  87. package/docs/fundamentals/systems/overlays/overview.md +5 -5
  88. package/docs/fundamentals/systems/overlays/use-cases.md +2 -2
  89. package/docs/fundamentals/tools/helpers/overview.md +1 -1
  90. package/docs/fundamentals/tools/singleton-manager/overview.md +4 -4
  91. package/docs/guides/how-to/create-a-custom-field.md +5 -5
  92. package/docs/guides/how-to/create-a-form.md +4 -4
  93. package/docs/guides/how-to/extend-a-native-input.md +2 -2
  94. package/docs/guides/how-to/index.md +1 -1
  95. package/docs/guides/index.md +8 -8
  96. package/docs/guides/principles/index.md +5 -5
  97. package/docs/guides/principles/styling.md +1 -1
  98. package/exports/overlays.js +0 -6
  99. package/overlays.js +0 -6
  100. package/package.json +6 -2
  101. package/vscode.css-custom-data.json +5 -0
  102. package/vscode.html-custom-data.json +789 -0
  103. package/web-types.json +2016 -0
  104. package/components/menu/CHANGELOG.md +0 -37
  105. package/components/menu/README.md +0 -334
  106. package/components/menu/index.js +0 -2
  107. package/components/menu/lion-menu.js +0 -3
  108. package/components/menu/package.json +0 -46
  109. package/components/menu/requirements.temp.md +0 -12
  110. package/components/menu/src/InteractiveListMixin.js +0 -840
  111. package/components/menu/src/LionMenu.js +0 -421
  112. package/components/menu/src/MoreButtonMenuMixin.js +0 -278
  113. package/components/menu/src/MultiLevelListMixin.js +0 -305
  114. package/components/menu/src/utils/isInView.js +0 -26
  115. package/components/menu/src/utils/listItemInteractions.js +0 -124
  116. package/components/menu/test/InteractiveListMixin.test.js +0 -3
  117. package/components/menu/test/MoreButtonMenuMixin.test.js +0 -4
  118. package/components/menu/test/MultiLevelListMixin.test.js +0 -3
  119. package/components/menu/test/lion-menu-interactions.test.js +0 -3
  120. package/components/menu/test/lion-menu.test.js +0 -14
  121. package/components/menu/test-helpers/mimicKeyPress.js +0 -9
  122. package/components/menu/test-suites/InteractiveListMixin.suite.js +0 -454
  123. package/components/menu/test-suites/LionMenu.suite.js +0 -114
  124. package/components/menu/test-suites/LionMenuInteractions.suite.js +0 -583
  125. package/components/menu/test-suites/MoreButtonMenuMixin.suite.js +0 -372
  126. package/components/menu/test-suites/MultiLevelListMixin.suite.js +0 -303
  127. package/components/menu/types/InteractiveListMixinTypes.d.ts +0 -84
  128. package/components/overlays/NEXT.md +0 -49
  129. package/dist-types/components/menu/index.d.ts +0 -3
  130. package/dist-types/components/menu/index.d.ts.map +0 -1
  131. package/dist-types/components/menu/lion-menu.d.ts +0 -2
  132. package/dist-types/components/menu/lion-menu.d.ts.map +0 -1
  133. package/dist-types/components/menu/src/MoreButtonMenuMixin.d.ts +0 -39
  134. package/dist-types/components/menu/src/MoreButtonMenuMixin.d.ts.map +0 -1
  135. package/dist-types/components/menu/src/utils/isInView.d.ts +0 -9
  136. package/dist-types/components/menu/src/utils/isInView.d.ts.map +0 -1
  137. package/dist-types/components/menu/src/utils/listItemInteractions.d.ts +0 -48
  138. package/dist-types/components/menu/src/utils/listItemInteractions.d.ts.map +0 -1
  139. package/dist-types/components/menu/test/InteractiveListMixin.test.d.ts +0 -2
  140. package/dist-types/components/menu/test/InteractiveListMixin.test.d.ts.map +0 -1
  141. package/dist-types/components/menu/test/MoreButtonMenuMixin.test.d.ts +0 -2
  142. package/dist-types/components/menu/test/MoreButtonMenuMixin.test.d.ts.map +0 -1
  143. package/dist-types/components/menu/test/MultiLevelListMixin.test.d.ts +0 -2
  144. package/dist-types/components/menu/test/MultiLevelListMixin.test.d.ts.map +0 -1
  145. package/dist-types/components/menu/test/lion-menu-interactions.test.d.ts +0 -2
  146. package/dist-types/components/menu/test/lion-menu-interactions.test.d.ts.map +0 -1
  147. package/dist-types/components/menu/test/lion-menu.test.d.ts +0 -2
  148. package/dist-types/components/menu/test/lion-menu.test.d.ts.map +0 -1
  149. package/dist-types/components/menu/test-helpers/mimicKeyPress.d.ts +0 -7
  150. package/dist-types/components/menu/test-helpers/mimicKeyPress.d.ts.map +0 -1
  151. package/dist-types/components/menu/test-suites/InteractiveListMixin.suite.d.ts +0 -11
  152. package/dist-types/components/menu/test-suites/InteractiveListMixin.suite.d.ts.map +0 -1
  153. package/dist-types/components/menu/test-suites/LionMenu.suite.d.ts +0 -9
  154. package/dist-types/components/menu/test-suites/LionMenu.suite.d.ts.map +0 -1
  155. package/dist-types/components/menu/test-suites/LionMenuInteractions.suite.d.ts +0 -5
  156. package/dist-types/components/menu/test-suites/LionMenuInteractions.suite.d.ts.map +0 -1
  157. package/dist-types/components/menu/test-suites/MoreButtonMenuMixin.suite.d.ts +0 -11
  158. package/dist-types/components/menu/test-suites/MoreButtonMenuMixin.suite.d.ts.map +0 -1
  159. package/dist-types/components/menu/test-suites/MultiLevelListMixin.suite.d.ts +0 -11
  160. package/dist-types/components/menu/test-suites/MultiLevelListMixin.suite.d.ts.map +0 -1
  161. package/dist-types/exports/define/lion-item.d.ts +0 -2
  162. package/dist-types/exports/define/lion-item.d.ts.map +0 -1
  163. package/dist-types/exports/define/lion-menu.d.ts +0 -2
  164. package/dist-types/exports/define/lion-menu.d.ts.map +0 -1
  165. package/dist-types/exports/menu-test-suites.d.ts +0 -4
  166. package/dist-types/exports/menu-test-suites.d.ts.map +0 -1
  167. package/dist-types/exports/menu.d.ts +0 -3
  168. package/dist-types/exports/menu.d.ts.map +0 -1
  169. package/docs/components/menu/api-table.md +0 -121
  170. package/docs/components/menu/applyMenuDemoStyles.js +0 -173
  171. package/docs/components/menu/extensions.md +0 -262
  172. package/docs/components/menu/index.md +0 -13
  173. package/docs/components/menu/overview.md +0 -422
  174. package/docs/components/menu/src/DemoNavigationBar.js +0 -441
  175. package/docs/components/menu/src/DemoSpinButton.js +0 -215
  176. package/docs/components/menu/src/DemoToolbar.js +0 -101
  177. package/docs/components/menu/src/DemoTree.js +0 -55
  178. package/docs/components/menu/src/navigation-bar-types.js +0 -41
  179. package/docs/components/menu/use-cases.md +0 -74
  180. package/exports/define/lion-item.js +0 -3
  181. package/exports/define/lion-menu.js +0 -3
  182. package/exports/menu-test-suites.js +0 -4
  183. package/exports/menu.js +0 -3
  184. package/menu-test-suites.js +0 -4
  185. package/menu.js +0 -3
@@ -1,5 +1,6 @@
1
1
  import { dedupeMixin } from '@open-wc/dedupe-mixin';
2
2
  import { OverlayController } from './OverlayController.js';
3
+ import { isEqualConfig } from './utils/is-equal-config.js';
3
4
 
4
5
  /**
5
6
  * @typedef {<T>(ingOverlayHost:T) => void} PostProcessor
@@ -31,7 +32,10 @@ export const OverlayMixinImplementation = superclass => {
31
32
  class OverlayMixin extends superclass {
32
33
  static get properties() {
33
34
  return {
34
- opened: { type: Boolean, reflect: true },
35
+ opened: {
36
+ type: Boolean,
37
+ reflect: true,
38
+ },
35
39
  };
36
40
  }
37
41
 
@@ -65,13 +69,13 @@ export const OverlayMixinImplementation = superclass => {
65
69
 
66
70
  /** @param {OverlayConfig} value */
67
71
  set config(value) {
68
- // The OverlayController already guards against redundant updates
69
- // (see OverlayController#updateConfig), so we delegate unconditionally here.
70
- if (this._overlayCtrl) {
72
+ const shouldUpdate = !isEqualConfig(this.config, value);
73
+
74
+ if (this._overlayCtrl && shouldUpdate) {
71
75
  this._overlayCtrl.updateConfig(value);
72
76
  }
73
77
  this.__config = value;
74
- if (this._overlayCtrl) {
78
+ if (this._overlayCtrl && shouldUpdate) {
75
79
  this.__syncToOverlayController();
76
80
  }
77
81
  }
@@ -156,8 +160,6 @@ export const OverlayMixinImplementation = superclass => {
156
160
  */
157
161
  // eslint-disable-next-line class-methods-use-this
158
162
  _setupOpenCloseListeners() {
159
- // Keeps the close-overlay event private for the controller.
160
- // (we already have )
161
163
  /**
162
164
  * @param {{ stopPropagation: () => void; }} ev
163
165
  */
@@ -215,6 +217,12 @@ export const OverlayMixinImplementation = superclass => {
215
217
  // @ts-expect-error
216
218
  static enabledWarnings = super.enabledWarnings?.filter(w => w !== 'change-in-update') || [];
217
219
 
220
+ get _overlayInvokerNode() {
221
+ return /** @type {HTMLElement | undefined} */ (
222
+ Array.from(this.children).find(child => child.slot === 'invoker')
223
+ );
224
+ }
225
+
218
226
  /**
219
227
  * @overridable
220
228
  */
@@ -247,77 +255,13 @@ export const OverlayMixinImplementation = superclass => {
247
255
  );
248
256
  }
249
257
 
250
- /**
251
- * Returns the element that can actually receive focus inside the passed
252
- * invoker (wrapper) element: the element itself when it is focusable,
253
- * otherwise the first focusable descendant.
254
- * @param {Element|null|undefined} focusableElOrWrapper
255
- * @returns {Element|null}
256
- */
257
- static _getFocusableInvokerEl(focusableElOrWrapper) {
258
- if (!focusableElOrWrapper) return null;
259
- const focusableSelector = '[tabindex], button, a[href], [role=button]';
260
- return focusableElOrWrapper.matches(focusableSelector)
261
- ? focusableElOrWrapper
262
- : focusableElOrWrapper.querySelector(focusableSelector);
263
- }
264
-
265
- /**
266
- * The node that opens/closes this overlay.
267
- *
268
- * Resolved in a stable, declarative way (independent of the exact DOM order)
269
- * by looking, in order, for:
270
- * 1. a child with `[slot="invoker"]`
271
- * 2. any element in the same root that opts in via `[data-invoker]` and
272
- * references this host by id (`for="<id>"`)
273
- * 3. a preceding sibling that opts in via `[data-invoker]`
274
- * @protected
275
- */
276
- get _overlayInvokerNode() {
277
- if (!this.__invokerNode) {
278
- this.__invokerNode = this._getInvokerNode();
279
- }
280
- return this.__invokerNode;
281
- }
282
-
283
- /**
284
- * @protected
285
- * @returns {Element|null}
286
- */
287
- _getInvokerNode() {
288
- const ctor = /** @type {typeof OverlayMixin} */ (this.constructor);
289
-
290
- const slottedNode = Array.from(this.children).find(child => child.slot === 'invoker');
291
- if (slottedNode) {
292
- return ctor._getFocusableInvokerEl(slottedNode);
293
- }
294
-
295
- if (this.id) {
296
- // Reference the invoker declaratively: `<button data-invoker for="my-menu">`
297
- const root = /** @type {Document|ShadowRoot} */ (this.getRootNode());
298
- const explicitInvoker = root.querySelector?.(`[data-invoker][for="${this.id}"]`);
299
- if (explicitInvoker) {
300
- return ctor._getFocusableInvokerEl(explicitInvoker);
301
- }
302
- }
303
-
304
- // Fall back to a preceding sibling that opted in via [data-invoker]
305
- const { previousElementSibling } = this;
306
- return previousElementSibling && previousElementSibling.hasAttribute('data-invoker')
307
- ? ctor._getFocusableInvokerEl(previousElementSibling)
308
- : null;
309
- }
310
-
311
258
  /** @protected */
312
259
  _setupOverlayCtrl() {
313
260
  if (this.#hasSetup) return;
314
-
315
- const invokerNode = this._overlayInvokerNode;
316
-
317
261
  const config = {
318
262
  contentNode: this._overlayContentNode,
319
263
  contentWrapperNode: this._overlayContentWrapperNode,
320
- invokerNode: invokerNode && invokerNode instanceof HTMLElement ? invokerNode : undefined,
264
+ invokerNode: this._overlayInvokerNode,
321
265
  referenceNode: this._overlayReferenceNode,
322
266
  backdropNode: this._overlayBackdropNode,
323
267
  };
@@ -338,8 +282,6 @@ export const OverlayMixinImplementation = superclass => {
338
282
 
339
283
  /** @protected */
340
284
  _teardownOverlayCtrl() {
341
- // Make sure that dynamic behavior (e.g. responsive) is possible by allowing multiple setups and teardowns of the overlay controller.
342
- this.#hasSetup = false;
343
285
  if (!this._overlayCtrl) return;
344
286
 
345
287
  this._teardownOpenCloseListeners();
@@ -492,7 +434,6 @@ export const OverlayMixinImplementation = superclass => {
492
434
  for (const postProcessor of overlayMixinPostProcessors) {
493
435
  postProcessor(OverlayMixin);
494
436
  }
495
- // @ts-ignore https://github.com/microsoft/TypeScript/issues/36821#issuecomment-588375051
496
- return OverlayMixin;
437
+ return /** @type {* & OverlayMixin} */ (OverlayMixin);
497
438
  };
498
439
  export const OverlayMixin = dedupeMixin(OverlayMixinImplementation);
@@ -124,7 +124,7 @@ export function adoptStyle(renderRoot, style, { teardown = false } = {}) {
124
124
  if (!teardown) {
125
125
  // @ts-ignore
126
126
  // eslint-disable-next-line no-param-reassign
127
- renderRoot.adoptedStyleSheets = [...(renderRoot.adoptedStyleSheets || []), sheet];
127
+ renderRoot.adoptedStyleSheets = [...renderRoot.adoptedStyleSheets, sheet];
128
128
  } else if (renderRoot.adoptedStyleSheets.includes(sheet)) {
129
129
  // @ts-ignore
130
130
  // eslint-disable-next-line no-param-reassign
@@ -12,24 +12,15 @@
12
12
  */
13
13
  export function isEqualConfig(a, b) {
14
14
  if (typeof a !== 'object' || typeof b !== 'object' || a === null || b === null) {
15
- if (typeof a === 'function' && typeof b === 'function') {
16
- return /** @type {Function} */ (a).toString() === /** @type {Function} */ (b).toString();
17
- }
18
15
  return a === b;
19
16
  }
20
- if (a instanceof Node && b instanceof Node) {
21
- return a === b;
22
- }
23
-
24
- const aProps = Object.keys(a);
25
- const bProps = Object.keys(b);
17
+ const aObj = /** @type {Record<string, any>} */ (a);
18
+ const bObj = /** @type {Record<string, any>} */ (b);
19
+ const aProps = Object.keys(aObj);
20
+ const bProps = Object.keys(bObj);
26
21
  if (aProps.length !== bProps.length) {
27
22
  return false;
28
23
  }
29
- return aProps.every(
30
- prop =>
31
- Object.prototype.hasOwnProperty.call(b, prop) &&
32
- // @ts-ignore - dynamic property access
33
- isEqualConfig(a[prop], b[prop]),
34
- );
24
+ const isEqual = /** @param {string} prop */ prop => isEqualConfig(aObj[prop], bObj[prop]);
25
+ return aProps.every(isEqual);
35
26
  }
@@ -115,35 +115,26 @@ const withLocalTestConfig = () =>
115
115
  */
116
116
  async function createNestedEscControllers(parentContent) {
117
117
  const childContent = /** @type {HTMLDivElement} */ (parentContent.querySelector('div[id]'));
118
+ // Assert valid fixure
119
+ const isValidFixture =
120
+ (parentContent.id.startsWith('parent-overlay--hidesOnEsc') ||
121
+ parentContent.id.startsWith('parent-overlay--hidesOnOutsideEsc')) &&
122
+ (childContent.id.startsWith('child-overlay--hidesOnEsc') ||
123
+ childContent.id.startsWith('child-overlay--hidesOnOutsideEsc'));
124
+ if (!isValidFixture) {
125
+ throw new Error('Provide a valid fixture');
126
+ }
118
127
 
119
128
  if (parentContent.hasAttribute('data-convert-to-shadow-root')) {
120
129
  const shadowRootParent = parentContent.attachShadow({ mode: 'open' });
121
130
  shadowRootParent.appendChild(childContent);
122
131
  }
123
132
 
124
- const parentConfig = {};
125
- const childConfig = {};
126
-
127
133
  const parentHasOutsideOnEsc = parentContent.id.startsWith('parent-overlay--hidesOnOutsideEsc');
128
134
  const childHasOutsideOnEsc = childContent.id.startsWith('child-overlay--hidesOnOutsideEsc');
129
135
 
130
- if (parentHasOutsideOnEsc) {
131
- parentConfig.hidesOnOutsideEsc = true;
132
- } else {
133
- parentConfig.hidesOnEsc = true;
134
- }
135
- if (childHasOutsideOnEsc) {
136
- childConfig.hidesOnOutsideEsc = true;
137
- } else {
138
- childConfig.hidesOnEsc = true;
139
- }
140
-
141
- const parentHasSyncChildrenCloseState =
142
- parentContent.dataset.syncChildrenCloseState !== undefined;
143
-
144
- if (parentHasSyncChildrenCloseState) {
145
- parentConfig.syncChildrenCloseState = true;
146
- }
136
+ const parentConfig = parentHasOutsideOnEsc ? { hidesOnOutsideEsc: true } : { hidesOnEsc: true };
137
+ const childConfig = childHasOutsideOnEsc ? { hidesOnOutsideEsc: true } : { hidesOnEsc: true };
147
138
 
148
139
  const parentOverlay = new OverlayController({
149
140
  ...withGlobalTestConfig(),
@@ -292,9 +283,8 @@ describe('OverlayController', () => {
292
283
  contentNode,
293
284
  });
294
285
  };
295
-
296
286
  expect(createOverlayController).to.throw(
297
- '[OverlayController] Could not find a render target, makes sure contentNode has a parent element (or contentWrapperNode is connected)',
287
+ '[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.',
298
288
  );
299
289
  });
300
290
 
@@ -356,21 +346,6 @@ describe('OverlayController', () => {
356
346
  await ctrl.hide();
357
347
  expect(ctrl.isShown).to.be.false;
358
348
  });
359
-
360
- it('cleans up the dom structure it created', async () => {
361
- const contentNode = /** @type {HTMLElement} */ (fixtureSync(html`<div>my content</div>`));
362
- const ctrl = new OverlayController({
363
- placementMode: 'global',
364
- contentNode,
365
- });
366
- await ctrl.show();
367
- expect(ctrl.contentWrapperNode).to.exist;
368
- expect(ctrl.__wrappingDialogNode).to.exist;
369
-
370
- await ctrl.teardown();
371
- expect(ctrl.contentWrapperNode).to.not.exist;
372
- expect(ctrl.__wrappingDialogNode).to.not.exist;
373
- });
374
349
  });
375
350
 
376
351
  describe('Node Configuration', () => {
@@ -428,7 +403,7 @@ describe('OverlayController', () => {
428
403
  { ignoreAttributes: ['closedby'] },
429
404
  );
430
405
 
431
- expect(el).lightDom.to.equal(`<div data-content="" slot="content">projected</div>`);
406
+ expect(el).lightDom.to.equal(`<div slot="content">projected</div>`);
432
407
  });
433
408
  });
434
409
 
@@ -450,7 +425,7 @@ describe('OverlayController', () => {
450
425
  `
451
426
  <dialog data-overlay-outer-wrapper="" open="" role="none" style="${wrappingDialogNodeStyle}">
452
427
  <div data-id="content-wrapper">
453
- <div data-content="" id="content">non projected</div>
428
+ <div id="content">non projected</div>
454
429
  </div>
455
430
  </dialog>
456
431
  `,
@@ -645,7 +620,6 @@ describe('OverlayController', () => {
645
620
  });
646
621
  });
647
622
 
648
- // TODO: make features modular (so they can be treeshaken) and test their lifecycle within this desrcibe
649
623
  describe('Feature Configuration', () => {
650
624
  describe('trapsKeyboardFocus', () => {
651
625
  it('focuses the overlay on show', async () => {
@@ -889,7 +863,10 @@ describe('OverlayController', () => {
889
863
 
890
864
  describe('Nested hidesOnEsc / hidesOnOutsideEsc', () => {
891
865
  describe('Parent has hidesOnEsc and child has hidesOnOutsideEsc', () => {
892
- it('on [Escape] press in child overlay: parent hides, child stays shown', async () => {
866
+ // TODO: This test is flaky. We need to investigate why the child overlay
867
+ // is not staying shown after the parent overlay is hidden. The failing line
868
+ // is highlighted below.
869
+ it.skip('on [Escape] press in child overlay: parent hides, child stays shown', async () => {
893
870
  const parentContent = /** @type {HTMLDivElement} */ (
894
871
  await fixture(
895
872
  html` <!-- -->
@@ -900,16 +877,12 @@ describe('OverlayController', () => {
900
877
  );
901
878
  const { parentOverlay, childOverlay } = await createNestedEscControllers(parentContent);
902
879
  await mimicEscapePress(childOverlay.contentNode);
903
- await childOverlay._showComplete;
904
- await parentOverlay._showComplete;
905
- await childOverlay._hideComplete;
906
- await parentOverlay._hideComplete;
907
- if (!childOverlay.isShown) {
908
- await waitUntil(() => childOverlay.isShown);
909
- }
910
- if (parentOverlay.isShown) {
911
- await waitUntil(() => !parentOverlay.isShown);
912
- }
880
+ await waitUntil(() => !parentOverlay.isShown);
881
+
882
+ // TODO: This is the failing line ("sometimes").
883
+ // The child overlay is not staying shown after the parent overlay is hidden.
884
+ await waitUntil(() => childOverlay.isShown);
885
+
913
886
  await childOverlay.teardown();
914
887
  await parentOverlay.teardown();
915
888
  });
@@ -1015,7 +988,6 @@ describe('OverlayController', () => {
1015
988
  });
1016
989
  });
1017
990
  });
1018
-
1019
991
  describe('hidesOnOutsideClick', () => {
1020
992
  it('hides on outside click', async () => {
1021
993
  const contentNode = /** @type {HTMLElement} */ (await fixture('<div>Content</div>'));
@@ -1736,97 +1708,6 @@ describe('OverlayController', () => {
1736
1708
  expect(ctrl1.hasActiveBackdrop).to.be.true;
1737
1709
  });
1738
1710
  });
1739
-
1740
- describe('elementToFocusOnShow', () => {
1741
- it('adds tabindex="-1" to the content node when elementToFocusOnShow is true', async () => {
1742
- const ctrl = new OverlayController({
1743
- ...withGlobalTestConfig(),
1744
- isBlocking: false,
1745
- elementToFocusOnShow: true,
1746
- });
1747
- const contentNode = /** @type {HTMLElement} */ (await fixture('<div>Content</div>'));
1748
- ctrl.updateConfig({ contentNode });
1749
- await ctrl.show();
1750
- expect(contentNode.getAttribute('tabindex')).to.equal('-1');
1751
- });
1752
-
1753
- it('makes contentNode the root of "next tab flow"', async () => {
1754
- const ctrl = new OverlayController({
1755
- ...withGlobalTestConfig(),
1756
- isBlocking: false,
1757
- elementToFocusOnShow: true,
1758
- });
1759
- const contentNode = /** @type {HTMLElement} */ (
1760
- await fixture('<div><button>Button</button></div>')
1761
- );
1762
- ctrl.updateConfig({ contentNode });
1763
- await ctrl.show();
1764
- const button = /** @type {HTMLButtonElement} */ (contentNode.querySelector('button'));
1765
- button.focus();
1766
- expect(isActiveElement(button)).to.be.true;
1767
- });
1768
- });
1769
-
1770
- describe('syncChildrenCloseState', () => {
1771
- it('does not close all children of nested controllers when syncChildrenCloseState is false', async () => {
1772
- const parentContent = /** @type {HTMLDivElement} */ (
1773
- await fixture(
1774
- html` <!-- -->
1775
- <div data-sync-children-close-state id="parent-overlay">
1776
- <div id="child-overlay">we open our child and it will close when parent does</div>
1777
- </div>`,
1778
- )
1779
- );
1780
- const { parentOverlay, childOverlay } = await createNestedEscControllers(parentContent);
1781
- expect(parentOverlay.isShown).to.be.true;
1782
- expect(childOverlay.isShown).to.be.true;
1783
-
1784
- await parentOverlay.hide();
1785
- await childOverlay._hideComplete;
1786
- expect(parentOverlay.isShown).to.be.false;
1787
- expect(childOverlay.isShown).to.be.false;
1788
- });
1789
-
1790
- it('does not close all children of nested controllers when syncChildrenCloseState is false', async () => {
1791
- const parentContent = /** @type {HTMLDivElement} */ (
1792
- await fixture(
1793
- html` <!-- -->
1794
- <div id="parent-overlay">
1795
- <div id="child-overlay">
1796
- we open our child and it will not close when parent does
1797
- </div>
1798
- </div>`,
1799
- )
1800
- );
1801
- const { parentOverlay, childOverlay } = await createNestedEscControllers(parentContent);
1802
- expect(parentOverlay.isShown).to.be.true;
1803
- expect(childOverlay.isShown).to.be.true;
1804
-
1805
- await parentOverlay.hide();
1806
- expect(parentOverlay.isShown).to.be.false;
1807
- expect(childOverlay.isShown).to.be.true;
1808
- });
1809
- });
1810
-
1811
- describe('isActivated', () => {
1812
- it('allows to conditionally disable overlay/openable functionality (for responsive context like nav menus, accordions/collapsibles vs plain headings/content etc.)', async () => {
1813
- const ctrl = new OverlayController({
1814
- ...withGlobalTestConfig(),
1815
- isActivated: false,
1816
- });
1817
- expect(ctrl.__hasSetup).to.be.false;
1818
- ctrl.updateConfig({
1819
- isActivated: true,
1820
- });
1821
- expect(ctrl.__hasSetup).to.be.true;
1822
- });
1823
- });
1824
-
1825
- // TODO
1826
- describe('hideVisually', () => {});
1827
-
1828
- // TODO
1829
- describe('requireConnectedNodes', () => {});
1830
1711
  });
1831
1712
 
1832
1713
  describe('Show / Hide / Toggle', () => {
@@ -2417,7 +2298,6 @@ describe('OverlayController', () => {
2417
2298
  });
2418
2299
 
2419
2300
  it('should run with scroll prevention', async () => {
2420
- await overlayControllerPreventsScroll.hide();
2421
2301
  await overlayControllerPreventsScroll.show();
2422
2302
 
2423
2303
  expect(
@@ -540,13 +540,13 @@ export function runOverlayMixinSuite({ tagString, tag, suffix = '' }) {
540
540
  it('works with cache directive when reconnected', async () => {
541
541
  class CachingContext extends LitElement {
542
542
  static properties = {
543
- showOverlay: { type: Boolean },
543
+ switched: { type: Boolean },
544
544
  };
545
545
 
546
546
  constructor() {
547
547
  super();
548
548
 
549
- this.showOverlay = true;
549
+ this.switched = false;
550
550
  }
551
551
 
552
552
  get overlayEl() {
@@ -555,12 +555,12 @@ export function runOverlayMixinSuite({ tagString, tag, suffix = '' }) {
555
555
 
556
556
  render() {
557
557
  return html`${cache(
558
- this.showOverlay
559
- ? html`<${tag} id="myOverlay">
558
+ this.switched
559
+ ? html`something else`
560
+ : html`<${tag} id="myOverlay">
560
561
  <div slot="content">content b</div>
561
562
  <button slot="invoker">invoker button b</button>
562
- </${tag}>`
563
- : html`something else`,
563
+ </${tag}>`,
564
564
  )}`;
565
565
  }
566
566
  }
@@ -581,7 +581,7 @@ export function runOverlayMixinSuite({ tagString, tag, suffix = '' }) {
581
581
  // @ts-expect-error [allow-protected] in tests
582
582
  const setupSpy = sinon.spy(el.overlayEl, '_setupOverlayCtrl');
583
583
 
584
- el.showOverlay = false;
584
+ el.switched = true;
585
585
  // render the new content
586
586
  await el.updateComplete;
587
587
  // wait for the teardown to complete
@@ -591,7 +591,7 @@ export function runOverlayMixinSuite({ tagString, tag, suffix = '' }) {
591
591
  expect(teardownSpy.callCount).to.equal(1);
592
592
  expect(setupSpy.callCount).to.equal(0);
593
593
 
594
- el.showOverlay = true;
594
+ el.switched = false;
595
595
  await el.updateComplete;
596
596
  expect(setupSpy.callCount).to.equal(1);
597
597
 
@@ -26,7 +26,9 @@ export declare class ArrowHost {
26
26
 
27
27
  protected _defineOverlayConfig(): OverlayConfig;
28
28
 
29
- protected _getPopperArrowConfig(popperConfigToExtendFrom: Partial<PopperOptions>): Partial<PopperOptions>;
29
+ protected _getPopperArrowConfig(
30
+ popperConfigToExtendFrom: Partial<PopperOptions>,
31
+ ): Partial<PopperOptions>;
30
32
 
31
33
  private __setupRepositionCompletePromise(): void;
32
34
 
@@ -21,6 +21,7 @@ export type OverlayPhase =
21
21
  | 'add'
22
22
  | 'remove';
23
23
 
24
+
24
25
  export interface ViewportConfig {
25
26
  placement: ViewportPlacement;
26
27
  }
@@ -96,30 +97,14 @@ export interface OverlayConfig {
96
97
  /** By default, the tooltip content is a 'description' for the invoker (uses aria-describedby) Setting this property to 'label' makes the content function as a label (via aria-labelledby) */
97
98
  invokerRelation?: 'label' | 'description';
98
99
 
100
+ /** render a div instead of dialog */
101
+ _noDialogEl?: Boolean;
102
+
99
103
  /**
100
104
  * Determines the conditions hiding/showing should be based on. It gets the OverlayController as input and returns an object with
101
105
  * functions with Overlay phases as keys
102
106
  */
103
107
  visibilityTriggerFunction?: Function;
108
+ }
104
109
 
105
- /**
106
- * Whether the overlay content should receive focus when shown.
107
- */
108
- elementToFocusOnShow?: boolean;
109
-
110
- /*
111
- * By default, we function either as overlay or disclosure. In some cases, this should be dynamically set (think of responsive changes).
112
- * or it depends on the context (a top level menu is not openable (unless it's a context menu), its children menus are).
113
- */
114
- isActivated?: boolean;
115
-
116
- /**
117
- * By default, an error is thrown when contentNode is not connected to the DOM.
118
- * This allows to prepare nodes and later connect them to dom.
119
- */
120
- requireConnectedNodes?: boolean;
121
-
122
- syncChildrenCloseState?: boolean;
123
110
 
124
- _shouldTeardownDomStructure?: boolean;
125
- }
@@ -17,8 +17,6 @@ export interface DefineOverlayConfig {
17
17
  }
18
18
 
19
19
  export declare class OverlayHost {
20
- static _getFocusableInvokerEl(focusableElOrWrapper: Element): Element | null;
21
-
22
20
  opened: Boolean;
23
21
  get config(): Partial<OverlayConfig>;
24
22
  set config(value: Partial<OverlayConfig>);