@lion/ui 0.18.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 (279) 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 +2 -0
  5. package/components/collapsible/src/DisclosureMixin.js +313 -0
  6. package/components/collapsible/test-suites/DisclosureMixin.suite.js +30 -0
  7. package/components/collapsible/types/DisclosureMixinTypes.ts +48 -0
  8. package/components/combobox/test/lion-combobox.test.js +1 -0
  9. package/components/form-core/src/form-group/FormGroupMixin.js +7 -0
  10. package/components/form-core/src/registration/FormRegistrarMixin.js +11 -0
  11. package/components/form-core/test/FormControlMixin.test.js +1 -0
  12. package/components/form-core/test/validate/Validator.test.js +2 -0
  13. package/components/form-core/test-suites/ValidateMixin.suite.js +2 -0
  14. package/components/form-core/test-suites/ValidateMixinFeedbackPart.suite.js +1 -0
  15. package/components/input-amount-dropdown/src/LionInputAmountDropdown.js +6 -4
  16. package/components/input-amount-dropdown/test/LionInputAmountDropdown.test.js +20 -1
  17. package/components/input-amount-dropdown/test-suites/LionInputAmountDropdown.suite.js +24 -0
  18. package/components/input-datepicker/src/localizeNamespaceLoader.js +1 -0
  19. package/components/input-datepicker/test/lion-input-datepicker.test.js +5 -6
  20. package/components/localize/test/date/formatDate.test.js +1 -0
  21. package/components/menu/CHANGELOG.md +37 -0
  22. package/components/menu/README.md +335 -0
  23. package/components/menu/index.js +2 -0
  24. package/components/menu/lion-menu-overlay.js +3 -0
  25. package/components/menu/lion-menu.js +3 -0
  26. package/components/menu/lion-spinbutton.js +3 -0
  27. package/components/menu/lion-toolbar.js +3 -0
  28. package/components/menu/lion-tree.js +3 -0
  29. package/components/menu/package.json +46 -0
  30. package/components/menu/requirements.temp.md +12 -0
  31. package/components/menu/src/InteractiveListMixin.js +840 -0
  32. package/components/menu/src/LionMenu.js +250 -0
  33. package/components/menu/src/LionMenuHybrid.js +46 -0
  34. package/components/menu/src/LionMenuOverlay.js +155 -0
  35. package/components/menu/src/LionSpinbutton.js +213 -0
  36. package/components/menu/src/LionToolbar.js +94 -0
  37. package/components/menu/src/LionTree.js +52 -0
  38. package/components/menu/src/MoreButtonMenuMixin.js +278 -0
  39. package/components/menu/src/MultiLevelListMixin.js +311 -0
  40. package/components/menu/src/utils/isInView.js +26 -0
  41. package/components/menu/src/utils/listItemInteractions.js +124 -0
  42. package/components/menu/test/InteractiveListMixin.test.js +3 -0
  43. package/components/menu/test/MoreButtonMenuMixin.test.js +4 -0
  44. package/components/menu/test/MultiLevelListMixin.test.js +3 -0
  45. package/components/menu/test/lion-menu-hybrid.test.js +3 -0
  46. package/components/menu/test/lion-menu.test.js +11 -0
  47. package/components/menu/test/lion-toolbar.test.js +8 -0
  48. package/components/menu/test/lion-tree.test.js +7 -0
  49. package/components/menu/test-helpers/mimicKeyPress.js +9 -0
  50. package/components/menu/test-suites/InteractiveListMixin.suite.js +454 -0
  51. package/components/menu/test-suites/LionMenu.suite.js +113 -0
  52. package/components/menu/test-suites/LionMenuHybrid.suite.js +583 -0
  53. package/components/menu/test-suites/MoreButtonMenuMixin.suite.js +372 -0
  54. package/components/menu/test-suites/MultiLevelListMixin.suite.js +303 -0
  55. package/components/menu/types/InteractiveListMixinTypes.d.ts +84 -0
  56. package/components/navigation-bar/README.md +1 -0
  57. package/components/navigation-bar/src/LionNavigationBar.js +439 -0
  58. package/components/navigation-bar/src/types.js +41 -0
  59. package/components/overlays/NEXT.md +49 -0
  60. package/components/overlays/src/OverlayController.js +278 -110
  61. package/components/overlays/src/OverlayMixin.js +58 -11
  62. package/components/overlays/src/OverlaysManager.js +2 -2
  63. package/components/overlays/src/configurations/visibility-trigger-partials/withHoverInteraction.js +100 -26
  64. package/components/overlays/src/utils/adopt-styles.js +3 -2
  65. package/components/overlays/src/utils/get-focusable-elements.js +4 -0
  66. package/components/overlays/src/utils/is-equal-config.js +10 -6
  67. package/components/overlays/test/OverlayController.test.js +127 -14
  68. package/components/overlays/test/utils-tests/is-equal-config.test.js +1 -1
  69. package/components/overlays/test/withHoverInteraction.test.js +90 -0
  70. package/components/overlays/test-suites/OverlayMixin.suite.js +8 -8
  71. package/components/overlays/types/ArrowMixinTypes.ts +3 -1
  72. package/components/overlays/types/OverlayConfig.ts +20 -5
  73. package/components/overlays/types/OverlayMixinTypes.ts +2 -0
  74. package/components/select-rich/test/lion-select-rich.test.js +3 -0
  75. package/custom-elements.json +30446 -17381
  76. package/dist-types/components/button/src/LionButton.d.ts +1 -0
  77. package/dist-types/components/button/src/LionButton.d.ts.map +1 -1
  78. package/dist-types/components/button/test-suites/LionButton.suite.d.ts.map +1 -1
  79. package/dist-types/components/calendar/src/LionCalendar.d.ts.map +1 -1
  80. package/dist-types/components/collapsible/src/DisclosureMixin.d.ts +3 -0
  81. package/dist-types/components/collapsible/src/DisclosureMixin.d.ts.map +1 -0
  82. package/dist-types/components/collapsible/test-suites/DisclosureMixin.suite.d.ts +2 -0
  83. package/dist-types/components/collapsible/test-suites/DisclosureMixin.suite.d.ts.map +1 -0
  84. package/dist-types/components/collapsible/types/DisclosureMixinTypes.d.ts +24 -0
  85. package/dist-types/components/collapsible/types/DisclosureMixinTypes.d.ts.map +1 -0
  86. package/dist-types/components/combobox/src/LionCombobox.d.ts +1 -1
  87. package/dist-types/components/dialog/src/LionDialog.d.ts +6 -2
  88. package/dist-types/components/dialog/src/LionDialog.d.ts.map +1 -1
  89. package/dist-types/components/form-core/src/form-group/FormGroupMixin.d.ts.map +1 -1
  90. package/dist-types/components/form-core/src/registration/FormRegistrarMixin.d.ts.map +1 -1
  91. package/dist-types/components/form-core/test-suites/ValidateMixin.suite.d.ts.map +1 -1
  92. package/dist-types/components/form-core/test-suites/ValidateMixinFeedbackPart.suite.d.ts.map +1 -1
  93. package/dist-types/components/input-amount-dropdown/src/LionInputAmountDropdown.d.ts +0 -9
  94. package/dist-types/components/input-amount-dropdown/src/LionInputAmountDropdown.d.ts.map +1 -1
  95. package/dist-types/components/input-amount-dropdown/test/LionInputAmountDropdown.test.d.ts.map +1 -1
  96. package/dist-types/components/input-amount-dropdown/test-suites/LionInputAmountDropdown.suite.d.ts.map +1 -1
  97. package/dist-types/components/input-datepicker/src/LionInputDatepicker.d.ts +1 -1
  98. package/dist-types/components/input-datepicker/src/localizeNamespaceLoader.d.ts.map +1 -1
  99. package/dist-types/components/menu/index.d.ts +3 -0
  100. package/dist-types/components/menu/index.d.ts.map +1 -0
  101. package/dist-types/components/menu/lion-menu-overlay.d.ts +2 -0
  102. package/dist-types/components/menu/lion-menu-overlay.d.ts.map +1 -0
  103. package/dist-types/components/menu/lion-menu.d.ts +2 -0
  104. package/dist-types/components/menu/lion-menu.d.ts.map +1 -0
  105. package/dist-types/components/menu/lion-spinbutton.d.ts +2 -0
  106. package/dist-types/components/menu/lion-spinbutton.d.ts.map +1 -0
  107. package/dist-types/components/menu/lion-toolbar.d.ts +2 -0
  108. package/dist-types/components/menu/lion-toolbar.d.ts.map +1 -0
  109. package/dist-types/components/menu/lion-tree.d.ts +2 -0
  110. package/dist-types/components/menu/lion-tree.d.ts.map +1 -0
  111. package/dist-types/components/menu/src/InteractiveListMixin.d.ts +617 -0
  112. package/dist-types/components/menu/src/InteractiveListMixin.d.ts.map +1 -0
  113. package/dist-types/components/menu/src/LionMenu.d.ts +635 -0
  114. package/dist-types/components/menu/src/LionMenu.d.ts.map +1 -0
  115. package/dist-types/components/menu/src/LionMenuHybrid.d.ts +19 -0
  116. package/dist-types/components/menu/src/LionMenuHybrid.d.ts.map +1 -0
  117. package/dist-types/components/menu/src/LionMenuOverlay.d.ts +1015 -0
  118. package/dist-types/components/menu/src/LionMenuOverlay.d.ts.map +1 -0
  119. package/dist-types/components/menu/src/LionSpinbutton.d.ts +58 -0
  120. package/dist-types/components/menu/src/LionSpinbutton.d.ts.map +1 -0
  121. package/dist-types/components/menu/src/LionToolbar.d.ts +8 -0
  122. package/dist-types/components/menu/src/LionToolbar.d.ts.map +1 -0
  123. package/dist-types/components/menu/src/LionTree.d.ts +447 -0
  124. package/dist-types/components/menu/src/LionTree.d.ts.map +1 -0
  125. package/dist-types/components/menu/src/MoreButtonMenuMixin.d.ts +39 -0
  126. package/dist-types/components/menu/src/MoreButtonMenuMixin.d.ts.map +1 -0
  127. package/dist-types/components/menu/src/MultiLevelListMixin.d.ts +503 -0
  128. package/dist-types/components/menu/src/MultiLevelListMixin.d.ts.map +1 -0
  129. package/dist-types/components/menu/src/utils/isInView.d.ts +9 -0
  130. package/dist-types/components/menu/src/utils/isInView.d.ts.map +1 -0
  131. package/dist-types/components/menu/src/utils/listItemInteractions.d.ts +48 -0
  132. package/dist-types/components/menu/src/utils/listItemInteractions.d.ts.map +1 -0
  133. package/dist-types/components/menu/test/InteractiveListMixin.test.d.ts +2 -0
  134. package/dist-types/components/menu/test/InteractiveListMixin.test.d.ts.map +1 -0
  135. package/dist-types/components/menu/test/MoreButtonMenuMixin.test.d.ts +2 -0
  136. package/dist-types/components/menu/test/MoreButtonMenuMixin.test.d.ts.map +1 -0
  137. package/dist-types/components/menu/test/MultiLevelListMixin.test.d.ts +2 -0
  138. package/dist-types/components/menu/test/MultiLevelListMixin.test.d.ts.map +1 -0
  139. package/dist-types/components/menu/test/lion-menu-hybrid.test.d.ts +2 -0
  140. package/dist-types/components/menu/test/lion-menu-hybrid.test.d.ts.map +1 -0
  141. package/dist-types/components/menu/test/lion-menu.test.d.ts +2 -0
  142. package/dist-types/components/menu/test/lion-menu.test.d.ts.map +1 -0
  143. package/dist-types/components/menu/test/lion-toolbar.test.d.ts +2 -0
  144. package/dist-types/components/menu/test/lion-toolbar.test.d.ts.map +1 -0
  145. package/dist-types/components/menu/test/lion-tree.test.d.ts +2 -0
  146. package/dist-types/components/menu/test/lion-tree.test.d.ts.map +1 -0
  147. package/dist-types/components/menu/test-helpers/mimicKeyPress.d.ts +7 -0
  148. package/dist-types/components/menu/test-helpers/mimicKeyPress.d.ts.map +1 -0
  149. package/dist-types/components/menu/test-suites/InteractiveListMixin.suite.d.ts +14 -0
  150. package/dist-types/components/menu/test-suites/InteractiveListMixin.suite.d.ts.map +1 -0
  151. package/dist-types/components/menu/test-suites/LionMenu.suite.d.ts +9 -0
  152. package/dist-types/components/menu/test-suites/LionMenu.suite.d.ts.map +1 -0
  153. package/dist-types/components/menu/test-suites/LionMenuHybrid.suite.d.ts +5 -0
  154. package/dist-types/components/menu/test-suites/LionMenuHybrid.suite.d.ts.map +1 -0
  155. package/dist-types/components/menu/test-suites/MoreButtonMenuMixin.suite.d.ts +14 -0
  156. package/dist-types/components/menu/test-suites/MoreButtonMenuMixin.suite.d.ts.map +1 -0
  157. package/dist-types/components/menu/test-suites/MultiLevelListMixin.suite.d.ts +11 -0
  158. package/dist-types/components/menu/test-suites/MultiLevelListMixin.suite.d.ts.map +1 -0
  159. package/dist-types/components/navigation-bar/src/LionNavigationBar.d.ts +238 -0
  160. package/dist-types/components/navigation-bar/src/LionNavigationBar.d.ts.map +1 -0
  161. package/dist-types/components/navigation-bar/src/types.d.ts +85 -0
  162. package/dist-types/components/navigation-bar/src/types.d.ts.map +1 -0
  163. package/dist-types/components/overlays/src/OverlayController.d.ts +24 -12
  164. package/dist-types/components/overlays/src/OverlayController.d.ts.map +1 -1
  165. package/dist-types/components/overlays/src/OverlayMixin.d.ts.map +1 -1
  166. package/dist-types/components/overlays/src/configurations/visibility-trigger-partials/withHoverInteraction.d.ts +8 -2
  167. package/dist-types/components/overlays/src/configurations/visibility-trigger-partials/withHoverInteraction.d.ts.map +1 -1
  168. package/dist-types/components/overlays/src/utils/get-focusable-elements.d.ts.map +1 -1
  169. package/dist-types/components/overlays/src/utils/is-equal-config.d.ts.map +1 -1
  170. package/dist-types/components/overlays/test/withHoverInteraction.test.d.ts +2 -0
  171. package/dist-types/components/overlays/test/withHoverInteraction.test.d.ts.map +1 -0
  172. package/dist-types/components/overlays/types/ArrowMixinTypes.d.ts.map +1 -1
  173. package/dist-types/components/overlays/types/OverlayConfig.d.ts +12 -2
  174. package/dist-types/components/overlays/types/OverlayConfig.d.ts.map +1 -1
  175. package/dist-types/components/overlays/types/OverlayMixinTypes.d.ts +1 -0
  176. package/dist-types/components/overlays/types/OverlayMixinTypes.d.ts.map +1 -1
  177. package/dist-types/components/select-rich/src/LionSelectRich.d.ts +11 -3
  178. package/dist-types/components/select-rich/src/LionSelectRich.d.ts.map +1 -1
  179. package/dist-types/components/tooltip/src/LionTooltip.d.ts +1 -1
  180. package/dist-types/exports/define/lion-item.d.ts +2 -0
  181. package/dist-types/exports/define/lion-item.d.ts.map +1 -0
  182. package/dist-types/exports/define/lion-menu-overlay.d.ts +2 -0
  183. package/dist-types/exports/define/lion-menu-overlay.d.ts.map +1 -0
  184. package/dist-types/exports/define/lion-menu.d.ts +2 -0
  185. package/dist-types/exports/define/lion-menu.d.ts.map +1 -0
  186. package/dist-types/exports/define/lion-navigation-bar.d.ts +2 -0
  187. package/dist-types/exports/define/lion-navigation-bar.d.ts.map +1 -0
  188. package/dist-types/exports/define/lion-toolbar.d.ts +2 -0
  189. package/dist-types/exports/define/lion-toolbar.d.ts.map +1 -0
  190. package/dist-types/exports/define/lion-tree.d.ts +2 -0
  191. package/dist-types/exports/define/lion-tree.d.ts.map +1 -0
  192. package/dist-types/exports/menu-test-suites.d.ts +4 -0
  193. package/dist-types/exports/menu-test-suites.d.ts.map +1 -0
  194. package/dist-types/exports/menu.d.ts +7 -0
  195. package/dist-types/exports/menu.d.ts.map +1 -0
  196. package/dist-types/exports/navigation-bar.d.ts +2 -0
  197. package/dist-types/exports/navigation-bar.d.ts.map +1 -0
  198. package/dist-types/exports/overlays.d.ts +3 -0
  199. package/dist-types/exports/overlays.d.ts.map +1 -1
  200. package/dist-types/tsconfig.tsbuildinfo +1 -1
  201. package/docs/components/checkbox-group/overview.md +2 -2
  202. package/docs/components/collapsible/overview.md +1 -1
  203. package/docs/components/combobox/api-table.md +21 -8
  204. package/docs/components/combobox/overview.md +1 -1
  205. package/docs/components/combobox/use-cases.md +1 -1
  206. package/docs/components/dialog/api-table.md +31 -6
  207. package/docs/components/dialog/overview.md +1 -1
  208. package/docs/components/fieldset/overview.md +5 -5
  209. package/docs/components/form/overview.md +3 -3
  210. package/docs/components/form/use-cases.md +2 -2
  211. package/docs/components/icon/use-cases.md +1 -1
  212. package/docs/components/input/overview.md +1 -1
  213. package/docs/components/input-amount/overview.md +3 -3
  214. package/docs/components/input-amount-dropdown/api-table.md +1 -1
  215. package/docs/components/input-date/overview.md +3 -3
  216. package/docs/components/input-datepicker/api-table.md +21 -4
  217. package/docs/components/input-datepicker/overview.md +5 -5
  218. package/docs/components/input-email/overview.md +2 -2
  219. package/docs/components/input-file/overview.md +1 -1
  220. package/docs/components/input-iban/overview.md +2 -2
  221. package/docs/components/input-range/overview.md +2 -2
  222. package/docs/components/input-stepper/overview.md +1 -1
  223. package/docs/components/input-tel/overview.md +1 -1
  224. package/docs/components/input-tel/use-cases.md +6 -6
  225. package/docs/components/input-tel-dropdown/overview.md +1 -1
  226. package/docs/components/listbox/use-cases.md +1 -1
  227. package/docs/components/menu/api-table.md +460 -0
  228. package/docs/components/menu/applyMenuDemoStyles.js +173 -0
  229. package/docs/components/menu/extensions.md +262 -0
  230. package/docs/components/menu/index.md +13 -0
  231. package/docs/components/menu/overview.md +422 -0
  232. package/docs/components/menu/use-cases.md +77 -0
  233. package/docs/components/radio-group/overview.md +3 -3
  234. package/docs/components/select/use-cases.md +1 -1
  235. package/docs/components/select-rich/api-table.md +21 -5
  236. package/docs/components/select-rich/use-cases.md +2 -2
  237. package/docs/components/tabs/examples.md +1 -1
  238. package/docs/components/tooltip/api-table.md +36 -11
  239. package/docs/components/tooltip/use-cases.md +22 -0
  240. package/docs/fundamentals/index.md +4 -4
  241. package/docs/fundamentals/node-tools/publish-docs/overview.md +3 -3
  242. package/docs/fundamentals/node-tools/rocket-preset-extend-lion-docs/overview.md +2 -2
  243. package/docs/fundamentals/rationales/accessibility.md +1 -1
  244. package/docs/fundamentals/systems/core/SlotMixin.md +1 -1
  245. package/docs/fundamentals/systems/core/overview.md +1 -1
  246. package/docs/fundamentals/systems/form/formatting-and-parsing.md +4 -4
  247. package/docs/fundamentals/systems/form/model-value.md +1 -1
  248. package/docs/fundamentals/systems/form/overview.md +28 -28
  249. package/docs/fundamentals/systems/form/validate.md +2 -2
  250. package/docs/fundamentals/systems/localize/overview.md +4 -4
  251. package/docs/fundamentals/systems/overlays/api-table.md +36 -34
  252. package/docs/fundamentals/systems/overlays/configuration.md +2 -2
  253. package/docs/fundamentals/systems/overlays/overview.md +5 -5
  254. package/docs/fundamentals/systems/overlays/use-cases.md +2 -2
  255. package/docs/fundamentals/tools/helpers/overview.md +1 -1
  256. package/docs/fundamentals/tools/singleton-manager/overview.md +4 -4
  257. package/docs/guides/how-to/create-a-custom-field.md +5 -5
  258. package/docs/guides/how-to/create-a-form.md +4 -4
  259. package/docs/guides/how-to/extend-a-native-input.md +2 -2
  260. package/docs/guides/how-to/index.md +1 -1
  261. package/docs/guides/index.md +8 -8
  262. package/docs/guides/principles/index.md +5 -5
  263. package/docs/guides/principles/styling.md +1 -1
  264. package/exports/collapsible.js +1 -0
  265. package/exports/define/lion-item.js +3 -0
  266. package/exports/define/lion-menu-overlay.js +3 -0
  267. package/exports/define/lion-menu.js +3 -0
  268. package/exports/define/lion-navigation-bar.js +3 -0
  269. package/exports/define/lion-toolbar.js +3 -0
  270. package/exports/define/lion-tree.js +3 -0
  271. package/exports/menu-test-suites.js +4 -0
  272. package/exports/menu.js +7 -0
  273. package/exports/navigation-bar.js +1 -0
  274. package/exports/overlays.js +6 -0
  275. package/menu-test-suites.js +4 -0
  276. package/menu.js +7 -0
  277. package/navigation-bar.js +1 -0
  278. package/overlays.js +6 -0
  279. package/package.json +1 -1
@@ -0,0 +1,94 @@
1
+ /* eslint-disable import/no-extraneous-dependencies */
2
+ import { LionMenu } from './LionMenu.js';
3
+ import { setChecked, toggleChecked } from './utils/listItemInteractions.js';
4
+
5
+ /**
6
+ * @typedef {import('../types/InteractiveListMixinTypes.js').InteractiveListItemRole} InteractiveListItemRole
7
+ */
8
+
9
+ export class LionToolbar extends LionMenu {
10
+ constructor() {
11
+ super();
12
+
13
+ this._listRole = 'toolbar';
14
+ this.bar = true;
15
+ }
16
+
17
+ /**
18
+ * Allows groups ([role=radiogroup|checkboxgroup]) within one level.
19
+ * In case we deal with [role=checkbox], we treat it as multiple choice group
20
+ * @override InteractiveListMixin
21
+ * @param {number} index
22
+ */
23
+ setCheckedIndex(index) {
24
+ const item = this.listItems[index];
25
+ if (item) {
26
+ // @ts-ignore - InteractiveListItemRole type
27
+ const role = /** @type {InteractiveListItemRole} */ (item.getAttribute('role'));
28
+ let listItemsWithinGroup = this.listItems;
29
+ let multiple = this.multipleChoice;
30
+ if (role === 'radio' || role === 'checkbox') {
31
+ /**
32
+ * If index = 1 (radio 'Red'), closest group will be div[role=radiogroup]
33
+ * @example
34
+ * <lion-toolbar>
35
+ * <div role="radiogroup" aria-label="Text Color">
36
+ * <button role="radio" aria-checked="false">Blue</button>
37
+ * <button role="radio" aria-checked="true">Red</button>
38
+ * <button role="radio" aria-checked="false">Green</button>
39
+ * </div>
40
+ * <div role="separator"></div>
41
+ * <div role="checkboxgroup" aria-label="Text Color">
42
+ * <button role="checkbox" aria-checked="false">Blue</button>
43
+ * <button role="checkbox" aria-checked="true">Red</button>
44
+ * <button role="checkbox" aria-checked="false">Green</button>
45
+ * </div>
46
+ * </lion-toolbar>
47
+ */
48
+ let closestGroup;
49
+ if (role === 'radio') {
50
+ closestGroup = item.closest('[role="radiogroup"]');
51
+ } else if (role === 'checkbox') {
52
+ closestGroup = item.closest('[role="checkboxgroup"]');
53
+ }
54
+
55
+ const group = closestGroup && this.contains(closestGroup) ? closestGroup : this;
56
+ listItemsWithinGroup = this.listItems.filter(listItem => group.contains(listItem));
57
+ multiple = role === 'checkbox';
58
+ }
59
+
60
+ if (!multiple) {
61
+ // Uncheck all
62
+ listItemsWithinGroup.forEach(listItem => {
63
+ setChecked(listItem, true);
64
+ });
65
+ setChecked(this.listItems[index]);
66
+ } else {
67
+ toggleChecked(this.listItems[index]);
68
+ }
69
+ }
70
+ }
71
+
72
+ /**
73
+ * @param {*} newItems
74
+ */
75
+ _initListItems(newItems) {
76
+ super._initListItems(newItems);
77
+
78
+ // @ts-ignore - forEach parameter
79
+ newItems.forEach(item => {
80
+ if (
81
+ item.getAttribute('role') === 'button' ||
82
+ (item.tagName === 'BUTTON' && !item.hasAttribute('role'))
83
+ ) {
84
+ const initialAriaPressed = item.getAttribute('aria-pressed');
85
+ item.setAttribute('aria-pressed', initialAriaPressed || 'false');
86
+
87
+ item.addEventListener('click', () => {
88
+ const ariaPressed = item.getAttribute('aria-pressed') === 'true';
89
+ item.setAttribute('aria-pressed', `${!ariaPressed}`);
90
+ });
91
+ }
92
+ });
93
+ }
94
+ }
@@ -0,0 +1,52 @@
1
+ /* eslint-disable import/no-extraneous-dependencies */
2
+ import { LitElement } from 'lit';
3
+ import { MultiLevelListMixin } from './MultiLevelListMixin.js';
4
+
5
+ // @ts-ignore - class extension with mixin
6
+ export class LionTree extends MultiLevelListMixin(LitElement) {
7
+ constructor() {
8
+ super();
9
+
10
+ /** @configure InteractiveListMixin */
11
+ this._listRole = 'tree';
12
+ /** @configure InteractiveListMixin */
13
+ this._activateOnTypedChars = true;
14
+ /** @configure DisclosureMixin */
15
+ this.invokerInteraction = 'click';
16
+ }
17
+
18
+ /**
19
+ * @param {*} changedProperties
20
+ */
21
+ updated(changedProperties) {
22
+ super.updated(changedProperties);
23
+
24
+ if (changedProperties.has('level')) {
25
+ if (this.level > 1) {
26
+ this._listNode.setAttribute('role', 'group');
27
+ }
28
+ this.__setAriaLevelForListItems();
29
+ }
30
+ }
31
+
32
+ /**
33
+ * @param {*} newItems
34
+ */
35
+ _initListItems(newItems) {
36
+ // @ts-ignore - parameter types
37
+ super._initListItems(newItems);
38
+
39
+ this.__setAriaLevelForListItems();
40
+ // @ts-ignore - forEach parameters
41
+ newItems.forEach((item, index) => {
42
+ item.setAttribute('aria-posinset', `${index + 1}`);
43
+ item.setAttribute('aria-setsize', `${this.listItems.length}`);
44
+ });
45
+ }
46
+
47
+ __setAriaLevelForListItems() {
48
+ this.listItems.forEach(item => {
49
+ item.setAttribute?.('aria-level', `${this.level + 1}`);
50
+ });
51
+ }
52
+ }
@@ -0,0 +1,278 @@
1
+ // eslint-disable-next-line import/no-extraneous-dependencies
2
+ import { css } from 'lit';
3
+
4
+ const styles = css`
5
+ /** More button is hidden by default */
6
+ [data-more-button-wrapper] {
7
+ display: none;
8
+ }
9
+
10
+ [data-more-button-menu][data-open]:not(:has([role='listitem'] [aria-expanded='true'])) {
11
+ position: absolute;
12
+ overflow: visible;
13
+ height: auto;
14
+ width: auto;
15
+ top: 100%;
16
+ }
17
+
18
+ /** N.B. this is a simplified version of sr-only. when we move to overlayctrl, we should build this into overlayctrl */
19
+ [data-more-button-menu] {
20
+ overflow: hidden;
21
+ height: 0;
22
+ width: 0;
23
+ }
24
+
25
+ [role='list']:has(> [data-more-button-wrapper]) > [role='listitem'] > :is(button, a) {
26
+ white-space: nowrap;
27
+ }
28
+ `;
29
+
30
+ // @ts-ignore - JS mixin typing
31
+ export const MoreButtonMenuMixin = superclass =>
32
+ class MoreButtonMenuMixinClass extends superclass {
33
+ constructor() {
34
+ super();
35
+ this.__resizeTimeout = null;
36
+ this.isMoreButtonShown = null;
37
+ this.handleResize = this.handleResize.bind(this);
38
+ }
39
+
40
+ disconnectedCallback() {
41
+ window.removeEventListener('resize', this.handleResize);
42
+ if (this.__resizeTimeout) {
43
+ clearTimeout(this.__resizeTimeout);
44
+ }
45
+ super.disconnectedCallback?.();
46
+ }
47
+
48
+ _initMoreButtonMenu() {
49
+ this._createMoreButtonWrapper();
50
+ window.addEventListener('resize', this.handleResize);
51
+ this.handleResize();
52
+ }
53
+
54
+ // eslint-disable-next-line class-methods-use-this
55
+ _getDeepActiveElement() {
56
+ let host = document.activeElement || document.body;
57
+ while (host?.shadowRoot?.activeElement) {
58
+ host = host.shadowRoot.activeElement;
59
+ }
60
+ return host;
61
+ }
62
+
63
+ _createMoreButtonWrapper() {
64
+ const moreButtonWrapper = document.createElement('div');
65
+ const style = document.createElement('style');
66
+ style.textContent = styles.cssText;
67
+ moreButtonWrapper.appendChild(style);
68
+ moreButtonWrapper.setAttribute('data-more-button-wrapper', '');
69
+ [...this.getMoreButtonSlotProjection().childNodes].forEach(node =>
70
+ moreButtonWrapper.appendChild(node),
71
+ );
72
+ const moreButton = moreButtonWrapper.querySelector('button');
73
+ moreButton?.setAttribute('data-more-button', '');
74
+ moreButton?.setAttribute('tabindex', '-1');
75
+ moreButton?.setAttribute('aria-expanded', 'false');
76
+ const moreButtonMenu = document.createElement('div');
77
+ moreButtonMenu.setAttribute('data-more-button-menu', '');
78
+ moreButtonMenu.setAttribute('tabindex', '-1');
79
+ moreButtonWrapper.appendChild(moreButtonMenu);
80
+ this._listNode.appendChild(moreButtonWrapper);
81
+
82
+ const isElementDirectFocusableItemUnderMoreButtonMenu = (/** @type {Element} */ element) =>
83
+ (this.listItems.includes(element) && moreButtonMenu.contains(element)) ||
84
+ element === moreButtonMenu;
85
+
86
+ moreButtonMenu.addEventListener(
87
+ 'focusin',
88
+ /** @type {FocusEvent} */ event => {
89
+ const target = /** @type {HTMLElement} */ (event?.target);
90
+ if (!isElementDirectFocusableItemUnderMoreButtonMenu(target)) return;
91
+
92
+ // If applicable hide any other L2 menus
93
+ this.querySelector('[level="2"]:has([data-open])')?._overlayCtrl?.hide();
94
+
95
+ // A user did `Shift + Tab` from L2 menu to More menu
96
+ if (target?.getAttribute('aria-expanded') === 'true') {
97
+ // close L2 menu
98
+ target?.click();
99
+ }
100
+ moreButton?.setAttribute('aria-expanded', 'true');
101
+ moreButtonMenu.setAttribute('data-open', '');
102
+ },
103
+ );
104
+
105
+ moreButtonMenu.addEventListener('focusout', () => {
106
+ // We need this timeout for Safari/WebKit.
107
+ // Unfortunately, an in progress click gets canceled when overflow:hidden is applied.
108
+ // Although mousedown would work instead, the consuming developer should have the freedom to apply all possible interaction pattterns.
109
+ // Especially, we should be compatible with 'withClickInteraction'
110
+ setTimeout(() => {
111
+ if (isElementDirectFocusableItemUnderMoreButtonMenu(this._getDeepActiveElement())) return;
112
+ moreButton?.setAttribute('aria-expanded', 'false');
113
+
114
+ moreButtonMenu.removeAttribute('data-open');
115
+ }, 100);
116
+ });
117
+
118
+ moreButton?.addEventListener('click', () => {
119
+ if (moreButtonMenu.getAttribute('data-open') === null) {
120
+ moreButtonMenu?.focus({ preventScroll: true });
121
+ moreButtonMenu.setAttribute('data-open', '');
122
+ }
123
+ });
124
+ }
125
+
126
+ getMoreButtonSlotProjection() {
127
+ return this.querySelector('[slot="more-button"]');
128
+ }
129
+
130
+ getMoreButtonMenu() {
131
+ return this.querySelector('[data-more-button-menu]');
132
+ }
133
+
134
+ getMoreButtonMenuWrapper() {
135
+ return this.querySelector('[data-more-button-wrapper]');
136
+ }
137
+
138
+ displayMoreButton() {
139
+ this.getMoreButtonMenuWrapper().style.display = 'block';
140
+ this.isMoreButtonShown = true;
141
+ }
142
+
143
+ hideMoreButton() {
144
+ this.getMoreButtonMenuWrapper().style.display = 'none';
145
+ this.isMoreButtonShown = false;
146
+ }
147
+
148
+ doItemsFit() {
149
+ this.style.display = 'none';
150
+ const parentWidth = this.parentElement.clientWidth;
151
+ this.style.display = '';
152
+ return (
153
+ this._listNode.scrollWidth === this._listNode.clientWidth &&
154
+ this._listNode.scrollWidth <= parentWidth
155
+ );
156
+ }
157
+
158
+ getListItems() {
159
+ const listNode = this._listNode;
160
+ return Array.from(listNode.querySelectorAll(':scope > [role="listitem"]'));
161
+ }
162
+
163
+ /**
164
+ * @param {Node} listItem
165
+ */
166
+ getListItemWithAdjacentNodes = listItem => {
167
+ const markerNodeType = this.nodeType && Node.COMMENT_NODE;
168
+ /** @param {Node | null | undefined} node */
169
+ const isMarkerComment = node => node?.nodeType === markerNodeType && node?.nodeValue === '';
170
+
171
+ const previousNodes = [];
172
+ let { previousSibling } = listItem;
173
+ while (previousSibling) {
174
+ if (previousSibling.nodeType === Node.ELEMENT_NODE) {
175
+ break;
176
+ }
177
+ previousNodes.unshift(previousSibling);
178
+ if (isMarkerComment(previousSibling)) {
179
+ break;
180
+ }
181
+ ({ previousSibling } = previousSibling);
182
+ }
183
+
184
+ const nextNodes = [];
185
+ let { nextSibling } = listItem;
186
+ while (nextSibling) {
187
+ if (nextSibling.nodeType === Node.ELEMENT_NODE) {
188
+ break;
189
+ }
190
+ nextNodes.push(nextSibling);
191
+
192
+ if (isMarkerComment(nextSibling)) {
193
+ break;
194
+ }
195
+
196
+ ({ nextSibling } = nextSibling);
197
+ }
198
+
199
+ const fragment = document.createDocumentFragment();
200
+ const nodes = [...previousNodes, listItem, ...nextNodes];
201
+ nodes.forEach(node => fragment.appendChild(node));
202
+ return fragment;
203
+ };
204
+
205
+ /**
206
+ * @param {{ moreButtonMenuElement: HTMLButtonElement, listItem: HTMLElement }} opts
207
+ */
208
+ moveItemToMoreButtonMenuFromMainMenu({ moreButtonMenuElement, listItem }) {
209
+ const fragment = this.getListItemWithAdjacentNodes(listItem);
210
+ moreButtonMenuElement.prepend(fragment);
211
+ // eslint-disable-next-line no-param-reassign
212
+ listItem.style.display = '';
213
+ this.displayMoreButton();
214
+ }
215
+
216
+ moveAllItemsToMainMenuFromMoreButtonMenu() {
217
+ const moreButtonMenu = this.getMoreButtonMenu();
218
+ const moreButtonMenuWrapper = this.getMoreButtonMenuWrapper();
219
+ if (moreButtonMenu.childNodes.length === 0) {
220
+ return;
221
+ }
222
+ [...moreButtonMenu.childNodes].forEach(node => {
223
+ moreButtonMenuWrapper.before(node);
224
+ });
225
+ }
226
+
227
+ renderAllItemsInMainMenu() {
228
+ this.moveAllItemsToMainMenuFromMoreButtonMenu();
229
+ }
230
+
231
+ hideItemsOneByOneInMainMenuUntilTheyFit() {
232
+ let hiddenItemsCount = 0;
233
+ const mainMenuItems = this.getListItems();
234
+ for (let i = mainMenuItems.length - 1; i >= 0 && !this.doItemsFit(); i -= 1) {
235
+ mainMenuItems[i].style.display = 'none';
236
+ hiddenItemsCount += 1;
237
+ }
238
+ return hiddenItemsCount;
239
+ }
240
+
241
+ /**
242
+ * @param {number} hiddenItemsCount
243
+ */
244
+ moveHiddenItemsFromMainMenuToMoreButtonMenu(hiddenItemsCount) {
245
+ const moreButtonMenuElement = this.getMoreButtonMenu();
246
+ const listItems = this._listNode.querySelectorAll(':scope > [role="listitem"]');
247
+ for (let i = 0; i < hiddenItemsCount; i += 1) {
248
+ const listItem = listItems[listItems.length - 1 - i];
249
+ this.moveItemToMoreButtonMenuFromMainMenu({ moreButtonMenuElement, listItem });
250
+ }
251
+ }
252
+
253
+ handleResize() {
254
+ if (this.__resizeTimeout) {
255
+ return;
256
+ }
257
+
258
+ this.style.visibility = 'hidden';
259
+
260
+ this.__resizeTimeout = setTimeout(() => {
261
+ this.__resizeTimeout = null;
262
+
263
+ this.renderAllItemsInMainMenu();
264
+ this.hideMoreButton();
265
+
266
+ if (this.doItemsFit()) {
267
+ this.style.visibility = '';
268
+ return;
269
+ }
270
+
271
+ this.style.visibility = 'hidden';
272
+ this.displayMoreButton();
273
+ const hiddenItemsCount = this.hideItemsOneByOneInMainMenuUntilTheyFit();
274
+ this.moveHiddenItemsFromMainMenuToMoreButtonMenu(hiddenItemsCount);
275
+ this.style.visibility = '';
276
+ }, 50);
277
+ }
278
+ };