@lion/ui 0.19.1 → 0.20.0-menu-system.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 (348) hide show
  1. package/collapsible.js +1 -0
  2. package/components/button/src/LionButton.js +4 -0
  3. package/components/button/test-suites/LionButton.suite.js +1 -0
  4. package/components/calendar/src/LionCalendar.js +3 -1
  5. package/components/calendar/test/lion-calendar.test.js +47 -67
  6. package/components/collapsible/src/DisclosureMixin.js +313 -0
  7. package/components/collapsible/test-suites/DisclosureMixin.suite.js +30 -0
  8. package/components/collapsible/types/DisclosureMixinTypes.ts +48 -0
  9. package/components/combobox/test/lion-combobox.test.js +1 -0
  10. package/components/form-core/src/form-group/FormGroupMixin.js +7 -0
  11. package/components/form-core/src/registration/FormRegistrarMixin.js +11 -0
  12. package/components/form-core/test/FormControlMixin.test.js +1 -0
  13. package/components/form-core/test/validate/Validator.test.js +2 -0
  14. package/components/form-core/test-suites/ValidateMixin.suite.js +2 -0
  15. package/components/form-core/test-suites/ValidateMixinFeedbackPart.suite.js +1 -0
  16. package/components/input-datepicker/src/localizeNamespaceLoader.js +1 -0
  17. package/components/input-datepicker/test/lion-input-datepicker.test.js +9 -19
  18. package/components/input-email/src/LionInputEmail.js +0 -2
  19. package/components/input-email/test/lion-input-email.test.js +0 -6
  20. package/components/input-file/src/validators.js +1 -31
  21. package/components/input-file/test/FileValidators.test.js +0 -31
  22. package/components/input-file/translations/bg.js +0 -1
  23. package/components/input-file/translations/cs.js +0 -1
  24. package/components/input-file/translations/de.js +0 -2
  25. package/components/input-file/translations/en.js +0 -1
  26. package/components/input-file/translations/es.js +0 -1
  27. package/components/input-file/translations/fr.js +0 -1
  28. package/components/input-file/translations/hu.js +0 -1
  29. package/components/input-file/translations/id.js +0 -1
  30. package/components/input-file/translations/it.js +0 -1
  31. package/components/input-file/translations/nl.js +0 -1
  32. package/components/input-file/translations/pl.js +0 -1
  33. package/components/input-file/translations/ro.js +0 -1
  34. package/components/input-file/translations/ru.js +0 -1
  35. package/components/input-file/translations/sk.js +0 -1
  36. package/components/input-file/translations/uk.js +0 -1
  37. package/components/input-file/translations/zh.js +0 -1
  38. package/components/input-tel/src/LionInputTel.js +1 -1
  39. package/components/input-tel/test-suites/LionInputTel.suite.js +0 -7
  40. package/components/localize/test/date/formatDate.test.js +1 -0
  41. package/components/menu/CHANGELOG.md +37 -0
  42. package/components/menu/README.md +335 -0
  43. package/components/menu/index.js +2 -0
  44. package/components/menu/lion-menu-overlay.js +3 -0
  45. package/components/menu/lion-menu.js +3 -0
  46. package/components/menu/lion-spinbutton.js +3 -0
  47. package/components/menu/lion-toolbar.js +3 -0
  48. package/components/menu/lion-tree.js +3 -0
  49. package/components/menu/package.json +46 -0
  50. package/components/menu/requirements.temp.md +12 -0
  51. package/components/menu/src/InteractiveListMixin.js +840 -0
  52. package/components/menu/src/LionMenu.js +250 -0
  53. package/components/menu/src/LionMenuHybrid.js +46 -0
  54. package/components/menu/src/LionMenuOverlay.js +155 -0
  55. package/components/menu/src/LionSpinbutton.js +213 -0
  56. package/components/menu/src/LionToolbar.js +94 -0
  57. package/components/menu/src/LionTree.js +52 -0
  58. package/components/menu/src/MoreButtonMenuMixin.js +278 -0
  59. package/components/menu/src/MultiLevelListMixin.js +311 -0
  60. package/components/menu/src/utils/isInView.js +26 -0
  61. package/components/menu/src/utils/listItemInteractions.js +124 -0
  62. package/components/menu/test/InteractiveListMixin.test.js +3 -0
  63. package/components/menu/test/MoreButtonMenuMixin.test.js +4 -0
  64. package/components/menu/test/MultiLevelListMixin.test.js +3 -0
  65. package/components/menu/test/lion-menu-hybrid.test.js +3 -0
  66. package/components/menu/test/lion-menu.test.js +11 -0
  67. package/components/menu/test/lion-toolbar.test.js +8 -0
  68. package/components/menu/test/lion-tree.test.js +7 -0
  69. package/components/menu/test-helpers/mimicKeyPress.js +9 -0
  70. package/components/menu/test-suites/InteractiveListMixin.suite.js +454 -0
  71. package/components/menu/test-suites/LionMenu.suite.js +113 -0
  72. package/components/menu/test-suites/LionMenuHybrid.suite.js +583 -0
  73. package/components/menu/test-suites/MoreButtonMenuMixin.suite.js +372 -0
  74. package/components/menu/test-suites/MultiLevelListMixin.suite.js +303 -0
  75. package/components/menu/types/InteractiveListMixinTypes.d.ts +84 -0
  76. package/components/navigation-bar/README.md +1 -0
  77. package/components/navigation-bar/src/LionNavigationBar.js +439 -0
  78. package/components/navigation-bar/src/types.js +41 -0
  79. package/components/overlays/NEXT.md +49 -0
  80. package/components/overlays/src/OverlayController.js +278 -110
  81. package/components/overlays/src/OverlayMixin.js +58 -11
  82. package/components/overlays/src/OverlaysManager.js +2 -2
  83. package/components/overlays/src/configurations/visibility-trigger-partials/withHoverInteraction.js +9 -41
  84. package/components/overlays/src/utils/adopt-styles.js +3 -2
  85. package/components/overlays/src/utils/get-focusable-elements.js +4 -0
  86. package/components/overlays/src/utils/is-equal-config.js +10 -6
  87. package/components/overlays/test/OverlayController.test.js +127 -14
  88. package/components/overlays/test/utils-tests/is-equal-config.test.js +1 -1
  89. package/components/overlays/test/withHoverInteraction.test.js +0 -28
  90. package/components/overlays/test-suites/OverlayMixin.suite.js +8 -8
  91. package/components/overlays/types/ArrowMixinTypes.ts +3 -1
  92. package/components/overlays/types/OverlayConfig.ts +20 -5
  93. package/components/overlays/types/OverlayMixinTypes.ts +2 -0
  94. package/components/select-rich/test/lion-select-rich.test.js +3 -0
  95. package/custom-elements.json +30458 -17734
  96. package/dist-types/components/button/src/LionButton.d.ts +1 -0
  97. package/dist-types/components/button/src/LionButton.d.ts.map +1 -1
  98. package/dist-types/components/button/test-suites/LionButton.suite.d.ts.map +1 -1
  99. package/dist-types/components/calendar/src/LionCalendar.d.ts.map +1 -1
  100. package/dist-types/components/calendar/test/lion-calendar.test.d.ts.map +1 -1
  101. package/dist-types/components/collapsible/src/DisclosureMixin.d.ts +3 -0
  102. package/dist-types/components/collapsible/src/DisclosureMixin.d.ts.map +1 -0
  103. package/dist-types/components/collapsible/test-suites/DisclosureMixin.suite.d.ts +2 -0
  104. package/dist-types/components/collapsible/test-suites/DisclosureMixin.suite.d.ts.map +1 -0
  105. package/dist-types/components/collapsible/types/DisclosureMixinTypes.d.ts +24 -0
  106. package/dist-types/components/collapsible/types/DisclosureMixinTypes.d.ts.map +1 -0
  107. package/dist-types/components/combobox/src/LionCombobox.d.ts +1 -1
  108. package/dist-types/components/dialog/src/LionDialog.d.ts +6 -2
  109. package/dist-types/components/dialog/src/LionDialog.d.ts.map +1 -1
  110. package/dist-types/components/form-core/src/form-group/FormGroupMixin.d.ts.map +1 -1
  111. package/dist-types/components/form-core/src/registration/FormRegistrarMixin.d.ts.map +1 -1
  112. package/dist-types/components/form-core/test-suites/ValidateMixin.suite.d.ts.map +1 -1
  113. package/dist-types/components/form-core/test-suites/ValidateMixinFeedbackPart.suite.d.ts.map +1 -1
  114. package/dist-types/components/input-datepicker/src/LionInputDatepicker.d.ts +1 -1
  115. package/dist-types/components/input-datepicker/src/localizeNamespaceLoader.d.ts.map +1 -1
  116. package/dist-types/components/input-datepicker/test/lion-input-datepicker.test.d.ts.map +1 -1
  117. package/dist-types/components/input-email/src/LionInputEmail.d.ts.map +1 -1
  118. package/dist-types/components/input-file/src/validators.d.ts +0 -11
  119. package/dist-types/components/input-file/src/validators.d.ts.map +1 -1
  120. package/dist-types/components/input-file/translations/bg-BG.d.ts +0 -1
  121. package/dist-types/components/input-file/translations/bg.d.ts +0 -1
  122. package/dist-types/components/input-file/translations/cs-CZ.d.ts +0 -1
  123. package/dist-types/components/input-file/translations/cs.d.ts +0 -1
  124. package/dist-types/components/input-file/translations/de-DE.d.ts +0 -1
  125. package/dist-types/components/input-file/translations/de.d.ts +0 -1
  126. package/dist-types/components/input-file/translations/en-AU.d.ts +0 -1
  127. package/dist-types/components/input-file/translations/en-GB.d.ts +0 -1
  128. package/dist-types/components/input-file/translations/en-PH.d.ts +0 -1
  129. package/dist-types/components/input-file/translations/en-US.d.ts +0 -1
  130. package/dist-types/components/input-file/translations/en.d.ts +0 -1
  131. package/dist-types/components/input-file/translations/es-ES.d.ts +0 -1
  132. package/dist-types/components/input-file/translations/es.d.ts +0 -1
  133. package/dist-types/components/input-file/translations/fr-BE.d.ts +0 -1
  134. package/dist-types/components/input-file/translations/fr-FR.d.ts +0 -1
  135. package/dist-types/components/input-file/translations/fr.d.ts +0 -1
  136. package/dist-types/components/input-file/translations/hu-HU.d.ts +0 -1
  137. package/dist-types/components/input-file/translations/hu.d.ts +0 -1
  138. package/dist-types/components/input-file/translations/id-ID.d.ts +0 -1
  139. package/dist-types/components/input-file/translations/id.d.ts +0 -1
  140. package/dist-types/components/input-file/translations/it-IT.d.ts +0 -1
  141. package/dist-types/components/input-file/translations/it.d.ts +0 -1
  142. package/dist-types/components/input-file/translations/nl-BE.d.ts +0 -1
  143. package/dist-types/components/input-file/translations/nl-NL.d.ts +0 -1
  144. package/dist-types/components/input-file/translations/nl.d.ts +0 -1
  145. package/dist-types/components/input-file/translations/pl-PL.d.ts +0 -1
  146. package/dist-types/components/input-file/translations/pl.d.ts +0 -1
  147. package/dist-types/components/input-file/translations/ro-RO.d.ts +0 -1
  148. package/dist-types/components/input-file/translations/ro.d.ts +0 -1
  149. package/dist-types/components/input-file/translations/ru-RU.d.ts +0 -1
  150. package/dist-types/components/input-file/translations/ru.d.ts +0 -1
  151. package/dist-types/components/input-file/translations/sk-SK.d.ts +0 -1
  152. package/dist-types/components/input-file/translations/sk.d.ts +0 -1
  153. package/dist-types/components/input-file/translations/uk-UA.d.ts +0 -1
  154. package/dist-types/components/input-file/translations/uk.d.ts +0 -1
  155. package/dist-types/components/input-file/translations/zh-CN.d.ts +0 -1
  156. package/dist-types/components/input-file/translations/zh.d.ts +0 -1
  157. package/dist-types/components/input-tel/src/LionInputTel.d.ts.map +1 -1
  158. package/dist-types/components/input-tel/test-suites/LionInputTel.suite.d.ts.map +1 -1
  159. package/dist-types/components/menu/index.d.ts +3 -0
  160. package/dist-types/components/menu/index.d.ts.map +1 -0
  161. package/dist-types/components/menu/lion-menu-overlay.d.ts +2 -0
  162. package/dist-types/components/menu/lion-menu-overlay.d.ts.map +1 -0
  163. package/dist-types/components/menu/lion-menu.d.ts +2 -0
  164. package/dist-types/components/menu/lion-menu.d.ts.map +1 -0
  165. package/dist-types/components/menu/lion-spinbutton.d.ts +2 -0
  166. package/dist-types/components/menu/lion-spinbutton.d.ts.map +1 -0
  167. package/dist-types/components/menu/lion-toolbar.d.ts +2 -0
  168. package/dist-types/components/menu/lion-toolbar.d.ts.map +1 -0
  169. package/dist-types/components/menu/lion-tree.d.ts +2 -0
  170. package/dist-types/components/menu/lion-tree.d.ts.map +1 -0
  171. package/dist-types/components/menu/src/InteractiveListMixin.d.ts +617 -0
  172. package/dist-types/components/menu/src/InteractiveListMixin.d.ts.map +1 -0
  173. package/dist-types/components/menu/src/LionMenu.d.ts +635 -0
  174. package/dist-types/components/menu/src/LionMenu.d.ts.map +1 -0
  175. package/dist-types/components/menu/src/LionMenuHybrid.d.ts +19 -0
  176. package/dist-types/components/menu/src/LionMenuHybrid.d.ts.map +1 -0
  177. package/dist-types/components/menu/src/LionMenuOverlay.d.ts +1015 -0
  178. package/dist-types/components/menu/src/LionMenuOverlay.d.ts.map +1 -0
  179. package/dist-types/components/menu/src/LionSpinbutton.d.ts +58 -0
  180. package/dist-types/components/menu/src/LionSpinbutton.d.ts.map +1 -0
  181. package/dist-types/components/menu/src/LionToolbar.d.ts +8 -0
  182. package/dist-types/components/menu/src/LionToolbar.d.ts.map +1 -0
  183. package/dist-types/components/menu/src/LionTree.d.ts +447 -0
  184. package/dist-types/components/menu/src/LionTree.d.ts.map +1 -0
  185. package/dist-types/components/menu/src/MoreButtonMenuMixin.d.ts +39 -0
  186. package/dist-types/components/menu/src/MoreButtonMenuMixin.d.ts.map +1 -0
  187. package/dist-types/components/menu/src/MultiLevelListMixin.d.ts +503 -0
  188. package/dist-types/components/menu/src/MultiLevelListMixin.d.ts.map +1 -0
  189. package/dist-types/components/menu/src/utils/isInView.d.ts +9 -0
  190. package/dist-types/components/menu/src/utils/isInView.d.ts.map +1 -0
  191. package/dist-types/components/menu/src/utils/listItemInteractions.d.ts +48 -0
  192. package/dist-types/components/menu/src/utils/listItemInteractions.d.ts.map +1 -0
  193. package/dist-types/components/menu/test/InteractiveListMixin.test.d.ts +2 -0
  194. package/dist-types/components/menu/test/InteractiveListMixin.test.d.ts.map +1 -0
  195. package/dist-types/components/menu/test/MoreButtonMenuMixin.test.d.ts +2 -0
  196. package/dist-types/components/menu/test/MoreButtonMenuMixin.test.d.ts.map +1 -0
  197. package/dist-types/components/menu/test/MultiLevelListMixin.test.d.ts +2 -0
  198. package/dist-types/components/menu/test/MultiLevelListMixin.test.d.ts.map +1 -0
  199. package/dist-types/components/menu/test/lion-menu-hybrid.test.d.ts +2 -0
  200. package/dist-types/components/menu/test/lion-menu-hybrid.test.d.ts.map +1 -0
  201. package/dist-types/components/menu/test/lion-menu.test.d.ts +2 -0
  202. package/dist-types/components/menu/test/lion-menu.test.d.ts.map +1 -0
  203. package/dist-types/components/menu/test/lion-toolbar.test.d.ts +2 -0
  204. package/dist-types/components/menu/test/lion-toolbar.test.d.ts.map +1 -0
  205. package/dist-types/components/menu/test/lion-tree.test.d.ts +2 -0
  206. package/dist-types/components/menu/test/lion-tree.test.d.ts.map +1 -0
  207. package/dist-types/components/menu/test-helpers/mimicKeyPress.d.ts +7 -0
  208. package/dist-types/components/menu/test-helpers/mimicKeyPress.d.ts.map +1 -0
  209. package/dist-types/components/menu/test-suites/InteractiveListMixin.suite.d.ts +14 -0
  210. package/dist-types/components/menu/test-suites/InteractiveListMixin.suite.d.ts.map +1 -0
  211. package/dist-types/components/menu/test-suites/LionMenu.suite.d.ts +9 -0
  212. package/dist-types/components/menu/test-suites/LionMenu.suite.d.ts.map +1 -0
  213. package/dist-types/components/menu/test-suites/LionMenuHybrid.suite.d.ts +5 -0
  214. package/dist-types/components/menu/test-suites/LionMenuHybrid.suite.d.ts.map +1 -0
  215. package/dist-types/components/menu/test-suites/MoreButtonMenuMixin.suite.d.ts +14 -0
  216. package/dist-types/components/menu/test-suites/MoreButtonMenuMixin.suite.d.ts.map +1 -0
  217. package/dist-types/components/menu/test-suites/MultiLevelListMixin.suite.d.ts +11 -0
  218. package/dist-types/components/menu/test-suites/MultiLevelListMixin.suite.d.ts.map +1 -0
  219. package/dist-types/components/navigation-bar/src/LionNavigationBar.d.ts +238 -0
  220. package/dist-types/components/navigation-bar/src/LionNavigationBar.d.ts.map +1 -0
  221. package/dist-types/components/navigation-bar/src/types.d.ts +85 -0
  222. package/dist-types/components/navigation-bar/src/types.d.ts.map +1 -0
  223. package/dist-types/components/overlays/src/OverlayController.d.ts +24 -12
  224. package/dist-types/components/overlays/src/OverlayController.d.ts.map +1 -1
  225. package/dist-types/components/overlays/src/OverlayMixin.d.ts.map +1 -1
  226. package/dist-types/components/overlays/src/configurations/visibility-trigger-partials/withHoverInteraction.d.ts.map +1 -1
  227. package/dist-types/components/overlays/src/utils/get-focusable-elements.d.ts.map +1 -1
  228. package/dist-types/components/overlays/src/utils/is-equal-config.d.ts.map +1 -1
  229. package/dist-types/components/overlays/types/ArrowMixinTypes.d.ts.map +1 -1
  230. package/dist-types/components/overlays/types/OverlayConfig.d.ts +12 -2
  231. package/dist-types/components/overlays/types/OverlayConfig.d.ts.map +1 -1
  232. package/dist-types/components/overlays/types/OverlayMixinTypes.d.ts +1 -0
  233. package/dist-types/components/overlays/types/OverlayMixinTypes.d.ts.map +1 -1
  234. package/dist-types/components/select-rich/src/LionSelectRich.d.ts +11 -3
  235. package/dist-types/components/select-rich/src/LionSelectRich.d.ts.map +1 -1
  236. package/dist-types/components/tooltip/src/LionTooltip.d.ts +1 -1
  237. package/dist-types/exports/define/lion-item.d.ts +2 -0
  238. package/dist-types/exports/define/lion-item.d.ts.map +1 -0
  239. package/dist-types/exports/define/lion-menu-overlay.d.ts +2 -0
  240. package/dist-types/exports/define/lion-menu-overlay.d.ts.map +1 -0
  241. package/dist-types/exports/define/lion-menu.d.ts +2 -0
  242. package/dist-types/exports/define/lion-menu.d.ts.map +1 -0
  243. package/dist-types/exports/define/lion-navigation-bar.d.ts +2 -0
  244. package/dist-types/exports/define/lion-navigation-bar.d.ts.map +1 -0
  245. package/dist-types/exports/define/lion-toolbar.d.ts +2 -0
  246. package/dist-types/exports/define/lion-toolbar.d.ts.map +1 -0
  247. package/dist-types/exports/define/lion-tree.d.ts +2 -0
  248. package/dist-types/exports/define/lion-tree.d.ts.map +1 -0
  249. package/dist-types/exports/input-file.d.ts +1 -1
  250. package/dist-types/exports/menu-test-suites.d.ts +4 -0
  251. package/dist-types/exports/menu-test-suites.d.ts.map +1 -0
  252. package/dist-types/exports/menu.d.ts +7 -0
  253. package/dist-types/exports/menu.d.ts.map +1 -0
  254. package/dist-types/exports/navigation-bar.d.ts +2 -0
  255. package/dist-types/exports/navigation-bar.d.ts.map +1 -0
  256. package/dist-types/exports/overlays.d.ts +3 -0
  257. package/dist-types/exports/overlays.d.ts.map +1 -1
  258. package/dist-types/tsconfig.tsbuildinfo +1 -1
  259. package/docs/components/checkbox-group/overview.md +2 -2
  260. package/docs/components/collapsible/overview.md +1 -1
  261. package/docs/components/combobox/api-table.md +21 -8
  262. package/docs/components/combobox/overview.md +1 -1
  263. package/docs/components/combobox/use-cases.md +1 -1
  264. package/docs/components/dialog/api-table.md +31 -6
  265. package/docs/components/dialog/overview.md +1 -1
  266. package/docs/components/fieldset/overview.md +5 -5
  267. package/docs/components/form/overview.md +3 -3
  268. package/docs/components/form/use-cases.md +2 -2
  269. package/docs/components/icon/use-cases.md +1 -1
  270. package/docs/components/input/overview.md +1 -1
  271. package/docs/components/input-amount/overview.md +3 -3
  272. package/docs/components/input-date/overview.md +3 -3
  273. package/docs/components/input-datepicker/api-table.md +21 -4
  274. package/docs/components/input-datepicker/overview.md +5 -5
  275. package/docs/components/input-email/api-table.md +1 -1
  276. package/docs/components/input-email/overview.md +2 -2
  277. package/docs/components/input-file/overview.md +1 -1
  278. package/docs/components/input-file/use-cases.md +0 -18
  279. package/docs/components/input-iban/overview.md +2 -2
  280. package/docs/components/input-range/overview.md +2 -2
  281. package/docs/components/input-stepper/overview.md +1 -1
  282. package/docs/components/input-tel/api-table.md +1 -1
  283. package/docs/components/input-tel/overview.md +1 -1
  284. package/docs/components/input-tel/use-cases.md +6 -6
  285. package/docs/components/input-tel-dropdown/api-table.md +1 -1
  286. package/docs/components/input-tel-dropdown/overview.md +1 -1
  287. package/docs/components/listbox/use-cases.md +1 -1
  288. package/docs/components/menu/api-table.md +460 -0
  289. package/docs/components/menu/applyMenuDemoStyles.js +173 -0
  290. package/docs/components/menu/extensions.md +262 -0
  291. package/docs/components/menu/index.md +13 -0
  292. package/docs/components/menu/overview.md +422 -0
  293. package/docs/components/menu/use-cases.md +77 -0
  294. package/docs/components/radio-group/overview.md +3 -3
  295. package/docs/components/select/use-cases.md +1 -1
  296. package/docs/components/select-rich/api-table.md +21 -5
  297. package/docs/components/select-rich/use-cases.md +2 -2
  298. package/docs/components/tabs/examples.md +1 -1
  299. package/docs/components/tooltip/api-table.md +36 -11
  300. package/docs/components/tooltip/use-cases.md +1 -34
  301. package/docs/fundamentals/index.md +4 -4
  302. package/docs/fundamentals/node-tools/publish-docs/overview.md +3 -3
  303. package/docs/fundamentals/node-tools/rocket-preset-extend-lion-docs/overview.md +2 -2
  304. package/docs/fundamentals/rationales/accessibility.md +1 -1
  305. package/docs/fundamentals/systems/core/SlotMixin.md +1 -1
  306. package/docs/fundamentals/systems/core/overview.md +1 -1
  307. package/docs/fundamentals/systems/form/formatting-and-parsing.md +4 -4
  308. package/docs/fundamentals/systems/form/model-value.md +1 -1
  309. package/docs/fundamentals/systems/form/overview.md +28 -28
  310. package/docs/fundamentals/systems/form/validate.md +2 -2
  311. package/docs/fundamentals/systems/localize/overview.md +4 -4
  312. package/docs/fundamentals/systems/overlays/api-table.md +36 -34
  313. package/docs/fundamentals/systems/overlays/configuration.md +2 -2
  314. package/docs/fundamentals/systems/overlays/overview.md +5 -5
  315. package/docs/fundamentals/systems/overlays/use-cases.md +2 -2
  316. package/docs/fundamentals/tools/helpers/overview.md +1 -1
  317. package/docs/fundamentals/tools/singleton-manager/overview.md +4 -4
  318. package/docs/guides/how-to/create-a-custom-field.md +5 -5
  319. package/docs/guides/how-to/create-a-form.md +4 -4
  320. package/docs/guides/how-to/extend-a-native-input.md +2 -2
  321. package/docs/guides/how-to/index.md +1 -1
  322. package/docs/guides/index.md +8 -8
  323. package/docs/guides/principles/index.md +5 -5
  324. package/docs/guides/principles/styling.md +1 -1
  325. package/exports/collapsible.js +1 -0
  326. package/exports/define/lion-item.js +3 -0
  327. package/exports/define/lion-menu-overlay.js +3 -0
  328. package/exports/define/lion-menu.js +3 -0
  329. package/exports/define/lion-navigation-bar.js +3 -0
  330. package/exports/define/lion-toolbar.js +3 -0
  331. package/exports/define/lion-tree.js +3 -0
  332. package/exports/input-file.js +1 -5
  333. package/exports/menu-test-suites.js +4 -0
  334. package/exports/menu.js +7 -0
  335. package/exports/navigation-bar.js +1 -0
  336. package/exports/overlays.js +6 -0
  337. package/input-file.js +1 -5
  338. package/menu-test-suites.js +4 -0
  339. package/menu.js +7 -0
  340. package/navigation-bar.js +1 -0
  341. package/overlays.js +6 -0
  342. package/package.json +2 -2
  343. package/components/calendar/test-suites/LionCalendar.suite.js +0 -79
  344. package/components/input-datepicker/test-suites/LionInputDatepicker.suite.js +0 -35
  345. package/dist-types/components/calendar/test-suites/LionCalendar.suite.d.ts +0 -5
  346. package/dist-types/components/calendar/test-suites/LionCalendar.suite.d.ts.map +0 -1
  347. package/dist-types/components/input-datepicker/test-suites/LionInputDatepicker.suite.d.ts +0 -7
  348. package/dist-types/components/input-datepicker/test-suites/LionInputDatepicker.suite.d.ts.map +0 -1
@@ -0,0 +1,372 @@
1
+ import { LitElement } from 'lit';
2
+ import { expect, html, fixture as _fixture, unsafeStatic, defineCE } from '@open-wc/testing';
3
+ import { sendMouse, resetMouse } from '@web/test-runner-commands';
4
+ import sinon from 'sinon';
5
+ import { getDeepActiveElement } from '@lion/ui/overlays.js';
6
+ import { InteractiveListMixin } from '../src/InteractiveListMixin.js';
7
+
8
+ class InteractiveListClass extends InteractiveListMixin(LitElement) {}
9
+
10
+ /**
11
+ * @typedef {import('../types/InteractiveListMixinTypes.js').InteractiveListItemRole} InteractiveListItemRole
12
+ */
13
+
14
+ /**
15
+ * @typedef {import('../src/LionMenu.js').LionMenu} LionMenu
16
+ * @typedef {import('lit').TemplateResult} TemplateResult
17
+ *
18
+ * * @typedef {Object} TestConfig
19
+ * @property {string} tagString
20
+ */
21
+
22
+ const fixture = /** @type {(arg: TemplateResult) => Promise<LionMenu>} */ (_fixture);
23
+
24
+ const l1Config = {
25
+ isBar: true,
26
+ hasFullWidthFlyout: true,
27
+ openableConfig: {
28
+ // We want disclosure behavior
29
+ placementMode: 'custom',
30
+ // N.B. we don't have an invoker...
31
+ isActivated: false,
32
+ inheritsReferenceWidth: 'none',
33
+ focusContentOnOpen: true,
34
+ },
35
+ };
36
+
37
+ /**
38
+ * @param {TestConfig} [customConfig]
39
+ */
40
+ export function runMoreButtonMenuMixinSuite(customConfig) {
41
+ const cfg = {
42
+ tagString: customConfig?.tagString || defineCE(InteractiveListClass),
43
+ };
44
+
45
+ const { tagString } = cfg;
46
+ const tag = unsafeStatic(tagString);
47
+
48
+ describe('MoreButtonMenuMixin', () => {
49
+ describe('Overflow handling', () => {
50
+ /** @type {import('sinon').SinonFakeTimers | null} */
51
+ let clock = null;
52
+
53
+ /** @param {HTMLElement} el */
54
+ const isMoreButtonShown = el => {
55
+ const wrapper = /** @type {HTMLElement | null} */ (
56
+ el.querySelector('[data-more-button-wrapper]')
57
+ );
58
+ return wrapper?.style.display !== 'none';
59
+ };
60
+
61
+ /** @param {HTMLElement} el */
62
+ const isMoreButtonMenuShown = el => {
63
+ const menu = el.querySelector('[data-more-button-menu]');
64
+ return menu ? getComputedStyle(menu).width !== '0px' : false;
65
+ };
66
+
67
+ /** @param {HTMLElement} el */
68
+ const getMoreButton = el =>
69
+ /** @type {HTMLElement | null} */ (el.querySelector('[data-more-button]'));
70
+ /** @param {HTMLElement} el */
71
+ const getMoreButtonMenu = el => el.querySelector('[data-more-button-menu]');
72
+
73
+ /**
74
+ * @param {HTMLElement} element
75
+ */
76
+ function getCoordinates(element) {
77
+ const { x, y, height } = element.getBoundingClientRect();
78
+
79
+ return {
80
+ x: Math.floor(x + window.pageXOffset),
81
+ y: Math.floor(y + window.pageYOffset + height / 2),
82
+ };
83
+ }
84
+ /** @param {HTMLElement} el */
85
+ const clickOnMoreButton = async el => {
86
+ const moreButton = getMoreButton(el);
87
+ if (!moreButton) {
88
+ return;
89
+ }
90
+ const { x, y } = getCoordinates(moreButton);
91
+ await sendMouse({ type: 'click', position: [x, y] });
92
+ clock?.tick(100);
93
+ };
94
+
95
+ /** @param {HTMLElement} el */
96
+ const getDirectListItemsUnderMoreButtonMenu = el => [
97
+ ...Array.from(
98
+ el.querySelectorAll('[data-more-button-menu] > [role="listitem"]'),
99
+ item => /** @type {HTMLElement} */ (item),
100
+ ),
101
+ ];
102
+
103
+ /** @param {HTMLElement} el */
104
+ const getDirectListItemsUnderMainMenu = el => [
105
+ ...Array.from(
106
+ el.querySelectorAll('[slot="list"] > [role="listitem"]'),
107
+ item => /** @type {HTMLElement} */ (item),
108
+ ),
109
+ ];
110
+
111
+ /** @param {HTMLElement & { updateComplete: Promise<unknown> }} el */
112
+ const waitResizeEventDebounce = async el => {
113
+ await el.updateComplete;
114
+ // wait for resize event debouncer
115
+ clock?.tick(55);
116
+ };
117
+
118
+ beforeEach(() => {
119
+ clock = sinon.useFakeTimers({
120
+ shouldAdvanceTime: true,
121
+ });
122
+ });
123
+ afterEach(async () => {
124
+ clock?.restore();
125
+ await resetMouse();
126
+ });
127
+
128
+ it('should show no More button when all items fit', async () => {
129
+ const el = await fixture(html`
130
+ <${tag} name="foo" ._activeMode="${'tabbable-disclosure'}" .itemWrap="${true}"
131
+ data-has-full-width-flyout orientation="horizontal" style="min-width: 170px; max-width: 170px;">
132
+ <div role="listitem" id="item1" style="min-width: 50px; max-width: 50px;">
133
+ <a href="#">Item 1</a>
134
+ </div>
135
+ <div role="listitem" id="item2" style="min-width: 50px; max-width: 50px;">
136
+ <a href="#">Item 2</a>
137
+ </div>
138
+ <div role="listitem" id="item3" style="min-width: 50px; max-width: 50px;">
139
+ <a href="#">Item 3</a>
140
+ </div>
141
+ <div slot="more-button" style="min-width: 50px; max-width: 50px;">
142
+ <button>More</button>
143
+ </div>
144
+ </${tag}>
145
+ `);
146
+ await waitResizeEventDebounce(el);
147
+ // 3 items is 150px. They fit into 170px parent
148
+ expect(isMoreButtonShown(el)).to.equal(false);
149
+ });
150
+
151
+ it('should show More button when not all items fit', async () => {
152
+ const el = await fixture(html`
153
+ <${tag}
154
+ .itemWrap="${true}"
155
+ ?data-has-full-width-flyout="${l1Config.hasFullWidthFlyout}"
156
+ .config="${l1Config.openableConfig}"
157
+ .bar="${l1Config.isBar}"
158
+ ._activeMode="${'tabbable-disclosure'}"
159
+ style="min-width: 170px; max-width: 170px;"
160
+ >
161
+ <div role="listitem" id="item1" style="min-width: 50px; max-width: 50px;">
162
+ <a href="#">Item 1</a>
163
+ </div>
164
+ <div role="listitem" id="item2" style="min-width: 50px; max-width: 50px;">
165
+ <a href="#">Item 2</a>
166
+ </div>
167
+ <div role="listitem" id="item3" style="min-width: 50px; max-width: 50px;">
168
+ <a href="#">Item 3</a>
169
+ </div>
170
+ <div role="listitem" id="item4" style="min-width: 50px; max-width: 50px;">
171
+ <a href="#">Item 4</a>
172
+ </div>
173
+ <div slot="more-button" style="min-width: 50px; max-width: 50px;">
174
+ <button>More</button>
175
+ </div>
176
+ </${tag}>
177
+ <style>
178
+ [orientation='horizontal'] ::slotted([slot='list']) {
179
+ display: flex;
180
+ }
181
+ </style>
182
+ `);
183
+
184
+ await waitResizeEventDebounce(el);
185
+ // 4 items is 200px. They don't fit into 170px parent. So More button should be shown
186
+ expect(isMoreButtonShown(el)).to.equal(true);
187
+ });
188
+
189
+ it('should show 2 items when clicking on `More` button', async () => {
190
+ const el = await fixture(html`
191
+ <${tag}
192
+ .itemWrap="${true}"
193
+ ?data-has-full-width-flyout="${l1Config.hasFullWidthFlyout}"
194
+ .config="${l1Config.openableConfig}"
195
+ .bar="${l1Config.isBar}"
196
+ ._activeMode="${'tabbable-disclosure'}"
197
+ style="min-width: 170px; max-width: 170px;"
198
+ >
199
+ <div role="listitem" id="item1" style="min-width: 50px; max-width: 50px;">
200
+ <a href="#">Item 1</a>
201
+ </div>
202
+ <div role="listitem" id="item2" style="min-width: 50px; max-width: 50px;">
203
+ <a href="#">Item 2</a>
204
+ </div>
205
+ <div role="listitem" id="item3" style="min-width: 50px; max-width: 50px;">
206
+ <a href="#">Item 3</a>
207
+ </div>
208
+ <div role="listitem" id="item4" style="min-width: 50px; max-width: 50px;">
209
+ <a href="#">Item 4</a>
210
+ </div>
211
+ <div slot="more-button" style="min-width: 50px; max-width: 50px;">
212
+ <button>More</button>
213
+ </div>
214
+ </${tag}>
215
+ `);
216
+
217
+ await waitResizeEventDebounce(el);
218
+ await clickOnMoreButton(el);
219
+
220
+ expect(isMoreButtonMenuShown(el)).to.equal(true);
221
+ const labels = getDirectListItemsUnderMoreButtonMenu(el).map(
222
+ item => item.textContent?.trim() ?? '',
223
+ );
224
+ expect(labels).to.deep.equal(['Item 3', 'Item 4']);
225
+ });
226
+
227
+ it('should focus more button menu container when clicking on `More` button', async () => {
228
+ const el = await fixture(html`
229
+ <${tag}
230
+ .itemWrap="${true}"
231
+ ?data-has-full-width-flyout="${l1Config.hasFullWidthFlyout}"
232
+ .config="${l1Config.openableConfig}"
233
+ .bar="${l1Config.isBar}"
234
+ ._activeMode="${'tabbable-disclosure'}"
235
+ style="min-width: 170px; max-width: 170px;"
236
+ >
237
+ <div role="listitem" id="item1" style="min-width: 50px; max-width: 50px;">
238
+ <a href="#">Item 1</a>
239
+ </div>
240
+ <div role="listitem" id="item2" style="min-width: 50px; max-width: 50px;">
241
+ <a href="#">Item 2</a>
242
+ </div>
243
+ <div role="listitem" id="item3" style="min-width: 50px; max-width: 50px;">
244
+ <a href="#">Item 3</a>
245
+ </div>
246
+ <div role="listitem" id="item4" style="min-width: 50px; max-width: 50px;">
247
+ <a href="#">Item 4</a>
248
+ </div>
249
+ <div slot="more-button" style="min-width: 50px; max-width: 50px;">
250
+ <button>More</button>
251
+ </div>
252
+ </${tag}>
253
+ `);
254
+
255
+ await waitResizeEventDebounce(el);
256
+ await clickOnMoreButton(el);
257
+
258
+ expect(isMoreButtonMenuShown(el)).to.equal(true);
259
+ expect(getDeepActiveElement() === getMoreButtonMenu(el)).to.equal(true);
260
+ });
261
+
262
+ it('should open and then close More button menu when clicking 2 times on the More button', async () => {
263
+ const el = await fixture(html`
264
+ <${tag}
265
+ .itemWrap="${true}"
266
+ ?data-has-full-width-flyout="${l1Config.hasFullWidthFlyout}"
267
+ .config="${l1Config.openableConfig}"
268
+ .bar="${l1Config.isBar}"
269
+ ._activeMode="${'tabbable-disclosure'}"
270
+ style="min-width: 170px; max-width: 170px;"
271
+ >
272
+ <div role="listitem" id="item1" style="min-width: 50px; max-width: 50px;">
273
+ <a href="#">Item 1</a>
274
+ </div>
275
+ <div role="listitem" id="item2" style="min-width: 50px; max-width: 50px;">
276
+ <a href="#">Item 2</a>
277
+ </div>
278
+ <div role="listitem" id="item3" style="min-width: 50px; max-width: 50px;">
279
+ <a href="#">Item 3</a>
280
+ </div>
281
+ <div role="listitem" id="item4" style="min-width: 50px; max-width: 50px;">
282
+ <a href="#">Item 4</a>
283
+ </div>
284
+ <div slot="more-button" style="min-width: 50px; max-width: 50px;">
285
+ <button>More</button>
286
+ </div>
287
+ </${tag}>
288
+ `);
289
+
290
+ await waitResizeEventDebounce(el);
291
+ expect(isMoreButtonMenuShown(el)).to.equal(false);
292
+ await clickOnMoreButton(el);
293
+ expect(isMoreButtonMenuShown(el)).to.equal(true);
294
+ await clickOnMoreButton(el);
295
+ expect(isMoreButtonMenuShown(el)).to.equal(false);
296
+ });
297
+
298
+ it('should remove `More` button when making font smaller', async () => {
299
+ const el = await fixture(html`
300
+ <${tag} name="foo" ._activeMode="${'tabbable-disclosure'}" .itemWrap="${true}"
301
+ data-has-full-width-flyout orientation="horizontal" style="min-width: 170px; max-width: 170px;">
302
+ <div role="listitem" id="item1" style="min-width: 50px; max-width: 50px;">
303
+ <a href="#">Item 1</a>
304
+ </div>
305
+ <div role="listitem" id="item2" style="min-width: 50px; max-width: 50px;">
306
+ <a href="#">Item 2</a>
307
+ </div>
308
+ <div role="listitem" id="item3" style="min-width: 50px; max-width: 50px;">
309
+ <a href="#">Item 3</a>
310
+ </div>
311
+ <div slot="more-button" style="min-width: 50px; max-width: 50px;">
312
+ <button>More</button>
313
+ </div>
314
+ </${tag}>
315
+ `);
316
+ await waitResizeEventDebounce(el);
317
+
318
+ /**
319
+ * Make font smaller for first level items to force
320
+ * the menu render all 4 items and no `More` button
321
+ */
322
+ getDirectListItemsUnderMainMenu(el).forEach(item => {
323
+ // eslint-disable-next-line no-param-reassign
324
+ item.style.fontSize = '12px';
325
+ });
326
+ el?.dispatchEvent(new CustomEvent('resize', { composed: true, bubbles: true }));
327
+ await waitResizeEventDebounce(el);
328
+ expect(isMoreButtonShown(el)).to.equal(false);
329
+ });
330
+
331
+ it('should add `More` button when making font larger', async () => {
332
+ const el = await fixture(html`
333
+ <${tag}
334
+ .itemWrap="${true}"
335
+ ?data-has-full-width-flyout="${l1Config.hasFullWidthFlyout}"
336
+ .config="${l1Config.openableConfig}"
337
+ .bar="${l1Config.isBar}"
338
+ ._activeMode="${'tabbable-disclosure'}"
339
+ style="min-width: 170px; max-width: 170px;"
340
+ >
341
+ <div role="listitem" id="item1" style="min-width: 50px; max-width: 50px;">
342
+ <a href="#">Item 1</a>
343
+ </div>
344
+ <div role="listitem" id="item2" style="min-width: 50px; max-width: 50px;">
345
+ <a href="#">Item 2</a>
346
+ </div>
347
+ <div role="listitem" id="item3" style="min-width: 50px; max-width: 50px;">
348
+ <a href="#">Item 3</a>
349
+ </div>
350
+ <div slot="more-button" style="min-width: 50px; max-width: 50px;">
351
+ <button>More</button>
352
+ </div>
353
+ </${tag}>
354
+ `);
355
+ await waitResizeEventDebounce(el);
356
+
357
+ expect(getDirectListItemsUnderMainMenu(el).length).to.equal(3);
358
+ /**
359
+ * Make font larger for first level items to force
360
+ * the More button to appear
361
+ */
362
+ getDirectListItemsUnderMainMenu(el).forEach(item => {
363
+ // eslint-disable-next-line no-param-reassign
364
+ item.style.fontSize = '40px';
365
+ });
366
+ el?.dispatchEvent(new CustomEvent('resize', { composed: true, bubbles: true }));
367
+ await waitResizeEventDebounce(el);
368
+ expect(isMoreButtonShown(el)).to.equal(true);
369
+ });
370
+ });
371
+ });
372
+ }
@@ -0,0 +1,303 @@
1
+ import { LitElement } from 'lit';
2
+ import { expect, html, fixture as _fixture, unsafeStatic, defineCE } from '@open-wc/testing';
3
+ import sinon from 'sinon';
4
+ import { MultiLevelListMixin } from '../src/MultiLevelListMixin.js';
5
+ import { InteractiveListMixin } from '../src/InteractiveListMixin.js';
6
+ import { mimicKeyPress } from '../test-helpers/mimicKeyPress.js';
7
+
8
+ class MultiLevelListClass extends MultiLevelListMixin(LitElement) {}
9
+ class InteractiveListClass extends InteractiveListMixin(LitElement) {}
10
+
11
+ /**
12
+ * @typedef {import('../src/LionMenu.js').LionMenu} LionMenu
13
+ * @typedef {import('lit').TemplateResult} TemplateResult
14
+ *
15
+ * @typedef {Object} TestConfig
16
+ * @property {string} tagString
17
+ * @property {string} tagChildString
18
+ */
19
+
20
+ const fixture = /** @type {(arg: TemplateResult) => Promise<LionMenu>} */ (_fixture);
21
+
22
+ /**
23
+ * @param {TestConfig} [customConfig]
24
+ */
25
+ export function runMultiLevelListMixinSuite(customConfig) {
26
+ const cfg = {
27
+ tagString: customConfig?.tagString || defineCE(MultiLevelListClass),
28
+ tagChildString: customConfig?.tagChildString || defineCE(InteractiveListClass),
29
+ };
30
+
31
+ const { tagString, tagChildString } = cfg;
32
+ const tag = unsafeStatic(tagString);
33
+ const tagChild = unsafeStatic(tagChildString);
34
+
35
+ describe('MultiLevelListMixin', () => {
36
+ it('has sublists', async () => {
37
+ const el = await fixture(html`
38
+ <${tag}>
39
+ <div role="listitem" id="item-0">
40
+ <button data-invoker>Item 0</button>
41
+ <${tagChild}>
42
+ <div role="listitem" id="item-0-0">
43
+ <a href="#foo">Sub item 0</a>
44
+ </div>
45
+ <div role="listitem" id="item-0-1">
46
+ <a href="#bar">Sub item 1</a>
47
+ </div>
48
+ </${tagChild}>
49
+ </div>
50
+ <div role="listitem" id="item-1">
51
+ <a href="#baz">Item 1</a>
52
+ </div>
53
+ </${tag}>
54
+ `);
55
+ const subList = /** @type {MultiLevelListClass} */ (el.querySelector(tagChildString));
56
+ expect(subList).to.exist;
57
+ expect(subList.level).to.equal(2);
58
+ });
59
+
60
+ it('inherits checked state from children when checked via href match', async () => {
61
+ const el = await fixture(html`
62
+ <${tag}>
63
+ <div role="listitem" id="item-0">
64
+ <button data-invoker>Item 0</button>
65
+ <${tagChild}>
66
+ <div role="listitem" id="item-0-0">
67
+ <a href="${window.location.href}">Sub item 0</a>
68
+ </div>
69
+ <div role="listitem" id="item-0-1">
70
+ <a href="#bar">Sub item 1</a>
71
+ </div>
72
+ </${tagChild}>
73
+ </div>
74
+ <div role="listitem" id="item-1">
75
+ <a href="#baz">Item 1</a>
76
+ </div>
77
+ </${tag}>
78
+ `);
79
+ if (el.role === 'list') {
80
+ const item0 = el.listItems[0];
81
+ expect(item0.getAttribute('aria-current')).to.equal('true');
82
+ }
83
+ });
84
+
85
+ describe('Interactions', () => {
86
+ describe('Keyboard navigation', () => {
87
+ it('navigates between L1 items on [ArrowDown] [ArrowUp] keys', async () => {
88
+ const el = await fixture(html`
89
+ <${tag}>
90
+ <div role="listitem" id="item-0">
91
+ <button data-invoker>Item 0</button>
92
+ <${tagChild}>
93
+ <div role="listitem" id="item-0-0">
94
+ <a href="${window.location.href}">Sub item 0</a>
95
+ </div>
96
+ <div role="listitem" id="item-0-1">
97
+ <a href="#bar">Sub item 1</a>
98
+ </div>
99
+ </${tagChild}>
100
+ </div>
101
+ <div role="listitem" id="item-1">
102
+ <a href="#baz">Item 1</a>
103
+ </div>
104
+ <div role="listitem" id="item-2">
105
+ <a href="#foobar">Item 2</a>
106
+ </div>
107
+ </${tag}>
108
+ `);
109
+
110
+ const { _listNode } = el;
111
+
112
+ // Normalize
113
+ el.activeIndex = 0;
114
+
115
+ mimicKeyPress(_listNode, 'ArrowDown');
116
+ expect(el.activeIndex).to.be.equal(1);
117
+ mimicKeyPress(_listNode, 'ArrowDown');
118
+ expect(el.activeIndex).to.be.equal(2);
119
+ mimicKeyPress(_listNode, 'ArrowUp');
120
+ expect(el.activeIndex).to.be.equal(1);
121
+ });
122
+
123
+ it('stops navigation by default at end of option list', async () => {
124
+ const el = await fixture(html`
125
+ <${tag}>
126
+ <div role="listitem" id="item-0">
127
+ <button data-invoker>Item 0</button>
128
+ <${tagChild}>
129
+ <div role="listitem" id="item-0-0">
130
+ <a href="${window.location.href}">Sub item 0</a>
131
+ </div>
132
+ <div role="listitem" id="item-0-1">
133
+ <a href="#bar">Sub item 1</a>
134
+ </div>
135
+ </${tagChild}>
136
+ </div>
137
+ <div role="listitem" id="item-1">
138
+ <a href="#baz">Item 1</a>
139
+ </div>
140
+ <div role="listitem" id="item-2">
141
+ <a href="#foobar">Item 2</a>
142
+ </div>
143
+ </${tag}>
144
+ `);
145
+
146
+ const { _listNode } = el;
147
+
148
+ // Normalize
149
+ el.activeIndex = 0;
150
+
151
+ mimicKeyPress(_listNode, 'ArrowUp');
152
+ expect(el.activeIndex).to.be.equal(0);
153
+
154
+ el.activeIndex = 2;
155
+ mimicKeyPress(_listNode, 'ArrowDown');
156
+ expect(el.activeIndex).to.be.equal(2);
157
+ });
158
+
159
+ it('opens subList on [Enter] key press', async () => {
160
+ const el = await fixture(html`
161
+ <${tag}>
162
+ <div role="listitem" id="item-0">
163
+ <button data-invoker>Item 0</button>
164
+ <${tagChild}>
165
+ <div role="listitem" id="item-0-0">
166
+ <div>Sub item 0</div>
167
+ </div>
168
+ <div role="listitem" id="item-0-1">
169
+ <div>Sub item 1</div>
170
+ </div>
171
+ </${tagChild}>
172
+ </div>
173
+ <div role="listitem" id="item-1">
174
+ <div>Item 1</div>
175
+ </div>
176
+ </${tag}>
177
+ `);
178
+
179
+ const { _listNode } = el;
180
+
181
+ // Normalize
182
+ el.activeIndex = 0;
183
+ const clickSpy = sinon.spy(el.activeItem, 'click');
184
+
185
+ mimicKeyPress(_listNode, 'Enter');
186
+ expect(clickSpy).to.have.been.calledOnce;
187
+ });
188
+
189
+ it('navigates between L2 items on [ArrowDown] [ArrowUp] keys', async () => {
190
+ const el = await fixture(html`
191
+ <${tag} orientation="horizontal">
192
+ <div role="listitem" id="item-0">
193
+ <button data-invoker>Item 0</button>
194
+ <${tagChild}>
195
+ <div role="listitem" id="item-0-0">
196
+ <a href="#foo">Sub item 0</a>
197
+ </div>
198
+ <div role="listitem" id="item-0-1">
199
+ <a href="#bar">Sub item 1</a>
200
+ </div>
201
+ <div role="listitem" id="item-0-2">
202
+ <a href="#baz">Sub item 2</a>
203
+ </div>
204
+ </${tagChild}>
205
+ </div>
206
+ <div role="listitem" id="item-1">
207
+ <a href="#foobar">Item 1</a>
208
+ </div>
209
+ </${tag}>
210
+ `);
211
+
212
+ const subList = /** @type {MultiLevelListClass} */ (el.querySelector(tagChildString));
213
+ const { _listNode } = subList;
214
+
215
+ // Normalize
216
+ subList.activeIndex = 0;
217
+
218
+ mimicKeyPress(_listNode, 'ArrowDown');
219
+ expect(subList.activeIndex).to.be.equal(1);
220
+ mimicKeyPress(_listNode, 'ArrowDown');
221
+ expect(subList.activeIndex).to.be.equal(2);
222
+ mimicKeyPress(_listNode, 'ArrowUp');
223
+ expect(subList.activeIndex).to.be.equal(1);
224
+ });
225
+
226
+ it('close method gets called on [ArrowUp] key when in L2 and horizontal', async () => {
227
+ const el = await fixture(html`
228
+ <${tag}>
229
+ <div role="listitem" id="item-0">
230
+ <button data-invoker>Item 0</button>
231
+ <${tagChild}>
232
+ <div role="listitem" id="item-0-0">
233
+ <div>Sub item 0</div>
234
+ </div>
235
+ <div role="listitem" id="item-0-1">
236
+ <div>Sub item 1</div>
237
+ </div>
238
+ <div role="listitem" id="item-0-2">
239
+ <div>Sub item 2</div>
240
+ </div>
241
+ </${tagChild}>
242
+ </div>
243
+ <div role="listitem" id="item-1">
244
+ <div>Item 1</div>
245
+ </div>
246
+ </${tag}>
247
+ `);
248
+ const subList = /** @type {MultiLevelListClass} */ (el.querySelector(tagChildString));
249
+ // @ts-ignore
250
+ if (subList?.close) {
251
+ // @ts-ignore
252
+ const closeSpy = sinon.spy(subList, 'close');
253
+ const { _listNode } = subList;
254
+
255
+ // Normalize
256
+ subList.activeIndex = 0;
257
+ subList.orientation = 'horizontal';
258
+
259
+ mimicKeyPress(_listNode, 'ArrowUp');
260
+ expect(closeSpy).to.have.been.calledOnce;
261
+ }
262
+ });
263
+
264
+ it('close method gets called on [ArrowLeft] key when in L2 and vertical', async () => {
265
+ const el = await fixture(html`
266
+ <${tag}>
267
+ <div role="listitem" id="item-0">
268
+ <button data-invoker>Item 0</button>
269
+ <${tagChild} orientation="vertical">
270
+ <div role="listitem" id="item-0-0">
271
+ <a href="#foo">Sub item 0</a>
272
+ </div>
273
+ <div role="listitem" id="item-0-1">
274
+ <a href="#bar">Sub item 1</a>
275
+ </div>
276
+ <div role="listitem" id="item-0-2">
277
+ <a href="#baz">Sub item 2</a>
278
+ </div>
279
+ </${tagChild}>
280
+ </div>
281
+ <div role="listitem" id="item-1">
282
+ <a href="#foobar">Item 1</a>
283
+ </div>
284
+ </${tag}>
285
+ `);
286
+ const subList = /** @type {MultiLevelListClass} */ (el.querySelector(tagChildString));
287
+ // @ts-ignore
288
+ if (subList?.close) {
289
+ // @ts-ignore
290
+ const closeSpy = sinon.spy(subList, 'close');
291
+ const { _listNode } = subList;
292
+
293
+ // Normalize
294
+ subList.activeIndex = 0;
295
+
296
+ mimicKeyPress(_listNode, 'ArrowLeft');
297
+ expect(closeSpy).to.have.been.calledOnce;
298
+ }
299
+ });
300
+ });
301
+ });
302
+ });
303
+ }