@lion/ui 0.22.0 → 0.24.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 (901) hide show
  1. package/README.md +65 -0
  2. package/components/accordion/src/LionAccordion.js +31 -42
  3. package/components/accordion/test/lion-accordion.test.js +108 -134
  4. package/components/button/src/LionButton.js +9 -12
  5. package/components/button/src/LionButtonReset.js +0 -5
  6. package/components/button/src/LionButtonSubmit.js +7 -12
  7. package/components/button/test/demos.screenshots-test.js +50 -11
  8. package/components/button/test/lion-button.test.js +0 -1
  9. package/components/button/test-suites/LionButton.suite.js +135 -145
  10. package/components/button/test-suites/LionButtonReset.suite.js +54 -72
  11. package/components/button/test-suites/LionButtonSubmit.suite.js +49 -68
  12. package/components/calendar/src/LionCalendar.js +151 -104
  13. package/components/calendar/src/calendarStyle.js +0 -1
  14. package/components/calendar/src/utils/createMonth.js +3 -4
  15. package/components/calendar/src/utils/createMultipleMonth.js +15 -7
  16. package/components/calendar/src/utils/createWeek.js +0 -2
  17. package/components/calendar/src/utils/dataTemplate.js +8 -4
  18. package/components/calendar/src/utils/dayTemplate.js +0 -6
  19. package/components/calendar/src/utils/getDayMonthYear.js +6 -2
  20. package/components/calendar/test/demos.screenshots-test.js +40 -9
  21. package/components/calendar/test/lion-calendar.test.js +171 -282
  22. package/components/calendar/test/utils/createMonth.test.js +61 -22
  23. package/components/calendar/test/utils/createMultipleMonth.test.js +14 -7
  24. package/components/calendar/test/utils/createWeek.test.js +51 -17
  25. package/components/calendar/test/utils/dataTemplate.test.js +3 -4
  26. package/components/calendar/test/utils/dayTemplate.test.js +106 -34
  27. package/components/calendar/test/utils/getFirstDayNextMonth.test.js +0 -1
  28. package/components/calendar/test/utils/getLastDayPreviousMonth.test.js +0 -1
  29. package/components/calendar/test/utils/isSameDate.test.js +0 -1
  30. package/components/calendar/test/utils/snapshots/monthTemplate_en-GB_Sunday_2018-12.js +1 -2
  31. package/components/calendar/test-helpers/CalendarObject.js +31 -62
  32. package/components/calendar/test-helpers/DayObject.js +7 -15
  33. package/components/calendar/test-suites/LionCalendar.suite.js +7 -9
  34. package/components/checkbox-group/src/LionCheckboxIndeterminate.js +17 -30
  35. package/components/checkbox-group/test/lion-checkbox-group-integrations.test.js +0 -1
  36. package/components/checkbox-group/test/lion-checkbox-group.test.js +21 -16
  37. package/components/checkbox-group/test/lion-checkbox-indeterminate-integrations.test.js +3 -3
  38. package/components/checkbox-group/test/lion-checkbox-integrations.test.js +3 -2
  39. package/components/checkbox-group/test/lion-checkbox.test.js +30 -16
  40. package/components/checkbox-group/test-suites/CheckboxIndeterminate.suite.js +147 -191
  41. package/components/collapsible/src/LionCollapsible.js +10 -15
  42. package/components/collapsible/test/lion-collapsible.test.js +4 -18
  43. package/components/combobox/src/LionCombobox.js +45 -55
  44. package/components/combobox/src/utils/makeMatchingTextBold.js +2 -5
  45. package/components/combobox/src/validators.js +0 -1
  46. package/components/combobox/test/lion-combobox-integrations.test.js +6 -6
  47. package/components/combobox/test/lion-combobox.test.js +598 -860
  48. package/components/combobox/test/validators.test.js +6 -13
  49. package/components/combobox/test-helpers/combobox-helpers.js +24 -11
  50. package/components/core/src/DisabledMixin.js +61 -66
  51. package/components/core/src/DisabledWithTabIndexMixin.js +76 -83
  52. package/components/core/src/EventTargetShim.js +1 -4
  53. package/components/core/src/ScopedElementsMixin.js +4 -15
  54. package/components/core/src/ScopedStylesController.js +1 -5
  55. package/components/core/src/SlotMixin.js +236 -239
  56. package/components/core/src/browserDetection.js +5 -12
  57. package/components/core/test/DisabledMixin.test.js +24 -39
  58. package/components/core/test/DisabledWithTabIndexMixin.test.js +21 -34
  59. package/components/core/test/EventTargetShim.test.js +0 -8
  60. package/components/core/test/ScopedElementsMixin.test.js +22 -38
  61. package/components/core/test/ScopedStylesController.test.js +11 -20
  62. package/components/core/test/SlotMixin.test.js +102 -154
  63. package/components/core/test-helpers/getCachedFixture.js +5 -11
  64. package/components/core/types/SlotMixinTypes.ts +8 -3
  65. package/components/dialog/src/LionDialog.js +4 -3
  66. package/components/dialog/test/lion-dialog.integration.test.js +10 -20
  67. package/components/dialog/test/lion-dialog.test.js +48 -62
  68. package/components/dialog/test-helpers/test-router.js +4 -6
  69. package/components/drawer/src/LionDrawer.js +18 -34
  70. package/components/drawer/src/drawerStyle.js +0 -1
  71. package/components/drawer/test/lion-drawer.test.js +1 -17
  72. package/components/fieldset/test/lion-fieldset.test.js +6 -4
  73. package/components/form/src/LionForm.js +18 -13
  74. package/components/form/test/lion-form.test.js +22 -52
  75. package/components/form-core/src/FocusMixin.js +172 -174
  76. package/components/form-core/src/FormControlMixin.js +811 -813
  77. package/components/form-core/src/FormatMixin.js +537 -537
  78. package/components/form-core/src/InteractionStateMixin.js +196 -183
  79. package/components/form-core/src/LionField.js +9 -5
  80. package/components/form-core/src/NativeTextFieldMixin.js +114 -116
  81. package/components/form-core/src/choice-group/ChoiceGroupMixin.js +322 -357
  82. package/components/form-core/src/choice-group/ChoiceInputMixin.js +306 -296
  83. package/components/form-core/src/choice-group/CustomChoiceGroupMixin.js +114 -139
  84. package/components/form-core/src/form-group/FormElementsHaveNoError.js +0 -2
  85. package/components/form-core/src/form-group/FormGroupMixin.js +551 -557
  86. package/components/form-core/src/registration/FormRegisteringMixin.js +72 -71
  87. package/components/form-core/src/registration/FormRegistrarMixin.js +201 -217
  88. package/components/form-core/src/registration/FormRegistrarPortalMixin.js +31 -37
  89. package/components/form-core/src/utils/SyncUpdatableMixin.js +106 -117
  90. package/components/form-core/src/utils/getAriaElementsInRightDomOrder.js +1 -2
  91. package/components/form-core/src/validate/LionValidationFeedback.js +12 -8
  92. package/components/form-core/src/validate/Unparseable.js +4 -2
  93. package/components/form-core/src/validate/ValidateMixin.js +829 -883
  94. package/components/form-core/src/validate/Validator.js +3 -6
  95. package/components/form-core/src/validate/resultValidators/DefaultSuccess.js +1 -2
  96. package/components/form-core/src/validate/validators/DateValidators.js +0 -5
  97. package/components/form-core/src/validate/validators/NumberValidators.js +1 -5
  98. package/components/form-core/src/validate/validators/Required.js +1 -1
  99. package/components/form-core/src/validate/validators/StringValidators.js +1 -8
  100. package/components/form-core/test/FocusMixin.test.js +96 -82
  101. package/components/form-core/test/FormControlMixin.test.js +120 -176
  102. package/components/form-core/test/FormRegistrationMixins.test.js +0 -2
  103. package/components/form-core/test/FormatMixin.test.js +0 -1
  104. package/components/form-core/test/InteractionStateMixin.test.js +0 -1
  105. package/components/form-core/test/NativeTextFieldMixin.test.js +0 -1
  106. package/components/form-core/test/choice-group/ChoiceGroupMixin.test.js +0 -1
  107. package/components/form-core/test/choice-group/ChoiceInputMixin.test.js +0 -1
  108. package/components/form-core/test/choice-group/CustomChoiceGroupMixin.integrations.test.js +6 -8
  109. package/components/form-core/test/choice-group/CustomChoiceGroupMixin.test.js +0 -3
  110. package/components/form-core/test/form-group/FormGroupMixin.test.js +0 -1
  111. package/components/form-core/test/lion-field.test.js +88 -98
  112. package/components/form-core/test/utils/SyncUpdatableMixin.test.js +51 -65
  113. package/components/form-core/test/utils/getAriaElementsInRightDomOrder.test.js +3 -3
  114. package/components/form-core/test/validate/DateValidators.test.js +5 -27
  115. package/components/form-core/test/validate/NumberValidators.test.js +4 -16
  116. package/components/form-core/test/validate/Required.test.js +8 -21
  117. package/components/form-core/test/validate/ResultValidator.test.js +1 -2
  118. package/components/form-core/test/validate/StringValidators.test.js +4 -35
  119. package/components/form-core/test/validate/ValidateMixin.test.js +0 -1
  120. package/components/form-core/test/validate/ValidateMixinFeedbackPart.test.js +0 -1
  121. package/components/form-core/test/validate/Validator.test.js +39 -34
  122. package/components/form-core/test/validate/lion-validation-feedback.test.js +81 -43
  123. package/components/form-core/test-helpers/ExampleValidators.js +0 -5
  124. package/components/form-core/test-helpers/getFormControlMembers.js +2 -2
  125. package/components/form-core/test-helpers/mimicUserInput.js +5 -1
  126. package/components/form-core/test-suites/FormRegistrationMixins.suite.js +65 -122
  127. package/components/form-core/test-suites/FormatMixin.suite.js +202 -227
  128. package/components/form-core/test-suites/InteractionStateMixin.suite.js +47 -60
  129. package/components/form-core/test-suites/NativeTextFieldMixin.suite.js +8 -11
  130. package/components/form-core/test-suites/ValidateMixin.suite.js +280 -359
  131. package/components/form-core/test-suites/ValidateMixinFeedbackPart.suite.js +112 -163
  132. package/components/form-core/test-suites/choice-group/ChoiceGroupMixin.suite.js +185 -218
  133. package/components/form-core/test-suites/choice-group/ChoiceInputMixin.suite.js +116 -109
  134. package/components/form-core/test-suites/choice-group/CustomChoiceGroupMixin.suite.js +36 -70
  135. package/components/form-core/test-suites/form-group/FormGroupMixin-input.suite.js +57 -65
  136. package/components/form-core/test-suites/form-group/FormGroupMixin.suite.js +664 -523
  137. package/components/form-core/translations/bg-BG.js +0 -1
  138. package/components/form-core/translations/cs-CZ.js +0 -1
  139. package/components/form-core/translations/de-DE.js +0 -1
  140. package/components/form-core/translations/en-AU.js +0 -1
  141. package/components/form-core/translations/en-GB.js +0 -1
  142. package/components/form-core/translations/en-US.js +0 -1
  143. package/components/form-core/translations/es-ES.js +0 -1
  144. package/components/form-core/translations/fr-BE.js +0 -1
  145. package/components/form-core/translations/fr-FR.js +0 -1
  146. package/components/form-core/translations/hu-HU.js +0 -1
  147. package/components/form-core/translations/it-IT.js +0 -1
  148. package/components/form-core/translations/nl-BE.js +0 -1
  149. package/components/form-core/translations/nl-NL.js +0 -1
  150. package/components/form-core/translations/pl-PL.js +0 -1
  151. package/components/form-core/translations/ro-RO.js +0 -1
  152. package/components/form-core/translations/ru-RU.js +0 -1
  153. package/components/form-core/translations/sk-SK.js +0 -1
  154. package/components/form-core/translations/tr-TR.js +0 -1
  155. package/components/form-core/translations/uk-UA.js +0 -1
  156. package/components/form-core/types/choice-group/ChoiceGroupMixinTypes.ts +5 -0
  157. package/components/form-integrations/test/dialog-integrations.test.js +1 -4
  158. package/components/form-integrations/test/form-group-methods.test.js +28 -31
  159. package/components/form-integrations/test/form-integrations.test.js +27 -28
  160. package/components/form-integrations/test/form-validation-integrations.test.js +21 -29
  161. package/components/form-integrations/test/helpers/umbrella-form.js +3 -5
  162. package/components/form-integrations/test/model-value-consistency.test.js +75 -77
  163. package/components/form-integrations/test/model-value-event.test.js +10 -20
  164. package/components/helpers/src/SbActionLogger.js +13 -17
  165. package/components/helpers/src/SbLocaleSwitcher.js +5 -5
  166. package/components/helpers/src/sortEachDepth.js +0 -2
  167. package/components/helpers/test/renderLitAsNode.test.js +0 -4
  168. package/components/helpers/test/sb-action-logger.test.js +24 -55
  169. package/components/icon/src/IconManager.js +0 -2
  170. package/components/icon/src/LionIcon.js +2 -7
  171. package/components/icon/src/icons.js +0 -2
  172. package/components/icon/test/IconManager.test.js +0 -15
  173. package/components/icon/test/hammer.svg.js +3 -4
  174. package/components/icon/test/heart.svg.js +3 -4
  175. package/components/icon/test/lion-icon.test.js +14 -43
  176. package/components/input/src/LionInput.js +2 -8
  177. package/components/input/test/input-integrations.test.js +0 -5
  178. package/components/input/test/lion-input-integrations.test.js +0 -4
  179. package/components/input/test/lion-input.test.js +28 -58
  180. package/components/input/test-helpers/getInputMembers.js +2 -2
  181. package/components/input-amount/src/LionInputAmount.js +37 -26
  182. package/components/input-amount/src/formatters.js +4 -5
  183. package/components/input-amount/src/parsers.js +0 -3
  184. package/components/input-amount/test/formatters.test.js +102 -80
  185. package/components/input-amount/test/lion-input-amount-integrations.test.js +0 -4
  186. package/components/input-amount/test/lion-input-amount.test.js +155 -164
  187. package/components/input-amount/test/parsers.test.js +33 -17
  188. package/components/input-amount/test/preprocessors.test.js +0 -3
  189. package/components/input-amount-dropdown/src/LionInputAmountDropdown.js +49 -59
  190. package/components/input-amount-dropdown/src/currencyUtil.js +8 -7
  191. package/components/input-amount-dropdown/src/parsers.js +0 -1
  192. package/components/input-amount-dropdown/src/validators.js +0 -1
  193. package/components/input-amount-dropdown/test/LionInputAmountDropdown.test.js +34 -36
  194. package/components/input-amount-dropdown/test/lion-input-amount-dropdown-integrations.test.js +18 -13
  195. package/components/input-amount-dropdown/test-helpers/mimicUserChangingDropdown.js +5 -1
  196. package/components/input-amount-dropdown/test-suites/LionInputAmountDropdown.suite.js +132 -107
  197. package/components/input-date/src/LionInputDate.js +4 -3
  198. package/components/input-date/test/lion-input-date-integrations.test.js +0 -3
  199. package/components/input-date/test/lion-input-date.test.js +19 -32
  200. package/components/input-datepicker/src/LionInputDatepicker.js +17 -29
  201. package/components/input-datepicker/src/localizeNamespaceLoader.js +1 -2
  202. package/components/input-datepicker/test/lion-input-datepicker-integrations.test.js +0 -3
  203. package/components/input-datepicker/test/lion-input-datepicker.test.js +88 -153
  204. package/components/input-datepicker/test-helpers/DatepickerInputObject.js +9 -12
  205. package/components/input-datepicker/test-suites/LionInputDatepicker.suite.js +6 -4
  206. package/components/input-datepicker/translations/bg-BG.js +0 -1
  207. package/components/input-datepicker/translations/cs-CZ.js +0 -1
  208. package/components/input-datepicker/translations/de-DE.js +0 -1
  209. package/components/input-datepicker/translations/en-AU.js +0 -1
  210. package/components/input-datepicker/translations/en-GB.js +0 -1
  211. package/components/input-datepicker/translations/en-US.js +0 -1
  212. package/components/input-datepicker/translations/es-ES.js +0 -1
  213. package/components/input-datepicker/translations/fr-BE.js +0 -1
  214. package/components/input-datepicker/translations/fr-FR.js +0 -1
  215. package/components/input-datepicker/translations/hu-HU.js +0 -1
  216. package/components/input-datepicker/translations/it-IT.js +0 -1
  217. package/components/input-datepicker/translations/nl-BE.js +0 -1
  218. package/components/input-datepicker/translations/nl-NL.js +0 -1
  219. package/components/input-datepicker/translations/pl-PL.js +0 -1
  220. package/components/input-datepicker/translations/ro-RO.js +0 -1
  221. package/components/input-datepicker/translations/ru-RU.js +0 -1
  222. package/components/input-datepicker/translations/sk-SK.js +0 -1
  223. package/components/input-datepicker/translations/tr-TR.js +0 -1
  224. package/components/input-datepicker/translations/uk-UA.js +0 -1
  225. package/components/input-email/test/lion-input-email-integrations.test.js +0 -2
  226. package/components/input-email/test/lion-input-email.test.js +1 -7
  227. package/components/input-file/src/FileHandle.js +0 -3
  228. package/components/input-file/src/LionInputFile.js +85 -83
  229. package/components/input-file/src/LionSelectedFileList.js +12 -12
  230. package/components/input-file/src/validators.js +10 -9
  231. package/components/input-file/test/FileValidators.test.js +170 -80
  232. package/components/input-file/test/lion-input-file.test.js +160 -244
  233. package/components/input-file/test/lion-selected-file-list.test.js +13 -22
  234. package/components/input-file/translations/bg-BG.js +0 -1
  235. package/components/input-file/translations/cs-CZ.js +0 -1
  236. package/components/input-file/translations/de-DE.js +0 -1
  237. package/components/input-file/translations/en-AU.js +0 -1
  238. package/components/input-file/translations/en-GB.js +0 -1
  239. package/components/input-file/translations/en-PH.js +0 -1
  240. package/components/input-file/translations/en-US.js +0 -1
  241. package/components/input-file/translations/en.js +2 -1
  242. package/components/input-file/translations/es-ES.js +0 -1
  243. package/components/input-file/translations/fr-BE.js +0 -1
  244. package/components/input-file/translations/fr-FR.js +0 -1
  245. package/components/input-file/translations/hu-HU.js +0 -1
  246. package/components/input-file/translations/id-ID.js +0 -1
  247. package/components/input-file/translations/id.js +2 -1
  248. package/components/input-file/translations/it-IT.js +0 -1
  249. package/components/input-file/translations/nl-BE.js +0 -1
  250. package/components/input-file/translations/nl-NL.js +0 -1
  251. package/components/input-file/translations/pl-PL.js +0 -1
  252. package/components/input-file/translations/ro-RO.js +0 -1
  253. package/components/input-file/translations/ru-RU.js +0 -1
  254. package/components/input-file/translations/sk-SK.js +0 -1
  255. package/components/input-file/translations/uk-UA.js +0 -1
  256. package/components/input-file/translations/zh-CN.js +0 -1
  257. package/components/input-iban/src/validators.js +6 -11
  258. package/components/input-iban/test/formatters.test.js +0 -3
  259. package/components/input-iban/test/lion-input-iban-integrations.test.js +0 -2
  260. package/components/input-iban/test/lion-input-iban.test.js +1 -9
  261. package/components/input-iban/test/parsers.test.js +0 -2
  262. package/components/input-iban/test/validators.test.js +0 -12
  263. package/components/input-iban/translations/bg-BG.js +0 -1
  264. package/components/input-iban/translations/cs-CZ.js +0 -1
  265. package/components/input-iban/translations/de-DE.js +0 -1
  266. package/components/input-iban/translations/en-AU.js +0 -1
  267. package/components/input-iban/translations/en-GB.js +0 -1
  268. package/components/input-iban/translations/en-US.js +0 -1
  269. package/components/input-iban/translations/es-ES.js +0 -1
  270. package/components/input-iban/translations/fr-BE.js +0 -1
  271. package/components/input-iban/translations/fr-FR.js +0 -1
  272. package/components/input-iban/translations/hu-HU.js +0 -1
  273. package/components/input-iban/translations/it-IT.js +0 -1
  274. package/components/input-iban/translations/nl-BE.js +0 -1
  275. package/components/input-iban/translations/nl-NL.js +0 -1
  276. package/components/input-iban/translations/pl-PL.js +0 -1
  277. package/components/input-iban/translations/ro-RO.js +0 -1
  278. package/components/input-iban/translations/ru-RU.js +0 -1
  279. package/components/input-iban/translations/sk-SK.js +0 -1
  280. package/components/input-iban/translations/uk-UA.js +0 -1
  281. package/components/input-range/src/LionInputRange.js +18 -19
  282. package/components/input-range/test/lion-input-range.test.js +23 -48
  283. package/components/input-range/translations/bg-BG.js +0 -1
  284. package/components/input-range/translations/cs-CZ.js +0 -1
  285. package/components/input-range/translations/de-DE.js +0 -1
  286. package/components/input-range/translations/en-AU.js +0 -1
  287. package/components/input-range/translations/en-GB.js +0 -1
  288. package/components/input-range/translations/en-PH.js +0 -1
  289. package/components/input-range/translations/en-US.js +0 -1
  290. package/components/input-range/translations/es-ES.js +0 -1
  291. package/components/input-range/translations/fr-BE.js +0 -1
  292. package/components/input-range/translations/fr-FR.js +0 -1
  293. package/components/input-range/translations/hu-HU.js +0 -1
  294. package/components/input-range/translations/it-IT.js +0 -1
  295. package/components/input-range/translations/nl-BE.js +0 -1
  296. package/components/input-range/translations/nl-NL.js +0 -1
  297. package/components/input-range/translations/pl-PL.js +0 -1
  298. package/components/input-range/translations/ro-RO.js +0 -1
  299. package/components/input-range/translations/ru-RU.js +0 -1
  300. package/components/input-range/translations/sk-SK.js +0 -1
  301. package/components/input-range/translations/uk-UA.js +0 -1
  302. package/components/input-range/translations/zh-CN.js +0 -1
  303. package/components/input-stepper/src/LionInputStepper.js +19 -38
  304. package/components/input-stepper/test/lion-input-stepper-integrations.test.js +0 -1
  305. package/components/input-stepper/test/lion-input-stepper.test.js +0 -1
  306. package/components/input-stepper/test-suites/lion-input-stepper.integration.suite.js +0 -2
  307. package/components/input-stepper/test-suites/lion-input-stepper.suite.js +56 -105
  308. package/components/input-stepper/translations/bg-BG.js +0 -1
  309. package/components/input-stepper/translations/cs-CZ.js +0 -1
  310. package/components/input-stepper/translations/de-DE.js +0 -1
  311. package/components/input-stepper/translations/en-AU.js +0 -1
  312. package/components/input-stepper/translations/en-GB.js +0 -1
  313. package/components/input-stepper/translations/en-US.js +0 -1
  314. package/components/input-stepper/translations/es-ES.js +0 -1
  315. package/components/input-stepper/translations/fr-BE.js +0 -1
  316. package/components/input-stepper/translations/fr-FR.js +0 -1
  317. package/components/input-stepper/translations/hu-HU.js +0 -1
  318. package/components/input-stepper/translations/it-IT.js +0 -1
  319. package/components/input-stepper/translations/nl-BE.js +0 -1
  320. package/components/input-stepper/translations/nl-NL.js +0 -1
  321. package/components/input-stepper/translations/pl-PL.js +0 -1
  322. package/components/input-stepper/translations/ro-RO.js +0 -1
  323. package/components/input-stepper/translations/ru-RU.js +0 -1
  324. package/components/input-stepper/translations/sk-SK.js +0 -1
  325. package/components/input-stepper/translations/uk-UA.js +0 -1
  326. package/components/input-tel/src/LionInputTel.js +53 -37
  327. package/components/input-tel/src/PhoneUtilManager.js +6 -4
  328. package/components/input-tel/src/formatters.js +12 -10
  329. package/components/input-tel/src/parsers.js +3 -3
  330. package/components/input-tel/src/preprocessors.js +15 -7
  331. package/components/input-tel/src/validators.js +4 -6
  332. package/components/input-tel/test/LionInputTel.test.js +4 -2
  333. package/components/input-tel/test/formatters.test.js +22 -10
  334. package/components/input-tel/test/parsers.test.js +40 -11
  335. package/components/input-tel/test/preprocessors.test.js +24 -13
  336. package/components/input-tel/test/validators.test.js +15 -13
  337. package/components/input-tel/test-helpers/mockPhoneUtilManager.js +7 -6
  338. package/components/input-tel/test-suites/LionInputTel.suite.js +33 -73
  339. package/components/input-tel/translations/bg-BG.js +0 -1
  340. package/components/input-tel/translations/cs-CZ.js +0 -1
  341. package/components/input-tel/translations/de-DE.js +0 -1
  342. package/components/input-tel/translations/en-AU.js +0 -1
  343. package/components/input-tel/translations/en-GB.js +0 -1
  344. package/components/input-tel/translations/en-US.js +0 -1
  345. package/components/input-tel/translations/es-ES.js +0 -1
  346. package/components/input-tel/translations/fr-BE.js +0 -1
  347. package/components/input-tel/translations/fr-FR.js +0 -1
  348. package/components/input-tel/translations/hu-HU.js +0 -1
  349. package/components/input-tel/translations/it-IT.js +0 -1
  350. package/components/input-tel/translations/nl-BE.js +0 -1
  351. package/components/input-tel/translations/nl-NL.js +0 -1
  352. package/components/input-tel/translations/pl-PL.js +0 -1
  353. package/components/input-tel/translations/ro-RO.js +0 -1
  354. package/components/input-tel/translations/ru-RU.js +0 -1
  355. package/components/input-tel/translations/sk-SK.js +0 -1
  356. package/components/input-tel/translations/uk-UA.js +0 -1
  357. package/components/input-tel-dropdown/src/LionInputTelDropdown.js +10 -28
  358. package/components/input-tel-dropdown/src/regionCodeToLocale.js +3 -1
  359. package/components/input-tel-dropdown/test/LionInputTelDropdown.test.js +31 -38
  360. package/components/input-tel-dropdown/test/regionCodeToLocale.test.js +0 -1
  361. package/components/input-tel-dropdown/test-helpers/mimicUserChangingDropdown.js +5 -1
  362. package/components/input-tel-dropdown/test-suites/LionInputTelDropdown--parentheses.suite.js +16 -11
  363. package/components/input-tel-dropdown/test-suites/LionInputTelDropdown.suite.js +54 -79
  364. package/components/listbox/src/LionListbox.js +4 -1
  365. package/components/listbox/src/LionOption.js +8 -7
  366. package/components/listbox/src/LionOptions.js +0 -3
  367. package/components/listbox/src/ListboxMixin.js +801 -819
  368. package/components/listbox/test/lion-listbox.test.js +0 -1
  369. package/components/listbox/test/lion-option.test.js +53 -64
  370. package/components/listbox/test/lion-options.test.js +3 -4
  371. package/components/listbox/test-helpers/getListboxMembers.js +6 -3
  372. package/components/listbox/test-suites/ListboxMixin.suite.js +101 -261
  373. package/components/listbox/types/ListboxMixinTypes.ts +7 -1
  374. package/components/localize/src/LocalizeManager.js +40 -40
  375. package/components/localize/src/LocalizeMixin.js +130 -157
  376. package/components/localize/src/date/formatDate.js +1 -5
  377. package/components/localize/src/date/getDateFormatBasedOnLocale.js +5 -3
  378. package/components/localize/src/date/getMonthNames.js +3 -5
  379. package/components/localize/src/date/getWeekdayNames.js +1 -5
  380. package/components/localize/src/date/parseDate.js +5 -20
  381. package/components/localize/src/date/utils/normalizeIntlDate.js +0 -7
  382. package/components/localize/src/getLocalizeManager.js +0 -3
  383. package/components/localize/src/number/formatNumber.js +3 -7
  384. package/components/localize/src/number/formatNumberToParts.js +52 -18
  385. package/components/localize/src/number/getCurrencyName.js +5 -5
  386. package/components/localize/src/number/getFractionDigits.js +4 -4
  387. package/components/localize/src/number/getSeparatorsFromNumber.js +1 -3
  388. package/components/localize/src/number/parseNumber.js +0 -3
  389. package/components/localize/src/number/utils/normalize-format-number-to-parts/forceAddGroupSeparators.js +0 -1
  390. package/components/localize/src/number/utils/normalize-format-number-to-parts/forceSpaceBetweenCurrencyCodeAndNumber.js +4 -1
  391. package/components/localize/test/LocalizeManager.test.js +385 -278
  392. package/components/localize/test/LocalizeMixin.test.js +28 -112
  393. package/components/localize/test/date/formatDate.test.js +18 -48
  394. package/components/localize/test/date/getDateFormatBasedOnLocale.test.js +0 -3
  395. package/components/localize/test/date/getMonthNames.test.js +27 -12
  396. package/components/localize/test/date/getWeekdayNames.test.js +93 -49
  397. package/components/localize/test/date/normalizeDateTime.test.js +0 -2
  398. package/components/localize/test/date/parseDate.test.js +12 -16
  399. package/components/localize/test/getLocalizeManager.test.js +0 -3
  400. package/components/localize/test/isLocalizeESModule.test.js +32 -13
  401. package/components/localize/test/localize.test.js +0 -4
  402. package/components/localize/test/number/formatNumber.test.js +215 -106
  403. package/components/localize/test/number/formatNumberToParts.test.js +31 -38
  404. package/components/localize/test/number/getCurrencyName.test.js +20 -6
  405. package/components/localize/test/number/getDecimalSeparator.test.js +5 -4
  406. package/components/localize/test/number/getFractionDigits.test.js +0 -2
  407. package/components/localize/test/number/getGroupSeparator.test.js +0 -2
  408. package/components/localize/test/number/getSeparatorsFromNumber.test.js +5 -3
  409. package/components/localize/test/number/parseNumber.test.js +123 -56
  410. package/components/localize/test/side-effect-free-entrypoint.test.js +0 -6
  411. package/components/localize/test-helpers/fake-imports.js +11 -6
  412. package/components/localize/test-helpers/localizeTearDown.js +0 -1
  413. package/components/menu/README.md +360 -0
  414. package/components/menu/src/InteractiveListMixin.js +866 -0
  415. package/components/menu/src/LionMenu.js +423 -0
  416. package/components/menu/src/MoreButtonMenuMixin.js +272 -0
  417. package/components/menu/src/MultiLevelListMixin.js +306 -0
  418. package/components/menu/src/utils/isInView.js +25 -0
  419. package/components/menu/src/utils/listItemInteractions.js +124 -0
  420. package/components/menu/test/InteractiveListMixin.test.js +2 -0
  421. package/components/menu/test/MoreButtonMenuMixin.test.js +5 -0
  422. package/components/menu/test/MultiLevelListMixin.test.js +2 -0
  423. package/components/menu/test/lion-menu-interactions.test.js +2 -0
  424. package/components/menu/test/lion-menu.test.js +18 -0
  425. package/components/menu/test-helpers/mimicKeyPress.js +19 -0
  426. package/components/menu/test-suites/InteractiveListMixin.suite.js +498 -0
  427. package/components/menu/test-suites/LionMenu.suite.js +107 -0
  428. package/components/menu/test-suites/LionMenuInteractions.suite.js +561 -0
  429. package/components/menu/test-suites/MoreButtonMenuMixin.suite.js +365 -0
  430. package/components/menu/test-suites/MultiLevelListMixin.suite.js +291 -0
  431. package/components/menu/types/InteractiveListMixinTypes.ts +126 -0
  432. package/components/menu/types/MoreButtonMenuMixinTypes.ts +51 -0
  433. package/components/menu/types/MultiLevelListMixinTypes.ts +28 -0
  434. package/components/menu/types/OverlayWithListInvokerMixinTypes.ts +61 -0
  435. package/components/overlays/NEXT.md +49 -0
  436. package/components/overlays/src/ArrowMixin.js +111 -127
  437. package/components/overlays/src/OverlayController.js +440 -246
  438. package/components/overlays/src/OverlayMixin.js +130 -68
  439. package/components/overlays/src/OverlaysManager.js +30 -32
  440. package/components/overlays/src/configurations/visibility-trigger-partials/withClickInteraction.js +0 -1
  441. package/components/overlays/src/configurations/visibility-trigger-partials/withHoverInteraction.js +11 -11
  442. package/components/overlays/src/configurations/withBottomSheetConfig.js +12 -13
  443. package/components/overlays/src/configurations/withDropdownConfig.js +4 -2
  444. package/components/overlays/src/configurations/withModalDialogConfig.js +12 -13
  445. package/components/overlays/src/configurations/withPopoverConfig.js +27 -25
  446. package/components/overlays/src/configurations/withTooltipConfig.js +15 -13
  447. package/components/overlays/src/overlayDocumentStyle.js +1 -1
  448. package/components/overlays/src/overlayShadowDomStyle.js +0 -1
  449. package/components/overlays/src/singleton.js +0 -2
  450. package/components/overlays/src/utils/adopt-styles.js +19 -19
  451. package/components/overlays/src/utils/deep-contains.js +7 -6
  452. package/components/overlays/src/utils/get-focusable-elements.js +7 -10
  453. package/components/overlays/src/utils/inert-siblings.js +2 -4
  454. package/components/overlays/src/utils/is-equal-config.js +14 -6
  455. package/components/overlays/src/utils/is-visible.js +0 -1
  456. package/components/overlays/src/utils/simulate-tab.js +1 -4
  457. package/components/overlays/src/utils/sort-by-tabindex.js +2 -4
  458. package/components/overlays/test/ArrowMixin.test.js +18 -30
  459. package/components/overlays/test/OverlayController.test.js +551 -533
  460. package/components/overlays/test/OverlayMixin.test.js +0 -2
  461. package/components/overlays/test/OverlaysManager.test.js +30 -35
  462. package/components/overlays/test/global-positioning.test.js +6 -10
  463. package/components/overlays/test/local-positioning.test.js +101 -103
  464. package/components/overlays/test/utils-tests/active-element.test.js +12 -27
  465. package/components/overlays/test/utils-tests/adopt-styles.test.js +25 -56
  466. package/components/overlays/test/utils-tests/deep-contains.test.js +73 -74
  467. package/components/overlays/test/utils-tests/get-focusable-elements.test.js +6 -23
  468. package/components/overlays/test/utils-tests/is-equal-config.test.js +32 -13
  469. package/components/overlays/test/utils-tests/visibility.test.js +44 -79
  470. package/components/overlays/test-helpers/createShadowHost.js +5 -3
  471. package/components/overlays/test-helpers/normalizeTransformStyle.js +2 -4
  472. package/components/overlays/test-suites/OverlayMixin.suite.js +159 -188
  473. package/components/overlays/test-suites/WithHoverInteraction.suite.js +96 -79
  474. package/components/overlays/translations/bg-BG.js +0 -1
  475. package/components/overlays/translations/cs-CZ.js +0 -1
  476. package/components/overlays/translations/de-DE.js +0 -1
  477. package/components/overlays/translations/en-AU.js +0 -1
  478. package/components/overlays/translations/en-GB.js +0 -1
  479. package/components/overlays/translations/en-US.js +0 -1
  480. package/components/overlays/translations/es-ES.js +0 -1
  481. package/components/overlays/translations/fr-BE.js +0 -1
  482. package/components/overlays/translations/fr-FR.js +0 -1
  483. package/components/overlays/translations/hu-HU.js +0 -1
  484. package/components/overlays/translations/it-IT.js +0 -1
  485. package/components/overlays/translations/nl-BE.js +0 -1
  486. package/components/overlays/translations/nl-NL.js +0 -1
  487. package/components/overlays/translations/pl-PL.js +0 -1
  488. package/components/overlays/translations/ro-RO.js +0 -1
  489. package/components/overlays/translations/ru-RU.js +0 -1
  490. package/components/overlays/translations/sk-SK.js +0 -1
  491. package/components/overlays/translations/tr-TR.js +0 -1
  492. package/components/overlays/translations/uk-UA.js +0 -1
  493. package/components/overlays/types/ArrowMixinTypes.ts +1 -3
  494. package/components/overlays/types/OverlayConfig.ts +20 -5
  495. package/components/overlays/types/OverlayMixinTypes.ts +2 -0
  496. package/components/pagination/src/LionPagination.js +9 -12
  497. package/components/pagination/test/lion-pagination.test.js +18 -50
  498. package/components/progress-indicator/src/LionProgressIndicator.js +10 -12
  499. package/components/progress-indicator/test/lion-progress-indicator.test.js +1 -22
  500. package/components/radio-group/src/LionRadioGroup.js +1 -2
  501. package/components/radio-group/test/lion-radio-group-integrations.test.js +0 -1
  502. package/components/radio-group/test/lion-radio-group.test.js +27 -27
  503. package/components/radio-group/test/lion-radio-integrations.test.js +3 -2
  504. package/components/radio-group/test/lion-radio.test.js +30 -16
  505. package/components/select/src/LionSelect.js +12 -13
  506. package/components/select/test/lion-select.test.js +7 -12
  507. package/components/select-rich/src/LionSelectInvoker.js +18 -11
  508. package/components/select-rich/src/LionSelectRich.js +32 -43
  509. package/components/select-rich/test/demos.screenshots-test.js +40 -9
  510. package/components/select-rich/test/lion-select-invoker.test.js +26 -43
  511. package/components/select-rich/test/lion-select-listbox-suite-integration.test.js +3 -3
  512. package/components/select-rich/test/lion-select-rich-dialog-integration.test.js +4 -9
  513. package/components/select-rich/test/lion-select-rich-interaction.test.js +154 -101
  514. package/components/select-rich/test/lion-select-rich-upgrade.test.js +26 -0
  515. package/components/select-rich/test/lion-select-rich.test.js +153 -195
  516. package/components/select-rich/test-helpers/getSelectRichMembers.js +4 -1
  517. package/components/steps/src/LionStep.js +21 -12
  518. package/components/steps/src/LionSteps.js +25 -25
  519. package/components/steps/test/lion-step.test.js +18 -25
  520. package/components/steps/test/lion-steps.test.js +45 -78
  521. package/components/switch/src/LionSwitch.js +2 -7
  522. package/components/switch/src/LionSwitchButton.js +5 -6
  523. package/components/switch/test/lion-switch-button.test.js +16 -28
  524. package/components/switch/test/lion-switch.test.js +17 -31
  525. package/components/tabs/src/LionTabs.js +25 -28
  526. package/components/tabs/test/lion-tabs.test.js +156 -154
  527. package/components/textarea/src/LionTextarea.js +4 -23
  528. package/components/textarea/test/lion-textarea-integrations.test.js +0 -5
  529. package/components/textarea/test/lion-textarea.test.js +2 -28
  530. package/components/tooltip/src/LionTooltip.js +6 -6
  531. package/components/tooltip/test/lion-tooltip.test.js +75 -102
  532. package/components/validate-messages/src/getLocalizedMessage.js +8 -7
  533. package/components/validate-messages/src/loadDefaultFeedbackMessages.js +3 -1
  534. package/components/validate-messages/src/loadDefaultFeedbackMessagesNoSideEffects.js +9 -5
  535. package/components/validate-messages/src/per-entrypoint/loadComboboxMessagesNoSideEffects.js +5 -2
  536. package/components/validate-messages/src/per-entrypoint/loadFormCoreMessagesNoSideEffects.js +99 -35
  537. package/components/validate-messages/src/per-entrypoint/loadInputTelMessagesNoSideEffects.js +4 -3
  538. package/components/validate-messages/test/loadDefaultFeedbackMessages.test.js +5 -3
  539. package/components/validate-messages/test/loadDefaultFeedbackMessagesNoSideEffects.test.js +80 -45
  540. package/components/validate-messages/translations/bg-BG.js +0 -1
  541. package/components/validate-messages/translations/cs-CZ.js +0 -1
  542. package/components/validate-messages/translations/de-DE.js +0 -1
  543. package/components/validate-messages/translations/en-AU.js +0 -1
  544. package/components/validate-messages/translations/en-GB.js +0 -1
  545. package/components/validate-messages/translations/en-PH.js +0 -1
  546. package/components/validate-messages/translations/en-US.js +0 -1
  547. package/components/validate-messages/translations/es-ES.js +0 -1
  548. package/components/validate-messages/translations/fr-BE.js +0 -1
  549. package/components/validate-messages/translations/fr-FR.js +0 -1
  550. package/components/validate-messages/translations/hu-HU.js +0 -1
  551. package/components/validate-messages/translations/it-IT.js +0 -1
  552. package/components/validate-messages/translations/nl-BE.js +0 -1
  553. package/components/validate-messages/translations/nl-NL.js +0 -1
  554. package/components/validate-messages/translations/pl-PL.js +0 -1
  555. package/components/validate-messages/translations/ro-RO.js +0 -1
  556. package/components/validate-messages/translations/ru-RU.js +0 -1
  557. package/components/validate-messages/translations/sk-SK.js +0 -1
  558. package/components/validate-messages/translations/tr-TR.js +0 -1
  559. package/components/validate-messages/translations/uk-UA.js +0 -1
  560. package/custom-elements.json +3312 -206
  561. package/dist-types/components/combobox/src/LionCombobox.d.ts +1 -1
  562. package/dist-types/components/combobox/src/LionCombobox.d.ts.map +1 -1
  563. package/dist-types/components/core/src/SlotMixin.d.ts +6 -1
  564. package/dist-types/components/core/src/SlotMixin.d.ts.map +1 -1
  565. package/dist-types/components/core/types/SlotMixinTypes.d.ts +5 -1
  566. package/dist-types/components/core/types/SlotMixinTypes.d.ts.map +1 -1
  567. package/dist-types/components/dialog/src/LionDialog.d.ts +6 -2
  568. package/dist-types/components/dialog/src/LionDialog.d.ts.map +1 -1
  569. package/dist-types/components/form-core/src/LionField.d.ts +3 -1
  570. package/dist-types/components/form-core/src/LionField.d.ts.map +1 -1
  571. package/dist-types/components/form-core/src/choice-group/ChoiceGroupMixin.d.ts.map +1 -1
  572. package/dist-types/components/form-core/types/choice-group/ChoiceGroupMixinTypes.d.ts +5 -0
  573. package/dist-types/components/form-core/types/choice-group/ChoiceGroupMixinTypes.d.ts.map +1 -1
  574. package/dist-types/components/input-amount/src/LionInputAmount.d.ts +3 -1
  575. package/dist-types/components/input-amount/src/LionInputAmount.d.ts.map +1 -1
  576. package/dist-types/components/input-amount/src/formatters.d.ts +6 -4
  577. package/dist-types/components/input-amount/src/formatters.d.ts.map +1 -1
  578. package/dist-types/components/input-datepicker/src/LionInputDatepicker.d.ts +1 -1
  579. package/dist-types/components/input-tel/src/LionInputTel.d.ts +6 -6
  580. package/dist-types/components/input-tel/src/LionInputTel.d.ts.map +1 -1
  581. package/dist-types/components/input-tel/src/PhoneUtilManager.d.ts +2 -2
  582. package/dist-types/components/input-tel/src/PhoneUtilManager.d.ts.map +1 -1
  583. package/dist-types/components/input-tel/src/formatters.d.ts +2 -2
  584. package/dist-types/components/input-tel/src/formatters.d.ts.map +1 -1
  585. package/dist-types/components/input-tel/src/preprocessors.d.ts +2 -2
  586. package/dist-types/components/input-tel/src/preprocessors.d.ts.map +1 -1
  587. package/dist-types/components/input-tel/test/validators.test.d.ts +1 -1
  588. package/dist-types/components/input-tel/test/validators.test.d.ts.map +1 -1
  589. package/dist-types/components/listbox/src/LionOption.d.ts +5 -2
  590. package/dist-types/components/listbox/src/LionOption.d.ts.map +1 -1
  591. package/dist-types/components/listbox/src/ListboxMixin.d.ts.map +1 -1
  592. package/dist-types/components/listbox/types/ListboxMixinTypes.d.ts +7 -1
  593. package/dist-types/components/listbox/types/ListboxMixinTypes.d.ts.map +1 -1
  594. package/dist-types/components/menu/src/InteractiveListMixin.d.ts +35 -0
  595. package/dist-types/components/menu/src/InteractiveListMixin.d.ts.map +1 -0
  596. package/dist-types/components/menu/src/LionMenu.d.ts +129 -0
  597. package/dist-types/components/menu/src/LionMenu.d.ts.map +1 -0
  598. package/dist-types/components/menu/src/MoreButtonMenuMixin.d.ts +8 -0
  599. package/dist-types/components/menu/src/MoreButtonMenuMixin.d.ts.map +1 -0
  600. package/dist-types/components/menu/src/MultiLevelListMixin.d.ts +7 -0
  601. package/dist-types/components/menu/src/MultiLevelListMixin.d.ts.map +1 -0
  602. package/dist-types/components/menu/src/utils/isInView.d.ts +9 -0
  603. package/dist-types/components/menu/src/utils/isInView.d.ts.map +1 -0
  604. package/dist-types/components/menu/src/utils/listItemInteractions.d.ts +48 -0
  605. package/dist-types/components/menu/src/utils/listItemInteractions.d.ts.map +1 -0
  606. package/dist-types/components/menu/test/InteractiveListMixin.test.d.ts +2 -0
  607. package/dist-types/components/menu/test/InteractiveListMixin.test.d.ts.map +1 -0
  608. package/dist-types/components/menu/test/MoreButtonMenuMixin.test.d.ts +2 -0
  609. package/dist-types/components/menu/test/MoreButtonMenuMixin.test.d.ts.map +1 -0
  610. package/dist-types/components/menu/test/MultiLevelListMixin.test.d.ts +2 -0
  611. package/dist-types/components/menu/test/MultiLevelListMixin.test.d.ts.map +1 -0
  612. package/dist-types/components/menu/test/lion-menu-interactions.test.d.ts +2 -0
  613. package/dist-types/components/menu/test/lion-menu-interactions.test.d.ts.map +1 -0
  614. package/dist-types/components/menu/test/lion-menu.test.d.ts +2 -0
  615. package/dist-types/components/menu/test/lion-menu.test.d.ts.map +1 -0
  616. package/dist-types/components/menu/test-helpers/mimicKeyPress.d.ts +7 -0
  617. package/dist-types/components/menu/test-helpers/mimicKeyPress.d.ts.map +1 -0
  618. package/dist-types/components/menu/test-suites/InteractiveListMixin.suite.d.ts +11 -0
  619. package/dist-types/components/menu/test-suites/InteractiveListMixin.suite.d.ts.map +1 -0
  620. package/dist-types/components/menu/test-suites/LionMenu.suite.d.ts +9 -0
  621. package/dist-types/components/menu/test-suites/LionMenu.suite.d.ts.map +1 -0
  622. package/dist-types/components/menu/test-suites/LionMenuInteractions.suite.d.ts +5 -0
  623. package/dist-types/components/menu/test-suites/LionMenuInteractions.suite.d.ts.map +1 -0
  624. package/dist-types/components/menu/test-suites/MoreButtonMenuMixin.suite.d.ts +11 -0
  625. package/dist-types/components/menu/test-suites/MoreButtonMenuMixin.suite.d.ts.map +1 -0
  626. package/dist-types/components/menu/test-suites/MultiLevelListMixin.suite.d.ts +11 -0
  627. package/dist-types/components/menu/test-suites/MultiLevelListMixin.suite.d.ts.map +1 -0
  628. package/dist-types/components/menu/types/InteractiveListMixinTypes.d.ts +72 -0
  629. package/dist-types/components/menu/types/InteractiveListMixinTypes.d.ts.map +1 -0
  630. package/dist-types/components/menu/types/MoreButtonMenuMixinTypes.d.ts +30 -0
  631. package/dist-types/components/menu/types/MoreButtonMenuMixinTypes.d.ts.map +1 -0
  632. package/dist-types/components/menu/types/MultiLevelListMixinTypes.d.ts +16 -0
  633. package/dist-types/components/menu/types/MultiLevelListMixinTypes.d.ts.map +1 -0
  634. package/dist-types/components/menu/types/OverlayWithListInvokerMixinTypes.d.ts +35 -0
  635. package/dist-types/components/menu/types/OverlayWithListInvokerMixinTypes.d.ts.map +1 -0
  636. package/dist-types/components/overlays/src/OverlayController.d.ts +22 -5
  637. package/dist-types/components/overlays/src/OverlayController.d.ts.map +1 -1
  638. package/dist-types/components/overlays/src/OverlayMixin.d.ts.map +1 -1
  639. package/dist-types/components/overlays/src/OverlaysManager.d.ts.map +1 -1
  640. package/dist-types/components/overlays/src/overlayDocumentStyle.d.ts.map +1 -1
  641. package/dist-types/components/overlays/src/utils/is-equal-config.d.ts.map +1 -1
  642. package/dist-types/components/overlays/types/ArrowMixinTypes.d.ts.map +1 -1
  643. package/dist-types/components/overlays/types/OverlayConfig.d.ts +12 -2
  644. package/dist-types/components/overlays/types/OverlayConfig.d.ts.map +1 -1
  645. package/dist-types/components/overlays/types/OverlayMixinTypes.d.ts +1 -0
  646. package/dist-types/components/overlays/types/OverlayMixinTypes.d.ts.map +1 -1
  647. package/dist-types/components/select-rich/src/LionSelectInvoker.d.ts +3 -1
  648. package/dist-types/components/select-rich/src/LionSelectInvoker.d.ts.map +1 -1
  649. package/dist-types/components/select-rich/src/LionSelectRich.d.ts +13 -2
  650. package/dist-types/components/select-rich/src/LionSelectRich.d.ts.map +1 -1
  651. package/dist-types/components/select-rich/test/lion-select-rich-interaction.test.d.ts.map +1 -1
  652. package/dist-types/components/select-rich/test/lion-select-rich-upgrade.test.d.ts +2 -0
  653. package/dist-types/components/select-rich/test/lion-select-rich-upgrade.test.d.ts.map +1 -0
  654. package/dist-types/components/tooltip/src/LionTooltip.d.ts +1 -1
  655. package/dist-types/exports/define/lion-item.d.ts +2 -0
  656. package/dist-types/exports/define/lion-item.d.ts.map +1 -0
  657. package/dist-types/exports/define/lion-menu.d.ts +2 -0
  658. package/dist-types/exports/define/lion-menu.d.ts.map +1 -0
  659. package/dist-types/exports/define/lion-menuitem.d.ts +2 -0
  660. package/dist-types/exports/define/lion-menuitem.d.ts.map +1 -0
  661. package/dist-types/exports/menu-test-suites.d.ts +4 -0
  662. package/dist-types/exports/menu-test-suites.d.ts.map +1 -0
  663. package/dist-types/exports/menu.d.ts +3 -0
  664. package/dist-types/exports/menu.d.ts.map +1 -0
  665. package/dist-types/exports/overlays.d.ts +6 -0
  666. package/dist-types/exports/overlays.d.ts.map +1 -1
  667. package/dist-types/tsconfig.tsbuildinfo +1 -1
  668. package/docs/components/accordion/overview.md +2 -2
  669. package/docs/components/accordion/reference.md +2 -2
  670. package/docs/components/accordion/use-cases.md +2 -2
  671. package/docs/components/button/examples.md +2 -2
  672. package/docs/components/button/extensions.md +2 -2
  673. package/docs/components/button/overview.md +2 -2
  674. package/docs/components/button/use-cases.md +2 -2
  675. package/docs/components/calendar/overview.md +2 -2
  676. package/docs/components/calendar/use-cases.md +2 -2
  677. package/docs/components/checkbox-group/overview.md +4 -4
  678. package/docs/components/checkbox-group/use-cases.md +2 -2
  679. package/docs/components/collapsible/examples.md +2 -2
  680. package/docs/components/collapsible/overview.md +3 -3
  681. package/docs/components/collapsible/use-cases.md +2 -2
  682. package/docs/components/combobox/api-table.md +53 -39
  683. package/docs/components/combobox/extensions.md +2 -2
  684. package/docs/components/combobox/overview.md +3 -3
  685. package/docs/components/combobox/use-cases.md +3 -3
  686. package/docs/components/dialog/api-table.md +32 -6
  687. package/docs/components/dialog/overview.md +3 -3
  688. package/docs/components/dialog/use-cases.md +2 -2
  689. package/docs/components/drawer/overview.md +2 -2
  690. package/docs/components/drawer/use-cases.md +2 -2
  691. package/docs/components/fieldset/overview.md +7 -7
  692. package/docs/components/fieldset/use-cases.md +2 -2
  693. package/docs/components/form/overview.md +5 -5
  694. package/docs/components/form/use-cases.md +4 -4
  695. package/docs/components/icon/overview.md +2 -2
  696. package/docs/components/icon/use-cases.md +3 -3
  697. package/docs/components/input/overview.md +3 -3
  698. package/docs/components/input/use-cases.md +2 -2
  699. package/docs/components/input-amount/api-table.md +9 -7
  700. package/docs/components/input-amount/overview.md +5 -5
  701. package/docs/components/input-amount/use-cases.md +17 -6
  702. package/docs/components/input-amount-dropdown/api-table.md +2 -0
  703. package/docs/components/input-amount-dropdown/use-cases.md +2 -2
  704. package/docs/components/input-date/overview.md +5 -5
  705. package/docs/components/input-date/use-cases.md +2 -2
  706. package/docs/components/input-datepicker/api-table.md +63 -45
  707. package/docs/components/input-datepicker/overview.md +7 -7
  708. package/docs/components/input-datepicker/use-cases.md +2 -2
  709. package/docs/components/input-email/overview.md +4 -4
  710. package/docs/components/input-email/use-cases.md +2 -2
  711. package/docs/components/input-file/overview.md +3 -3
  712. package/docs/components/input-file/use-cases.md +2 -2
  713. package/docs/components/input-iban/overview.md +4 -4
  714. package/docs/components/input-iban/use-cases.md +2 -2
  715. package/docs/components/input-range/overview.md +4 -4
  716. package/docs/components/input-range/use-cases.md +2 -2
  717. package/docs/components/input-stepper/overview.md +3 -3
  718. package/docs/components/input-stepper/use-cases.md +2 -2
  719. package/docs/components/input-tel/overview.md +3 -3
  720. package/docs/components/input-tel/use-cases.md +8 -8
  721. package/docs/components/input-tel-dropdown/extensions.md +2 -2
  722. package/docs/components/input-tel-dropdown/overview.md +3 -3
  723. package/docs/components/input-tel-dropdown/use-cases.md +2 -2
  724. package/docs/components/listbox/overview.md +2 -2
  725. package/docs/components/listbox/use-cases.md +3 -3
  726. package/docs/components/menu/api-table.md +44 -0
  727. package/docs/components/menu/applyMenuDemoStyles.js +173 -0
  728. package/docs/components/menu/extensions.md +262 -0
  729. package/docs/components/menu/index.md +13 -0
  730. package/docs/components/menu/migration.md +129 -0
  731. package/docs/components/menu/overview.md +448 -0
  732. package/docs/components/menu/src/DemoNavigationBar.js +441 -0
  733. package/docs/components/menu/src/DemoSpinButton.js +215 -0
  734. package/docs/components/menu/src/DemoToolbar.js +101 -0
  735. package/docs/components/menu/src/DemoTree.js +55 -0
  736. package/docs/components/menu/src/navigation-bar-types.js +41 -0
  737. package/docs/components/menu/use-cases.md +74 -0
  738. package/docs/components/pagination/overview.md +2 -2
  739. package/docs/components/pagination/use-cases.md +2 -2
  740. package/docs/components/progress-indicator/examples.md +2 -2
  741. package/docs/components/progress-indicator/overview.md +2 -2
  742. package/docs/components/radio-group/overview.md +5 -5
  743. package/docs/components/radio-group/use-cases.md +2 -2
  744. package/docs/components/select/overview.md +2 -2
  745. package/docs/components/select/use-cases.md +3 -3
  746. package/docs/components/select-rich/api-table.md +51 -33
  747. package/docs/components/select-rich/examples.md +2 -2
  748. package/docs/components/select-rich/overview.md +2 -2
  749. package/docs/components/select-rich/use-cases.md +4 -4
  750. package/docs/components/steps/overview.md +2 -2
  751. package/docs/components/steps/use-cases.md +2 -2
  752. package/docs/components/switch/overview.md +2 -2
  753. package/docs/components/switch/reference.md +2 -2
  754. package/docs/components/switch/use-cases.md +2 -2
  755. package/docs/components/tabs/examples.md +3 -3
  756. package/docs/components/tabs/overview.md +2 -2
  757. package/docs/components/tabs/use-cases.md +2 -2
  758. package/docs/components/textarea/overview.md +2 -2
  759. package/docs/components/textarea/use-cases.md +2 -2
  760. package/docs/components/tooltip/api-table.md +33 -7
  761. package/docs/components/tooltip/examples.md +2 -2
  762. package/docs/components/tooltip/overview.md +2 -2
  763. package/docs/components/tooltip/use-cases.md +2 -2
  764. package/docs/fundamentals/index.md +4 -4
  765. package/docs/fundamentals/node-tools/babel-plugin-extend-docs/index.md +2 -2
  766. package/docs/fundamentals/node-tools/babel-plugin-extend-docs/overview.md +2 -2
  767. package/docs/fundamentals/node-tools/providence-analytics/index.md +2 -2
  768. package/docs/fundamentals/node-tools/providence-analytics/overview.md +3 -3
  769. package/docs/fundamentals/node-tools/publish-docs/index.md +2 -2
  770. package/docs/fundamentals/node-tools/publish-docs/overview.md +5 -5
  771. package/docs/fundamentals/node-tools/remark-extend/index.md +2 -2
  772. package/docs/fundamentals/node-tools/remark-extend/overview.md +2 -2
  773. package/docs/fundamentals/node-tools/rocket-preset-extend-lion-docs/index.md +2 -2
  774. package/docs/fundamentals/node-tools/rocket-preset-extend-lion-docs/overview.md +4 -4
  775. package/docs/fundamentals/rationales/TypeScript.md +62 -2
  776. package/docs/fundamentals/rationales/accessibility.md +5 -5
  777. package/docs/fundamentals/rationales/side-effects.md +2 -2
  778. package/docs/fundamentals/rationales/versioning.md +2 -2
  779. package/docs/fundamentals/systems/core/SlotMixin.md +3 -3
  780. package/docs/fundamentals/systems/core/index.md +2 -2
  781. package/docs/fundamentals/systems/core/overview.md +3 -3
  782. package/docs/fundamentals/systems/form/formatting-and-parsing.md +6 -6
  783. package/docs/fundamentals/systems/form/index.md +2 -2
  784. package/docs/fundamentals/systems/form/interaction-states.md +2 -2
  785. package/docs/fundamentals/systems/form/model-value.md +3 -3
  786. package/docs/fundamentals/systems/form/overview.md +30 -30
  787. package/docs/fundamentals/systems/form/styling.md +2 -2
  788. package/docs/fundamentals/systems/form/use-cases.md +2 -2
  789. package/docs/fundamentals/systems/form/validate.md +4 -4
  790. package/docs/fundamentals/systems/icon/index.md +2 -2
  791. package/docs/fundamentals/systems/icon/overview.md +2 -2
  792. package/docs/fundamentals/systems/localize/dates.md +2 -2
  793. package/docs/fundamentals/systems/localize/index.md +2 -2
  794. package/docs/fundamentals/systems/localize/numbers.md +2 -2
  795. package/docs/fundamentals/systems/localize/overview.md +6 -6
  796. package/docs/fundamentals/systems/localize/rationale.md +2 -2
  797. package/docs/fundamentals/systems/localize/text.md +2 -2
  798. package/docs/fundamentals/systems/localize/use-cases.md +2 -2
  799. package/docs/fundamentals/systems/overlays/_edge-cases.md +2 -2
  800. package/docs/fundamentals/systems/overlays/api-table.md +46 -43
  801. package/docs/fundamentals/systems/overlays/configuration.md +4 -4
  802. package/docs/fundamentals/systems/overlays/index.md +2 -2
  803. package/docs/fundamentals/systems/overlays/overview.md +7 -7
  804. package/docs/fundamentals/systems/overlays/rationale.md +2 -2
  805. package/docs/fundamentals/systems/overlays/use-cases.md +4 -4
  806. package/docs/fundamentals/tools/ajax/index.md +2 -2
  807. package/docs/fundamentals/tools/ajax/overview.md +2 -2
  808. package/docs/fundamentals/tools/ajax/use-cases.md +2 -2
  809. package/docs/fundamentals/tools/helpers/action-logger.md +2 -2
  810. package/docs/fundamentals/tools/helpers/index.md +2 -2
  811. package/docs/fundamentals/tools/helpers/overview.md +3 -3
  812. package/docs/fundamentals/tools/singleton-manager/example-complex/index.md +2 -2
  813. package/docs/fundamentals/tools/singleton-manager/example-fail/index.md +2 -2
  814. package/docs/fundamentals/tools/singleton-manager/example-success/index.md +2 -2
  815. package/docs/fundamentals/tools/singleton-manager/index.md +2 -2
  816. package/docs/fundamentals/tools/singleton-manager/overview.md +6 -6
  817. package/docs/guides/how-to/create-a-custom-field.md +7 -7
  818. package/docs/guides/how-to/create-a-form.md +6 -6
  819. package/docs/guides/how-to/extend-a-native-input.md +4 -4
  820. package/docs/guides/how-to/get-started.md +2 -2
  821. package/docs/guides/how-to/index.md +1 -1
  822. package/docs/guides/index.md +8 -8
  823. package/docs/guides/principles/definitions-and-terms.md +2 -2
  824. package/docs/guides/principles/index.md +5 -5
  825. package/docs/guides/principles/scoped-elements.md +2 -2
  826. package/docs/guides/principles/styling.md +3 -3
  827. package/docs/guides/principles/subclasser-apis.md +2 -2
  828. package/exports/define/lion-accordion.js +0 -1
  829. package/exports/define/lion-button-reset.js +0 -1
  830. package/exports/define/lion-button-submit.js +0 -1
  831. package/exports/define/lion-button.js +0 -1
  832. package/exports/define/lion-calendar.js +0 -1
  833. package/exports/define/lion-checkbox-group.js +0 -1
  834. package/exports/define/lion-checkbox-indeterminate.js +0 -1
  835. package/exports/define/lion-checkbox.js +0 -1
  836. package/exports/define/lion-collapsible.js +0 -1
  837. package/exports/define/lion-combobox.js +0 -1
  838. package/exports/define/lion-dialog.js +0 -1
  839. package/exports/define/lion-drawer.js +0 -1
  840. package/exports/define/lion-field.js +0 -1
  841. package/exports/define/lion-fieldset.js +0 -1
  842. package/exports/define/lion-form.js +0 -1
  843. package/exports/define/lion-icon.js +0 -1
  844. package/exports/define/lion-input-amount-dropdown.js +0 -1
  845. package/exports/define/lion-input-amount.js +0 -1
  846. package/exports/define/lion-input-date.js +0 -1
  847. package/exports/define/lion-input-datepicker.js +0 -1
  848. package/exports/define/lion-input-email.js +0 -1
  849. package/exports/define/lion-input-file.js +0 -1
  850. package/exports/define/lion-input-iban.js +0 -1
  851. package/exports/define/lion-input-range.js +0 -1
  852. package/exports/define/lion-input-stepper.js +0 -1
  853. package/exports/define/lion-input-tel-dropdown.js +0 -1
  854. package/exports/define/lion-input-tel.js +0 -1
  855. package/exports/define/lion-input.js +0 -1
  856. package/exports/define/lion-item.js +2 -0
  857. package/exports/define/lion-listbox.js +0 -1
  858. package/exports/define/lion-menu.js +2 -0
  859. package/exports/define/lion-menuitem.js +2 -0
  860. package/exports/define/lion-option.js +0 -1
  861. package/exports/define/lion-options.js +0 -1
  862. package/exports/define/lion-pagination.js +0 -1
  863. package/exports/define/lion-progress-indicator.js +0 -1
  864. package/exports/define/lion-radio-group.js +0 -1
  865. package/exports/define/lion-radio.js +0 -1
  866. package/exports/define/lion-select-invoker.js +0 -1
  867. package/exports/define/lion-select-rich.js +0 -1
  868. package/exports/define/lion-select.js +0 -1
  869. package/exports/define/lion-selected-file-list.js +0 -1
  870. package/exports/define/lion-step.js +0 -1
  871. package/exports/define/lion-steps.js +0 -1
  872. package/exports/define/lion-switch-button.js +0 -1
  873. package/exports/define/lion-switch.js +0 -1
  874. package/exports/define/lion-tabs.js +0 -1
  875. package/exports/define/lion-textarea.js +0 -1
  876. package/exports/define/lion-tooltip.js +0 -1
  877. package/exports/define/lion-validation-feedback.js +0 -1
  878. package/exports/define-helpers/sb-action-logger.js +0 -1
  879. package/exports/define-helpers/sb-locale-switcher.js +0 -1
  880. package/exports/form-core.js +0 -8
  881. package/exports/localize-no-side-effects.js +0 -1
  882. package/exports/localize.js +0 -2
  883. package/exports/menu-test-suites.js +4 -0
  884. package/exports/menu.js +3 -0
  885. package/exports/overlays.js +6 -4
  886. package/generated/awesome-phonenumber/LICENSE +22 -0
  887. package/generated/awesome-phonenumber/LICENSE.closure-library +176 -0
  888. package/generated/awesome-phonenumber/LICENSE.libphonenumber +176 -0
  889. package/generated/awesome-phonenumber/checksums.json +6 -0
  890. package/generated/awesome-phonenumber/index-esm.mjs +817 -0
  891. package/generated/awesome-phonenumber/index.d.ts +227 -0
  892. package/generated/awesome-phonenumber/index.js +45 -0
  893. package/generated/awesome-phonenumber/lib/index.js +710 -0
  894. package/generated/awesome-phonenumber/package.json +9 -0
  895. package/generated/awesome-phonenumber/provenance.json +13 -0
  896. package/menu-test-suites.js +4 -0
  897. package/menu.js +3 -0
  898. package/overlays.js +6 -0
  899. package/package.json +35 -6
  900. package/vscode.html-custom-data.json +76 -8
  901. package/web-types.json +202 -17
@@ -14,7 +14,6 @@ import {
14
14
  html,
15
15
  waitUntil,
16
16
  } from '@open-wc/testing';
17
-
18
17
  import { isActiveElement } from '../../core/test-helpers/isActiveElement.js';
19
18
  import { createShadowHost } from '../test-helpers/createShadowHost.js';
20
19
  import { _adoptStyleUtils } from '../src/utils/adopt-styles.js';
@@ -45,7 +44,9 @@ async function mimicEscapePress(element) {
45
44
  }
46
45
 
47
46
  // Send the event
48
- await sendKeys({ press: 'Escape' });
47
+ await sendKeys({
48
+ press: 'Escape',
49
+ });
49
50
  // Wait for at least a microtask, so that possible property effects are performed
50
51
  await aTimeout(0);
51
52
  }
@@ -55,7 +56,7 @@ async function mimicEscapePress(element) {
55
56
  * @returns {boolean}
56
57
  */
57
58
  function isRegisteredOnManager(ctrlToFind) {
58
- return Boolean(ctrlToFind.manager?.list?.find(ctrl => ctrlToFind === ctrl));
59
+ return Boolean(ctrlToFind.manager?.list?.find((ctrl) => ctrlToFind === ctrl));
59
60
  }
60
61
 
61
62
  /**
@@ -84,7 +85,7 @@ function getProtectedMembers(overlayControllerEl) {
84
85
  /**
85
86
  * @param {HTMLElement} element
86
87
  * */
87
- const isInViewport = element => {
88
+ const isInViewport = (element) => {
88
89
  const rect = element.getBoundingClientRect();
89
90
  return (
90
91
  rect.top >= 0 &&
@@ -93,49 +94,49 @@ const isInViewport = element => {
93
94
  rect.right <= (window.innerWidth || document.documentElement.clientWidth)
94
95
  );
95
96
  };
96
-
97
- const withGlobalTestConfig = () =>
98
- /** @type {OverlayConfig} */ ({
99
- placementMode: 'global',
100
- contentNode: /** @type {HTMLElement} */ (fixtureSync(html`<div>my content</div>`)),
101
- });
102
-
103
- const withLocalTestConfig = () =>
104
- /** @type {OverlayConfig} */ ({
105
- placementMode: 'local',
106
- contentNode: /** @type {HTMLElement} */ (fixtureSync(html`<div>my content</div>`)),
107
- invokerNode: /** @type {HTMLElement} */ (
108
- fixtureSync(html` <div role="button" style="width: 100px; height: 20px;">Invoker</div> `)
109
- ),
110
- });
97
+ const withGlobalTestConfig = () => /** @type {OverlayConfig} */ ({
98
+ placementMode: 'global',
99
+ contentNode: /** @type {HTMLElement} */ fixtureSync(html`<div>my content</div>`),
100
+ });
101
+ const withLocalTestConfig = () => /** @type {OverlayConfig} */ ({
102
+ placementMode: 'local',
103
+ contentNode: /** @type {HTMLElement} */ fixtureSync(html`<div>my content</div>`),
104
+ invokerNode:
105
+ /** @type {HTMLElement} */
106
+ fixtureSync(html` <div role="button" style="width: 100px; height: 20px;">Invoker</div> `),
107
+ });
111
108
 
112
109
  /**
113
110
  * @param {HTMLDivElement} parentContent
114
111
  * @returns {Promise<{parentOverlay: OverlayController; childOverlay: OverlayController}>}
115
112
  */
116
113
  async function createNestedEscControllers(parentContent) {
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
- }
127
-
114
+ const childContent = /** @type {HTMLDivElement} */ parentContent.querySelector('div[id]');
128
115
  if (parentContent.hasAttribute('data-convert-to-shadow-root')) {
129
- const shadowRootParent = parentContent.attachShadow({ mode: 'open' });
116
+ const shadowRootParent = parentContent.attachShadow({
117
+ mode: 'open',
118
+ });
130
119
  shadowRootParent.appendChild(childContent);
131
120
  }
132
-
121
+ const parentConfig = {};
122
+ const childConfig = {};
133
123
  const parentHasOutsideOnEsc = parentContent.id.startsWith('parent-overlay--hidesOnOutsideEsc');
134
124
  const childHasOutsideOnEsc = childContent.id.startsWith('child-overlay--hidesOnOutsideEsc');
135
-
136
- const parentConfig = parentHasOutsideOnEsc ? { hidesOnOutsideEsc: true } : { hidesOnEsc: true };
137
- const childConfig = childHasOutsideOnEsc ? { hidesOnOutsideEsc: true } : { hidesOnEsc: true };
138
-
125
+ if (parentHasOutsideOnEsc) {
126
+ parentConfig.hidesOnOutsideEsc = true;
127
+ } else {
128
+ parentConfig.hidesOnEsc = true;
129
+ }
130
+ if (childHasOutsideOnEsc) {
131
+ childConfig.hidesOnOutsideEsc = true;
132
+ } else {
133
+ childConfig.hidesOnEsc = true;
134
+ }
135
+ const parentHasSyncChildrenCloseState =
136
+ parentContent.dataset.syncChildrenCloseState !== undefined;
137
+ if (parentHasSyncChildrenCloseState) {
138
+ parentConfig.syncChildrenCloseState = true;
139
+ }
139
140
  const parentOverlay = new OverlayController({
140
141
  ...withGlobalTestConfig(),
141
142
  contentNode: parentContent,
@@ -146,19 +147,18 @@ async function createNestedEscControllers(parentContent) {
146
147
  contentNode: childContent,
147
148
  ...childConfig,
148
149
  });
149
-
150
150
  await parentOverlay.show();
151
151
  await childOverlay.show();
152
-
153
- return { parentOverlay, childOverlay };
152
+ return {
153
+ parentOverlay,
154
+ childOverlay,
155
+ };
154
156
  }
155
-
156
157
  afterEach(() => {
157
158
  overlays.teardown();
158
159
  // clean document.body from the DOM nodes left by previous tests
159
160
  document.body.innerHTML = '';
160
161
  });
161
-
162
162
  describe('OverlayController', () => {
163
163
  describe('Init', () => {
164
164
  it('adds OverlayController instance to OverlayManager', async () => {
@@ -168,7 +168,6 @@ describe('OverlayController', () => {
168
168
  expect(ctrl.manager).to.equal(overlays);
169
169
  expect(overlays.list).to.include(ctrl);
170
170
  });
171
-
172
171
  it('prepares a content node wrapper', async () => {
173
172
  const ctrl = new OverlayController({
174
173
  ...withGlobalTestConfig(),
@@ -176,12 +175,11 @@ describe('OverlayController', () => {
176
175
  expect(ctrl.content).not.to.be.undefined;
177
176
  expect(ctrl.contentNode.parentElement).to.equal(ctrl.contentWrapperNode);
178
177
  });
179
-
180
178
  describe('Stylesheets', () => {
181
179
  it('calls adoptStyles', async () => {
182
180
  const spy = sinon.spy(_adoptStyleUtils, 'adoptStyle');
183
181
  const { shadowHost, cleanupShadowHost } = createShadowHost();
184
- const contentNode = /** @type {HTMLElement} */ (await fixture('<div>contentful</div>'));
182
+ const contentNode = /** @type {HTMLElement} */ await fixture('<div>contentful</div>');
185
183
  shadowHost.appendChild(contentNode);
186
184
  new OverlayController({
187
185
  ...withLocalTestConfig(),
@@ -191,7 +189,6 @@ describe('OverlayController', () => {
191
189
  cleanupShadowHost();
192
190
  });
193
191
  });
194
-
195
192
  describe('Z-index on local overlays', () => {
196
193
  /** @type {HTMLElement} */
197
194
  let contentNode;
@@ -201,7 +198,8 @@ describe('OverlayController', () => {
201
198
  */
202
199
  async function createZNode(zIndexVal, { mode } = {}) {
203
200
  if (mode === 'global') {
204
- contentNode = /** @type {HTMLElement} */ (
201
+ contentNode =
202
+ /** @type {HTMLElement} */
205
203
  await fixture(html`
206
204
  <div class="z-index--${zIndexVal}">
207
205
  <style>
@@ -211,69 +209,92 @@ describe('OverlayController', () => {
211
209
  </style>
212
210
  I should be on top
213
211
  </div>
214
- `)
215
- );
212
+ `);
216
213
  }
217
214
  if (mode === 'inline') {
218
- contentNode = /** @type {HTMLElement} */ (
219
- await fixture(html` <div>I should be on top</div> `)
220
- );
215
+ contentNode =
216
+ /** @type {HTMLElement} */
217
+ await fixture(html` <div>I should be on top</div> `);
221
218
  contentNode.style.zIndex = zIndexVal;
222
219
  }
223
220
  return contentNode;
224
221
  }
225
-
226
222
  it('sets a z-index to make sure overlay is painted on top of siblings', async () => {
227
223
  const ctrl = new OverlayController({
228
224
  ...withLocalTestConfig(),
229
- contentNode: await createZNode('auto', { mode: 'global' }),
225
+ contentNode: await createZNode('auto', {
226
+ mode: 'global',
227
+ }),
230
228
  });
231
229
  await ctrl.show();
232
230
  // @ts-expect-error find out why config would/could be undfined
233
231
  expect(ctrl.content.style.zIndex).to.equal(`${ctrl.config.zIndex + 1}`);
234
- ctrl.updateConfig({ contentNode: await createZNode('auto', { mode: 'inline' }) });
232
+ ctrl.updateConfig({
233
+ contentNode: await createZNode('auto', {
234
+ mode: 'inline',
235
+ }),
236
+ });
235
237
  await ctrl.show();
236
238
  // @ts-expect-error find out why config would/could be undfined
237
239
  expect(ctrl.content.style.zIndex).to.equal(`${ctrl.config.zIndex + 1}`);
238
-
239
- ctrl.updateConfig({ contentNode: await createZNode('0', { mode: 'global' }) });
240
+ ctrl.updateConfig({
241
+ contentNode: await createZNode('0', {
242
+ mode: 'global',
243
+ }),
244
+ });
240
245
  await ctrl.show();
241
246
  // @ts-expect-error find out why config would/could be undfined
242
247
  expect(ctrl.content.style.zIndex).to.equal(`${ctrl.config.zIndex + 1}`);
243
- ctrl.updateConfig({ contentNode: await createZNode('0', { mode: 'inline' }) });
248
+ ctrl.updateConfig({
249
+ contentNode: await createZNode('0', {
250
+ mode: 'inline',
251
+ }),
252
+ });
244
253
  await ctrl.show();
245
254
  // @ts-expect-error find out why config would/could be undfined
246
255
  expect(ctrl.content.style.zIndex).to.equal(`${ctrl.config.zIndex + 1}`);
247
256
  });
248
-
249
257
  it.skip("doesn't set a z-index when contentNode already has >= 1", async () => {
250
258
  const ctrl = new OverlayController({
251
259
  ...withLocalTestConfig(),
252
- contentNode: await createZNode('1', { mode: 'global' }),
260
+ contentNode: await createZNode('1', {
261
+ mode: 'global',
262
+ }),
253
263
  });
254
264
  await ctrl.show();
255
265
  expect(ctrl.content.style.zIndex).to.equal('');
256
- ctrl.updateConfig({ contentNode: await createZNode('auto', { mode: 'inline' }) });
266
+ ctrl.updateConfig({
267
+ contentNode: await createZNode('auto', {
268
+ mode: 'inline',
269
+ }),
270
+ });
257
271
  await ctrl.show();
258
272
  expect(ctrl.content.style.zIndex).to.equal('');
259
-
260
- ctrl.updateConfig({ contentNode: await createZNode('2', { mode: 'global' }) });
273
+ ctrl.updateConfig({
274
+ contentNode: await createZNode('2', {
275
+ mode: 'global',
276
+ }),
277
+ });
261
278
  await ctrl.show();
262
279
  expect(ctrl.content.style.zIndex).to.equal('');
263
- ctrl.updateConfig({ contentNode: await createZNode('2', { mode: 'inline' }) });
280
+ ctrl.updateConfig({
281
+ contentNode: await createZNode('2', {
282
+ mode: 'inline',
283
+ }),
284
+ });
264
285
  await ctrl.show();
265
286
  expect(ctrl.content.style.zIndex).to.equal('');
266
287
  });
267
-
268
288
  it("doesn't touch the value of .contentNode", async () => {
269
289
  const ctrl = new OverlayController({
270
290
  ...withLocalTestConfig(),
271
- contentNode: await createZNode('auto', { mode: 'global' }),
291
+ contentNode: await createZNode('auto', {
292
+ mode: 'global',
293
+ }),
272
294
  });
273
295
  expect(ctrl.contentNode.style.zIndex).to.equal('');
274
296
  });
275
297
  });
276
-
277
298
  describe('Offline content', () => {
278
299
  it('throws when passing a content node that was created "offline"', async () => {
279
300
  const contentNode = document.createElement('div');
@@ -284,12 +305,11 @@ describe('OverlayController', () => {
284
305
  });
285
306
  };
286
307
  expect(createOverlayController).to.throw(
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.',
308
+ '[OverlayController] Could not find a render target, makes sure contentNode has a parent element (or contentWrapperNode is connected)',
288
309
  );
289
310
  });
290
-
291
311
  it('succeeds when passing a content node that was created "online"', async () => {
292
- const contentNode = /** @type {HTMLElement} */ (fixtureSync('<div>'));
312
+ const contentNode = /** @type {HTMLElement} */ fixtureSync('<div>');
293
313
  const overlay = new OverlayController({
294
314
  ...withLocalTestConfig(),
295
315
  contentNode,
@@ -303,16 +323,12 @@ describe('OverlayController', () => {
303
323
  describe('Teardown', () => {
304
324
  it('unregisters itself from overlayManager', async () => {
305
325
  const ctrl = new OverlayController(withGlobalTestConfig());
306
-
307
326
  expect(isRegisteredOnManager(ctrl)).to.be.true;
308
-
309
327
  ctrl.teardown();
310
-
311
328
  expect(isRegisteredOnManager(ctrl)).to.be.false;
312
329
  });
313
-
314
330
  it('handles removal from DOM gracefully when overlay is open', async () => {
315
- const contentNode = /** @type {HTMLElement} */ (fixtureSync(html`<div>my content</div>`));
331
+ const contentNode = /** @type {HTMLElement} */ fixtureSync(html`<div>my content</div>`);
316
332
  const ctrl = new OverlayController({
317
333
  placementMode: 'global',
318
334
  contentNode,
@@ -330,7 +346,6 @@ describe('OverlayController', () => {
330
346
  // Teardown should complete without errors
331
347
  expect(isRegisteredOnManager(ctrl)).to.be.false;
332
348
  });
333
-
334
349
  it('does not throw when hide() is called after teardown() on a shown controller', async () => {
335
350
  const ctrl = new OverlayController({
336
351
  ...withGlobalTestConfig(),
@@ -346,12 +361,24 @@ describe('OverlayController', () => {
346
361
  await ctrl.hide();
347
362
  expect(ctrl.isShown).to.be.false;
348
363
  });
364
+ it('cleans up the dom structure it created', async () => {
365
+ const contentNode = /** @type {HTMLElement} */ fixtureSync(html`<div>my content</div>`);
366
+ const ctrl = new OverlayController({
367
+ placementMode: 'global',
368
+ contentNode,
369
+ });
370
+ await ctrl.show();
371
+ expect(ctrl.contentWrapperNode).to.exist;
372
+ expect(ctrl.__wrappingDialogNode).to.exist;
373
+ await ctrl.teardown();
374
+ expect(ctrl.contentWrapperNode).to.not.exist;
375
+ expect(ctrl.__wrappingDialogNode).to.not.exist;
376
+ });
349
377
  });
350
-
351
378
  describe('Node Configuration', () => {
352
379
  describe('Content', async () => {
353
380
  it('accepts a .contentNode for displaying content of the overlay', async () => {
354
- const myContentNode = /** @type {HTMLElement} */ (fixtureSync('<p>direct node</p>'));
381
+ const myContentNode = /** @type {HTMLElement} */ fixtureSync('<p>direct node</p>');
355
382
  const ctrl = new OverlayController({
356
383
  ...withGlobalTestConfig(),
357
384
  contentNode: myContentNode,
@@ -359,7 +386,6 @@ describe('OverlayController', () => {
359
386
  expect(ctrl.contentNode).to.have.trimmed.text('direct node');
360
387
  expect(ctrl.contentNode).to.equal(myContentNode);
361
388
  });
362
-
363
389
  describe('Embedded dom structure', async () => {
364
390
  describe('When projected in shadow dom', async () => {
365
391
  it('wraps a .contentWrapperNode for style application and a <dialog role="none"> for top layer paints', async () => {
@@ -367,27 +393,25 @@ describe('OverlayController', () => {
367
393
  class extends HTMLElement {
368
394
  constructor() {
369
395
  super();
370
- this.attachShadow({ mode: 'open' });
396
+ this.attachShadow({
397
+ mode: 'open',
398
+ });
371
399
  }
372
-
373
400
  connectedCallback() {
374
401
  /** @type {ShadowRoot} */
375
- (this.shadowRoot).innerHTML = '<slot name="content"></slot>';
402
+ this.shadowRoot.innerHTML = '<slot name="content"></slot>';
376
403
  this.innerHTML = '<div slot="content">projected</div>';
377
404
  }
378
405
  },
379
406
  );
380
-
381
- const el = /** @type {HTMLElement} */ (fixtureSync(`<${tagString}></${tagString}>`));
382
- const myContentNode = /** @type {HTMLElement} */ (el.querySelector('[slot=content]'));
407
+ const el = /** @type {HTMLElement} */ fixtureSync(`<${tagString}></${tagString}>`);
408
+ const myContentNode = /** @type {HTMLElement} */ el.querySelector('[slot=content]');
383
409
  const ctrl = new OverlayController({
384
410
  ...withGlobalTestConfig(),
385
411
  contentNode: myContentNode,
386
412
  });
387
-
388
413
  expect(ctrl.contentNode.assignedSlot?.parentElement).to.equal(ctrl.contentWrapperNode);
389
414
  expect(ctrl.contentWrapperNode.parentElement?.tagName).to.equal('DIALOG');
390
-
391
415
  normalizeOverlayContentWapper(ctrl.contentWrapperNode);
392
416
 
393
417
  // The total dom structure created...
@@ -400,24 +424,23 @@ describe('OverlayController', () => {
400
424
  </div>
401
425
  </dialog>
402
426
  `,
403
- { ignoreAttributes: ['closedby'] },
427
+ {
428
+ ignoreAttributes: ['closedby'],
429
+ },
404
430
  );
405
-
406
- expect(el).lightDom.to.equal(`<div slot="content">projected</div>`);
431
+ expect(el).lightDom.to.equal(`<div data-content="" slot="content">projected</div>`);
407
432
  });
408
433
  });
409
-
410
434
  describe('When in light dom', async () => {
411
435
  it('wraps a .contentWrapperNode for style application and a <dialog role="none"> for top layer paints', async () => {
412
436
  const el = fixtureSync('<section><div id="content">non projected</div></section>');
413
- const myContentNode = /** @type {HTMLElement} */ (el.querySelector('#content'));
437
+ const myContentNode = /** @type {HTMLElement} */ el.querySelector('#content');
414
438
  const ctrl = new OverlayController({
415
439
  ...withGlobalTestConfig(),
416
440
  contentNode: myContentNode,
417
441
  });
418
442
  expect(ctrl.contentNode.parentElement).to.equal(ctrl.contentWrapperNode);
419
443
  expect(ctrl.contentWrapperNode.parentElement?.tagName).to.equal('DIALOG');
420
-
421
444
  normalizeOverlayContentWapper(ctrl.contentWrapperNode);
422
445
 
423
446
  // The total dom structure created...
@@ -425,43 +448,126 @@ describe('OverlayController', () => {
425
448
  `
426
449
  <dialog data-overlay-outer-wrapper="" open="" role="none" style="${wrappingDialogNodeStyle}">
427
450
  <div data-id="content-wrapper">
428
- <div id="content">non projected</div>
451
+ <div data-content="" id="content">non projected</div>
429
452
  </div>
430
453
  </dialog>
431
454
  `,
432
- { ignoreAttributes: ['closedby'] },
455
+ {
456
+ ignoreAttributes: ['closedby'],
457
+ },
433
458
  );
434
459
  });
435
460
  });
436
-
461
+ describe('When .contentWrapperNode is provided in a host that is not connected yet', () => {
462
+ /** @param {{ nested?: boolean }} [opts] */
463
+ function createDisconnectedHost({ nested = false } = {}) {
464
+ const host = document.createElement('div');
465
+ const shadowRoot = host.attachShadow({
466
+ mode: 'open',
467
+ });
468
+ const wrapper = document.createElement('div');
469
+ wrapper.setAttribute('data-id', 'content-wrapper');
470
+ wrapper.innerHTML = '<slot name="content"></slot>';
471
+ if (nested) {
472
+ const section = document.createElement('section');
473
+ section.appendChild(wrapper);
474
+ shadowRoot.appendChild(section);
475
+ } else {
476
+ shadowRoot.appendChild(wrapper);
477
+ }
478
+ const content = document.createElement('div');
479
+ content.slot = 'content';
480
+ content.textContent = 'projected';
481
+ host.appendChild(content);
482
+ return {
483
+ host,
484
+ shadowRoot,
485
+ wrapper,
486
+ content,
487
+ };
488
+ }
489
+ it('does not throw and keeps the projected slot inside the wrapper', async () => {
490
+ const { host, shadowRoot, wrapper, content } = createDisconnectedHost();
491
+ expect(wrapper.isConnected).to.be.false;
492
+ const slot = /** @type {HTMLSlotElement} */ content.assignedSlot;
493
+ const ctrl = new OverlayController({
494
+ ...withGlobalTestConfig(),
495
+ contentNode: content,
496
+ contentWrapperNode: wrapper,
497
+ });
498
+ expect(ctrl.contentWrapperNode).to.equal(wrapper);
499
+ expect(wrapper.parentElement?.tagName).to.equal('DIALOG');
500
+ expect(slot.parentElement).to.equal(wrapper);
501
+ expect(content.parentElement).to.equal(host);
502
+ expect(shadowRoot.querySelectorAll('slot').length).to.equal(1);
503
+ });
504
+ it('restores the same relocated slot at its original position on teardown', async () => {
505
+ const { host, shadowRoot, wrapper, content } = createDisconnectedHost({
506
+ nested: true,
507
+ });
508
+ const section = /** @type {HTMLElement} */ shadowRoot.querySelector('section');
509
+ const slot = /** @type {HTMLSlotElement} */ content.assignedSlot;
510
+ const ctrl = new OverlayController({
511
+ ...withGlobalTestConfig(),
512
+ contentNode: content,
513
+ contentWrapperNode: wrapper,
514
+ });
515
+ ctrl.teardown();
516
+ expect(content.parentElement).to.equal(host);
517
+ expect(wrapper.parentElement).to.equal(section);
518
+ expect(slot.parentElement).to.equal(wrapper);
519
+ expect(shadowRoot.querySelector('dialog')).to.be.null;
520
+ expect(shadowRoot.querySelector('slot')).to.equal(slot);
521
+ });
522
+ it('survives repeated updateConfig calls and keeps slot ownership', async () => {
523
+ const { host, shadowRoot, wrapper, content } = createDisconnectedHost();
524
+ const slot = /** @type {HTMLSlotElement} */ content.assignedSlot;
525
+ const ctrl = new OverlayController({
526
+ ...withGlobalTestConfig(),
527
+ contentNode: content,
528
+ contentWrapperNode: wrapper,
529
+ });
530
+ expect(() =>
531
+ ctrl.updateConfig({
532
+ trapsKeyboardFocus: true,
533
+ }),
534
+ ).to.not.throw();
535
+ expect(() =>
536
+ ctrl.updateConfig({
537
+ trapsKeyboardFocus: false,
538
+ }),
539
+ ).to.not.throw();
540
+ expect(content.parentElement).to.equal(host);
541
+ expect(shadowRoot.querySelectorAll('slot').length).to.equal(1);
542
+ expect(shadowRoot.querySelector('slot')).to.equal(slot);
543
+ expect(wrapper.contains(slot)).to.be.true;
544
+ });
545
+ });
437
546
  describe('When .contenWrapperNode provided', async () => {
438
547
  it('keeps the .contentWrapperNode for style application and wraps a <dialog role="none"> for top layer paints', async () => {
439
548
  const tagString = defineCE(
440
549
  class extends HTMLElement {
441
550
  constructor() {
442
551
  super();
443
- this.attachShadow({ mode: 'open' });
552
+ this.attachShadow({
553
+ mode: 'open',
554
+ });
444
555
  }
445
-
446
556
  connectedCallback() {
447
557
  /** @type {ShadowRoot} */
448
- (this.shadowRoot).innerHTML = '<div><slot name="content"></slot></div>';
558
+ this.shadowRoot.innerHTML = '<div><slot name="content"></slot></div>';
449
559
  this.innerHTML = '<div slot="content">projected</div>';
450
560
  }
451
561
  },
452
562
  );
453
-
454
- const el = /** @type {HTMLElement} */ (fixtureSync(`<${tagString}></${tagString}>`));
455
- const myContentNode = /** @type {HTMLElement} */ (el.querySelector('[slot=content]'));
456
- const myContentWrapper = /** @type {HTMLElement} */ (
457
- el.shadowRoot?.querySelector('div')
458
- );
563
+ const el = /** @type {HTMLElement} */ fixtureSync(`<${tagString}></${tagString}>`);
564
+ const myContentNode = /** @type {HTMLElement} */ el.querySelector('[slot=content]');
565
+ const myContentWrapper = /** @type {HTMLElement} */ el.shadowRoot?.querySelector('div');
459
566
  const ctrl = new OverlayController({
460
567
  ...withGlobalTestConfig(),
461
568
  contentNode: myContentNode,
462
569
  contentWrapperNode: myContentWrapper,
463
570
  });
464
-
465
571
  normalizeOverlayContentWapper(ctrl.contentWrapperNode);
466
572
 
467
573
  // The total dom structure created...
@@ -473,21 +579,23 @@ describe('OverlayController', () => {
473
579
  </div>
474
580
  </dialog>
475
581
  `,
476
- { ignoreAttributes: ['closedby'] },
582
+ {
583
+ ignoreAttributes: ['closedby'],
584
+ },
477
585
  );
478
586
  });
479
-
480
587
  it("uses the .contentWrapperNode as container for Popper's arrow", async () => {
481
588
  const tagString = defineCE(
482
589
  class extends HTMLElement {
483
590
  constructor() {
484
591
  super();
485
- this.attachShadow({ mode: 'open' });
592
+ this.attachShadow({
593
+ mode: 'open',
594
+ });
486
595
  }
487
-
488
596
  connectedCallback() {
489
597
  /** @type {ShadowRoot} */
490
- (this.shadowRoot).innerHTML = `
598
+ this.shadowRoot.innerHTML = `
491
599
  <div>
492
600
  <div id="arrow"></div>
493
601
  <slot name="content"></slot>
@@ -496,18 +604,14 @@ describe('OverlayController', () => {
496
604
  }
497
605
  },
498
606
  );
499
-
500
- const el = /** @type {HTMLElement} */ (fixtureSync(`<${tagString}></${tagString}>`));
501
- const myContentNode = /** @type {HTMLElement} */ (el.querySelector('[slot=content]'));
502
- const myContentWrapper = /** @type {HTMLElement} */ (
503
- el.shadowRoot?.querySelector('div')
504
- );
607
+ const el = /** @type {HTMLElement} */ fixtureSync(`<${tagString}></${tagString}>`);
608
+ const myContentNode = /** @type {HTMLElement} */ el.querySelector('[slot=content]');
609
+ const myContentWrapper = /** @type {HTMLElement} */ el.shadowRoot?.querySelector('div');
505
610
  const ctrl = new OverlayController({
506
611
  ...withLocalTestConfig(),
507
612
  contentNode: myContentNode,
508
613
  contentWrapperNode: myContentWrapper,
509
614
  });
510
-
511
615
  normalizeOverlayContentWapper(ctrl.contentWrapperNode);
512
616
 
513
617
  // The total dom structure created...
@@ -520,16 +624,17 @@ describe('OverlayController', () => {
520
624
  </div>
521
625
  </dialog>
522
626
  `,
523
- { ignoreAttributes: ['closedby'] },
627
+ {
628
+ ignoreAttributes: ['closedby'],
629
+ },
524
630
  );
525
631
  });
526
632
  });
527
633
  });
528
634
  });
529
-
530
635
  describe('Invoker / Reference', async () => {
531
636
  it('accepts a .invokerNode to directly set invoker', async () => {
532
- const myInvokerNode = /** @type {HTMLElement} */ (fixtureSync('<button>invoke</button>'));
637
+ const myInvokerNode = /** @type {HTMLElement} */ fixtureSync('<button>invoke</button>');
533
638
  const ctrl = new OverlayController({
534
639
  ...withGlobalTestConfig(),
535
640
  invokerNode: myInvokerNode,
@@ -537,10 +642,9 @@ describe('OverlayController', () => {
537
642
  expect(ctrl.invokerNode).to.equal(myInvokerNode);
538
643
  expect(ctrl.referenceNode).to.equal(undefined);
539
644
  });
540
-
541
645
  it('accepts a .referenceNode as positioning anchor different from .invokerNode', async () => {
542
- const myInvokerNode = /** @type {HTMLElement} */ (fixtureSync('<button>invoke</button>'));
543
- const myReferenceNode = /** @type {HTMLElement} */ (fixtureSync('<div>anchor</div>'));
646
+ const myInvokerNode = /** @type {HTMLElement} */ fixtureSync('<button>invoke</button>');
647
+ const myReferenceNode = /** @type {HTMLElement} */ fixtureSync('<div>anchor</div>');
544
648
  const ctrl = new OverlayController({
545
649
  ...withGlobalTestConfig(),
546
650
  invokerNode: myInvokerNode,
@@ -550,33 +654,30 @@ describe('OverlayController', () => {
550
654
  expect(ctrl.invokerNode).to.not.equal(ctrl.referenceNode);
551
655
  });
552
656
  });
553
-
554
657
  describe('Backdrop', () => {
555
658
  it('creates a .backdropNode inside <dialog> for guaranteed top layer paints and positioning opportunities', async () => {
556
659
  const tagString = defineCE(
557
660
  class extends HTMLElement {
558
661
  constructor() {
559
662
  super();
560
- this.attachShadow({ mode: 'open' });
663
+ this.attachShadow({
664
+ mode: 'open',
665
+ });
561
666
  }
562
-
563
667
  connectedCallback() {
564
668
  /** @type {ShadowRoot} */
565
- (this.shadowRoot).innerHTML = '<slot name="content"></slot>';
669
+ this.shadowRoot.innerHTML = '<slot name="content"></slot>';
566
670
  this.innerHTML = '<div slot="content">projected</div>';
567
671
  }
568
672
  },
569
673
  );
570
-
571
- const el = /** @type {HTMLElement} */ (fixtureSync(`<${tagString}></${tagString}>`));
572
- const myContentNode = /** @type {HTMLElement} */ (el.querySelector('[slot=content]'));
573
-
674
+ const el = /** @type {HTMLElement} */ fixtureSync(`<${tagString}></${tagString}>`);
675
+ const myContentNode = /** @type {HTMLElement} */ el.querySelector('[slot=content]');
574
676
  const ctrl = new OverlayController({
575
677
  ...withGlobalTestConfig(),
576
678
  contentNode: myContentNode,
577
679
  hasBackdrop: true,
578
680
  });
579
-
580
681
  normalizeOverlayContentWapper(ctrl.contentWrapperNode);
581
682
 
582
683
  // The total dom structure created...
@@ -590,36 +691,35 @@ describe('OverlayController', () => {
590
691
  </div>
591
692
  </dialog>
592
693
  `,
593
- { ignoreAttributes: ['closedby'] },
694
+ {
695
+ ignoreAttributes: ['closedby'],
696
+ },
594
697
  );
595
698
  });
596
699
  });
597
-
598
700
  describe('When contentWrapperNode needs to be provided for correct arrow positioning', () => {
599
701
  it('uses contentWrapperNode as provided for local positioning', async () => {
600
- const el = /** @type {HTMLElement} */ (
702
+ const el =
703
+ /** @type {HTMLElement} */
601
704
  await fixture(html`
602
705
  <div id="contentWrapperNode">
603
706
  <div id="contentNode"></div>
604
707
  <my-arrow></my-arrow>
605
708
  </div>
606
- `)
607
- );
608
-
609
- const contentNode = /** @type {HTMLElement} */ (el.querySelector('#contentNode'));
709
+ `);
710
+ const contentNode = /** @type {HTMLElement} */ el.querySelector('#contentNode');
610
711
  const contentWrapperNode = el;
611
-
612
712
  const ctrl = new OverlayController({
613
713
  ...withLocalTestConfig(),
614
714
  contentNode,
615
715
  contentWrapperNode,
616
716
  });
617
-
618
717
  expect(ctrl.contentWrapperNode).to.equal(contentWrapperNode);
619
718
  });
620
719
  });
621
720
  });
622
721
 
722
+ // TODO: make features modular (so they can be treeshaken) and test their lifecycle within this desrcibe
623
723
  describe('Feature Configuration', () => {
624
724
  describe('trapsKeyboardFocus', () => {
625
725
  it('focuses the overlay on show', async () => {
@@ -630,27 +730,28 @@ describe('OverlayController', () => {
630
730
  await ctrl.show();
631
731
  expect(isActiveElement(ctrl.contentNode)).to.be.true;
632
732
  });
633
-
634
733
  it('keeps focus within the overlay e.g. you can not tab out by accident', async () => {
635
- const contentNode = /** @type {HTMLElement} */ (
636
- await fixture(html` <div><input id="input1" /><input id="input2" /></div> `)
637
- );
734
+ const contentNode =
735
+ /** @type {HTMLElement} */
736
+ await fixture(html` <div><input id="input1" /><input id="input2" /></div> `);
638
737
  const ctrl = new OverlayController({
639
738
  ...withGlobalTestConfig(),
640
739
  trapsKeyboardFocus: true,
641
740
  contentNode,
642
741
  });
643
742
  await ctrl.show();
644
-
645
743
  await fixture(html`<button>click me</button>`);
646
744
  const input1 = ctrl.contentNode.querySelectorAll('input')[0];
647
745
  const input2 = ctrl.contentNode.querySelectorAll('input')[1];
648
746
  input2.focus();
649
- await sendKeys({ press: 'Tab' });
650
-
747
+ await sendKeys({
748
+ press: 'Tab',
749
+ });
651
750
  if (browserDetection.isChrome) {
652
751
  expect(isActiveElement(document.body)).to.be.true;
653
- await sendKeys({ press: 'Tab' });
752
+ await sendKeys({
753
+ press: 'Tab',
754
+ });
654
755
  expect(isActiveElement(input1)).to.be.true;
655
756
  }
656
757
  if (browserDetection.isFirefox) {
@@ -658,37 +759,40 @@ describe('OverlayController', () => {
658
759
  // once we focus on the latest focusable element, `input2` in this case,
659
760
  // any further Tab presses keeps the focus on `input2` element
660
761
  expect(isActiveElement(input2)).to.be.true;
661
- await sendKeys({ press: 'Tab' });
762
+ await sendKeys({
763
+ press: 'Tab',
764
+ });
662
765
  expect(isActiveElement(input2)).to.be.true;
663
766
  }
664
767
  if (browserDetection.isMacSafari) {
665
768
  expect(isActiveElement(document.body)).to.be.true;
666
- await sendKeys({ press: 'Tab' });
769
+ await sendKeys({
770
+ press: 'Tab',
771
+ });
667
772
  expect(isActiveElement(ctrl.contentNode)).to.be.true;
668
- await sendKeys({ press: 'Tab' });
773
+ await sendKeys({
774
+ press: 'Tab',
775
+ });
669
776
  expect(isActiveElement(input1)).to.be.true;
670
777
  }
671
778
  });
672
-
673
779
  it('focuses the element with [autofocus] when dialog gets opened', async () => {
674
- const contentNode = /** @type {HTMLElement} */ (
675
- await fixture(html` <div><input id="input1" /><input id="input2" autofocus /></div> `)
676
- );
780
+ const contentNode =
781
+ /** @type {HTMLElement} */
782
+ await fixture(html` <div><input id="input1" /><input id="input2" autofocus /></div> `);
677
783
  const ctrl = new OverlayController({
678
784
  ...withGlobalTestConfig(),
679
785
  trapsKeyboardFocus: true,
680
786
  contentNode,
681
787
  });
682
788
  await ctrl.show();
683
-
684
789
  const input2 = ctrl.contentNode.querySelectorAll('input')[1];
685
790
  expect(isActiveElement(input2)).to.be.true;
686
791
  });
687
-
688
792
  it('focuses the contentNode when dialog gets opened and there is no [autofocus]', async () => {
689
- const contentNode = /** @type {HTMLElement} */ (
690
- await fixture(html` <div><input id="input1" /><input id="input2" /></div> `)
691
- );
793
+ const contentNode =
794
+ /** @type {HTMLElement} */
795
+ await fixture(html` <div><input id="input1" /><input id="input2" /></div> `);
692
796
  const ctrl = new OverlayController({
693
797
  ...withGlobalTestConfig(),
694
798
  trapsKeyboardFocus: true,
@@ -697,57 +801,48 @@ describe('OverlayController', () => {
697
801
  await ctrl.show();
698
802
  expect(isActiveElement(contentNode)).to.be.true;
699
803
  });
700
-
701
804
  it('allows to move the focus outside of the overlay if trapsKeyboardFocus is disabled', async () => {
702
- const contentNode = /** @type {HTMLElement} */ (await fixture(html`<div><input /></div>`));
703
-
805
+ const contentNode = /** @type {HTMLElement} */ await fixture(html`<div><input /></div>`);
704
806
  const ctrl = new OverlayController({
705
807
  ...withGlobalTestConfig(),
706
808
  contentNode,
707
809
  trapsKeyboardFocus: false,
708
810
  });
709
811
  // add element to dom to allow focus
710
- /** @type {HTMLElement} */ (await fixture(html`${ctrl.content}`));
812
+ /** @type {HTMLElement} */
813
+ await fixture(html`${ctrl.content}`);
711
814
  await ctrl.show();
712
-
713
- const elOutside = /** @type {HTMLElement} */ (await fixture(html`<input />`));
714
- const input = /** @type {HTMLInputElement} */ (ctrl.contentNode.querySelector('input'));
715
-
815
+ const elOutside = /** @type {HTMLElement} */ await fixture(html`<input />`);
816
+ const input = /** @type {HTMLInputElement} */ ctrl.contentNode.querySelector('input');
716
817
  input.focus();
717
818
  simulateTab();
718
-
719
819
  expect(isActiveElement(elOutside)).to.be.true;
720
820
  });
721
-
722
821
  it('keeps focus within overlay with multiple overlays with all traps on true', async () => {
723
822
  const ctrl0 = new OverlayController({
724
823
  ...withGlobalTestConfig(),
725
824
  trapsKeyboardFocus: true,
726
825
  });
727
-
728
826
  const ctrl1 = new OverlayController({
729
827
  ...withGlobalTestConfig(),
730
828
  trapsKeyboardFocus: true,
731
829
  });
732
-
733
830
  await ctrl0.show();
734
831
  await ctrl1.show();
735
832
  expect(isActiveElement(ctrl1.contentNode)).to.be.true;
736
-
737
833
  await ctrl1.hide();
738
834
  expect(isActiveElement(ctrl0.contentNode)).to.be.true;
739
835
  });
740
-
741
836
  it('warns when contentNode is a host for a shadowRoot', async () => {
742
837
  const warnSpy = sinon.spy(console, 'warn');
743
-
744
- const contentNode = /** @type {HTMLDivElement} */ (await fixture(html` <div></div> `));
745
- contentNode.attachShadow({ mode: 'open' });
746
- const shadowRootContentNode = /** @type {HTMLElement} */ (
747
- await fixture(html` <div><input id="input1" /><input id="input2" /></div> `)
748
- );
838
+ const contentNode = /** @type {HTMLDivElement} */ await fixture(html` <div></div> `);
839
+ contentNode.attachShadow({
840
+ mode: 'open',
841
+ });
842
+ const shadowRootContentNode =
843
+ /** @type {HTMLElement} */
844
+ await fixture(html` <div><input id="input1" /><input id="input2" /></div> `);
749
845
  contentNode.shadowRoot?.appendChild(shadowRootContentNode);
750
-
751
846
  const ctrl = new OverlayController({
752
847
  ...withGlobalTestConfig(),
753
848
  trapsKeyboardFocus: true,
@@ -762,7 +857,6 @@ describe('OverlayController', () => {
762
857
  warnSpy.restore();
763
858
  });
764
859
  });
765
-
766
860
  describe('hidesOnEsc', () => {
767
861
  it('hides on [Escape] press', async () => {
768
862
  const ctrl = new OverlayController({
@@ -773,7 +867,6 @@ describe('OverlayController', () => {
773
867
  await mimicEscapePress(ctrl.contentNode);
774
868
  expect(ctrl.isShown).to.be.false;
775
869
  });
776
-
777
870
  it('stays shown on [Escape] press with `.hidesOnEsc` set to false', async () => {
778
871
  const ctrl = new OverlayController({
779
872
  ...withGlobalTestConfig(),
@@ -783,7 +876,6 @@ describe('OverlayController', () => {
783
876
  await mimicEscapePress(ctrl.contentNode);
784
877
  expect(ctrl.isShown).to.be.true;
785
878
  });
786
-
787
879
  it('stays shown on [Escape] press on outside element', async () => {
788
880
  const ctrl = new OverlayController({
789
881
  ...withGlobalTestConfig(),
@@ -793,7 +885,6 @@ describe('OverlayController', () => {
793
885
  await mimicEscapePress(document);
794
886
  expect(ctrl.isShown).to.be.true;
795
887
  });
796
-
797
888
  it('stays shown on [Escape] press with modal <dialog> and `.hidesOnEsc` is false', async () => {
798
889
  const ctrl = new OverlayController({
799
890
  ...withGlobalTestConfig(),
@@ -804,25 +895,21 @@ describe('OverlayController', () => {
804
895
  await mimicEscapePress(ctrl.contentNode);
805
896
  expect(ctrl.isShown).to.be.true;
806
897
  });
807
-
808
898
  it('parent stays shown on [Escape] press in a nested overlay', async () => {
809
- const parentContent = /** @type {HTMLDivElement} */ (
899
+ const parentContent =
900
+ /** @type {HTMLDivElement} */
810
901
  await fixture(
811
902
  html` <!-- -->
812
903
  <div id="parent-overlay--hidesOnEsc">
813
904
  <div id="child-overlay--hidesOnEsc">we press [Escape] here</div>
814
905
  </div>`,
815
- )
816
- );
906
+ );
817
907
  const { parentOverlay, childOverlay } = await createNestedEscControllers(parentContent);
818
-
819
908
  await mimicEscapePress(childOverlay.contentNode);
820
-
821
909
  expect(parentOverlay.isShown).to.be.true;
822
910
  expect(childOverlay.isShown).to.be.false;
823
911
  });
824
912
  });
825
-
826
913
  describe('hidesOnOutsideEsc', () => {
827
914
  it('hides on [Escape] press on outside element', async () => {
828
915
  const ctrl = new OverlayController({
@@ -833,7 +920,6 @@ describe('OverlayController', () => {
833
920
  await mimicEscapePress(document);
834
921
  expect(ctrl.isShown).to.be.false;
835
922
  });
836
-
837
923
  it('stays shown on [Escape] press on inside element', async () => {
838
924
  const ctrl = new OverlayController({
839
925
  ...withGlobalTestConfig(),
@@ -843,146 +929,133 @@ describe('OverlayController', () => {
843
929
  await mimicEscapePress(ctrl.contentNode);
844
930
  expect(ctrl.isShown).to.be.true;
845
931
  });
846
-
847
932
  it('stays shown on [Escape] press in a nested overlay', async () => {
848
- const parentContent = /** @type {HTMLDivElement} */ (
933
+ const parentContent =
934
+ /** @type {HTMLDivElement} */
849
935
  await fixture(
850
936
  html` <!-- -->
851
937
  <div id="parent-overlay--hidesOnOutsideEsc">
852
938
  <div id="child-overlay--hidesOnOutsideEsc">we press [Escape] here</div>
853
939
  </div>`,
854
- )
855
- );
940
+ );
856
941
  const { parentOverlay, childOverlay } = await createNestedEscControllers(parentContent);
857
- mimicEscapePress(childOverlay.contentNode);
858
-
942
+ await mimicEscapePress(childOverlay.contentNode);
859
943
  expect(parentOverlay.isShown).to.be.true;
860
944
  expect(childOverlay.isShown).to.be.true;
861
945
  });
862
946
  });
863
-
864
947
  describe('Nested hidesOnEsc / hidesOnOutsideEsc', () => {
865
948
  describe('Parent has hidesOnEsc and child has hidesOnOutsideEsc', () => {
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 () => {
870
- const parentContent = /** @type {HTMLDivElement} */ (
949
+ it('on [Escape] press in child overlay: parent hides, child stays shown', async () => {
950
+ const parentContent =
951
+ /** @type {HTMLDivElement} */
871
952
  await fixture(
872
953
  html` <!-- -->
873
954
  <div id="parent-overlay--hidesOnEsc">
874
955
  <div id="child-overlay--hidesOnOutsideEsc">we press [Escape] here</div>
875
956
  </div>`,
876
- )
877
- );
957
+ );
878
958
  const { parentOverlay, childOverlay } = await createNestedEscControllers(parentContent);
879
959
  await mimicEscapePress(childOverlay.contentNode);
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
-
960
+ await childOverlay._showComplete;
961
+ await parentOverlay._showComplete;
962
+ await childOverlay._hideComplete;
963
+ await parentOverlay._hideComplete;
964
+ if (!childOverlay.isShown) {
965
+ await waitUntil(() => childOverlay.isShown);
966
+ }
967
+ if (parentOverlay.isShown) {
968
+ await waitUntil(() => !parentOverlay.isShown);
969
+ }
886
970
  await childOverlay.teardown();
887
971
  await parentOverlay.teardown();
888
972
  });
889
-
890
973
  it('on [Escape] press outside overlays: parent stays shown, child hides', async () => {
891
- const parentContent = /** @type {HTMLDivElement} */ (
974
+ const parentContent =
975
+ /** @type {HTMLDivElement} */
892
976
  await fixture(
893
977
  html` <!-- we press [Escape] here -->
894
978
  <div id="parent-overlay--hidesOnEsc">
895
979
  <div id="child-overlay--hidesOnOutsideEsc"></div>
896
980
  </div>`,
897
- )
898
- );
981
+ );
899
982
  const { parentOverlay, childOverlay } = await createNestedEscControllers(parentContent);
900
983
  await mimicEscapePress(document);
901
-
902
984
  expect(parentOverlay.isShown).to.be.true;
903
985
  expect(childOverlay.isShown).to.be.false;
904
986
  });
905
-
906
987
  it('on [Escape] press in parent overlay: parent is hidden, child is hidden', async () => {
907
- const parentContent = /** @type {HTMLDivElement} */ (
988
+ const parentContent =
989
+ /** @type {HTMLDivElement} */
908
990
  await fixture(
909
991
  html` <!-- -->
910
992
  <div id="parent-overlay--hidesOnEsc">
911
993
  we press [Escape] here
912
994
  <div id="child-overlay--hidesOnOutsideEsc"></div>
913
995
  </div>`,
914
- )
915
- );
996
+ );
916
997
  const { parentOverlay, childOverlay } = await createNestedEscControllers(parentContent);
917
998
  await mimicEscapePress(parentContent);
918
-
919
999
  expect(parentOverlay.isShown).to.be.false;
920
1000
  expect(childOverlay.isShown).to.be.false;
921
1001
  });
922
1002
  });
923
1003
  describe('Parent has hidesOnOutsideEsc and child has hidesOnEsc', () => {
924
1004
  it('on [Escape] press in child overlay: parent stays shown, child hides', async () => {
925
- const parentContent = /** @type {HTMLDivElement} */ (
1005
+ const parentContent =
1006
+ /** @type {HTMLDivElement} */
926
1007
  await fixture(
927
1008
  html` <!-- -->
928
1009
  <div id="parent-overlay--hidesOnOutsideEsc">
929
1010
  <div id="child-overlay--hidesOnEsc">we press [Escape] here</div>
930
1011
  </div>`,
931
- )
932
- );
1012
+ );
933
1013
  const { parentOverlay, childOverlay } = await createNestedEscControllers(parentContent);
934
1014
  await mimicEscapePress(childOverlay.contentNode);
935
-
936
1015
  expect(parentOverlay.isShown).to.be.true;
937
1016
  expect(childOverlay.isShown).to.be.false;
938
1017
  });
939
-
940
1018
  it('on [Escape] press outside overlays: parent hides, child stays shown', async () => {
941
- const parentContent = /** @type {HTMLDivElement} */ (
1019
+ const parentContent =
1020
+ /** @type {HTMLDivElement} */
942
1021
  await fixture(
943
1022
  html` <!-- we press [Escape] here -->
944
1023
  <div id="parent-overlay--hidesOnOutsideEsc">
945
1024
  <div id="child-overlay--hidesOnEsc"></div>
946
1025
  </div>`,
947
- )
948
- );
1026
+ );
949
1027
  const { parentOverlay, childOverlay } = await createNestedEscControllers(parentContent);
950
1028
  await mimicEscapePress(document);
951
-
952
1029
  expect(parentOverlay.isShown).to.be.false;
953
1030
  expect(childOverlay.isShown).to.be.true;
954
1031
  });
955
-
956
1032
  it('on [Escape] press in parent overlay: parent hides, child stays shown', async () => {
957
- const parentContent = /** @type {HTMLDivElement} */ (
1033
+ const parentContent =
1034
+ /** @type {HTMLDivElement} */
958
1035
  await fixture(
959
1036
  html` <!-- we press [Escape] here -->
960
1037
  <div id="parent-overlay--hidesOnOutsideEsc">
961
1038
  <div id="child-overlay--hidesOnEsc"></div>
962
1039
  </div>`,
963
- )
964
- );
1040
+ );
965
1041
  const { parentOverlay, childOverlay } = await createNestedEscControllers(parentContent);
966
1042
  await mimicEscapePress(document);
967
-
968
1043
  expect(parentOverlay.isShown).to.be.false;
969
1044
  expect(childOverlay.isShown).to.be.true;
970
1045
  });
971
1046
  });
972
-
973
1047
  describe('With shadow dom', () => {
974
1048
  it('on [Escape] press in child overlay in shadow root: parent hides, child stays shown', async () => {
975
- const parentContent = /** @type {HTMLDivElement} */ (
1049
+ const parentContent =
1050
+ /** @type {HTMLDivElement} */
976
1051
  await fixture(
977
1052
  html` <!-- -->
978
1053
  <div id="parent-overlay--hidesOnEsc" data-convert-to-shadow-root>
979
1054
  <div id="child-overlay--hidesOnOutsideEsc">we press [Escape] here</div>
980
1055
  </div>`,
981
- )
982
- );
1056
+ );
983
1057
  const { parentOverlay, childOverlay } = await createNestedEscControllers(parentContent);
984
1058
  await mimicEscapePress(childOverlay.contentNode);
985
-
986
1059
  expect(parentOverlay.isShown).to.be.false;
987
1060
  expect(childOverlay.isShown).to.be.true;
988
1061
  });
@@ -990,7 +1063,7 @@ describe('OverlayController', () => {
990
1063
  });
991
1064
  describe('hidesOnOutsideClick', () => {
992
1065
  it('hides on outside click', async () => {
993
- const contentNode = /** @type {HTMLElement} */ (await fixture('<div>Content</div>'));
1066
+ const contentNode = /** @type {HTMLElement} */ await fixture('<div>Content</div>');
994
1067
  const ctrl = new OverlayController({
995
1068
  ...withGlobalTestConfig(),
996
1069
  hidesOnOutsideClick: true,
@@ -1000,16 +1073,16 @@ describe('OverlayController', () => {
1000
1073
  mimicClick(document.body);
1001
1074
  await aTimeout(0);
1002
1075
  expect(ctrl.isShown).to.be.false;
1003
-
1004
1076
  await ctrl.show();
1005
- await mimicClick(document.body, { isAsync: true });
1077
+ await mimicClick(document.body, {
1078
+ isAsync: true,
1079
+ });
1006
1080
  await aTimeout(0);
1007
1081
  expect(ctrl.isShown).to.be.false;
1008
1082
  });
1009
-
1010
1083
  it('doesn\'t hide on "inside" click', async () => {
1011
- const invokerNode = /** @type {HTMLElement} */ (await fixture('<button>Invoker</button>'));
1012
- const contentNode = /** @type {HTMLElement} */ (await fixture('<div>Content</div>'));
1084
+ const invokerNode = /** @type {HTMLElement} */ await fixture('<button>Invoker</button>');
1085
+ const contentNode = /** @type {HTMLElement} */ await fixture('<div>Content</div>');
1013
1086
  const ctrl = new OverlayController({
1014
1087
  ...withGlobalTestConfig(),
1015
1088
  hidesOnOutsideClick: true,
@@ -1026,12 +1099,13 @@ describe('OverlayController', () => {
1026
1099
  // Don't hide on inside (content) click
1027
1100
  ctrl.contentNode.click();
1028
1101
  await aTimeout(0);
1029
-
1030
1102
  expect(ctrl.isShown).to.be.true;
1031
1103
 
1032
1104
  // Don't hide on inside mousedown & outside mouseup
1033
- await mimicClick(ctrl.contentNode, { releaseElement: document.body, isAsync: true });
1034
-
1105
+ await mimicClick(ctrl.contentNode, {
1106
+ releaseElement: document.body,
1107
+ isAsync: true,
1108
+ });
1035
1109
  await aTimeout(0);
1036
1110
  expect(ctrl.isShown).to.be.true;
1037
1111
 
@@ -1041,48 +1115,46 @@ describe('OverlayController', () => {
1041
1115
  await ctrl.show();
1042
1116
  expect(ctrl.isShown).to.be.true;
1043
1117
  });
1044
-
1045
1118
  it('only hides when both mousedown and mouseup events are outside', async () => {
1046
- const contentNode = /** @type {HTMLElement} */ (await fixture('<div>Content</div>'));
1119
+ const contentNode = /** @type {HTMLElement} */ await fixture('<div>Content</div>');
1047
1120
  const ctrl = new OverlayController({
1048
1121
  ...withGlobalTestConfig(),
1049
1122
  hidesOnOutsideClick: true,
1050
1123
  contentNode,
1051
- invokerNode: /** @type {HTMLElement} */ (
1124
+ invokerNode:
1125
+ /** @type {HTMLElement} */
1052
1126
  fixtureSync(html`
1053
1127
  <div role="button" style="width: 100px; height: 20px;">Invoker</div>
1054
- `)
1055
- ),
1128
+ `),
1056
1129
  });
1057
1130
  await ctrl.show();
1058
- mimicClick(document.body, { releaseElement: contentNode });
1131
+ mimicClick(document.body, {
1132
+ releaseElement: contentNode,
1133
+ });
1059
1134
  await aTimeout(0);
1060
1135
  expect(ctrl.isShown).to.be.true;
1061
-
1062
- mimicClick(contentNode, { releaseElement: document.body });
1136
+ mimicClick(contentNode, {
1137
+ releaseElement: document.body,
1138
+ });
1063
1139
  await aTimeout(0);
1064
1140
  expect(ctrl.isShown).to.be.true;
1065
-
1066
1141
  mimicClick(document.body, {
1067
- releaseElement: /** @type {HTMLElement} */ (ctrl.invokerNode),
1142
+ releaseElement: /** @type {HTMLElement} */ ctrl.invokerNode,
1068
1143
  });
1069
1144
  await aTimeout(0);
1070
1145
  expect(ctrl.isShown).to.be.true;
1071
-
1072
- mimicClick(/** @type {HTMLElement} */ (ctrl.invokerNode), {
1146
+ mimicClick(/** @type {HTMLElement} */ ctrl.invokerNode, {
1073
1147
  releaseElement: document.body,
1074
1148
  });
1075
1149
  await aTimeout(0);
1076
1150
  expect(ctrl.isShown).to.be.true;
1077
-
1078
1151
  mimicClick(document.body);
1079
1152
  await aTimeout(0);
1080
1153
  expect(ctrl.isShown).to.be.false;
1081
1154
  });
1082
-
1083
1155
  it('doesn\'t hide on "inside sub shadow dom" click', async () => {
1084
- const invokerNode = /** @type {HTMLElement} */ (await fixture('<button>Invoker</button>'));
1085
- const contentNode = /** @type {HTMLElement} */ (await fixture('<div>Content</div>'));
1156
+ const invokerNode = /** @type {HTMLElement} */ await fixture('<button>Invoker</button>');
1157
+ const contentNode = /** @type {HTMLElement} */ await fixture('<div>Content</div>');
1086
1158
  const ctrl = new OverlayController({
1087
1159
  ...withGlobalTestConfig(),
1088
1160
  hidesOnOutsideClick: true,
@@ -1096,25 +1168,26 @@ describe('OverlayController', () => {
1096
1168
  class extends HTMLElement {
1097
1169
  constructor() {
1098
1170
  super();
1099
- this.attachShadow({ mode: 'open' });
1171
+ this.attachShadow({
1172
+ mode: 'open',
1173
+ });
1100
1174
  }
1101
-
1102
1175
  connectedCallback() {
1103
1176
  /** @type {ShadowRoot} */
1104
- (this.shadowRoot).innerHTML = '<div><button>click me</button></div>';
1177
+ this.shadowRoot.innerHTML = '<div><button>click me</button></div>';
1105
1178
  }
1106
1179
  },
1107
1180
  );
1108
1181
  const tag = unsafeStatic(tagString);
1109
1182
  ctrl.updateConfig({
1110
- contentNode: /** @type {HTMLElement} */ (
1183
+ contentNode:
1184
+ /** @type {HTMLElement} */
1111
1185
  await fixture(html`
1112
1186
  <div>
1113
1187
  <div>Content</div>
1114
1188
  <${tag}></${tag}>
1115
1189
  </div>
1116
- `)
1117
- ),
1190
+ `),
1118
1191
  });
1119
1192
  await ctrl.show();
1120
1193
 
@@ -1122,7 +1195,6 @@ describe('OverlayController', () => {
1122
1195
  /** @type {ShadowRoot} */
1123
1196
  // @ts-expect-error
1124
1197
  ctrl.contentNode.querySelector(tagString).shadowRoot.querySelector('button').click();
1125
-
1126
1198
  await aTimeout(0);
1127
1199
  expect(ctrl.isShown).to.be.true;
1128
1200
 
@@ -1132,12 +1204,11 @@ describe('OverlayController', () => {
1132
1204
  await ctrl.show();
1133
1205
  expect(ctrl.isShown).to.be.true;
1134
1206
  });
1135
-
1136
1207
  it('works with 3rd party code using "event.stopPropagation()" on bubble phase', async () => {
1137
- const invokerNode = /** @type {HTMLElement} */ (
1138
- await fixture('<div role="button">Invoker</div>')
1139
- );
1140
- const contentNode = /** @type {HTMLElement} */ (await fixture('<div>Content</div>'));
1208
+ const invokerNode =
1209
+ /** @type {HTMLElement} */
1210
+ await fixture('<div role="button">Invoker</div>');
1211
+ const contentNode = /** @type {HTMLElement} */ await fixture('<div>Content</div>');
1141
1212
  const ctrl = new OverlayController({
1142
1213
  ...withLocalTestConfig(),
1143
1214
  hidesOnOutsideClick: true,
@@ -1145,22 +1216,17 @@ describe('OverlayController', () => {
1145
1216
  invokerNode,
1146
1217
  });
1147
1218
  const stopProp = (/** @type {Event} */ e) => e.stopPropagation();
1148
- const dom = await fixture(
1149
- `
1219
+ const dom = await fixture(`
1150
1220
  <div>
1151
1221
  <div id="popup">${invokerNode}${contentNode}</div>
1152
1222
  <div id="third-party-noise" @click="${stopProp}" @mousedown="${stopProp}" @mouseup="${stopProp}">
1153
1223
  This element prevents our handlers from reaching the document click handler.
1154
1224
  </div>
1155
1225
  </div>
1156
- `,
1157
- );
1158
-
1226
+ `);
1159
1227
  await ctrl.show();
1160
1228
  expect(ctrl.isShown).to.equal(true);
1161
-
1162
- const noiseEl = /** @type {HTMLElement} */ (dom.querySelector('#third-party-noise'));
1163
-
1229
+ const noiseEl = /** @type {HTMLElement} */ dom.querySelector('#third-party-noise');
1164
1230
  mimicClick(noiseEl);
1165
1231
  await aTimeout(0);
1166
1232
  expect(ctrl.isShown).to.equal(false);
@@ -1169,12 +1235,11 @@ describe('OverlayController', () => {
1169
1235
  await ctrl.show();
1170
1236
  expect(ctrl.isShown).to.equal(true);
1171
1237
  });
1172
-
1173
1238
  it('works with 3rd party code using "event.stopPropagation()" on capture phase', async () => {
1174
- const invokerNode = /** @type {HTMLElement} */ (
1175
- await fixture(html`<div role="button">Invoker</div>`)
1176
- );
1177
- const contentNode = /** @type {HTMLElement} */ (await fixture('<div>Content</div>'));
1239
+ const invokerNode =
1240
+ /** @type {HTMLElement} */
1241
+ await fixture(html`<div role="button">Invoker</div>`);
1242
+ const contentNode = /** @type {HTMLElement} */ await fixture('<div>Content</div>');
1178
1243
  const ctrl = new OverlayController({
1179
1244
  ...withLocalTestConfig(),
1180
1245
  hidesOnOutsideClick: true,
@@ -1182,7 +1247,8 @@ describe('OverlayController', () => {
1182
1247
  invokerNode,
1183
1248
  });
1184
1249
  const stopProp = (/** @type {Event} */ e) => e.stopPropagation();
1185
- const dom = /** @type {HTMLElement} */ (
1250
+ const dom =
1251
+ /** @type {HTMLElement} */
1186
1252
  await fixture(`
1187
1253
  <div>
1188
1254
  <div id="popup">${invokerNode}${ctrl.content}</div>
@@ -1190,18 +1256,13 @@ describe('OverlayController', () => {
1190
1256
  This element prevents our handlers from reaching the document click handler.
1191
1257
  </div>
1192
1258
  </div>
1193
- `)
1194
- );
1195
-
1196
- const noiseEl = /** @type {HTMLElement} */ (dom.querySelector('#third-party-noise'));
1197
-
1259
+ `);
1260
+ const noiseEl = /** @type {HTMLElement} */ dom.querySelector('#third-party-noise');
1198
1261
  noiseEl.addEventListener('click', stopProp, true);
1199
1262
  noiseEl.addEventListener('mousedown', stopProp, true);
1200
1263
  noiseEl.addEventListener('mouseup', stopProp, true);
1201
-
1202
1264
  await ctrl.show();
1203
1265
  expect(ctrl.isShown).to.equal(true);
1204
-
1205
1266
  mimicClick(noiseEl);
1206
1267
  await aTimeout(0);
1207
1268
  expect(ctrl.isShown).to.equal(false);
@@ -1210,17 +1271,16 @@ describe('OverlayController', () => {
1210
1271
  await ctrl.show();
1211
1272
  expect(ctrl.isShown).to.equal(true);
1212
1273
  });
1213
-
1214
1274
  it('doesn\'t hide on "inside label" click', async () => {
1215
- const contentNode = /** @type {HTMLElement} */ (
1275
+ const contentNode =
1276
+ /** @type {HTMLElement} */
1216
1277
  await fixture(`
1217
1278
  <div>
1218
1279
  <label for="test">test</label>
1219
1280
  <input id="test">
1220
1281
  Content
1221
- </div>`)
1222
- );
1223
- const labelNode = /** @type {HTMLElement} */ (contentNode.querySelector('label[for=test]'));
1282
+ </div>`);
1283
+ const labelNode = /** @type {HTMLElement} */ contentNode.querySelector('label[for=test]');
1224
1284
  const ctrl = new OverlayController({
1225
1285
  ...withGlobalTestConfig(),
1226
1286
  hidesOnOutsideClick: true,
@@ -1231,27 +1291,22 @@ describe('OverlayController', () => {
1231
1291
  // Don't hide on label click
1232
1292
  labelNode.click();
1233
1293
  await aTimeout(0);
1234
-
1235
1294
  expect(ctrl.isShown).to.be.true;
1236
1295
  });
1237
-
1238
1296
  it('hides when window is blurred (useful for iframes)', async () => {
1239
1297
  const ctrl = new OverlayController({
1240
1298
  ...withGlobalTestConfig(),
1241
1299
  hidesOnOutsideClick: true,
1242
1300
  });
1243
1301
  await ctrl.show();
1244
-
1245
1302
  window.dispatchEvent(new Event('blur'));
1246
1303
  await aTimeout(0);
1247
-
1248
1304
  expect(ctrl.isShown).to.be.false;
1249
1305
  });
1250
1306
  });
1251
-
1252
1307
  describe('elementToFocusAfterHide', () => {
1253
1308
  it('focuses body when hiding by default', async () => {
1254
- const contentNode = /** @type {HTMLElement} */ (await fixture('<div><input /></div>'));
1309
+ const contentNode = /** @type {HTMLElement} */ await fixture('<div><input /></div>');
1255
1310
  const ctrl = new OverlayController({
1256
1311
  ...withGlobalTestConfig(),
1257
1312
  viewportConfig: {
@@ -1259,90 +1314,78 @@ describe('OverlayController', () => {
1259
1314
  },
1260
1315
  contentNode,
1261
1316
  });
1262
-
1263
1317
  await ctrl.show();
1264
- const input = /** @type {HTMLInputElement} */ (contentNode.querySelector('input'));
1318
+ const input = /** @type {HTMLInputElement} */ contentNode.querySelector('input');
1265
1319
  input.focus();
1266
1320
  expect(isActiveElement(input)).to.be.true;
1267
-
1268
1321
  await ctrl.hide();
1269
1322
  expect(isActiveElement(document.body)).to.be.true;
1270
1323
  });
1271
-
1272
1324
  it('supports elementToFocusAfterHide option to focus it when hiding', async () => {
1273
- const input = /** @type {HTMLElement} */ (await fixture('<input />'));
1274
- const contentNode = /** @type {HTMLElement} */ (
1275
- await fixture('<div><textarea></textarea></div>')
1276
- );
1325
+ const input = /** @type {HTMLElement} */ await fixture('<input />');
1326
+ const contentNode =
1327
+ /** @type {HTMLElement} */
1328
+ await fixture('<div><textarea></textarea></div>');
1277
1329
  const ctrl = new OverlayController({
1278
1330
  ...withGlobalTestConfig(),
1279
1331
  elementToFocusAfterHide: input,
1280
1332
  contentNode,
1281
1333
  });
1282
-
1283
1334
  await ctrl.show();
1284
- const textarea = /** @type {HTMLTextAreaElement} */ (contentNode.querySelector('textarea'));
1335
+ const textarea = /** @type {HTMLTextAreaElement} */ contentNode.querySelector('textarea');
1285
1336
  textarea.focus();
1286
1337
  expect(isActiveElement(textarea)).to.be.true;
1287
-
1288
1338
  await ctrl.hide();
1289
1339
  expect(isActiveElement(input)).to.be.true;
1290
1340
  expect(isInViewport(input)).to.be.true;
1291
1341
  });
1292
-
1293
1342
  it('supports elementToFocusAfterHide option when shadowRoot involved', async () => {
1294
- const input = /** @type {HTMLElement} */ (await fixture('<input />'));
1295
- const contentNode = /** @type {HTMLElement} */ (
1296
- await fixture('<div><textarea></textarea></div>')
1297
- );
1298
-
1343
+ const input = /** @type {HTMLElement} */ await fixture('<input />');
1344
+ const contentNode =
1345
+ /** @type {HTMLElement} */
1346
+ await fixture('<div><textarea></textarea></div>');
1299
1347
  const shadowHost = document.createElement('div');
1300
- shadowHost.attachShadow({ mode: 'open' });
1301
- /** @type {ShadowRoot} */ (shadowHost.shadowRoot).innerHTML = `<slot></slot>`;
1348
+ shadowHost.attachShadow({
1349
+ mode: 'open',
1350
+ });
1351
+ /** @type {ShadowRoot} */
1352
+ shadowHost.shadowRoot.innerHTML = `<slot></slot>`;
1302
1353
  shadowHost.appendChild(contentNode);
1303
1354
  document.body.appendChild(shadowHost);
1304
-
1305
1355
  const ctrl = new OverlayController({
1306
1356
  ...withGlobalTestConfig(),
1307
1357
  elementToFocusAfterHide: input,
1308
1358
  contentNode,
1309
1359
  });
1310
-
1311
1360
  await ctrl.show();
1312
- const textarea = /** @type {HTMLTextAreaElement} */ (contentNode.querySelector('textarea'));
1361
+ const textarea = /** @type {HTMLTextAreaElement} */ contentNode.querySelector('textarea');
1313
1362
  textarea.focus();
1314
1363
  expect(isActiveElement(textarea)).to.be.true;
1315
-
1316
1364
  await ctrl.hide();
1317
1365
  expect(isActiveElement(input)).to.be.true;
1318
-
1319
1366
  document.body.removeChild(shadowHost);
1320
1367
  });
1321
-
1322
1368
  it(`only sets focus when outside world didn't take over already`, async () => {
1323
- const input = /** @type {HTMLElement} */ (await fixture('<input />'));
1324
- const outsideButton = /** @type {HTMLButtonElement} */ (await fixture('<button></button>'));
1325
- const contentNode = /** @type {HTMLElement} */ (await fixture('<div>/div>'));
1369
+ const input = /** @type {HTMLElement} */ await fixture('<input />');
1370
+ const outsideButton = /** @type {HTMLButtonElement} */ await fixture('<button></button>');
1371
+ const contentNode = /** @type {HTMLElement} */ await fixture('<div>/div>');
1326
1372
  const ctrl = new OverlayController({
1327
1373
  ...withGlobalTestConfig(),
1328
1374
  elementToFocusAfterHide: input,
1329
1375
  contentNode,
1330
1376
  });
1331
-
1332
1377
  await ctrl.show();
1333
1378
  // an outside element has taken over focus
1334
1379
  outsideButton.focus();
1335
1380
  expect(isActiveElement(outsideButton)).to.be.true;
1336
-
1337
1381
  await ctrl.hide();
1338
1382
  expect(isActiveElement(outsideButton)).to.be.true;
1339
1383
  });
1340
-
1341
1384
  it('allows to set elementToFocusAfterHide on show', async () => {
1342
- const input = /** @type {HTMLElement} */ (await fixture('<input />'));
1343
- const contentNode = /** @type {HTMLElement} */ (
1344
- await fixture('<div><textarea></textarea></div>')
1345
- );
1385
+ const input = /** @type {HTMLElement} */ await fixture('<input />');
1386
+ const contentNode =
1387
+ /** @type {HTMLElement} */
1388
+ await fixture('<div><textarea></textarea></div>');
1346
1389
  const ctrl = new OverlayController({
1347
1390
  ...withGlobalTestConfig(),
1348
1391
  viewportConfig: {
@@ -1350,31 +1393,25 @@ describe('OverlayController', () => {
1350
1393
  },
1351
1394
  contentNode,
1352
1395
  });
1353
-
1354
1396
  await ctrl.show(input);
1355
- const textarea = /** @type {HTMLTextAreaElement} */ (contentNode.querySelector('textarea'));
1397
+ const textarea = /** @type {HTMLTextAreaElement} */ contentNode.querySelector('textarea');
1356
1398
  textarea.focus();
1357
1399
  expect(isActiveElement(textarea)).to.be.true;
1358
-
1359
1400
  await ctrl.hide();
1360
1401
  expect(isActiveElement(input)).to.be.true;
1361
1402
  });
1362
1403
  });
1363
-
1364
1404
  describe('preventsScroll', () => {
1365
1405
  it('prevent scrolling the background', async () => {
1366
1406
  const ctrl = new OverlayController({
1367
1407
  ...withGlobalTestConfig(),
1368
1408
  preventsScroll: true,
1369
1409
  });
1370
-
1371
1410
  await ctrl.show();
1372
1411
  expect(Array.from(document.body.classList)).to.contain('overlays-scroll-lock');
1373
-
1374
1412
  await ctrl.hide();
1375
1413
  expect(Array.from(document.body.classList)).to.not.contain('overlays-scroll-lock');
1376
1414
  });
1377
-
1378
1415
  it('keeps preventing of scrolling when multiple overlays are opened and closed', async () => {
1379
1416
  const ctrl0 = new OverlayController({
1380
1417
  ...withGlobalTestConfig(),
@@ -1384,13 +1421,11 @@ describe('OverlayController', () => {
1384
1421
  ...withGlobalTestConfig(),
1385
1422
  preventsScroll: true,
1386
1423
  });
1387
-
1388
1424
  await ctrl0.show();
1389
1425
  await ctrl1.show();
1390
1426
  await ctrl1.hide();
1391
1427
  expect(Array.from(document.body.classList)).to.contain('overlays-scroll-lock');
1392
1428
  });
1393
-
1394
1429
  it('does not accumulate body margins when nested overlays have preventsScroll', async () => {
1395
1430
  const ctrl0 = new OverlayController({
1396
1431
  ...withGlobalTestConfig(),
@@ -1400,45 +1435,35 @@ describe('OverlayController', () => {
1400
1435
  ...withGlobalTestConfig(),
1401
1436
  preventsScroll: true,
1402
1437
  });
1403
-
1404
1438
  const originalMarginRight = document.body.style.marginRight;
1405
-
1406
1439
  await ctrl0.show();
1407
1440
  const marginAfterFirst = document.body.style.marginRight;
1408
-
1409
1441
  await ctrl1.show();
1410
1442
  const marginAfterSecond = document.body.style.marginRight;
1411
1443
 
1412
1444
  // The margin should NOT increase further when second overlay opens
1413
1445
  expect(marginAfterSecond).to.equal(marginAfterFirst);
1414
-
1415
1446
  await ctrl1.hide();
1416
1447
  // After hiding second, first still prevents scroll — margin stays
1417
1448
  expect(document.body.style.marginRight).to.equal(marginAfterFirst);
1418
-
1419
1449
  await ctrl0.hide();
1420
1450
  // After hiding all, original margin is restored
1421
1451
  expect(document.body.style.marginRight).to.equal(originalMarginRight);
1422
1452
  });
1423
-
1424
1453
  it('restores body margin when overlay with preventsScroll is torn down while shown', async () => {
1425
1454
  const ctrl = new OverlayController({
1426
1455
  ...withGlobalTestConfig(),
1427
1456
  preventsScroll: true,
1428
1457
  });
1429
-
1430
1458
  const originalMarginRight = document.body.style.marginRight;
1431
-
1432
1459
  await ctrl.show();
1433
1460
  const marginAfterShow = document.body.style.marginRight;
1434
1461
  // Margin should be set after show
1435
1462
  expect(marginAfterShow).to.not.equal(originalMarginRight);
1436
-
1437
1463
  ctrl.teardown();
1438
1464
  // Margin should be restored after teardown
1439
1465
  expect(document.body.style.marginRight).to.equal(originalMarginRight);
1440
1466
  });
1441
-
1442
1467
  it('does not break body margin when teardown() is called on a hidden overlay', async () => {
1443
1468
  const ctrl0 = new OverlayController({
1444
1469
  ...withGlobalTestConfig(),
@@ -1448,7 +1473,6 @@ describe('OverlayController', () => {
1448
1473
  ...withGlobalTestConfig(),
1449
1474
  preventsScroll: true,
1450
1475
  });
1451
-
1452
1476
  const originalMarginRight = document.body.style.marginRight;
1453
1477
 
1454
1478
  // Show first overlay
@@ -1466,13 +1490,11 @@ describe('OverlayController', () => {
1466
1490
  // Now margin should be restored
1467
1491
  expect(document.body.style.marginRight).to.equal(originalMarginRight);
1468
1492
  });
1469
-
1470
1493
  it('does not break body margin when updateConfig() is called on a hidden overlay', async () => {
1471
1494
  const ctrl = new OverlayController({
1472
1495
  ...withGlobalTestConfig(),
1473
1496
  preventsScroll: true,
1474
1497
  });
1475
-
1476
1498
  const originalMarginRight = document.body.style.marginRight;
1477
1499
 
1478
1500
  // updateConfig calls teardown internally
@@ -1494,7 +1516,6 @@ describe('OverlayController', () => {
1494
1516
  expect(document.body.style.marginRight).to.equal(originalMarginRight);
1495
1517
  });
1496
1518
  });
1497
-
1498
1519
  describe('hasBackdrop', () => {
1499
1520
  it('has no backdrop by default', async () => {
1500
1521
  const ctrl = new OverlayController({
@@ -1503,7 +1524,6 @@ describe('OverlayController', () => {
1503
1524
  await ctrl.show();
1504
1525
  expect(ctrl.backdropNode).to.be.undefined;
1505
1526
  });
1506
-
1507
1527
  it('supports a backdrop option', async () => {
1508
1528
  const ctrl = new OverlayController({
1509
1529
  ...withGlobalTestConfig(),
@@ -1512,7 +1532,6 @@ describe('OverlayController', () => {
1512
1532
  await ctrl.show();
1513
1533
  expect(ctrl.backdropNode).to.be.undefined;
1514
1534
  await ctrl.hide();
1515
-
1516
1535
  const controllerWithBackdrop = new OverlayController({
1517
1536
  ...withGlobalTestConfig(),
1518
1537
  hasBackdrop: true,
@@ -1520,7 +1539,6 @@ describe('OverlayController', () => {
1520
1539
  await controllerWithBackdrop.show();
1521
1540
  expect(controllerWithBackdrop.backdropNode).to.have.class('overlays__backdrop');
1522
1541
  });
1523
-
1524
1542
  it('reenables the backdrop when shown/hidden/shown', async () => {
1525
1543
  const ctrl = new OverlayController({
1526
1544
  ...withGlobalTestConfig(),
@@ -1532,7 +1550,6 @@ describe('OverlayController', () => {
1532
1550
  await ctrl.show();
1533
1551
  expect(ctrl.backdropNode).to.have.class('overlays__backdrop');
1534
1552
  });
1535
-
1536
1553
  it('adds and stacks backdrops if .hasBackdrop is enabled', async () => {
1537
1554
  const ctrl0 = new OverlayController({
1538
1555
  ...withGlobalTestConfig(),
@@ -1540,7 +1557,6 @@ describe('OverlayController', () => {
1540
1557
  });
1541
1558
  await ctrl0.show();
1542
1559
  expect(ctrl0.backdropNode).to.have.class('overlays__backdrop');
1543
-
1544
1560
  const ctrl1 = new OverlayController({
1545
1561
  ...withGlobalTestConfig(),
1546
1562
  hasBackdrop: false,
@@ -1548,19 +1564,16 @@ describe('OverlayController', () => {
1548
1564
  await ctrl1.show();
1549
1565
  expect(ctrl0.backdropNode).to.have.class('overlays__backdrop');
1550
1566
  expect(ctrl1.backdropNode).to.be.undefined;
1551
-
1552
1567
  const ctrl2 = new OverlayController({
1553
1568
  ...withGlobalTestConfig(),
1554
1569
  hasBackdrop: true,
1555
1570
  });
1556
1571
  await ctrl2.show();
1557
-
1558
1572
  expect(ctrl0.backdropNode).to.have.class('overlays__backdrop');
1559
1573
  expect(ctrl1.backdropNode).to.be.undefined;
1560
1574
  expect(ctrl2.backdropNode).to.have.class('overlays__backdrop');
1561
1575
  });
1562
1576
  });
1563
-
1564
1577
  describe('locally placed overlay with hasBackdrop', () => {
1565
1578
  it('has no backdrop by default', async () => {
1566
1579
  const ctrl = new OverlayController({
@@ -1569,7 +1582,6 @@ describe('OverlayController', () => {
1569
1582
  await ctrl.show();
1570
1583
  expect(ctrl.backdropNode).to.be.undefined;
1571
1584
  });
1572
-
1573
1585
  it('supports a backdrop option', async () => {
1574
1586
  const ctrl = new OverlayController({
1575
1587
  ...withLocalTestConfig(),
@@ -1578,10 +1590,8 @@ describe('OverlayController', () => {
1578
1590
  await ctrl.show();
1579
1591
  expect(ctrl.backdropNode).to.be.undefined;
1580
1592
  await ctrl.hide();
1581
-
1582
1593
  const backdropNode = document.createElement('div');
1583
1594
  backdropNode.classList.add('custom-backdrop');
1584
-
1585
1595
  const controllerWithBackdrop = new OverlayController({
1586
1596
  ...withLocalTestConfig(),
1587
1597
  hasBackdrop: true,
@@ -1590,11 +1600,9 @@ describe('OverlayController', () => {
1590
1600
  await controllerWithBackdrop.show();
1591
1601
  expect(controllerWithBackdrop.backdropNode).to.have.class('custom-backdrop');
1592
1602
  });
1593
-
1594
1603
  it('reenables the backdrop when shown/hidden/shown', async () => {
1595
1604
  const backdropNode = document.createElement('div');
1596
1605
  backdropNode.classList.add('custom-backdrop');
1597
-
1598
1606
  const ctrl = new OverlayController({
1599
1607
  ...withLocalTestConfig(),
1600
1608
  hasBackdrop: true,
@@ -1606,11 +1614,9 @@ describe('OverlayController', () => {
1606
1614
  await ctrl.show();
1607
1615
  expect(ctrl.backdropNode).to.have.class('custom-backdrop');
1608
1616
  });
1609
-
1610
1617
  it('adds and stacks backdrops if .hasBackdrop is enabled', async () => {
1611
1618
  const backdropNode = document.createElement('div');
1612
1619
  backdropNode.classList.add('custom-backdrop-zero');
1613
-
1614
1620
  const ctrl0 = new OverlayController({
1615
1621
  ...withLocalTestConfig(),
1616
1622
  hasBackdrop: true,
@@ -1618,7 +1624,6 @@ describe('OverlayController', () => {
1618
1624
  });
1619
1625
  await ctrl0.show();
1620
1626
  expect(ctrl0.backdropNode).to.have.class('custom-backdrop-zero');
1621
-
1622
1627
  const ctrl1 = new OverlayController({
1623
1628
  ...withLocalTestConfig(),
1624
1629
  hasBackdrop: false,
@@ -1626,23 +1631,19 @@ describe('OverlayController', () => {
1626
1631
  await ctrl1.show();
1627
1632
  expect(ctrl0.backdropNode).to.have.class('custom-backdrop-zero');
1628
1633
  expect(ctrl1.backdropNode).to.be.undefined;
1629
-
1630
1634
  const anotherBackdropNode = document.createElement('div');
1631
1635
  anotherBackdropNode.classList.add('custom-backdrop-two');
1632
-
1633
1636
  const ctrl2 = new OverlayController({
1634
1637
  ...withLocalTestConfig(),
1635
1638
  hasBackdrop: true,
1636
1639
  backdropNode: anotherBackdropNode,
1637
1640
  });
1638
1641
  await ctrl2.show();
1639
-
1640
1642
  expect(ctrl0.backdropNode).to.have.class('custom-backdrop-zero');
1641
1643
  expect(ctrl1.backdropNode).to.be.undefined;
1642
1644
  expect(ctrl2.backdropNode).to.have.class('custom-backdrop-two');
1643
1645
  });
1644
1646
  });
1645
-
1646
1647
  describe('isBlocking', () => {
1647
1648
  it('prevents showing of other overlays', async () => {
1648
1649
  const ctrl0 = new OverlayController({
@@ -1661,30 +1662,25 @@ describe('OverlayController', () => {
1661
1662
  ...withGlobalTestConfig(),
1662
1663
  isBlocking: false,
1663
1664
  });
1664
-
1665
1665
  await ctrl0.show();
1666
1666
  await ctrl1.show();
1667
1667
  await ctrl2.show(); // blocking
1668
1668
  expect(ctrl0.__wrappingDialogNode).to.not.be.displayed;
1669
1669
  expect(ctrl1.__wrappingDialogNode).to.not.be.displayed;
1670
1670
  expect(ctrl2.__wrappingDialogNode).to.be.displayed;
1671
-
1672
1671
  await ctrl3.show();
1673
1672
  await ctrl3._showComplete;
1674
1673
  expect(ctrl3.__wrappingDialogNode).to.be.displayed;
1675
-
1676
1674
  await ctrl2.hide();
1677
1675
  await ctrl2._hideComplete;
1678
1676
  expect(ctrl0.__wrappingDialogNode).to.be.displayed;
1679
1677
  expect(ctrl1.__wrappingDialogNode).to.be.displayed;
1680
-
1681
1678
  await ctrl2.show(); // blocking
1682
1679
  expect(ctrl0.__wrappingDialogNode).to.not.be.displayed;
1683
1680
  expect(ctrl1.__wrappingDialogNode).to.not.be.displayed;
1684
1681
  expect(ctrl2.__wrappingDialogNode).to.be.displayed;
1685
1682
  expect(ctrl3.__wrappingDialogNode).to.not.be.displayed;
1686
1683
  });
1687
-
1688
1684
  it('keeps backdrop status when used in combination with blocking', async () => {
1689
1685
  const ctrl0 = new OverlayController({
1690
1686
  ...withGlobalTestConfig(),
@@ -1692,7 +1688,6 @@ describe('OverlayController', () => {
1692
1688
  hasBackdrop: true,
1693
1689
  });
1694
1690
  await ctrl0.show();
1695
-
1696
1691
  const ctrl1 = new OverlayController({
1697
1692
  ...withGlobalTestConfig(),
1698
1693
  isBlocking: false,
@@ -1702,14 +1697,100 @@ describe('OverlayController', () => {
1702
1697
  await ctrl1.hide();
1703
1698
  expect(ctrl0.hasActiveBackdrop).to.be.true;
1704
1699
  expect(ctrl1.hasActiveBackdrop).to.be.false;
1705
-
1706
1700
  await ctrl1.show();
1707
1701
  expect(ctrl0.hasActiveBackdrop).to.be.true;
1708
1702
  expect(ctrl1.hasActiveBackdrop).to.be.true;
1709
1703
  });
1710
1704
  });
1711
- });
1705
+ describe('elementToFocusOnShow', () => {
1706
+ it('adds tabindex="-1" to the content node when elementToFocusOnShow is true', async () => {
1707
+ const ctrl = new OverlayController({
1708
+ ...withGlobalTestConfig(),
1709
+ isBlocking: false,
1710
+ elementToFocusOnShow: true,
1711
+ });
1712
+ const contentNode = /** @type {HTMLElement} */ await fixture('<div>Content</div>');
1713
+ ctrl.updateConfig({
1714
+ contentNode,
1715
+ });
1716
+ await ctrl.show();
1717
+ expect(contentNode.getAttribute('tabindex')).to.equal('-1');
1718
+ });
1719
+ it('makes contentNode the root of "next tab flow"', async () => {
1720
+ const ctrl = new OverlayController({
1721
+ ...withGlobalTestConfig(),
1722
+ isBlocking: false,
1723
+ elementToFocusOnShow: true,
1724
+ });
1725
+ const contentNode =
1726
+ /** @type {HTMLElement} */
1727
+ await fixture('<div><button>Button</button></div>');
1728
+ ctrl.updateConfig({
1729
+ contentNode,
1730
+ });
1731
+ await ctrl.show();
1732
+ const button = /** @type {HTMLButtonElement} */ contentNode.querySelector('button');
1733
+ button.focus();
1734
+ expect(isActiveElement(button)).to.be.true;
1735
+ });
1736
+ });
1737
+ describe('syncChildrenCloseState', () => {
1738
+ it('does not close all children of nested controllers when syncChildrenCloseState is false', async () => {
1739
+ const parentContent =
1740
+ /** @type {HTMLDivElement} */
1741
+ await fixture(
1742
+ html` <!-- -->
1743
+ <div data-sync-children-close-state id="parent-overlay">
1744
+ <div id="child-overlay">we open our child and it will close when parent does</div>
1745
+ </div>`,
1746
+ );
1747
+ const { parentOverlay, childOverlay } = await createNestedEscControllers(parentContent);
1748
+ expect(parentOverlay.isShown).to.be.true;
1749
+ expect(childOverlay.isShown).to.be.true;
1750
+ await parentOverlay.hide();
1751
+ await childOverlay._hideComplete;
1752
+ expect(parentOverlay.isShown).to.be.false;
1753
+ expect(childOverlay.isShown).to.be.false;
1754
+ });
1755
+ it('does not close all children of nested controllers when syncChildrenCloseState is false', async () => {
1756
+ const parentContent =
1757
+ /** @type {HTMLDivElement} */
1758
+ await fixture(
1759
+ html` <!-- -->
1760
+ <div id="parent-overlay">
1761
+ <div id="child-overlay">
1762
+ we open our child and it will not close when parent does
1763
+ </div>
1764
+ </div>`,
1765
+ );
1766
+ const { parentOverlay, childOverlay } = await createNestedEscControllers(parentContent);
1767
+ expect(parentOverlay.isShown).to.be.true;
1768
+ expect(childOverlay.isShown).to.be.true;
1769
+ await parentOverlay.hide();
1770
+ expect(parentOverlay.isShown).to.be.false;
1771
+ expect(childOverlay.isShown).to.be.true;
1772
+ });
1773
+ });
1774
+ describe('isActivated', () => {
1775
+ it('allows to conditionally disable overlay/openable functionality (for responsive context like nav menus, accordions/collapsibles vs plain headings/content etc.)', async () => {
1776
+ const ctrl = new OverlayController({
1777
+ ...withGlobalTestConfig(),
1778
+ isActivated: false,
1779
+ });
1780
+ expect(ctrl.__hasSetup).to.be.false;
1781
+ ctrl.updateConfig({
1782
+ isActivated: true,
1783
+ });
1784
+ expect(ctrl.__hasSetup).to.be.true;
1785
+ });
1786
+ });
1712
1787
 
1788
+ // TODO
1789
+ describe('hideVisually', () => {});
1790
+
1791
+ // TODO
1792
+ describe('requireConnectedNodes', () => {});
1793
+ });
1713
1794
  describe('Show / Hide / Toggle', () => {
1714
1795
  it('has .isShown which defaults to false', async () => {
1715
1796
  const ctrl = new OverlayController({
@@ -1717,7 +1798,6 @@ describe('OverlayController', () => {
1717
1798
  });
1718
1799
  expect(ctrl.isShown).to.be.false;
1719
1800
  });
1720
-
1721
1801
  it('has async show() which shows the overlay', async () => {
1722
1802
  const ctrl = new OverlayController({
1723
1803
  ...withGlobalTestConfig(),
@@ -1726,55 +1806,44 @@ describe('OverlayController', () => {
1726
1806
  expect(ctrl.isShown).to.be.true;
1727
1807
  expect(ctrl.show()).to.be.instanceOf(Promise);
1728
1808
  });
1729
-
1730
1809
  it('has async hide() which hides the overlay', async () => {
1731
1810
  const ctrl = new OverlayController({
1732
1811
  ...withGlobalTestConfig(),
1733
1812
  });
1734
-
1735
1813
  await ctrl.hide();
1736
1814
  expect(ctrl.isShown).to.be.false;
1737
1815
  expect(ctrl.hide()).to.be.instanceOf(Promise);
1738
1816
  });
1739
-
1740
1817
  it('fires "show" event once overlay becomes shown', async () => {
1741
1818
  const showSpy = sinon.spy();
1742
1819
  const ctrl = new OverlayController({
1743
1820
  ...withGlobalTestConfig(),
1744
1821
  });
1745
-
1746
1822
  ctrl.addEventListener('show', showSpy);
1747
1823
  await ctrl.show();
1748
1824
  expect(showSpy.callCount).to.equal(1);
1749
1825
  await ctrl.show();
1750
1826
  expect(showSpy.callCount).to.equal(1);
1751
1827
  });
1752
-
1753
1828
  it('fires "before-show" event right before overlay becomes shown', async () => {
1754
1829
  const ctrl = new OverlayController({
1755
1830
  ...withGlobalTestConfig(),
1756
1831
  });
1757
-
1758
1832
  const eventSpy = sinon.spy();
1759
-
1760
1833
  ctrl.addEventListener('before-show', eventSpy);
1761
1834
  ctrl.addEventListener('show', eventSpy);
1762
-
1763
1835
  await ctrl.show();
1764
1836
  expect(eventSpy.getCall(0).args[0].type).to.equal('before-show');
1765
1837
  expect(eventSpy.getCall(1).args[0].type).to.equal('show');
1766
-
1767
1838
  expect(eventSpy.callCount).to.equal(2);
1768
1839
  await ctrl.show();
1769
1840
  expect(eventSpy.callCount).to.equal(2);
1770
1841
  });
1771
-
1772
1842
  it('fires "hide" event once overlay becomes hidden', async () => {
1773
1843
  const hideSpy = sinon.spy();
1774
1844
  const ctrl = new OverlayController({
1775
1845
  ...withGlobalTestConfig(),
1776
1846
  });
1777
-
1778
1847
  ctrl.addEventListener('hide', hideSpy);
1779
1848
  await ctrl.show();
1780
1849
  await ctrl.hide();
@@ -1782,38 +1851,29 @@ describe('OverlayController', () => {
1782
1851
  await ctrl.hide();
1783
1852
  expect(hideSpy.callCount).to.equal(1);
1784
1853
  });
1785
-
1786
1854
  it('fires "before-hide" event right before overlay becomes hidden', async () => {
1787
1855
  const ctrl = new OverlayController({
1788
1856
  ...withGlobalTestConfig(),
1789
1857
  });
1790
-
1791
1858
  const eventSpy = sinon.spy();
1792
-
1793
1859
  ctrl.addEventListener('before-hide', eventSpy);
1794
1860
  ctrl.addEventListener('hide', eventSpy);
1795
-
1796
1861
  await ctrl.show();
1797
1862
  await ctrl.hide();
1798
1863
  expect(eventSpy.getCall(0).args[0].type).to.equal('before-hide');
1799
1864
  expect(eventSpy.getCall(1).args[0].type).to.equal('hide');
1800
-
1801
1865
  expect(eventSpy.callCount).to.equal(2);
1802
1866
  await ctrl.hide();
1803
1867
  expect(eventSpy.callCount).to.equal(2);
1804
1868
  });
1805
-
1806
1869
  it('can be toggled', async () => {
1807
1870
  const ctrl = new OverlayController({
1808
1871
  ...withGlobalTestConfig(),
1809
1872
  });
1810
-
1811
1873
  await ctrl.toggle();
1812
1874
  expect(ctrl.isShown).to.be.true;
1813
-
1814
1875
  await ctrl.toggle();
1815
1876
  expect(ctrl.isShown).to.be.false;
1816
-
1817
1877
  await ctrl.toggle();
1818
1878
  expect(ctrl.isShown).to.be.true;
1819
1879
 
@@ -1822,7 +1882,6 @@ describe('OverlayController', () => {
1822
1882
  // check for show
1823
1883
  expect(ctrl.toggle()).to.be.instanceOf(Promise);
1824
1884
  });
1825
-
1826
1885
  it('makes sure the latest shown overlay is visible', async () => {
1827
1886
  const ctrl0 = new OverlayController({
1828
1887
  ...withGlobalTestConfig(),
@@ -1833,18 +1892,14 @@ describe('OverlayController', () => {
1833
1892
  await ctrl0.show();
1834
1893
  const rect = ctrl0.contentNode.getBoundingClientRect();
1835
1894
  const getTopEl = () => document.elementFromPoint(Math.ceil(rect.left), Math.ceil(rect.top));
1836
-
1837
1895
  await ctrl0.show();
1838
1896
  expect(getTopEl()).to.equal(ctrl0.contentNode);
1839
-
1840
1897
  await ctrl1.show();
1841
1898
  expect(getTopEl()).to.equal(ctrl1.contentNode);
1842
-
1843
1899
  await ctrl0.show();
1844
1900
  expect(getTopEl()).to.equal(ctrl0.contentNode);
1845
1901
  });
1846
-
1847
- it('awaits a "transitionHide" hook before hiding for real', done => {
1902
+ it('awaits a "transitionHide" hook before hiding for real', (done) => {
1848
1903
  const ctrl = new OverlayController({
1849
1904
  ...withGlobalTestConfig(),
1850
1905
  });
@@ -1853,12 +1908,10 @@ describe('OverlayController', () => {
1853
1908
  /** @type {{ (): void; (value?: void | PromiseLike<void> | undefined): void; }} */
1854
1909
  let hideTransitionFinished;
1855
1910
  ctrl.transitionHide = () =>
1856
- new Promise(resolve => {
1911
+ new Promise((resolve) => {
1857
1912
  hideTransitionFinished = resolve;
1858
1913
  });
1859
-
1860
1914
  ctrl.hide();
1861
-
1862
1915
  expect(getComputedStyle(ctrl.content).display).to.equal('block');
1863
1916
  setTimeout(() => {
1864
1917
  hideTransitionFinished();
@@ -1868,8 +1921,7 @@ describe('OverlayController', () => {
1868
1921
  }, 0);
1869
1922
  }, 0);
1870
1923
  });
1871
-
1872
- it('awaits a "transitionShow" hook before finishing the show method', done => {
1924
+ it('awaits a "transitionShow" hook before finishing the show method', (done) => {
1873
1925
  const ctrl = new OverlayController({
1874
1926
  ...withGlobalTestConfig(),
1875
1927
  });
@@ -1877,17 +1929,16 @@ describe('OverlayController', () => {
1877
1929
  /** @type {{ (): void; (value?: void | PromiseLike<void> | undefined): void; }} */
1878
1930
  let showTransitionFinished;
1879
1931
  ctrl.transitionShow = () =>
1880
- new Promise(resolve => {
1932
+ new Promise((resolve) => {
1881
1933
  showTransitionFinished = resolve;
1882
1934
  });
1883
1935
  ctrl.show();
1884
-
1885
1936
  let showIsDone = false;
1886
1937
 
1887
- /** @type {Promise<void>} */ (ctrl._showComplete).then(() => {
1938
+ /** @type {Promise<void>} */
1939
+ ctrl._showComplete.then(() => {
1888
1940
  showIsDone = true;
1889
1941
  });
1890
-
1891
1942
  expect(showIsDone).to.be.false;
1892
1943
  setTimeout(() => {
1893
1944
  showTransitionFinished();
@@ -1898,27 +1949,23 @@ describe('OverlayController', () => {
1898
1949
  }, 0);
1899
1950
  });
1900
1951
  });
1901
-
1902
1952
  describe('Update Configuration', () => {
1903
1953
  it('reinitializes content', async () => {
1904
1954
  const ctrl = new OverlayController({
1905
1955
  ...withLocalTestConfig(),
1906
- contentNode: /** @type {HTMLElement} */ (await fixture(html`<div>content1</div>`)),
1956
+ contentNode: /** @type {HTMLElement} */ await fixture(html`<div>content1</div>`),
1907
1957
  });
1908
1958
  await ctrl.show(); // Popper adds inline styles
1909
1959
  expect(ctrl.content.style.transform).not.to.be.undefined;
1910
1960
  expect(ctrl.contentNode.textContent).to.include('content1');
1911
-
1912
1961
  ctrl.updateConfig({
1913
1962
  placementMode: 'local',
1914
- contentNode: /** @type {HTMLElement} */ (await fixture(html`<div>content2</div>`)),
1963
+ contentNode: /** @type {HTMLElement} */ await fixture(html`<div>content2</div>`),
1915
1964
  });
1916
1965
  expect(ctrl.contentNode.textContent).to.include('content2');
1917
1966
  });
1918
-
1919
1967
  it('respects the initial config provided to new OverlayController(initialConfig)', async () => {
1920
- const contentNode = /** @type {HTMLElement} */ (fixtureSync(html`<div>my content</div>`));
1921
-
1968
+ const contentNode = /** @type {HTMLElement} */ fixtureSync(html`<div>my content</div>`);
1922
1969
  const ctrl = new OverlayController({
1923
1970
  // This is the shared config
1924
1971
  placementMode: 'global',
@@ -1937,46 +1984,44 @@ describe('OverlayController', () => {
1937
1984
 
1938
1985
  // Currently not working, enable again when we fix updateConfig
1939
1986
  it.skip('allows for updating viewport config placement only, while keeping the content shown', async () => {
1940
- const contentNode = /** @type {HTMLElement} */ (fixtureSync(html`<div>my content</div>`));
1941
-
1987
+ const contentNode = /** @type {HTMLElement} */ fixtureSync(html`<div>my content</div>`);
1942
1988
  const ctrl = new OverlayController({
1943
1989
  // This is the shared config
1944
1990
  placementMode: 'global',
1945
1991
  handlesAccessibility: true,
1946
1992
  contentNode,
1947
1993
  });
1948
-
1949
1994
  ctrl.show();
1950
1995
  expect(ctrl.contentWrapperNode.classList.contains('overlays__overlay-container--center'));
1951
1996
  expect(ctrl.isShown).to.be.true;
1952
-
1953
- ctrl.updateConfig({ viewportConfig: { placement: 'top-right' } });
1997
+ ctrl.updateConfig({
1998
+ viewportConfig: {
1999
+ placement: 'top-right',
2000
+ },
2001
+ });
1954
2002
  expect(ctrl.contentWrapperNode.classList.contains('overlays__overlay-container--top-right'));
1955
2003
  expect(ctrl.isShown).to.be.true;
1956
2004
  });
1957
-
1958
2005
  it('disables backdrop when switching to hasBackrop "false"', async () => {
1959
2006
  const ctrl = new OverlayController({
1960
2007
  ...withLocalTestConfig(),
1961
- contentNode: /** @type {HTMLElement} */ (await fixture(html`<div>content1</div>`)),
2008
+ contentNode: /** @type {HTMLElement} */ await fixture(html`<div>content1</div>`),
1962
2009
  hasBackdrop: true,
1963
2010
  });
1964
2011
  await ctrl.show(); // Popper adds inline styles
1965
2012
  expect(ctrl.backdropNode).not.to.be.undefined;
1966
2013
  expect(Array.from(ctrl.backdropNode.classList)).to.include('overlays__backdrop--visible');
1967
-
1968
2014
  ctrl.updateConfig({
1969
2015
  hasBackdrop: false,
1970
2016
  });
1971
2017
  expect(Array.from(ctrl.backdropNode.classList)).to.not.include('overlays__backdrop--visible');
1972
2018
  });
1973
2019
  });
1974
-
1975
2020
  describe('Accessibility', () => {
1976
2021
  it('synchronizes [aria-expanded] on invoker', async () => {
1977
- const invokerNode = /** @type {HTMLElement} */ (
1978
- await fixture('<div role="button">invoker</div>')
1979
- );
2022
+ const invokerNode =
2023
+ /** @type {HTMLElement} */
2024
+ await fixture('<div role="button">invoker</div>');
1980
2025
  const ctrl = new OverlayController({
1981
2026
  ...withLocalTestConfig(),
1982
2027
  handlesAccessibility: true,
@@ -1988,11 +2033,10 @@ describe('OverlayController', () => {
1988
2033
  await ctrl.hide();
1989
2034
  expect(ctrl.invokerNode?.getAttribute('aria-expanded')).to.equal('false');
1990
2035
  });
1991
-
1992
2036
  it('does not synchronize [aria-expanded] on invoker when the overlay is modal', async () => {
1993
- const invokerNode = /** @type {HTMLElement} */ (
1994
- await fixture('<div role="button">invoker</div>')
1995
- );
2037
+ const invokerNode =
2038
+ /** @type {HTMLElement} */
2039
+ await fixture('<div role="button">invoker</div>');
1996
2040
  const ctrl = new OverlayController({
1997
2041
  ...withLocalTestConfig(),
1998
2042
  trapsKeyboardFocus: true,
@@ -2005,7 +2049,6 @@ describe('OverlayController', () => {
2005
2049
  await ctrl.hide();
2006
2050
  expect(ctrl.invokerNode?.getAttribute('aria-expanded')).to.equal(null);
2007
2051
  });
2008
-
2009
2052
  it('creates unique id for content', async () => {
2010
2053
  const ctrl = new OverlayController({
2011
2054
  ...withLocalTestConfig(),
@@ -2014,11 +2057,10 @@ describe('OverlayController', () => {
2014
2057
  const { contentId } = getProtectedMembers(ctrl);
2015
2058
  expect(ctrl.contentNode.id).to.contain(contentId);
2016
2059
  });
2017
-
2018
2060
  it('preserves content id when present', async () => {
2019
- const contentNode = /** @type {HTMLElement} */ (
2020
- await fixture('<div id="preserved">content</div>')
2021
- );
2061
+ const contentNode =
2062
+ /** @type {HTMLElement} */
2063
+ await fixture('<div id="preserved">content</div>');
2022
2064
  const ctrl = new OverlayController({
2023
2065
  ...withLocalTestConfig(),
2024
2066
  handlesAccessibility: true,
@@ -2026,11 +2068,10 @@ describe('OverlayController', () => {
2026
2068
  });
2027
2069
  expect(ctrl.contentNode.id).to.contain('preserved');
2028
2070
  });
2029
-
2030
2071
  it('adds [role=dialog] on content', async () => {
2031
- const invokerNode = /** @type {HTMLElement} */ (
2032
- await fixture('<div role="button">invoker</div>')
2033
- );
2072
+ const invokerNode =
2073
+ /** @type {HTMLElement} */
2074
+ await fixture('<div role="button">invoker</div>');
2034
2075
  const ctrl = new OverlayController({
2035
2076
  ...withLocalTestConfig(),
2036
2077
  handlesAccessibility: true,
@@ -2038,14 +2079,13 @@ describe('OverlayController', () => {
2038
2079
  });
2039
2080
  expect(ctrl.contentNode.getAttribute('role')).to.equal('dialog');
2040
2081
  });
2041
-
2042
2082
  it('preserves [role] on content when present', async () => {
2043
- const invokerNode = /** @type {HTMLElement} */ (
2044
- await fixture('<div role="button">invoker</div>')
2045
- );
2046
- const contentNode = /** @type {HTMLElement} */ (
2047
- await fixture('<div role="menu">invoker</div>')
2048
- );
2083
+ const invokerNode =
2084
+ /** @type {HTMLElement} */
2085
+ await fixture('<div role="button">invoker</div>');
2086
+ const contentNode =
2087
+ /** @type {HTMLElement} */
2088
+ await fixture('<div role="menu">invoker</div>');
2049
2089
  const ctrl = new OverlayController({
2050
2090
  ...withLocalTestConfig(),
2051
2091
  handlesAccessibility: true,
@@ -2054,7 +2094,6 @@ describe('OverlayController', () => {
2054
2094
  });
2055
2095
  expect(ctrl.contentNode.getAttribute('role')).to.equal('menu');
2056
2096
  });
2057
-
2058
2097
  it('allows to not provide an invokerNode', async () => {
2059
2098
  let properlyInstantiated = false;
2060
2099
  try {
@@ -2065,7 +2104,7 @@ describe('OverlayController', () => {
2065
2104
  });
2066
2105
  properlyInstantiated = true;
2067
2106
  } catch (e) {
2068
- throw new Error(/** @type {Error} */ (e).message);
2107
+ throw new Error(/** @type {Error} */ e.message);
2069
2108
  }
2070
2109
  expect(properlyInstantiated).to.be.true;
2071
2110
  });
@@ -2073,28 +2112,25 @@ describe('OverlayController', () => {
2073
2112
  // TODO: check if we covered all functionality. "Inertness" should be handled by the platform with a modal overlay...
2074
2113
  it.skip('adds attributes inert and aria-hidden="true" on all siblings of rootNode if an overlay is shown', async () => {});
2075
2114
  it.skip('disables pointer events and selection on inert elements', async () => {});
2076
-
2077
2115
  describe('Alert dialog', () => {
2078
2116
  it('sets role="alertdialog" when isAlertDialog is set', async () => {
2079
- const invokerNode = /** @type {HTMLElement} */ (
2080
- await fixture('<div role="button">invoker</div>')
2081
- );
2117
+ const invokerNode =
2118
+ /** @type {HTMLElement} */
2119
+ await fixture('<div role="button">invoker</div>');
2082
2120
  const ctrl = new OverlayController({
2083
2121
  ...withLocalTestConfig(),
2084
2122
  handlesAccessibility: true,
2085
2123
  isAlertDialog: true,
2086
2124
  invokerNode,
2087
2125
  });
2088
-
2089
2126
  expect(ctrl.contentNode?.getAttribute('role')).to.equal('alertdialog');
2090
2127
  });
2091
2128
  });
2092
-
2093
2129
  describe('Tooltip', () => {
2094
2130
  it('adds [aria-describedby] on invoker', async () => {
2095
- const invokerNode = /** @type {HTMLElement} */ (
2096
- await fixture('<div role="button">invoker</div>')
2097
- );
2131
+ const invokerNode =
2132
+ /** @type {HTMLElement} */
2133
+ await fixture('<div role="button">invoker</div>');
2098
2134
  const ctrl = new OverlayController({
2099
2135
  ...withLocalTestConfig(),
2100
2136
  handlesAccessibility: true,
@@ -2102,14 +2138,12 @@ describe('OverlayController', () => {
2102
2138
  invokerNode,
2103
2139
  });
2104
2140
  const { contentId } = getProtectedMembers(ctrl);
2105
-
2106
2141
  expect(ctrl.invokerNode?.getAttribute('aria-describedby')).to.equal(contentId);
2107
2142
  });
2108
-
2109
2143
  it('adds [aria-labelledby] on invoker when invokerRelation is label', async () => {
2110
- const invokerNode = /** @type {HTMLElement} */ (
2111
- await fixture('<div role="button">invoker</div>')
2112
- );
2144
+ const invokerNode =
2145
+ /** @type {HTMLElement} */
2146
+ await fixture('<div role="button">invoker</div>');
2113
2147
  const ctrl = new OverlayController({
2114
2148
  ...withLocalTestConfig(),
2115
2149
  handlesAccessibility: true,
@@ -2118,15 +2152,13 @@ describe('OverlayController', () => {
2118
2152
  invokerNode,
2119
2153
  });
2120
2154
  const { contentId } = getProtectedMembers(ctrl);
2121
-
2122
2155
  expect(ctrl.invokerNode?.getAttribute('aria-describedby')).to.equal(null);
2123
2156
  expect(ctrl.invokerNode?.getAttribute('aria-labelledby')).to.equal(contentId);
2124
2157
  });
2125
-
2126
2158
  it('adds [role=tooltip] on content', async () => {
2127
- const invokerNode = /** @type {HTMLElement} */ (
2128
- await fixture('<div role="button">invoker</div>')
2129
- );
2159
+ const invokerNode =
2160
+ /** @type {HTMLElement} */
2161
+ await fixture('<div role="button">invoker</div>');
2130
2162
  const ctrl = new OverlayController({
2131
2163
  ...withLocalTestConfig(),
2132
2164
  handlesAccessibility: true,
@@ -2135,11 +2167,10 @@ describe('OverlayController', () => {
2135
2167
  });
2136
2168
  expect(ctrl.contentNode.getAttribute('role')).to.equal('tooltip');
2137
2169
  });
2138
-
2139
2170
  it('adds tabindex="-1" to the wrappingDialog element', async () => {
2140
- const invokerNode = /** @type {HTMLElement} */ (
2141
- await fixture('<div role="button">invoker</div>')
2142
- );
2171
+ const invokerNode =
2172
+ /** @type {HTMLElement} */
2173
+ await fixture('<div role="button">invoker</div>');
2143
2174
  const ctrl = new OverlayController({
2144
2175
  ...withLocalTestConfig(),
2145
2176
  handlesAccessibility: true,
@@ -2148,12 +2179,11 @@ describe('OverlayController', () => {
2148
2179
  });
2149
2180
  expect(ctrl.__wrappingDialogNode?.getAttribute('tabindex')).to.equal('-1');
2150
2181
  });
2151
-
2152
2182
  describe('Teardown', () => {
2153
2183
  it('restores [role] on dialog content', async () => {
2154
- const invokerNode = /** @type {HTMLElement} */ (
2155
- await fixture('<div role="button">invoker</div>')
2156
- );
2184
+ const invokerNode =
2185
+ /** @type {HTMLElement} */
2186
+ await fixture('<div role="button">invoker</div>');
2157
2187
  const ctrl = new OverlayController({
2158
2188
  ...withLocalTestConfig(),
2159
2189
  handlesAccessibility: true,
@@ -2163,14 +2193,13 @@ describe('OverlayController', () => {
2163
2193
  ctrl.teardown();
2164
2194
  expect(ctrl.contentNode.getAttribute('role')).to.equal(null);
2165
2195
  });
2166
-
2167
2196
  it('restores [role] on tooltip content', async () => {
2168
- const invokerNode = /** @type {HTMLElement} */ (
2169
- await fixture('<div role="button">invoker</div>')
2170
- );
2171
- const contentNode = /** @type {HTMLElement} */ (
2172
- await fixture('<div role="presentation">content</div>')
2173
- );
2197
+ const invokerNode =
2198
+ /** @type {HTMLElement} */
2199
+ await fixture('<div role="button">invoker</div>');
2200
+ const contentNode =
2201
+ /** @type {HTMLElement} */
2202
+ await fixture('<div role="presentation">content</div>');
2174
2203
  const ctrl = new OverlayController({
2175
2204
  ...withLocalTestConfig(),
2176
2205
  handlesAccessibility: true,
@@ -2182,14 +2211,13 @@ describe('OverlayController', () => {
2182
2211
  ctrl.teardown();
2183
2212
  expect(contentNode.getAttribute('role')).to.equal('presentation');
2184
2213
  });
2185
-
2186
2214
  it('restores [aria-describedby] on content', async () => {
2187
- const invokerNode = /** @type {HTMLElement} */ (
2188
- await fixture('<div role="button">invoker</div>')
2189
- );
2190
- const contentNode = /** @type {HTMLElement} */ (
2191
- await fixture('<div role="presentation">content</div>')
2192
- );
2215
+ const invokerNode =
2216
+ /** @type {HTMLElement} */
2217
+ await fixture('<div role="button">invoker</div>');
2218
+ const contentNode =
2219
+ /** @type {HTMLElement} */
2220
+ await fixture('<div role="presentation">content</div>');
2193
2221
  const ctrl = new OverlayController({
2194
2222
  ...withLocalTestConfig(),
2195
2223
  handlesAccessibility: true,
@@ -2201,14 +2229,13 @@ describe('OverlayController', () => {
2201
2229
  ctrl.teardown();
2202
2230
  expect(invokerNode.getAttribute('aria-describedby')).to.equal(null);
2203
2231
  });
2204
-
2205
2232
  it('restores [aria-labelledby] on content', async () => {
2206
- const invokerNode = /** @type {HTMLElement} */ (
2207
- await fixture('<div role="button">invoker</div>')
2208
- );
2209
- const contentNode = /** @type {HTMLElement} */ (
2210
- await fixture('<div role="presentation">content</div>')
2211
- );
2233
+ const invokerNode =
2234
+ /** @type {HTMLElement} */
2235
+ await fixture('<div role="button">invoker</div>');
2236
+ const contentNode =
2237
+ /** @type {HTMLElement} */
2238
+ await fixture('<div role="presentation">content</div>');
2212
2239
  const ctrl = new OverlayController({
2213
2240
  ...withLocalTestConfig(),
2214
2241
  handlesAccessibility: true,
@@ -2224,7 +2251,6 @@ describe('OverlayController', () => {
2224
2251
  });
2225
2252
  });
2226
2253
  });
2227
-
2228
2254
  describe('Exception handling', () => {
2229
2255
  it('throws if no .placementMode gets passed on', async () => {
2230
2256
  const contentNode = document.createElement('div');
@@ -2236,7 +2262,6 @@ describe('OverlayController', () => {
2236
2262
  });
2237
2263
  }).to.throw('[OverlayController] You need to provide a .placementMode ("global"|"local")');
2238
2264
  });
2239
-
2240
2265
  it('throws if invalid .placementMode gets passed on', async () => {
2241
2266
  expect(() => {
2242
2267
  new OverlayController({
@@ -2247,7 +2272,6 @@ describe('OverlayController', () => {
2247
2272
  '[OverlayController] "invalid" is not a valid .placementMode, use ("global"|"local")',
2248
2273
  );
2249
2274
  });
2250
-
2251
2275
  it('throws if no .contentNode gets passed on', async () => {
2252
2276
  expect(() => {
2253
2277
  new OverlayController({
@@ -2255,7 +2279,6 @@ describe('OverlayController', () => {
2255
2279
  });
2256
2280
  }).to.throw('[OverlayController] You need to provide a .contentNode');
2257
2281
  });
2258
-
2259
2282
  it('throws if handlesAccessibility is false for a tooltip', async () => {
2260
2283
  const contentNode = document.createElement('div');
2261
2284
  document.body.appendChild(contentNode);
@@ -2271,7 +2294,6 @@ describe('OverlayController', () => {
2271
2294
  );
2272
2295
  });
2273
2296
  });
2274
-
2275
2297
  describe('run _keepBodySize only with scroll prevention', () => {
2276
2298
  /**
2277
2299
  * @type {OverlayController}
@@ -2280,15 +2302,12 @@ describe('OverlayController', () => {
2280
2302
  ...withLocalTestConfig(),
2281
2303
  preventsScroll: false,
2282
2304
  });
2283
-
2284
2305
  const overlayControllerPreventsScroll = new OverlayController({
2285
2306
  ...withLocalTestConfig(),
2286
2307
  preventsScroll: true,
2287
2308
  });
2288
-
2289
2309
  it('should not run with scroll prevention', async () => {
2290
2310
  await overlayControllerNoPrevent.show();
2291
-
2292
2311
  expect(
2293
2312
  overlayControllerNoPrevent.manager.__forTesting.bodySizeVars.marginRightInline,
2294
2313
  ).to.equal(undefined);
@@ -2296,10 +2315,9 @@ describe('OverlayController', () => {
2296
2315
  undefined,
2297
2316
  );
2298
2317
  });
2299
-
2300
2318
  it('should run with scroll prevention', async () => {
2319
+ await overlayControllerPreventsScroll.hide();
2301
2320
  await overlayControllerPreventsScroll.show();
2302
-
2303
2321
  expect(
2304
2322
  overlayControllerPreventsScroll.manager.__forTesting.bodySizeVars.marginRightInline,
2305
2323
  ).to.not.equal(undefined);