@lion/ui 0.15.0 → 0.15.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 (265) hide show
  1. package/README.md +38 -12
  2. package/components/combobox/test/lion-combobox.test.js +50 -2
  3. package/components/core/src/SlotMixin.js +52 -0
  4. package/components/core/test/SlotMixin.test.js +85 -0
  5. package/components/dialog/test/lion-dialog.integration.test.js +170 -0
  6. package/components/input-amount-dropdown/src/localizeNamespaceLoader.js +53 -0
  7. package/components/input-amount-dropdown/translations/bg.js +5 -0
  8. package/components/input-amount-dropdown/translations/cs.js +5 -0
  9. package/components/input-amount-dropdown/translations/de.js +5 -0
  10. package/components/input-amount-dropdown/translations/es.js +5 -0
  11. package/components/input-amount-dropdown/translations/fr.js +5 -0
  12. package/components/input-amount-dropdown/translations/hu.js +5 -0
  13. package/components/input-amount-dropdown/translations/id.js +5 -0
  14. package/components/input-amount-dropdown/translations/it.js +5 -0
  15. package/components/input-amount-dropdown/translations/nl.js +5 -0
  16. package/components/input-amount-dropdown/translations/pl.js +5 -0
  17. package/components/input-amount-dropdown/translations/ro.js +5 -0
  18. package/components/input-amount-dropdown/translations/ru.js +5 -0
  19. package/components/input-amount-dropdown/translations/sk.js +5 -0
  20. package/components/input-amount-dropdown/translations/uk.js +5 -0
  21. package/components/input-amount-dropdown/translations/zh.js +5 -0
  22. package/components/listbox/src/ListboxMixin.js +3 -35
  23. package/components/overlays/src/ArrowMixin.js +10 -4
  24. package/components/overlays/src/OverlayController.js +34 -7
  25. package/components/overlays/test/OverlayController.test.js +4 -1
  26. package/components/overlays/test/OverlayMixin.test.js +2 -2
  27. package/components/overlays/test-suites/OverlayMixin.suite.js +57 -0
  28. package/custom-elements.json +2969 -207
  29. package/dist-types/components/core/src/ScopedElementsMixin.d.ts.map +1 -1
  30. package/dist-types/components/core/src/SlotMixin.d.ts +35 -0
  31. package/dist-types/components/core/src/SlotMixin.d.ts.map +1 -1
  32. package/dist-types/components/core/test/SlotMixin.test.d.ts.map +1 -1
  33. package/dist-types/components/dialog/test/lion-dialog.integration.test.d.ts +3 -0
  34. package/dist-types/components/dialog/test/lion-dialog.integration.test.d.ts.map +1 -0
  35. package/dist-types/components/input-amount-dropdown/src/localizeNamespaceLoader.d.ts +1 -1
  36. package/dist-types/components/input-amount-dropdown/src/localizeNamespaceLoader.d.ts.map +1 -1
  37. package/dist-types/components/input-amount-dropdown/translations/bg.d.ts +7 -0
  38. package/dist-types/components/input-amount-dropdown/translations/bg.d.ts.map +1 -0
  39. package/dist-types/components/input-amount-dropdown/translations/cs.d.ts +7 -0
  40. package/dist-types/components/input-amount-dropdown/translations/cs.d.ts.map +1 -0
  41. package/dist-types/components/input-amount-dropdown/translations/de.d.ts +7 -0
  42. package/dist-types/components/input-amount-dropdown/translations/de.d.ts.map +1 -0
  43. package/dist-types/components/input-amount-dropdown/translations/es.d.ts +7 -0
  44. package/dist-types/components/input-amount-dropdown/translations/es.d.ts.map +1 -0
  45. package/dist-types/components/input-amount-dropdown/translations/fr.d.ts +7 -0
  46. package/dist-types/components/input-amount-dropdown/translations/fr.d.ts.map +1 -0
  47. package/dist-types/components/input-amount-dropdown/translations/hu.d.ts +7 -0
  48. package/dist-types/components/input-amount-dropdown/translations/hu.d.ts.map +1 -0
  49. package/dist-types/components/input-amount-dropdown/translations/id.d.ts +7 -0
  50. package/dist-types/components/input-amount-dropdown/translations/id.d.ts.map +1 -0
  51. package/dist-types/components/input-amount-dropdown/translations/it.d.ts +7 -0
  52. package/dist-types/components/input-amount-dropdown/translations/it.d.ts.map +1 -0
  53. package/dist-types/components/input-amount-dropdown/translations/nl.d.ts +7 -0
  54. package/dist-types/components/input-amount-dropdown/translations/nl.d.ts.map +1 -0
  55. package/dist-types/components/input-amount-dropdown/translations/pl.d.ts +7 -0
  56. package/dist-types/components/input-amount-dropdown/translations/pl.d.ts.map +1 -0
  57. package/dist-types/components/input-amount-dropdown/translations/ro.d.ts +7 -0
  58. package/dist-types/components/input-amount-dropdown/translations/ro.d.ts.map +1 -0
  59. package/dist-types/components/input-amount-dropdown/translations/ru.d.ts +7 -0
  60. package/dist-types/components/input-amount-dropdown/translations/ru.d.ts.map +1 -0
  61. package/dist-types/components/input-amount-dropdown/translations/sk.d.ts +7 -0
  62. package/dist-types/components/input-amount-dropdown/translations/sk.d.ts.map +1 -0
  63. package/dist-types/components/input-amount-dropdown/translations/uk.d.ts +7 -0
  64. package/dist-types/components/input-amount-dropdown/translations/uk.d.ts.map +1 -0
  65. package/dist-types/components/input-amount-dropdown/translations/zh.d.ts +7 -0
  66. package/dist-types/components/input-amount-dropdown/translations/zh.d.ts.map +1 -0
  67. package/dist-types/components/listbox/src/ListboxMixin.d.ts.map +1 -1
  68. package/dist-types/components/overlays/src/ArrowMixin.d.ts.map +1 -1
  69. package/dist-types/components/overlays/src/OverlayController.d.ts +13 -4
  70. package/dist-types/components/overlays/src/OverlayController.d.ts.map +1 -1
  71. package/dist-types/components/overlays/test-suites/OverlayMixin.suite.d.ts.map +1 -1
  72. package/dist-types/tsconfig.tsbuildinfo +1 -1
  73. package/docs/components/accordion/index.md +1 -1
  74. package/docs/components/accordion/overview.md +1 -1
  75. package/docs/components/accordion/reference.md +1 -1
  76. package/docs/components/accordion/use-cases.md +1 -1
  77. package/docs/components/button/{extensions/bootstrap-button.mjs → assets/bootstrap-button.js} +10 -5
  78. package/docs/components/button/examples.md +1 -1
  79. package/docs/components/button/extensions.md +2 -2
  80. package/docs/components/button/index.md +2 -2
  81. package/docs/components/button/overview.md +4 -4
  82. package/docs/components/button/use-cases.md +6 -6
  83. package/docs/components/calendar/index.md +1 -1
  84. package/docs/components/calendar/overview.md +1 -1
  85. package/docs/components/calendar/use-cases.md +2 -2
  86. package/docs/components/checkbox-group/index.md +1 -1
  87. package/docs/components/checkbox-group/overview.md +3 -3
  88. package/docs/components/checkbox-group/use-cases.md +1 -1
  89. package/docs/components/collapsible/examples.md +1 -1
  90. package/docs/components/collapsible/index.md +1 -1
  91. package/docs/components/collapsible/overview.md +2 -2
  92. package/docs/components/collapsible/use-cases.md +1 -1
  93. package/docs/components/combobox/extensions.md +2 -1
  94. package/docs/components/combobox/index.md +1 -1
  95. package/docs/components/combobox/overview.md +2 -2
  96. package/docs/components/combobox/use-cases.md +2 -2
  97. package/docs/components/dialog/index.md +1 -1
  98. package/docs/components/dialog/overview.md +2 -2
  99. package/docs/components/dialog/use-cases.md +3 -3
  100. package/docs/components/drawer/index.md +1 -1
  101. package/docs/components/drawer/overview.md +1 -1
  102. package/docs/components/drawer/use-cases.md +1 -1
  103. package/docs/components/fieldset/index.md +1 -1
  104. package/docs/components/fieldset/overview.md +6 -6
  105. package/docs/components/fieldset/use-cases.md +1 -1
  106. package/docs/components/form/index.md +1 -1
  107. package/docs/components/form/overview.md +4 -4
  108. package/docs/components/form/use-cases.md +3 -3
  109. package/docs/components/icon/index.md +1 -1
  110. package/docs/components/icon/overview.md +1 -1
  111. package/docs/components/icon/use-cases.md +2 -15
  112. package/docs/components/index.md +1 -1
  113. package/docs/components/input/index.md +1 -1
  114. package/docs/components/input/overview.md +2 -2
  115. package/docs/components/input/use-cases.md +1 -1
  116. package/docs/components/input-amount/index.md +1 -1
  117. package/docs/components/input-amount/overview.md +4 -4
  118. package/docs/components/input-amount/use-cases.md +1 -1
  119. package/docs/components/input-amount-dropdown/index.md +1 -1
  120. package/docs/components/input-amount-dropdown/use-cases.md +1 -1
  121. package/docs/components/input-date/index.md +1 -1
  122. package/docs/components/input-date/overview.md +4 -4
  123. package/docs/components/input-date/use-cases.md +1 -1
  124. package/docs/components/input-datepicker/index.md +1 -1
  125. package/docs/components/input-datepicker/overview.md +6 -6
  126. package/docs/components/input-datepicker/use-cases.md +1 -1
  127. package/docs/components/input-email/index.md +1 -1
  128. package/docs/components/input-email/overview.md +3 -3
  129. package/docs/components/input-email/use-cases.md +1 -1
  130. package/docs/components/input-file/index.md +1 -1
  131. package/docs/components/input-file/overview.md +2 -2
  132. package/docs/components/input-file/use-cases.md +1 -1
  133. package/docs/components/input-iban/index.md +1 -1
  134. package/docs/components/input-iban/overview.md +3 -3
  135. package/docs/components/input-iban/use-cases.md +1 -1
  136. package/docs/components/input-range/index.md +1 -1
  137. package/docs/components/input-range/overview.md +3 -3
  138. package/docs/components/input-range/use-cases.md +1 -1
  139. package/docs/components/input-stepper/index.md +1 -1
  140. package/docs/components/input-stepper/overview.md +2 -2
  141. package/docs/components/input-stepper/use-cases.md +1 -1
  142. package/docs/components/input-tel/index.md +1 -1
  143. package/docs/components/input-tel/overview.md +2 -2
  144. package/docs/components/input-tel/use-cases.md +7 -7
  145. package/docs/components/input-tel-dropdown/extensions.md +1 -1
  146. package/docs/components/input-tel-dropdown/index.md +1 -1
  147. package/docs/components/input-tel-dropdown/overview.md +2 -2
  148. package/docs/components/input-tel-dropdown/use-cases.md +1 -1
  149. package/docs/components/listbox/index.md +1 -1
  150. package/docs/components/listbox/overview.md +1 -1
  151. package/docs/components/listbox/use-cases.md +2 -2
  152. package/docs/components/pagination/index.md +1 -1
  153. package/docs/components/pagination/overview.md +1 -1
  154. package/docs/components/pagination/use-cases.md +1 -1
  155. package/docs/components/progress-indicator/examples.md +1 -1
  156. package/docs/components/progress-indicator/index.md +1 -1
  157. package/docs/components/progress-indicator/overview.md +1 -1
  158. package/docs/components/radio-group/index.md +1 -1
  159. package/docs/components/radio-group/overview.md +4 -4
  160. package/docs/components/radio-group/use-cases.md +1 -1
  161. package/docs/components/select/index.md +1 -1
  162. package/docs/components/select/overview.md +1 -1
  163. package/docs/components/select/use-cases.md +2 -2
  164. package/docs/components/select-rich/examples.md +1 -1
  165. package/docs/components/select-rich/index.md +1 -1
  166. package/docs/components/select-rich/overview.md +1 -1
  167. package/docs/components/select-rich/use-cases.md +3 -3
  168. package/docs/components/steps/index.md +1 -1
  169. package/docs/components/steps/overview.md +1 -1
  170. package/docs/components/steps/use-cases.md +1 -1
  171. package/docs/components/switch/index.md +1 -1
  172. package/docs/components/switch/overview.md +1 -1
  173. package/docs/components/switch/reference.md +1 -1
  174. package/docs/components/switch/use-cases.md +1 -1
  175. package/docs/components/tabs/examples.md +2 -2
  176. package/docs/components/tabs/index.md +1 -1
  177. package/docs/components/tabs/overview.md +1 -1
  178. package/docs/components/tabs/use-cases.md +1 -1
  179. package/docs/components/textarea/index.md +1 -1
  180. package/docs/components/textarea/overview.md +1 -1
  181. package/docs/components/textarea/use-cases.md +1 -1
  182. package/docs/components/tooltip/examples.md +1 -1
  183. package/docs/components/tooltip/index.md +1 -1
  184. package/docs/components/tooltip/overview.md +1 -1
  185. package/docs/components/tooltip/use-cases.md +1 -1
  186. package/docs/fundamentals/index.md +4 -4
  187. package/docs/fundamentals/node-tools/babel-plugin-extend-docs/index.md +1 -1
  188. package/docs/fundamentals/node-tools/babel-plugin-extend-docs/overview.md +1 -1
  189. package/docs/fundamentals/node-tools/index.md +1 -1
  190. package/docs/fundamentals/node-tools/providence-analytics/index.md +1 -1
  191. package/docs/fundamentals/node-tools/providence-analytics/overview.md +1 -1
  192. package/docs/fundamentals/node-tools/publish-docs/index.md +1 -1
  193. package/docs/fundamentals/node-tools/publish-docs/overview.md +4 -4
  194. package/docs/fundamentals/node-tools/remark-extend/index.md +1 -1
  195. package/docs/fundamentals/node-tools/remark-extend/overview.md +1 -1
  196. package/docs/fundamentals/node-tools/rocket-preset-extend-lion-docs/index.md +1 -1
  197. package/docs/fundamentals/node-tools/rocket-preset-extend-lion-docs/overview.md +3 -3
  198. package/docs/fundamentals/rationales/TypeScript.md +1 -1
  199. package/docs/fundamentals/rationales/accessibility.md +2 -2
  200. package/docs/fundamentals/rationales/index.md +1 -1
  201. package/docs/fundamentals/rationales/side-effects.md +1 -1
  202. package/docs/fundamentals/rationales/versioning.md +1 -1
  203. package/docs/fundamentals/systems/core/SlotMixin.md +2 -2
  204. package/docs/fundamentals/systems/core/index.md +1 -1
  205. package/docs/fundamentals/systems/core/overview.md +2 -2
  206. package/docs/fundamentals/systems/form/formatting-and-parsing.md +5 -5
  207. package/docs/fundamentals/systems/form/index.md +1 -1
  208. package/docs/fundamentals/systems/form/interaction-states.md +1 -1
  209. package/docs/fundamentals/systems/form/model-value.md +2 -2
  210. package/docs/fundamentals/systems/form/overview.md +29 -29
  211. package/docs/fundamentals/systems/form/styling.md +1 -1
  212. package/docs/fundamentals/systems/form/use-cases.md +1 -1
  213. package/docs/fundamentals/systems/form/validate.md +3 -3
  214. package/docs/fundamentals/systems/icon/index.md +1 -1
  215. package/docs/fundamentals/systems/icon/overview.md +1 -1
  216. package/docs/fundamentals/systems/index.md +1 -1
  217. package/docs/fundamentals/systems/localize/api-table.md +3 -0
  218. package/docs/fundamentals/systems/localize/dates.md +1 -1
  219. package/docs/fundamentals/systems/localize/index.md +1 -1
  220. package/docs/fundamentals/systems/localize/numbers.md +1 -1
  221. package/docs/fundamentals/systems/localize/overview.md +5 -5
  222. package/docs/fundamentals/systems/localize/rationale.md +1 -1
  223. package/docs/fundamentals/systems/localize/text.md +5 -4
  224. package/docs/fundamentals/systems/localize/use-cases.md +1 -1
  225. package/docs/fundamentals/systems/overlays/_configuration-positioning.md +3 -3
  226. package/docs/fundamentals/systems/overlays/_edge-cases.md +3 -3
  227. package/docs/fundamentals/systems/overlays/api-table.md +3 -0
  228. package/docs/fundamentals/systems/overlays/assets/demo-overlay-positioning.mjs +1 -1
  229. package/docs/fundamentals/systems/overlays/configuration.md +5 -5
  230. package/docs/fundamentals/systems/overlays/index.md +1 -1
  231. package/docs/fundamentals/systems/overlays/overview.md +6 -6
  232. package/docs/fundamentals/systems/overlays/rationale.md +1 -1
  233. package/docs/fundamentals/systems/overlays/use-cases.md +6 -6
  234. package/docs/fundamentals/tools/ajax/index.md +1 -1
  235. package/docs/fundamentals/tools/ajax/overview.md +2 -2
  236. package/docs/fundamentals/tools/ajax/use-cases.md +3 -3
  237. package/docs/fundamentals/tools/helpers/action-logger.md +1 -1
  238. package/docs/fundamentals/tools/helpers/index.md +2 -2
  239. package/docs/fundamentals/tools/helpers/overview.md +2 -2
  240. package/docs/fundamentals/tools/index.md +1 -1
  241. package/docs/fundamentals/tools/singleton-manager/example-complex/index.md +1 -1
  242. package/docs/fundamentals/tools/singleton-manager/example-fail/demo-app.js +4 -4
  243. package/docs/fundamentals/tools/singleton-manager/example-fail/index.md +2 -2
  244. package/docs/fundamentals/tools/singleton-manager/example-fail/node_modules/{page-a/page-a.js → page-c/page-c.js} +2 -2
  245. package/docs/fundamentals/tools/singleton-manager/example-fail/node_modules/{page-b/page-b.js → page-d/page-d.js} +2 -2
  246. package/docs/fundamentals/tools/singleton-manager/example-success/demo-app.js +4 -4
  247. package/docs/fundamentals/tools/singleton-manager/example-success/index.md +2 -2
  248. package/docs/fundamentals/tools/singleton-manager/example-success/node_modules/{page-a/page-a.js → page-e/page-e.js} +2 -3
  249. package/docs/fundamentals/tools/singleton-manager/example-success/node_modules/{page-b/page-b.js → page-f/page-f.js} +2 -2
  250. package/docs/fundamentals/tools/singleton-manager/index.md +2 -2
  251. package/docs/fundamentals/tools/singleton-manager/overview.md +5 -5
  252. package/docs/guides/how-to/create-a-custom-field.md +5 -5
  253. package/docs/guides/how-to/create-a-form.md +4 -4
  254. package/docs/guides/how-to/extend-a-native-input.md +2 -2
  255. package/docs/guides/index.md +8 -8
  256. package/docs/guides/principles/index.md +5 -5
  257. package/docs/guides/principles/styling.md +1 -1
  258. package/package.json +1 -1
  259. /package/docs/fundamentals/systems/overlays/assets/{applyDemoOverlayStyles.mjs → applyDemoOverlayStyles.js} +0 -0
  260. /package/docs/fundamentals/systems/overlays/assets/{demo-el-using-overlaymixin.mjs → demo-el-using-overlaymixin.js} +0 -0
  261. /package/docs/fundamentals/systems/overlays/assets/{demo-overlay-backdrop.mjs → demo-overlay-backdrop.js} +0 -0
  262. /package/docs/fundamentals/tools/singleton-manager/example-fail/node_modules/{page-b → page-d}/node_modules/overlays/index.js +0 -0
  263. /package/docs/fundamentals/tools/singleton-manager/example-fail/node_modules/{page-b → page-d}/node_modules/overlays/instance.js +0 -0
  264. /package/docs/fundamentals/tools/singleton-manager/example-success/node_modules/{page-b → page-f}/node_modules/overlays/index.js +0 -0
  265. /package/docs/fundamentals/tools/singleton-manager/example-success/node_modules/{page-b → page-f}/node_modules/overlays/instance.js +0 -0
@@ -4,6 +4,7 @@ import { dedupeMixin } from '@open-wc/dedupe-mixin';
4
4
  import { ChoiceGroupMixin, FormControlMixin, FormRegistrarMixin } from '@lion/ui/form-core.js';
5
5
  import { ScopedElementsMixin } from '../../core/src/ScopedElementsMixin.js';
6
6
  import { LionOptions } from './LionOptions.js';
7
+ import { moveUserProvidedDefaultSlottablesToTarget } from '../../core/src/SlotMixin.js';
7
8
 
8
9
  // TODO: extract ListNavigationWithActiveDescendantMixin that can be reused in [role="menu"]
9
10
  // having children with [role="menuitem|menuitemcheckbox|menuitemradio|option"] and
@@ -21,39 +22,6 @@ import { LionOptions } from './LionOptions.js';
21
22
 
22
23
  // TODO: consider adding methods below to @lion/helpers
23
24
 
24
- /**
25
- * Sometimes, we want to provide best DX (direct slottables) and be accessible
26
- * at the same time.
27
- * In the first example below, we need to wrap our options in light dom in an element with
28
- * [role=listbox]. We could achieve this via the second example, but it would affect our
29
- * public api negatively. not allowing us to be forward compatible with the AOM spec:
30
- * https://wicg.github.io/aom/explainer.html
31
- * With this method, it's possible to watch elements in the default slot and move them
32
- * to the desired target (the element with [role=listbox]) in light dom.
33
- *
34
- * @example
35
- * # desired api
36
- * <sel-ect>
37
- * <opt-ion></opt-ion>
38
- * </sel-ect>
39
- * # desired end state
40
- * <sel-ect>
41
- * <div role="listbox" slot="lisbox">
42
- * <opt-ion></opt-ion>
43
- * </div>
44
- * </sel-ect>
45
- * @param {HTMLElement} source host of ShadowRoot with default <slot>
46
- * @param {HTMLElement} target the desired target in light dom
47
- */
48
- function moveDefaultSlottablesToTarget(source, target) {
49
- Array.from(source.childNodes).forEach((/** @type {* & Element} */ c) => {
50
- const isNamedSlottable = c.hasAttribute && c.hasAttribute('slot');
51
- if (!isNamedSlottable) {
52
- target.appendChild(c);
53
- }
54
- });
55
- }
56
-
57
25
  /**
58
26
  * @type {ListboxMixin}
59
27
  * @param {import('@open-wc/dedupe-mixin').Constructor<import('lit').LitElement>} superclass
@@ -899,9 +867,9 @@ const ListboxMixinImplementation = superclass =>
899
867
  );
900
868
 
901
869
  if (slot) {
902
- moveDefaultSlottablesToTarget(this, this._listboxNode);
870
+ moveUserProvidedDefaultSlottablesToTarget(this, this._listboxNode);
903
871
  slot.addEventListener('slotchange', () => {
904
- moveDefaultSlottablesToTarget(this, this._listboxNode);
872
+ moveUserProvidedDefaultSlottablesToTarget(this, this._listboxNode);
905
873
  });
906
874
  }
907
875
  }
@@ -64,8 +64,11 @@ export const ArrowMixinImplementation = superclass =>
64
64
 
65
65
  [data-popper-placement^='left'] .arrow {
66
66
  right: calc(
67
- -1 * (var(--tooltip-arrow-height) +
68
- (var(--tooltip-arrow-width) - var(--tooltip-arrow-height)) / 2)
67
+ -1 *
68
+ (
69
+ var(--tooltip-arrow-height) +
70
+ (var(--tooltip-arrow-width) - var(--tooltip-arrow-height)) / 2
71
+ )
69
72
  );
70
73
  }
71
74
 
@@ -75,8 +78,11 @@ export const ArrowMixinImplementation = superclass =>
75
78
 
76
79
  [data-popper-placement^='right'] .arrow {
77
80
  left: calc(
78
- -1 * (var(--tooltip-arrow-height) +
79
- (var(--tooltip-arrow-width) - var(--tooltip-arrow-height)) / 2)
81
+ -1 *
82
+ (
83
+ var(--tooltip-arrow-height) +
84
+ (var(--tooltip-arrow-width) - var(--tooltip-arrow-height)) / 2
85
+ )
80
86
  );
81
87
  }
82
88
 
@@ -197,15 +197,24 @@ export class OverlayController extends EventTarget {
197
197
  this._contentId = `overlay-content--${Math.random().toString(36).slice(2, 10)}`;
198
198
  /** @private */
199
199
  this.__originalAttrs = new Map();
200
+ /** @private */
201
+ this.__escKeyHandler = this.__escKeyHandler.bind(this);
200
202
  this.updateConfig(config);
201
203
  /** @private */
202
204
  this.__hasActiveTrapsKeyboardFocus = false;
203
205
  /** @private */
204
206
  this.__hasActiveBackdrop = true;
205
207
  /** @private */
206
- this.__escKeyHandler = this.__escKeyHandler.bind(this);
207
- /** @private */
208
208
  this.__cancelHandler = this.__cancelHandler.bind(this);
209
+ /**
210
+ * The property is used to skip `__escKeyHandler` handler for overlays that have been closed
211
+ * by `__escKeyHandlerCalled` previously.
212
+ * `__escKeyHandlerCalled` is set to `false` right before overlay show up
213
+ * `__escKeyHandlerCalled` is set to `true` when `__escKeyHandler` is called at least one time
214
+ * after each 'show' phase
215
+ * @private
216
+ */
217
+ this.__escKeyHandlerCalled = false;
209
218
  }
210
219
 
211
220
  /**
@@ -1211,13 +1220,21 @@ export class OverlayController extends EventTarget {
1211
1220
  * @returns {void}
1212
1221
  */
1213
1222
  __escKeyHandler(event) {
1214
- if (event.key !== 'Escape' || childDialogsClosedInEventLoopWeakmap.has(event)) return;
1223
+ if (
1224
+ event.key !== 'Escape' ||
1225
+ childDialogsClosedInEventLoopWeakmap.has(event) ||
1226
+ (!this.isShown && this.__escKeyHandlerCalled)
1227
+ ) {
1228
+ return;
1229
+ }
1215
1230
 
1216
1231
  const hasPressedInside =
1217
1232
  event.composedPath().includes(this.contentNode) ||
1233
+ (this.invokerNode && event.composedPath().includes(this.invokerNode)) ||
1218
1234
  deepContains(this.contentNode, /** @type {HTMLElement|ShadowRoot} */ (event.target));
1219
1235
 
1220
1236
  if (hasPressedInside) {
1237
+ this.__escKeyHandlerCalled = true;
1221
1238
  this.hide();
1222
1239
  // We could do event.stopPropagation() here, but we don't want to hide info for
1223
1240
  // the outside world about user interactions. Instead, we store the event in a WeakMap
@@ -1245,12 +1262,21 @@ export class OverlayController extends EventTarget {
1245
1262
  * @protected
1246
1263
  */
1247
1264
  _handleHidesOnEsc({ phase }) {
1248
- if (phase === 'show') {
1265
+ if (phase === 'init') {
1266
+ // we remove previously added (if any) event listener to guarantee
1267
+ // there is only one Escape handler added here.
1268
+ // Note `init` phase triggered on every `updateConfig` call and that
1269
+ // could happen multiple times during the component life cycle
1270
+ this.contentNode.removeEventListener('keyup', this.__escKeyHandler);
1249
1271
  this.contentNode.addEventListener('keyup', this.__escKeyHandler);
1250
1272
  if (this.invokerNode) {
1251
1273
  this.invokerNode.addEventListener('keyup', this.__escKeyHandler);
1252
1274
  }
1253
- } else if (phase === 'hide' || phase === 'teardown') {
1275
+ }
1276
+ if (phase === 'show') {
1277
+ this.__escKeyHandlerCalled = false;
1278
+ }
1279
+ if (phase === 'teardown') {
1254
1280
  this.contentNode.removeEventListener('keyup', this.__escKeyHandler);
1255
1281
  if (this.invokerNode) {
1256
1282
  this.invokerNode.removeEventListener('keyup', this.__escKeyHandler);
@@ -1263,9 +1289,10 @@ export class OverlayController extends EventTarget {
1263
1289
  * @protected
1264
1290
  */
1265
1291
  _handleHidesOnOutsideEsc({ phase }) {
1266
- if (phase === 'show') {
1292
+ if (phase === 'init') {
1293
+ document.removeEventListener('keyup', this.#outsideEscKeyHandler);
1267
1294
  document.addEventListener('keyup', this.#outsideEscKeyHandler);
1268
- } else if (phase === 'hide' || phase === 'teardown') {
1295
+ } else if (phase === 'teardown') {
1269
1296
  document.removeEventListener('keyup', this.#outsideEscKeyHandler);
1270
1297
  }
1271
1298
  }
@@ -799,6 +799,9 @@ describe('OverlayController', () => {
799
799
  const { parentOverlay, childOverlay } = await createNestedEscControllers(parentContent);
800
800
  await mimicEscapePress(childOverlay.contentNode);
801
801
 
802
+ // without this line, the test is unstable on FF sometimes
803
+ await aTimeout(0);
804
+
802
805
  expect(parentOverlay.isShown).to.be.false;
803
806
  expect(childOverlay.isShown).to.be.true;
804
807
 
@@ -1040,7 +1043,7 @@ describe('OverlayController', () => {
1040
1043
  // Don't hide on inside shadowDom click
1041
1044
  /** @type {ShadowRoot} */
1042
1045
  // @ts-expect-error
1043
- (ctrl.contentNode.querySelector(tagString).shadowRoot).querySelector('button').click();
1046
+ ctrl.contentNode.querySelector(tagString).shadowRoot.querySelector('button').click();
1044
1047
 
1045
1048
  await aTimeout(0);
1046
1049
  expect(ctrl.isShown).to.be.true;
@@ -7,9 +7,9 @@ const tagString = defineCE(
7
7
  class extends OverlayMixin(LitElement) {
8
8
  render() {
9
9
  return html`
10
- <button slot="invoker">invoker button</button>
10
+ <slot name="invoker"></slot>
11
11
  <div id="overlay-content-node-wrapper">
12
- <div slot="content">content of the overlay</div>
12
+ <slot name="content"></slot>
13
13
  </div>
14
14
  `;
15
15
  }
@@ -111,6 +111,63 @@ export function runOverlayMixinSuite({ tagString, tag, suffix = '' }) {
111
111
  expect(el.opened).to.be.false;
112
112
  });
113
113
 
114
+ /**
115
+ * In case OverlayMixin has a handler for Escape which sets `opened` to `false`,
116
+ * make sure it does not conflict with the Escape handler in OverlayController.
117
+ * */
118
+ it('syncs opened between overlayController and OverlayMixin on Escape', async () => {
119
+ const config = { hidesOnEsc: true };
120
+ const el = /** @type {OverlayEl} */ (
121
+ await fixture(html`
122
+ <${tag} id="main-dialog" .config="${config}">
123
+ <div slot="content" id="mainContent">
124
+ open nested overlay:
125
+ <${tag} id="sub-dialog" .config="${config}">
126
+ <div slot="content" id="nestedContent">
127
+ <input id="nestedContentInput">
128
+ </div>
129
+ <button slot="invoker" id="nestedInvoker">nested invoker button</button>
130
+ </${tag}>
131
+ </div>
132
+ <button slot="invoker" id="mainInvoker">invoker button</button>
133
+ </${tag}>
134
+ `)
135
+ );
136
+ await el.updateComplete;
137
+ const subDialog = /** @type {OverlayEl} */ (el.querySelector('#sub-dialog'));
138
+ const nestedContentInput = /** @type {OverlayEl} */ (el.querySelector('#nestedContentInput'));
139
+
140
+ // Note, OverlayController has Escape key listener added to "#nestedContent".
141
+ // And the sub-dialog adds the Escape key listener to "#nestedContentInput" which is a child evelement of "#nestedContent"
142
+ // In this case when "#nestedContentInput" is focused and Escape is pressed, the listener of "#nestedContentInput"
143
+ // is always called before the listener set for "#nestedContent" inside OverlayController.
144
+ // This way we check the scenario when OverlayController's `hide()` is called first from
145
+ // The OverlayMixin and it does not prevent OverlayController `hidesOnEsc` handler from being called
146
+ nestedContentInput?.addEventListener('keyup', (/** @type {* & KeyboardEvent} */ event) => {
147
+ if (event.key === 'Escape') {
148
+ subDialog.opened = false;
149
+ }
150
+ });
151
+
152
+ el.opened = true;
153
+ await el.updateComplete;
154
+ await el._overlayCtrl._showComplete;
155
+ expect(el.opened).to.be.true;
156
+ expect(el._overlayCtrl.isShown).to.be.true;
157
+
158
+ subDialog.opened = true;
159
+ await subDialog.updateComplete;
160
+ await subDialog._overlayCtrl._showComplete;
161
+ expect(subDialog.opened).to.be.true;
162
+ expect(subDialog._overlayCtrl.isShown).to.be.true;
163
+
164
+ await mimicEscapePress(nestedContentInput);
165
+ expect(subDialog.opened).to.be.false;
166
+ expect(subDialog._overlayCtrl.isShown).to.be.false;
167
+ expect(el.opened).to.be.true;
168
+ expect(el._overlayCtrl.isShown).to.be.true;
169
+ });
170
+
114
171
  // TODO: put this tests in OverlayController.test.js instead?
115
172
  it('does not change the body size when opened', async () => {
116
173
  const parentNode = document.createElement('div');